CLOUDSTACK-6170 (VMware root-disk support for managed storage)

This commit is contained in:
Mike Tutkowski 2014-04-17 12:55:19 -06:00
parent 4620c27ebf
commit c0910cbdb9
5 changed files with 406 additions and 777 deletions

View File

@ -19,8 +19,6 @@ package com.cloud.storage.resource;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
@ -33,6 +31,4 @@ public interface StoragePoolResource {
Answer execute(DestroyCommand cmd);
CopyVolumeAnswer execute(CopyVolumeCommand cmd);
CreateAnswer execute(CreateCommand cmd);
}

View File

@ -16,10 +16,6 @@
// under the License.
package com.cloud.hypervisor.vmware.manager;
import java.util.List;
import com.vmware.vim25.ManagedObjectReference;
import com.cloud.agent.api.Command;
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
import com.cloud.hypervisor.vmware.util.VmwareContext;
@ -32,16 +28,4 @@ public interface VmwareHostService {
VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd);
String getWorkerName(VmwareContext context, Command cmd, int workerSequence);
ManagedObjectReference prepareManagedDatastore(VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret) throws Exception;
ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String volumeName, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception;
void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception;
void removeManagedTargetsFromCluster(List<String> managedIqns) throws Exception;
}

View File

@ -38,9 +38,6 @@ import java.util.Random;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
@ -62,14 +59,6 @@ import com.vmware.vim25.DynamicProperty;
import com.vmware.vim25.HostCapability;
import com.vmware.vim25.HostHostBusAdapter;
import com.vmware.vim25.HostInternetScsiHba;
import com.vmware.vim25.HostInternetScsiHbaAuthenticationProperties;
import com.vmware.vim25.HostInternetScsiHbaStaticTarget;
import com.vmware.vim25.HostInternetScsiTargetTransport;
import com.vmware.vim25.HostScsiDisk;
import com.vmware.vim25.HostScsiTopology;
import com.vmware.vim25.HostScsiTopologyInterface;
import com.vmware.vim25.HostScsiTopologyLun;
import com.vmware.vim25.HostScsiTopologyTarget;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.ObjectContent;
import com.vmware.vim25.OptionValue;
@ -109,8 +98,6 @@ import org.apache.cloudstack.storage.to.VolumeObjectTO;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.AttachIsoCommand;
import com.cloud.agent.api.AttachVolumeAnswer;
import com.cloud.agent.api.AttachVolumeCommand;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.BackupSnapshotCommand;
import com.cloud.agent.api.CheckHealthAnswer;
@ -202,8 +189,6 @@ import com.cloud.agent.api.routing.SetNetworkACLCommand;
import com.cloud.agent.api.routing.SetSourceNatCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.MigrateVolumeAnswer;
@ -240,7 +225,6 @@ import com.cloud.hypervisor.vmware.mo.DatastoreFile;
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
import com.cloud.hypervisor.vmware.mo.DiskControllerType;
import com.cloud.hypervisor.vmware.mo.FeatureKeyConstants;
import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO;
import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
@ -276,7 +260,6 @@ import com.cloud.utils.DateUtil;
import com.cloud.utils.ExecutionResult;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.Ternary;
import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException;
@ -285,7 +268,6 @@ import com.cloud.utils.mgmt.JmxUtil;
import com.cloud.utils.mgmt.PropertyMapDynamicBean;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.ssh.SshHelper;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.PowerState;
import com.cloud.vm.VirtualMachine.State;
@ -340,6 +322,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
protected volatile long _cmdSequence = 1;
protected StorageSubsystemCommandHandler storageHandler;
private VmwareStorageProcessor _storageProcessor;
protected VirtualRoutingResource _vrResource;
@ -390,9 +373,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
mbean.addProp("Name", cmd.getClass().getSimpleName());
Class<? extends Command> clz = cmd.getClass();
if (clz == CreateCommand.class) {
answer = execute((CreateCommand)cmd);
} else if (cmd instanceof NetworkElementCommand) {
if (cmd instanceof NetworkElementCommand) {
return _vrResource.executeRequest((NetworkElementCommand)cmd);
} else if (clz == ReadyCommand.class) {
answer = execute((ReadyCommand)cmd);
@ -430,8 +411,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
answer = execute((DeleteStoragePoolCommand)cmd);
} else if (clz == CopyVolumeCommand.class) {
answer = execute((CopyVolumeCommand)cmd);
} else if (clz == AttachVolumeCommand.class) {
answer = execute((AttachVolumeCommand)cmd);
} else if (clz == AttachIsoCommand.class) {
answer = execute((AttachIsoCommand)cmd);
} else if (clz == ValidateSnapshotCommand.class) {
@ -1160,88 +1139,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return new ExecutionResult(true, null);
}
private ExecutionResult NetworkElementCommandnup(IpAssocCommand cmd) {
VmwareContext context = getServiceContext();
try {
VmwareHypervisorHost hyperHost = getHyperHost(context);
IpAddressTO[] ips = cmd.getIpAddresses();
String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
VmwareResource.getRouterSshControlIp(cmd);
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(routerName);
// command may sometimes be redirect to a wrong host, we relax
// the check and will try to find it within cluster
if (vmMo == null) {
if (hyperHost instanceof HostMO) {
ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO)hyperHost).getParentMor());
vmMo = clusterMo.findVmOnHyperHost(routerName);
}
}
if (vmMo == null) {
String msg = "Router " + routerName + " no longer exists to execute IPAssoc command";
s_logger.error(msg);
throw new Exception(msg);
}
for (IpAddressTO ip : ips) {
/**
* TODO support other networks
*/
URI broadcastUri = BroadcastDomainType.fromString(ip.getBroadcastUri());
if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) {
throw new InternalErrorException("Unable to assign a public IP to a VIF on network " + ip.getBroadcastUri());
}
String vlanId = BroadcastDomainType.getValue(broadcastUri);
String publicNeworkName = HypervisorHostHelper.getPublicNetworkNamePrefix(vlanId);
Pair<Integer, VirtualDevice> publicNicInfo = vmMo.getNicDeviceIndex(publicNeworkName);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Find public NIC index, public network name: " + publicNeworkName + ", index: " + publicNicInfo.first());
}
boolean removeVif = false;
if (!ip.isAdd() && ip.isFirstIP()) {
removeVif = true;
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unplug NIC " + publicNicInfo.first());
}
}
if (publicNicInfo.first().intValue() < 0) {
String msg = "Failed to find DomR VIF to associate/disassociate IP with.";
s_logger.error(msg);
throw new InternalErrorException(msg);
}
if (removeVif) {
String nicMasksStr = vmMo.getCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK);
int nicMasks = Integer.parseInt(nicMasksStr);
nicMasks &= ~(1 << publicNicInfo.first().intValue());
vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, String.valueOf(nicMasks));
HostMO hostMo = vmMo.getRunningHost();
List<NetworkDetails> networks = vmMo.getNetworksWithDetails();
for (NetworkDetails netDetails : networks) {
if (netDetails.getGCTag() != null && netDetails.getGCTag().equalsIgnoreCase("true")) {
if (netDetails.getVMMorsOnNetwork() == null || netDetails.getVMMorsOnNetwork().length == 1) {
cleanupNetwork(hostMo, netDetails);
}
}
}
}
}
} catch (Throwable e) {
s_logger.error("Unexpected exception: " + e.toString() + " will shortcut rest of IPAssoc commands", e);
return new ExecutionResult(false, e.toString());
}
return new ExecutionResult(true, null);
}
@Override
public ExecutionResult executeInVR(String routerIP, String script, String args) {
return executeInVR(routerIP, script, args, 120);
@ -1824,32 +1721,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
vmMo.ensureScsiDeviceController();
}
@Override
public ManagedObjectReference prepareManagedDatastore(VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret) throws Exception {
return getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort,
VmwareResource.trimIqn(iScsiName), chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
}
@Override
public ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String volumeName, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception {
ManagedObjectReference morDs = prepareManagedDatastore(hyperHost, iScsiName, storageHost, storagePort,
chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
DatastoreMO dsMo = new DatastoreMO(getServiceContext(null), morDs);
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeName != null ? volumeName : dsMo.getName());
if (!dsMo.fileExists(volumeDatastorePath)) {
createVmdk(cmd, dsMo, volumeDatastorePath, size);
}
return morDs;
}
int getReservedMemoryMb(VirtualMachineTO vmSpec) {
if (vmSpec.getDetails().get(Config.VmwareReserveMem.key()).equalsIgnoreCase("true")) {
return (int)(vmSpec.getMinRam() / (1024 * 1024));
@ -2348,7 +2219,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
// if the datastore is not present, we need to discover the iSCSI device that will support it,
// create the datastore, and create a VMDK file in the datastore
if (morDatastore == null) {
morDatastore = prepareManagedStorage(hyperHost, iScsiName,
morDatastore = _storageProcessor.prepareManagedStorage(context, hyperHost, iScsiName,
details.get(DiskTO.STORAGE_HOST), Integer.parseInt(details.get(DiskTO.STORAGE_PORT)),
volumeTO.getVolumeType() == Volume.Type.ROOT ? volumeTO.getName() : null,
details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET),
@ -3383,404 +3254,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return str.replace('/', '-');
}
private static String trimIqn(String iqn) {
String[] tmp = iqn.split("/");
if (tmp.length != 3) {
String msg = "Wrong format for iScsi path: " + iqn + ". It should be formatted as '/targetIQN/LUN'.";
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
return tmp[1].trim();
}
private void createVmdk(Command cmd, DatastoreMO dsMo, String vmdkDatastorePath, Long volumeSize) throws Exception {
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
String dummyVmName = getWorkerName(context, cmd, 0);
VirtualMachineMO vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
if (vmMo == null) {
throw new Exception("Unable to create a dummy VM for volume creation");
}
Long volumeSizeToUse = volumeSize < dsMo.getSummary().getFreeSpace() ? volumeSize : dsMo.getSummary().getFreeSpace();
vmMo.createDisk(vmdkDatastorePath, getMBsFromBytes(volumeSizeToUse), dsMo.getMor(), vmMo.getScsiDeviceControllerKey());
vmMo.detachDisk(vmdkDatastorePath, false);
vmMo.destroy();
}
@Override
public void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception {
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
deleteVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iqn), storageHost, storagePort, VmwareResource.trimIqn(iqn));
}
protected Answer execute(AttachVolumeCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource AttachVolumeCommand: " + _gson.toJson(cmd));
}
/*
* AttachVolumeCommand { "attach":true,"vmName":"i-2-1-KY","pooltype":"NetworkFilesystem",
* "volumeFolder":"/export/home/kelven/vmware-test/primary", "volumePath":"uuid",
* "volumeName":"volume name","deviceId":1 }
*/
try {
VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
if (vmMo == null) {
String msg = "Unable to find the VM to execute AttachVolumeCommand, vmName: " + cmd.getVmName();
s_logger.error(msg);
throw new Exception(msg);
}
ManagedObjectReference morDs = null;
if (cmd.getAttach() && cmd.isManaged()) {
morDs = prepareManagedStorage(hyperHost, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort(), null,
cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(),
cmd.getChapTargetUsername(), cmd.getChapTargetPassword(), cmd.getVolumeSize(), cmd);
}
else {
morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
}
if (morDs == null) {
String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + cmd.getVmName();
s_logger.error(msg);
throw new Exception(msg);
}
DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs);
String datastoreVolumePath = null;
if (cmd.isManaged()) {
datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
} else {
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), cmd.getVmName(), dsMo, cmd.getVolumePath());
datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
}
assert (datastoreVolumePath != null) : "Virtual disk file must exist in specified datastore for attach/detach operations.";
if (datastoreVolumePath == null) {
throw new CloudRuntimeException("Unable to find file " + cmd.getVolumePath() + ".vmdk in datastore " + dsMo.getName());
}
AttachVolumeAnswer answer = new AttachVolumeAnswer(cmd, cmd.getDeviceId(), datastoreVolumePath);
if (cmd.getAttach()) {
vmMo.attachDisk(new String[] {datastoreVolumePath}, morDs);
} else {
vmMo.removeAllSnapshots();
vmMo.detachDisk(datastoreVolumePath, false);
if (cmd.isManaged()) {
handleDatastoreAndVmdkDetach(cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort());
} else {
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, cmd.getVolumePath());
}
}
return answer;
} catch (Throwable e) {
if (e instanceof RemoteException) {
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
invalidateServiceContext();
}
String msg = "AttachVolumeCommand failed due to " + VmwareHelper.getExceptionMessage(e);
s_logger.error(msg, e);
return new AttachVolumeAnswer(cmd, msg);
}
}
@Override
public void removeManagedTargetsFromCluster(List<String> iqns) throws Exception {
List<HostInternetScsiHbaStaticTarget> lstManagedTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO cluster = new ClusterMO(context, morCluster);
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
HostMO host = new HostMO(context, lstHosts.get(0).first());
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
if (hba instanceof HostInternetScsiHba) {
List<HostInternetScsiHbaStaticTarget> lstTargets = ((HostInternetScsiHba)hba).getConfiguredStaticTarget();
if (lstTargets != null) {
for (HostInternetScsiHbaStaticTarget target : lstTargets) {
if (iqns.contains(target.getIScsiName())) {
lstManagedTargets.add(target);
}
}
}
}
}
addRemoveInternetScsiTargetsToAllHosts(false, lstManagedTargets, lstHosts);
rescanAllHosts(lstHosts);
}
private void addRemoveInternetScsiTargetsToAllHosts(final boolean add, final List<HostInternetScsiHbaStaticTarget> lstTargets,
final List<Pair<ManagedObjectReference, String>> lstHosts) throws Exception {
VmwareContext context = getServiceContext();
ExecutorService executorService = Executors.newFixedThreadPool(lstHosts.size());
final List<Exception> exceptions = new ArrayList<Exception>();
for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
HostMO host = new HostMO(context, hostPair.first());
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
boolean iScsiHbaConfigured = false;
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
if (hba instanceof HostInternetScsiHba) {
// just finding an instance of HostInternetScsiHba means that we have found at least one configured iSCSI HBA
// at least one iSCSI HBA must be configured before a CloudStack user can use this host for iSCSI storage
iScsiHbaConfigured = true;
final String iScsiHbaDevice = hba.getDevice();
final HostStorageSystemMO hss = hostStorageSystem;
executorService.submit(new Thread() {
@Override
public void run() {
try {
if (add) {
hss.addInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
} else {
hss.removeInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
}
hss.rescanHba(iScsiHbaDevice);
hss.rescanVmfs();
} catch (Exception ex) {
synchronized (exceptions) {
exceptions.add(ex);
}
}
}
});
}
}
if (!iScsiHbaConfigured) {
throw new Exception("An iSCSI HBA must be configured before a host can use iSCSI storage.");
}
}
executorService.shutdown();
if (!executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES)) {
throw new Exception("The system timed out before completing the task 'rescanAllHosts'.");
}
if (exceptions.size() > 0) {
throw new Exception(exceptions.get(0).getMessage());
}
}
private void rescanAllHosts(final List<Pair<ManagedObjectReference, String>> lstHosts) throws Exception {
VmwareContext context = getServiceContext();
ExecutorService executorService = Executors.newFixedThreadPool(lstHosts.size());
final List<Exception> exceptions = new ArrayList<Exception>();
for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
HostMO host = new HostMO(context, hostPair.first());
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
boolean iScsiHbaConfigured = false;
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
if (hba instanceof HostInternetScsiHba) {
// just finding an instance of HostInternetScsiHba means that we have found at least one configured iSCSI HBA
// at least one iSCSI HBA must be configured before a CloudStack user can use this host for iSCSI storage
iScsiHbaConfigured = true;
final String iScsiHbaDevice = hba.getDevice();
final HostStorageSystemMO hss = hostStorageSystem;
executorService.submit(new Thread() {
@Override
public void run() {
try {
hss.rescanHba(iScsiHbaDevice);
hss.rescanVmfs();
} catch (Exception ex) {
synchronized (exceptions) {
exceptions.add(ex);
}
}
}
});
}
}
if (!iScsiHbaConfigured) {
throw new Exception("An iSCSI HBA must be configured before a host can use iSCSI storage.");
}
}
executorService.shutdown();
if (!executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES)) {
throw new Exception("The system timed out before completing the task 'rescanAllHosts'.");
}
if (exceptions.size() > 0) {
throw new Exception(exceptions.get(0).getMessage());
}
}
private ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber,
String iqn, String chapName, String chapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
VmwareContext context = getServiceContext();
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO cluster = new ClusterMO(context, morCluster);
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
target.setAddress(storageIpAddress);
target.setPort(storagePortNumber);
target.setIScsiName(iqn);
if (StringUtils.isNotBlank(chapName) && StringUtils.isNotBlank(chapSecret)) {
HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties();
String strAuthType = "chapRequired";
auth.setChapAuthEnabled(true);
auth.setChapInherited(false);
auth.setChapAuthenticationType(strAuthType);
auth.setChapName(chapName);
auth.setChapSecret(chapSecret);
if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) {
auth.setMutualChapInherited(false);
auth.setMutualChapAuthenticationType(strAuthType);
auth.setMutualChapName(mutualChapName);
auth.setMutualChapSecret(mutualChapSecret);
}
target.setAuthenticationProperties(auth);
}
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
lstTargets.add(target);
addRemoveInternetScsiTargetsToAllHosts(true, lstTargets, lstHosts);
rescanAllHosts(lstHosts);
HostMO host = new HostMO(context, lstHosts.get(0).first());
HostDatastoreSystemMO hostDatastoreSystem = host.getHostDatastoreSystemMO();
ManagedObjectReference morDs = hostDatastoreSystem.findDatastoreByName(datastoreName);
if (morDs != null) {
return morDs;
}
rescanAllHosts(lstHosts);
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
List<HostScsiDisk> lstHostScsiDisks = hostDatastoreSystem.queryAvailableDisksForVmfs();
HostScsiDisk hostScsiDisk = getHostScsiDisk(hostStorageSystem.getStorageDeviceInfo().getScsiTopology(), lstHostScsiDisks, iqn);
if (hostScsiDisk == null) {
// check to see if the datastore actually does exist already
morDs = hostDatastoreSystem.findDatastoreByName(datastoreName);
if (morDs != null) {
return morDs;
}
throw new Exception("A relevant SCSI disk could not be located to use to create a datastore.");
}
morDs = hostDatastoreSystem.createVmfsDatastore(datastoreName, hostScsiDisk);
if (morDs != null) {
rescanAllHosts(lstHosts);
return morDs;
}
throw new Exception("Unable to create a datastore");
}
// the purpose of this method is to find the HostScsiDisk in the passed-in array that exists (if any) because
// we added the static iqn to an iSCSI HBA
private static HostScsiDisk getHostScsiDisk(HostScsiTopology hst, List<HostScsiDisk> lstHostScsiDisks, String iqn) {
for (HostScsiTopologyInterface adapter : hst.getAdapter()) {
if (adapter.getTarget() != null) {
for (HostScsiTopologyTarget target : adapter.getTarget()) {
if (target.getTransport() instanceof HostInternetScsiTargetTransport) {
String iScsiName = ((HostInternetScsiTargetTransport)target.getTransport()).getIScsiName();
if (iqn.equals(iScsiName)) {
for (HostScsiDisk hostScsiDisk : lstHostScsiDisks) {
for (HostScsiTopologyLun hstl : target.getLun()) {
if (hstl.getScsiLun().contains(hostScsiDisk.getUuid())) {
return hostScsiDisk;
}
}
}
}
}
}
}
}
return null;
}
private void deleteVmfsDatastore(VmwareHypervisorHost hyperHost, String volumeUuid, String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
// hyperHost.unmountDatastore(volumeUuid);
VmwareContext context = getServiceContext();
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO cluster = new ClusterMO(context, morCluster);
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
target.setAddress(storageIpAddress);
target.setPort(storagePortNumber);
target.setIScsiName(iqn);
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
lstTargets.add(target);
addRemoveInternetScsiTargetsToAllHosts(false, lstTargets, lstHosts);
rescanAllHosts(lstHosts);
}
protected Answer execute(AttachIsoCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource AttachIsoCommand: " + _gson.toJson(cmd));
@ -4530,195 +4003,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
private boolean createVMFullClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore,
ManagedObjectReference morPool) throws Exception {
if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName))
dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false);
s_logger.info("creating full clone from template");
if (!vmTemplate.createFullClone(vmdkName, dcMo.getVmFolder(), morPool, morDatastore)) {
String msg = "Unable to create full clone from the template";
s_logger.error(msg);
throw new Exception(msg);
}
// we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know
// to move files
s_logger.info("Move volume out of volume-wrapper VM ");
dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
dsMo.moveDatastoreFile(String.format("[%s] %s/%s-flat.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s-flat.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
return true;
}
private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore,
ManagedObjectReference morPool) throws Exception {
ManagedObjectReference morBaseSnapshot = vmTemplate.getSnapshotMor("cloud.template.base");
if (morBaseSnapshot == null) {
String msg = "Unable to find template base snapshot, invalid template";
s_logger.error(msg);
throw new Exception(msg);
}
if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName))
dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false);
s_logger.info("creating linked clone from template");
if (!vmTemplate.createLinkedClone(vmdkName, morBaseSnapshot, dcMo.getVmFolder(), morPool, morDatastore)) {
String msg = "Unable to clone from the template";
s_logger.error(msg);
throw new Exception(msg);
}
// we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know
// to move files
s_logger.info("Move volume out of volume-wrapper VM ");
dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
dsMo.moveDatastoreFile(String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
return true;
}
@Override
public CreateAnswer execute(CreateCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource CreateCommand: " + _gson.toJson(cmd));
}
StorageFilerTO pool = cmd.getPool();
DiskProfile dskch = cmd.getDiskCharacteristics();
try {
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, pool.getUuid());
if (morDatastore == null)
throw new Exception("Unable to find datastore in vSphere");
DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
if (dskch.getType() == Volume.Type.ROOT) {
// attach volume id to make the name unique
String vmdkName = dskch.getName() + "-" + dskch.getVolumeId();
if (cmd.getTemplateUrl() == null) {
// create a root volume for blank VM
String dummyVmName = getWorkerName(context, cmd, 0);
VirtualMachineMO vmMo = null;
try {
vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
if (vmMo == null) {
throw new Exception("Unable to create a dummy VM for volume creation");
}
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName);
s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath);
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo);
vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, -1);
vmMo.detachDisk(volumeDatastorePath, false);
VolumeTO vol =
new VolumeTO(cmd.getVolumeId(), dskch.getType(), pool.getType(), pool.getUuid(), dskch.getName(), pool.getPath(), vmdkName, dskch.getSize(),
null);
return new CreateAnswer(cmd, vol);
} finally {
s_logger.info("Destroy dummy VM after volume creation");
if (vmMo != null) {
s_logger.warn("Unable to destroy a null VM ManagedObjectReference");
vmMo.detachAllDisks();
vmMo.destroy();
}
}
} else {
VirtualMachineMO vmTemplate = VmwareHelper.pickOneVmOnRunningHost(dcMo.findVmByNameAndLabel(cmd.getTemplateUrl()), true);
if (vmTemplate == null) {
s_logger.warn("Template host in vSphere is not in connected state, request template reload");
return new CreateAnswer(cmd, "Template host in vSphere is not in connected state, request template reload", true);
}
ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
if (!_fullCloneFlag) {
createVMLinkedClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool);
} else {
createVMFullClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool);
}
VirtualMachineMO vmMo = new ClusterMO(context, morCluster).findVmOnHyperHost(vmdkName);
assert (vmMo != null);
s_logger.info("detach disks from volume-wrapper VM " + vmdkName);
vmMo.detachAllDisks();
s_logger.info("destroy volume-wrapper VM " + vmdkName);
vmMo.destroy();
String srcFile = String.format("[%s] %s/", dsMo.getName(), vmdkName);
dsMo.deleteFile(srcFile, dcMo.getMor(), true);
VolumeTO vol =
new VolumeTO(cmd.getVolumeId(), dskch.getType(), pool.getType(), pool.getUuid(), dskch.getName(), pool.getPath(), vmdkName, dskch.getSize(), null);
return new CreateAnswer(cmd, vol);
}
} else {
// create data volume
VirtualMachineMO vmMo = null;
String volumeUuid = UUID.randomUUID().toString().replace("-", "");
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeUuid);
String dummyVmName = getWorkerName(context, cmd, 0);
try {
vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
if (vmMo == null) {
throw new Exception("Unable to create a dummy VM for volume creation");
}
// s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath);
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo);
vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, vmMo.getScsiDeviceControllerKey());
vmMo.detachDisk(volumeDatastorePath, false);
VolumeTO vol =
new VolumeTO(cmd.getVolumeId(), dskch.getType(), pool.getType(), pool.getUuid(), dskch.getName(), pool.getPath(), volumeUuid, dskch.getSize(),
null);
return new CreateAnswer(cmd, vol);
} finally {
s_logger.info("Destroy dummy VM after volume creation");
if (vmMo != null) {
s_logger.warn("Unable to destroy a null VM ManagedObjectReference");
vmMo.detachAllDisks();
vmMo.destroy();
}
}
}
} catch (Throwable e) {
if (e instanceof RemoteException) {
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
invalidateServiceContext();
}
String msg = "CreateCommand failed due to " + VmwareHelper.getExceptionMessage(e);
s_logger.error(msg, e);
return new CreateAnswer(cmd, new Exception(e));
}
}
private static int getMBsFromBytes(long bytes) {
return (int)(bytes / (1024L * 1024L));
}
@Override
public void disconnected() {
}
@ -5751,9 +5035,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
value = (String)params.get("scripts.timeout");
int timeout = NumbersUtil.parseInt(value, 1440) * 1000;
VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
VmwareStorageProcessor storageProcessor =
new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null);
storageHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor);
_storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null);
storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor);
_vrResource = new VirtualRoutingResource(this);
if (!_vrResource.configure(name, params)) {

View File

@ -18,8 +18,6 @@ package com.cloud.storage.resource;
import java.util.List;
import javax.naming.OperationNotSupportedException;
import org.apache.log4j.Logger;
import com.google.gson.Gson;
@ -313,28 +311,4 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
public String getMountPoint(String storageUrl) {
return _resource.getRootDir(storageUrl);
}
@Override
public ManagedObjectReference prepareManagedDatastore(VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret) throws Exception {
throw new OperationNotSupportedException();
}
@Override
public ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String volumeName, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception {
throw new OperationNotSupportedException();
}
@Override
public void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception {
throw new OperationNotSupportedException();
}
@Override
public void removeManagedTargetsFromCluster(List<String> managedIqns) throws Exception {
throw new OperationNotSupportedException();
}
}

