use of org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo in project cloudstack by apache.
the class VmwareResource method execute.
protected Answer execute(MigrateWithStorageCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource MigrateWithStorageCommand: " + _gson.toJson(cmd));
}
VirtualMachineTO vmTo = cmd.getVirtualMachine();
String vmName = vmTo.getName();
VmwareHypervisorHost srcHyperHost = null;
VmwareHypervisorHost tgtHyperHost = null;
VirtualMachineMO vmMo = null;
ManagedObjectReference morDsAtTarget = null;
ManagedObjectReference morDsAtSource = null;
ManagedObjectReference morDc = null;
ManagedObjectReference morDcOfTargetHost = null;
ManagedObjectReference morTgtHost = new ManagedObjectReference();
ManagedObjectReference morTgtDatastore = new ManagedObjectReference();
VirtualMachineRelocateSpec relocateSpec = new VirtualMachineRelocateSpec();
List<VirtualMachineRelocateSpecDiskLocator> diskLocators = new ArrayList<VirtualMachineRelocateSpecDiskLocator>();
VirtualMachineRelocateSpecDiskLocator diskLocator = null;
String tgtDsName = "";
String tgtDsHost;
String tgtDsPath;
int tgtDsPort;
VolumeTO volume;
StorageFilerTO filerTo;
Set<String> mountedDatastoresAtSource = new HashSet<String>();
List<VolumeObjectTO> volumeToList = new ArrayList<VolumeObjectTO>();
Map<Long, Integer> volumeDeviceKey = new HashMap<Long, Integer>();
List<Pair<VolumeTO, StorageFilerTO>> volToFiler = cmd.getVolumeToFilerAsList();
String tgtHost = cmd.getTargetHost();
String tgtHostMorInfo = tgtHost.split("@")[0];
morTgtHost.setType(tgtHostMorInfo.split(":")[0]);
morTgtHost.setValue(tgtHostMorInfo.split(":")[1]);
try {
srcHyperHost = getHyperHost(getServiceContext());
tgtHyperHost = new HostMO(getServiceContext(), morTgtHost);
morDc = srcHyperHost.getHyperHostDatacenter();
morDcOfTargetHost = tgtHyperHost.getHyperHostDatacenter();
if (!morDc.getValue().equalsIgnoreCase(morDcOfTargetHost.getValue())) {
String msg = "Source host & target host are in different datacentesr";
throw new CloudRuntimeException(msg);
}
VmwareManager mgr = tgtHyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
String srcHostApiVersion = ((HostMO) srcHyperHost).getHostAboutInfo().getApiVersion();
// find VM through datacenter (VM is not at the target host yet)
vmMo = srcHyperHost.findVmOnPeerHyperHost(vmName);
if (vmMo == null) {
String msg = "VM " + vmName + " does not exist in VMware datacenter " + morDc.getValue();
s_logger.error(msg);
throw new Exception(msg);
}
vmName = vmMo.getName();
// Specify destination datastore location for each volume
for (Pair<VolumeTO, StorageFilerTO> entry : volToFiler) {
volume = entry.first();
filerTo = entry.second();
s_logger.debug("Preparing spec for volume : " + volume.getName());
morDsAtTarget = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(tgtHyperHost, filerTo.getUuid());
morDsAtSource = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(srcHyperHost, filerTo.getUuid());
if (morDsAtTarget == null) {
String msg = "Unable to find the target datastore: " + filerTo.getUuid() + " on target host: " + tgtHyperHost.getHyperHostName() + " to execute MigrateWithStorageCommand";
s_logger.error(msg);
throw new Exception(msg);
}
morTgtDatastore = morDsAtTarget;
// So since only the datastore will be changed first, ensure the target datastore is mounted on source host.
if (srcHostApiVersion.compareTo("5.1") < 0) {
tgtDsName = filerTo.getUuid().replace("-", "");
tgtDsHost = filerTo.getHost();
tgtDsPath = filerTo.getPath();
tgtDsPort = filerTo.getPort();
// If datastore is NFS and target datastore is not already mounted on source host then mount the datastore.
if (filerTo.getType().equals(StoragePoolType.NetworkFilesystem)) {
if (morDsAtSource == null) {
morDsAtSource = srcHyperHost.mountDatastore(false, tgtDsHost, tgtDsPort, tgtDsPath, tgtDsName);
if (morDsAtSource == null) {
throw new Exception("Unable to mount NFS datastore " + tgtDsHost + ":/" + tgtDsPath + " on " + _hostName);
}
mountedDatastoresAtSource.add(tgtDsName);
s_logger.debug("Mounted datastore " + tgtDsHost + ":/" + tgtDsPath + " on " + _hostName);
}
}
// If datastore is VMFS and target datastore is not mounted or accessible to source host then fail migration.
if (filerTo.getType().equals(StoragePoolType.VMFS)) {
if (morDsAtSource == null) {
s_logger.warn("If host version is below 5.1, then target VMFS datastore(s) need to manually mounted on source host for a successful live storage migration.");
throw new Exception("Target VMFS datastore: " + tgtDsPath + " is not mounted on source host: " + _hostName);
}
DatastoreMO dsAtSourceMo = new DatastoreMO(getServiceContext(), morDsAtSource);
String srcHostValue = srcHyperHost.getMor().getValue();
if (!dsAtSourceMo.isAccessibleToHost(srcHostValue)) {
s_logger.warn("If host version is below 5.1, then target VMFS datastore(s) need to accessible to source host for a successful live storage migration.");
throw new Exception("Target VMFS datastore: " + tgtDsPath + " is not accessible on source host: " + _hostName);
}
}
morTgtDatastore = morDsAtSource;
}
if (volume.getType() == Volume.Type.ROOT) {
relocateSpec.setDatastore(morTgtDatastore);
}
diskLocator = new VirtualMachineRelocateSpecDiskLocator();
diskLocator.setDatastore(morDsAtSource);
Pair<VirtualDisk, String> diskInfo = getVirtualDiskInfo(vmMo, volume.getPath() + ".vmdk");
String vmdkAbsFile = getAbsoluteVmdkFile(diskInfo.first());
if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) {
vmMo.updateAdapterTypeIfRequired(vmdkAbsFile);
}
int diskId = diskInfo.first().getKey();
diskLocator.setDiskId(diskId);
diskLocators.add(diskLocator);
volumeDeviceKey.put(volume.getId(), diskId);
}
// If a target datastore is provided for the VM, then by default all volumes associated with the VM will be migrated to that target datastore.
// Hence set the existing datastore as target datastore for volumes that are not to be migrated.
List<Pair<Integer, ManagedObjectReference>> diskDatastores = vmMo.getAllDiskDatastores();
for (Pair<Integer, ManagedObjectReference> diskDatastore : diskDatastores) {
if (!volumeDeviceKey.containsValue(diskDatastore.first().intValue())) {
diskLocator = new VirtualMachineRelocateSpecDiskLocator();
diskLocator.setDiskId(diskDatastore.first().intValue());
diskLocator.setDatastore(diskDatastore.second());
diskLocators.add(diskLocator);
}
}
relocateSpec.getDisk().addAll(diskLocators);
// Prepare network at target before migration
NicTO[] nics = vmTo.getNics();
for (NicTO nic : nics) {
// prepare network on the host
prepareNetworkFromNicInfo(new HostMO(getServiceContext(), morTgtHost), nic, false, vmTo.getType());
}
// Ensure secondary storage mounted on target host
Pair<String, Long> secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId));
String secStoreUrl = secStoreUrlAndId.first();
Long secStoreId = secStoreUrlAndId.second();
if (secStoreUrl == null) {
String msg = "secondary storage for dc " + _dcId + " is not ready yet?";
throw new Exception(msg);
}
mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId);
ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, tgtHyperHost);
if (morSecDs == null) {
String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl;
throw new Exception(msg);
}
if (srcHostApiVersion.compareTo("5.1") < 0) {
// Migrate VM's volumes to target datastore(s).
if (!vmMo.changeDatastore(relocateSpec)) {
throw new Exception("Change datastore operation failed during storage migration");
} else {
s_logger.debug("Successfully migrated storage of VM " + vmName + " to target datastore(s)");
}
// Migrate VM to target host.
ManagedObjectReference morPool = tgtHyperHost.getHyperHostOwnerResourcePool();
if (!vmMo.migrate(morPool, tgtHyperHost.getMor())) {
throw new Exception("VM migration to target host failed during storage migration");
} else {
s_logger.debug("Successfully migrated VM " + vmName + " from " + _hostName + " to " + tgtHyperHost.getHyperHostName());
}
} else {
// Simultaneously migrate VM's volumes to target datastore and VM to target host.
relocateSpec.setHost(tgtHyperHost.getMor());
relocateSpec.setPool(tgtHyperHost.getHyperHostOwnerResourcePool());
if (!vmMo.changeDatastore(relocateSpec)) {
throw new Exception("Change datastore operation failed during storage migration");
} else {
s_logger.debug("Successfully migrated VM " + vmName + " from " + _hostName + " to " + tgtHyperHost.getHyperHostName() + " and its storage to target datastore(s)");
}
}
// In case of a linked clone VM, if VM's disks are not consolidated, further VM operations such as volume snapshot, VM snapshot etc. will result in DB inconsistencies.
if (!vmMo.consolidateVmDisks()) {
s_logger.warn("VM disk consolidation failed after storage migration. Yet proceeding with VM migration.");
} else {
s_logger.debug("Successfully consolidated disks of VM " + vmName + ".");
}
// Update and return volume path and chain info for every disk because that could have changed after migration
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
for (Pair<VolumeTO, StorageFilerTO> entry : volToFiler) {
volume = entry.first();
long volumeId = volume.getId();
VirtualDisk[] disks = vmMo.getAllDiskDevice();
for (VirtualDisk disk : disks) {
if (volumeDeviceKey.get(volumeId) == disk.getKey()) {
VolumeObjectTO newVol = new VolumeObjectTO();
String newPath = vmMo.getVmdkFileBaseName(disk);
String poolName = entry.second().getUuid().replace("-", "");
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(newPath, poolName);
newVol.setId(volumeId);
newVol.setPath(newPath);
newVol.setChainInfo(_gson.toJson(diskInfo));
volumeToList.add(newVol);
break;
}
}
}
return new MigrateWithStorageAnswer(cmd, volumeToList);
} catch (Throwable e) {
if (e instanceof RemoteException) {
s_logger.warn("Encountered remote exception at vCenter, invalidating VMware session context");
invalidateServiceContext();
}
String msg = "MigrationCommand failed due to " + VmwareHelper.getExceptionMessage(e);
s_logger.warn(msg, e);
return new MigrateWithStorageAnswer(cmd, (Exception) e);
} finally {
// Cleanup datastores mounted on source host
for (String mountedDatastore : mountedDatastoresAtSource) {
s_logger.debug("Attempting to unmount datastore " + mountedDatastore + " at " + _hostName);
try {
srcHyperHost.unmountDatastore(mountedDatastore);
} catch (Exception unmountEx) {
s_logger.debug("Failed to unmount datastore " + mountedDatastore + " at " + _hostName + ". Seems the datastore is still being used by " + _hostName + ". Please unmount manually to cleanup.");
}
s_logger.debug("Successfully unmounted datastore " + mountedDatastore + " at " + _hostName);
}
}
}
use of org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo in project cloudstack by apache.
the class VmwareResource method postDiskConfigBeforeStart.
private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO[] sortedDisks, int ideControllerKey, int scsiControllerKey, Map<String, String> iqnToPath, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception {
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
for (DiskTO vol : sortedDisks) {
if (vol.getType() == Volume.Type.ISO)
continue;
VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData();
VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(diskInfoBuilder, vol, hyperHost, context);
assert (diskInfo != null);
String[] diskChain = diskInfo.getDiskChain();
assert (diskChain.length > 0);
Map<String, String> details = vol.getDetails();
boolean managed = false;
if (details != null) {
managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED));
}
DatastoreFile file = new DatastoreFile(diskChain[0]);
if (managed) {
DatastoreFile originalFile = new DatastoreFile(volumeTO.getPath());
if (!file.getFileBaseName().equalsIgnoreCase(originalFile.getFileBaseName())) {
if (s_logger.isInfoEnabled())
s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + diskChain[0]);
}
} else {
if (!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) {
if (s_logger.isInfoEnabled())
s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + file.getFileBaseName());
}
}
VolumeObjectTO volInSpec = getVolumeInSpec(vmSpec, volumeTO);
if (volInSpec != null) {
if (managed) {
String datastoreVolumePath = diskChain[0];
iqnToPath.put(details.get(DiskTO.IQN), datastoreVolumePath);
vol.setPath(datastoreVolumePath);
volumeTO.setPath(datastoreVolumePath);
volInSpec.setPath(datastoreVolumePath);
} else {
volInSpec.setPath(file.getFileBaseName());
}
volInSpec.setChainInfo(_gson.toJson(diskInfo));
}
}
}
use of org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo in project cloudstack by apache.
the class VolumeApiServiceImpl method updateMissingRootDiskController.
public void updateMissingRootDiskController(final VMInstanceVO vm, final String rootVolChainInfo) {
if (vm == null || !VirtualMachine.Type.User.equals(vm.getType()) || Strings.isNullOrEmpty(rootVolChainInfo)) {
return;
}
String rootDiskController = null;
try {
final VirtualMachineDiskInfo infoInChain = _gson.fromJson(rootVolChainInfo, VirtualMachineDiskInfo.class);
if (infoInChain != null) {
rootDiskController = infoInChain.getControllerFromDeviceBusName();
}
final UserVmVO userVmVo = _userVmDao.findById(vm.getId());
if ((rootDiskController != null) && (!rootDiskController.isEmpty())) {
_userVmDao.loadDetails(userVmVo);
_userVmMgr.persistDeviceBusInfo(userVmVo, rootDiskController);
}
} catch (JsonParseException e) {
s_logger.debug("Error parsing chain info json: " + e.getMessage());
}
}
use of org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo in project cloudstack by apache.
the class VirtualMachineDiskInfoBuilder method getDiskInfoByDeviceBusName.
public VirtualMachineDiskInfo getDiskInfoByDeviceBusName(String diskDeviceBusName) {
List<String> chain = disks.get(diskDeviceBusName);
if (chain != null && chain.size() > 0) {
VirtualMachineDiskInfo diskInfo = new VirtualMachineDiskInfo();
diskInfo.setDiskDeviceBusName(diskDeviceBusName);
diskInfo.setDiskChain(chain.toArray(new String[1]));
return diskInfo;
}
return null;
}
use of org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo in project cloudstack by apache.
the class VirtualMachineDiskInfoBuilder method getAllDiskInfo.
public List<VirtualMachineDiskInfo> getAllDiskInfo() {
List<VirtualMachineDiskInfo> infoList = new ArrayList<VirtualMachineDiskInfo>();
for (Map.Entry<String, List<String>> entry : disks.entrySet()) {
VirtualMachineDiskInfo diskInfo = new VirtualMachineDiskInfo();
diskInfo.setDiskDeviceBusName(entry.getKey());
diskInfo.setDiskChain(entry.getValue().toArray(new String[1]));
infoList.add(diskInfo);
}
return infoList;
}
Aggregations