View File

@ -27,11 +27,24 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.google.gson.Gson;
import com.vmware.vim25.HostHostBusAdapter;
import com.vmware.vim25.HostInternetScsiHba;
import com.vmware.vim25.HostInternetScsiHbaAuthenticationProperties;
import com.vmware.vim25.HostInternetScsiHbaStaticTarget;
import com.vmware.vim25.HostInternetScsiTargetTransport;
import com.vmware.vim25.HostScsiDisk;
import com.vmware.vim25.HostScsiTopology;
import com.vmware.vim25.HostScsiTopologyInterface;
import com.vmware.vim25.HostScsiTopologyLun;
import com.vmware.vim25.HostScsiTopologyTarget;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.VirtualDisk;
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
@ -64,7 +77,9 @@ import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
import com.cloud.hypervisor.vmware.mo.DatastoreFile;
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO;
import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfo;
@ -82,6 +97,7 @@ import com.cloud.storage.Volume;
import com.cloud.storage.template.OVAProcessor;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
import com.cloud.vm.VirtualMachine.State;
@ -262,7 +278,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
final ManagedObjectReference morDs;
if (managed) {
morDs = hostService.prepareManagedDatastore(hyperHost, managedStoragePoolName, storageHost, storagePort,
morDs = prepareManagedDatastore(context, hyperHost, managedStoragePoolName, storageHost, storagePort,
chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
}
else {
@ -319,32 +335,67 @@ public class VmwareStorageProcessor implements StorageProcessor {
private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore,
ManagedObjectReference morPool) throws Exception {
ManagedObjectReference morBaseSnapshot = vmTemplate.getSnapshotMor("cloud.template.base");
if (morBaseSnapshot == null) {
String msg = "Unable to find template base snapshot, invalid template";
s_logger.error(msg);
throw new Exception(msg);
}
if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName)) {
dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false);
}
s_logger.info("creating linked clone from template");
if (!vmTemplate.createLinkedClone(vmdkName, morBaseSnapshot, dcMo.getVmFolder(), morPool, morDatastore)) {
String msg = "Unable to clone from the template";
s_logger.error(msg);
throw new Exception(msg);
}
// we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know to move files
s_logger.info("Move volume out of volume-wrapper VM ");
dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
dsMo.moveDatastoreFile(String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
return true;
}
private boolean createVMFullClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore,
ManagedObjectReference morPool) throws Exception {
if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName)) {
dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false);
}
s_logger.info("creating full clone from template");
if (!vmTemplate.createFullClone(vmdkName, dcMo.getVmFolder(), morPool, morDatastore)) {
String msg = "Unable to create full clone from the template";
s_logger.error(msg);
throw new Exception(msg);
}
// we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know to move files
s_logger.info("Move volume out of volume-wrapper VM ");
dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
dsMo.moveDatastoreFile(String.format("[%s] %s/%s-flat.vmdk", dsMo.getName(), vmdkName, vmdkName), dcMo.getMor(), dsMo.getMor(),
String.format("[%s] %s-flat.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
return true;
}
@ -1241,7 +1292,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
VolumeObjectTO volumeTO = (VolumeObjectTO)disk.getData();
DataStoreTO primaryStore = volumeTO.getDataStore();
try {
VmwareHypervisorHost hyperHost = hostService.getHyperHost(hostService.getServiceContext(null), null);
VmwareContext context = hostService.getServiceContext(null);
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
if (vmMo == null) {
String msg = "Unable to find the VM to execute AttachVolumeCommand, vmName: " + vmName;
@ -1254,7 +1306,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
if (isAttach && isManaged) {
Map<String, String> details = disk.getDetails();
morDs = hostService.prepareManagedStorage(hyperHost, iScsiName, storageHost, storagePort, null,
morDs = prepareManagedStorage(context, hyperHost, iScsiName, storageHost, storagePort, null,
details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET),
details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET),
volumeTO.getSize(), cmd);
@ -1269,7 +1321,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
throw new Exception(msg);
}
DatastoreMO dsMo = new DatastoreMO(hostService.getServiceContext(null), morDs);
DatastoreMO dsMo = new DatastoreMO(context, morDs);
String datastoreVolumePath;
if (isAttach) {
@ -1301,7 +1353,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
vmMo.detachDisk(datastoreVolumePath, false);
if (isManaged) {
hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort);
handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort);
} else {
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath());
}
@ -1340,7 +1392,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) {
try {
VmwareHypervisorHost hyperHost = hostService.getHyperHost(hostService.getServiceContext(null), null);
VmwareContext context = hostService.getServiceContext(null);
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
if (vmMo == null) {
String msg = "Unable to find VM in vSphere to execute AttachIsoCommand, vmName: " + vmName;
@ -1390,7 +1443,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
// TODO, check if iso is already attached, or if there is a previous
// attachment
DatastoreMO secondaryDsMo = new DatastoreMO(hostService.getServiceContext(null), morSecondaryDs);
DatastoreMO secondaryDsMo = new DatastoreMO(context, morSecondaryDs);
String storeName = secondaryDsMo.getName();
String isoDatastorePath = String.format("[%s] %s/%s", storeName, isoStorePathFromRoot, isoFileName);
@ -1595,7 +1648,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
// this.hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort);
if (managedIqns != null && !managedIqns.isEmpty()) {
hostService.removeManagedTargetsFromCluster(managedIqns);
removeManagedTargetsFromCluster(managedIqns);
}
for (NetworkDetails netDetails : networks) {
@ -1648,6 +1701,345 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
}
private ManagedObjectReference prepareManagedDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret) throws Exception {
return getVmfsDatastore(context, hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort,
trimIqn(iScsiName), chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
}
private ManagedObjectReference getVmfsDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber,
String iqn, String chapName, String chapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO cluster = new ClusterMO(context, morCluster);
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
target.setAddress(storageIpAddress);
target.setPort(storagePortNumber);
target.setIScsiName(iqn);
if (StringUtils.isNotBlank(chapName) && StringUtils.isNotBlank(chapSecret)) {
HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties();
String strAuthType = "chapRequired";
auth.setChapAuthEnabled(true);
auth.setChapInherited(false);
auth.setChapAuthenticationType(strAuthType);
auth.setChapName(chapName);
auth.setChapSecret(chapSecret);
if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) {
auth.setMutualChapInherited(false);
auth.setMutualChapAuthenticationType(strAuthType);
auth.setMutualChapName(mutualChapName);
auth.setMutualChapSecret(mutualChapSecret);
}
target.setAuthenticationProperties(auth);
}
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
lstTargets.add(target);
addRemoveInternetScsiTargetsToAllHosts(context, true, lstTargets, lstHosts);
rescanAllHosts(context, lstHosts);
HostMO host = new HostMO(context, lstHosts.get(0).first());
HostDatastoreSystemMO hostDatastoreSystem = host.getHostDatastoreSystemMO();
ManagedObjectReference morDs = hostDatastoreSystem.findDatastoreByName(datastoreName);
if (morDs != null) {
return morDs;
}
rescanAllHosts(context, lstHosts);
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
List<HostScsiDisk> lstHostScsiDisks = hostDatastoreSystem.queryAvailableDisksForVmfs();
HostScsiDisk hostScsiDisk = getHostScsiDisk(hostStorageSystem.getStorageDeviceInfo().getScsiTopology(), lstHostScsiDisks, iqn);
if (hostScsiDisk == null) {
// check to see if the datastore actually does exist already
morDs = hostDatastoreSystem.findDatastoreByName(datastoreName);
if (morDs != null) {
return morDs;
}
throw new Exception("A relevant SCSI disk could not be located to use to create a datastore.");
}
morDs = hostDatastoreSystem.createVmfsDatastore(datastoreName, hostScsiDisk);
if (morDs != null) {
rescanAllHosts(context, lstHosts);
return morDs;
}
throw new Exception("Unable to create a datastore");
}
// the purpose of this method is to find the HostScsiDisk in the passed-in array that exists (if any) because
// we added the static iqn to an iSCSI HBA
private static HostScsiDisk getHostScsiDisk(HostScsiTopology hst, List<HostScsiDisk> lstHostScsiDisks, String iqn) {
for (HostScsiTopologyInterface adapter : hst.getAdapter()) {
if (adapter.getTarget() != null) {
for (HostScsiTopologyTarget target : adapter.getTarget()) {
if (target.getTransport() instanceof HostInternetScsiTargetTransport) {
String iScsiName = ((HostInternetScsiTargetTransport)target.getTransport()).getIScsiName();
if (iqn.equals(iScsiName)) {
for (HostScsiDisk hostScsiDisk : lstHostScsiDisks) {
for (HostScsiTopologyLun hstl : target.getLun()) {
if (hstl.getScsiLun().contains(hostScsiDisk.getUuid())) {
return hostScsiDisk;
}
}
}
}
}
}
}
}
return null;
}
private void deleteVmfsDatastore(VmwareHypervisorHost hyperHost, String volumeUuid, String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
// hyperHost.unmountDatastore(volumeUuid);
VmwareContext context = hostService.getServiceContext(null);
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO cluster = new ClusterMO(context, morCluster);
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
target.setAddress(storageIpAddress);
target.setPort(storagePortNumber);
target.setIScsiName(iqn);
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
lstTargets.add(target);
addRemoveInternetScsiTargetsToAllHosts(context, false, lstTargets, lstHosts);
rescanAllHosts(context, lstHosts);
}
private void createVmdk(Command cmd, DatastoreMO dsMo, String vmdkDatastorePath, Long volumeSize) throws Exception {
VmwareContext context = hostService.getServiceContext(null);
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
String dummyVmName = hostService.getWorkerName(context, cmd, 0);
VirtualMachineMO vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
if (vmMo == null) {
throw new Exception("Unable to create a dummy VM for volume creation");
}
Long volumeSizeToUse = volumeSize < dsMo.getSummary().getFreeSpace() ? volumeSize : dsMo.getSummary().getFreeSpace();
vmMo.createDisk(vmdkDatastorePath, getMBsFromBytes(volumeSizeToUse), dsMo.getMor(), vmMo.getScsiDeviceControllerKey());
vmMo.detachDisk(vmdkDatastorePath, false);
vmMo.destroy();
}
private static int getMBsFromBytes(long bytes) {
return (int)(bytes / (1024L * 1024L));
}
private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List<HostInternetScsiHbaStaticTarget> lstTargets,
List<Pair<ManagedObjectReference, String>> lstHosts) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(lstHosts.size());
final List<Exception> exceptions = new ArrayList<Exception>();
for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
HostMO host = new HostMO(context, hostPair.first());
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
boolean iScsiHbaConfigured = false;
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
if (hba instanceof HostInternetScsiHba) {
// just finding an instance of HostInternetScsiHba means that we have found at least one configured iSCSI HBA
// at least one iSCSI HBA must be configured before a CloudStack user can use this host for iSCSI storage
iScsiHbaConfigured = true;
final String iScsiHbaDevice = hba.getDevice();
final HostStorageSystemMO hss = hostStorageSystem;
executorService.submit(new Thread() {
@Override
public void run() {
try {
if (add) {
hss.addInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
} else {
hss.removeInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
}
hss.rescanHba(iScsiHbaDevice);
hss.rescanVmfs();
} catch (Exception ex) {
synchronized (exceptions) {
exceptions.add(ex);
}
}
}
});
}
}
if (!iScsiHbaConfigured) {
throw new Exception("An iSCSI HBA must be configured before a host can use iSCSI storage.");
}
}
executorService.shutdown();
if (!executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES)) {
throw new Exception("The system timed out before completing the task 'rescanAllHosts'.");
}
if (exceptions.size() > 0) {
throw new Exception(exceptions.get(0).getMessage());
}
}
private void rescanAllHosts(VmwareContext context, List<Pair<ManagedObjectReference, String>> lstHosts) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(lstHosts.size());
final List<Exception> exceptions = new ArrayList<Exception>();
for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
HostMO host = new HostMO(context, hostPair.first());
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
boolean iScsiHbaConfigured = false;
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
if (hba instanceof HostInternetScsiHba) {
// just finding an instance of HostInternetScsiHba means that we have found at least one configured iSCSI HBA
// at least one iSCSI HBA must be configured before a CloudStack user can use this host for iSCSI storage
iScsiHbaConfigured = true;
final String iScsiHbaDevice = hba.getDevice();
final HostStorageSystemMO hss = hostStorageSystem;
executorService.submit(new Thread() {
@Override
public void run() {
try {
hss.rescanHba(iScsiHbaDevice);
hss.rescanVmfs();
} catch (Exception ex) {
synchronized (exceptions) {
exceptions.add(ex);
}
}
}
});
}
}
if (!iScsiHbaConfigured) {
throw new Exception("An iSCSI HBA must be configured before a host can use iSCSI storage.");
}
}
executorService.shutdown();
if (!executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES)) {
throw new Exception("The system timed out before completing the task 'rescanAllHosts'.");
}
if (exceptions.size() > 0) {
throw new Exception(exceptions.get(0).getMessage());
}
}
private static String trimIqn(String iqn) {
String[] tmp = iqn.split("/");
if (tmp.length != 3) {
String msg = "Wrong format for iScsi path: " + iqn + ". It should be formatted as '/targetIQN/LUN'.";
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
return tmp[1].trim();
}
public ManagedObjectReference prepareManagedStorage(VmwareContext context, VmwareHypervisorHost hyperHost, String iScsiName,
String storageHost, int storagePort, String volumeName, String chapInitiatorUsername, String chapInitiatorSecret,
String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception {
ManagedObjectReference morDs = prepareManagedDatastore(context, hyperHost, iScsiName, storageHost, storagePort,
chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
DatastoreMO dsMo = new DatastoreMO(hostService.getServiceContext(null), morDs);
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeName != null ? volumeName : dsMo.getName());
if (!dsMo.fileExists(volumeDatastorePath)) {
createVmdk(cmd, dsMo, volumeDatastorePath, size);
}
return morDs;
}
private void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception {
VmwareContext context = hostService.getServiceContext(null);
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
deleteVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iqn), storageHost, storagePort, trimIqn(iqn));
}
private void removeManagedTargetsFromCluster(List<String> iqns) throws Exception {
List<HostInternetScsiHbaStaticTarget> lstManagedTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
VmwareContext context = hostService.getServiceContext(null);
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO cluster = new ClusterMO(context, morCluster);
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
HostMO host = new HostMO(context, lstHosts.get(0).first());
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
if (hba instanceof HostInternetScsiHba) {
List<HostInternetScsiHbaStaticTarget> lstTargets = ((HostInternetScsiHba)hba).getConfiguredStaticTarget();
if (lstTargets != null) {
for (HostInternetScsiHbaStaticTarget target : lstTargets) {
if (iqns.contains(target.getIScsiName())) {
lstManagedTargets.add(target);
}
}
}
}
}
addRemoveInternetScsiTargetsToAllHosts(context, false, lstManagedTargets, lstHosts);
rescanAllHosts(context, lstHosts);
}
private List<String> getManagedIqnsFromVirtualDisks(List<VirtualDisk> virtualDisks) {
List<String> managedIqns = new ArrayList<String>();