diff --git a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java index 2dd4023d98c..9fed0f913e1 100644 --- a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java +++ b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java @@ -30,6 +30,7 @@ import com.cloud.storage.Volume; public class MigrateVolumeCommand extends Command { long volumeId; String volumePath; + String chainInfo; StorageFilerTO pool; StorageFilerTO sourcePool; String attachedVmName; @@ -49,14 +50,22 @@ public class MigrateVolumeCommand extends Command { } public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout) { - this(volumeId,volumePath,pool,timeout); + this(volumeId, volumePath, pool, timeout); this.attachedVmName = attachedVmName; this.volumeType = volumeType; this.setWait(timeout); } - public MigrateVolumeCommand(long volumeId, String volumePath, String attachedVmName, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster) { - this(volumeId,volumePath,targetPool, attachedVmName, Volume.Type.UNKNOWN, -1); + public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout, String chainInfo) { + this(volumeId, volumePath, pool, timeout); + this.attachedVmName = attachedVmName; + this.volumeType = volumeType; + this.chainInfo = chainInfo; + this.setWait(timeout); + } + + public MigrateVolumeCommand(long volumeId, String volumePath, String attachedVmName, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster, String chainInfo) { + this(volumeId,volumePath,targetPool, attachedVmName, Volume.Type.UNKNOWN, -1, chainInfo); this.sourcePool = new StorageFilerTO(sourcePool); this.hostGuidInTargetCluster = hostGuidInTargetCluster; } @@ -134,4 +143,6 @@ public class MigrateVolumeCommand extends Command { public int getWaitInMillSeconds() { return getWait() * 1000; } + + public String getChainInfo() { return chainInfo; } } diff --git a/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java b/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java index 22cff13de25..70d4d3ebab4 100644 --- a/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java +++ b/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java @@ -29,6 +29,7 @@ public class ResizeVolumeCommand extends Command { private Long newSize; private boolean shrinkOk; private String vmInstance; + private String chainInfo; /* For managed storage */ private boolean managed; @@ -47,6 +48,11 @@ public class ResizeVolumeCommand extends Command { this.managed = false; } + public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, String chainInfo) { + this(path, pool, currentSize, newSize, shrinkOk, vmInstance); + this.chainInfo = chainInfo; + } + public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, boolean isManaged, String iScsiName) { this(path, pool, currentSize, newSize, shrinkOk, vmInstance); @@ -81,6 +87,8 @@ public class ResizeVolumeCommand extends Command { public String get_iScsiName() {return iScsiName; } + public String getChainInfo() {return chainInfo; } + /** * {@inheritDoc} */ diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 51e0c97a21e..74de7652a1f 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -24,6 +24,8 @@ import java.util.Map; import javax.inject.Inject; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.storage.Storage; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; @@ -447,8 +449,13 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { int waitInterval = NumbersUtil.parseInt(value, Integer.parseInt(Config.MigrateWait.getDefaultValue())); VolumeInfo volume = (VolumeInfo)srcData; + StoragePool srcPool = (StoragePool)dataStoreMgr.getDataStore(srcData.getDataStore().getId(), DataStoreRole.Primary); StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destData.getDataStore().getId(), DataStoreRole.Primary); - MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName(), volume.getVolumeType(), waitInterval); + MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName(), volume.getVolumeType(), waitInterval, volume.getChainInfo()); + if (srcPool.getParent() != 0) { + command.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); + } + EndPoint ep = selector.select(srcData, StorageAction.MIGRATEVOLUME); Answer answer = null; if (ep == null) { diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 0e93398b552..9958b222af9 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -775,9 +775,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String vmName = cmd.getInstanceName(); long newSize = cmd.getNewSize() / ResourceType.bytesToKiB; long oldSize = cmd.getCurrentSize() / ResourceType.bytesToKiB; + boolean managed = cmd.isManaged(); + String poolUUID = cmd.getPoolUuid(); + String chainInfo = cmd.getChainInfo(); boolean useWorkerVm = false; - VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); + VmwareContext context = getServiceContext(); + VmwareHypervisorHost hyperHost = getHyperHost(context); VirtualMachineMO vmMo = null; String vmdkDataStorePath = null; @@ -789,24 +793,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } else if (newSize == oldSize) { return new ResizeVolumeAnswer(cmd, true, "success", newSize * ResourceType.bytesToKiB); } - /* - // FR41 this is yet to fix - ManagedObjectReference morDS1 = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid()); - DatastoreMO dsMo1 = new DatastoreMO(hyperHost.getContext(), morDS1); - vmdkDataStorePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo1, path + VMDK_EXTENSION); - DatastoreFile dsFile1 = new DatastoreFile(vmdkDataStorePath); - - s_logger.debug("vDiskid does not exist for volume " + vmdkDataStorePath + " registering the disk now"); - VirtualStorageObjectManagerMO vStorageObjectManagerMO = new VirtualStorageObjectManagerMO(getServiceContext()); - try { - VStorageObject vStorageObject = vStorageObjectManagerMO.registerVirtualDisk(dsFile1, null, dsMo1.getOwnerDatacenter().second()); - VStorageObjectConfigInfo diskConfigInfo = vStorageObject.getConfig(); - ID vdiskId = diskConfigInfo.getId(); - } catch (Throwable e) { - if (e instanceof AlreadyExistsFaultMsg) { - - } - }*/ if (vmName.equalsIgnoreCase("none")) { // OfflineVmwareMigration: we need to refactor the worker vm creation out for use in migration methods as well as here @@ -852,26 +838,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception(msg); } - // OfflineVmwareMigration: 5. ignore/replace the rest of the try-block; It is the functional bit - Pair vdisk = vmMo.getDiskDevice(path); - - if (vdisk == null) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("resize volume done (failed)"); - } - - throw new Exception("No such disk device: " + path); - } - - // IDE virtual disk cannot be re-sized if VM is running - if (vdisk.second() != null && vdisk.second().contains("ide")) { - throw new Exception("Re-sizing a virtual disk over an IDE controller is not supported in the VMware hypervisor. " + - "Please re-try when virtual disk is attached to a VM using a SCSI controller."); - } - - if (cmd.isManaged()) { - VmwareContext context = getServiceContext(); + if (managed) { ManagedObjectReference morCluster = hyperHost.getHyperHostCluster(); ClusterMO clusterMO = new ClusterMO(context, morCluster); @@ -892,15 +860,26 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa _storageProcessor.expandDatastore(hostDatastoreSystem, dsMo); } - if (vdisk.second() != null && !vdisk.second().toLowerCase().startsWith("scsi")) { - s_logger.error("Unsupported disk device bus " + vdisk.second()); - throw new Exception("Unsupported disk device bus " + vdisk.second()); + boolean volumePathChangeObserved = false; + boolean datastoreChangeObserved = false; + + Pair pathAndChainInfo = getNewPathAndChainInfoInDatastoreCluster(vmMo, path, chainInfo, managed, cmd.get_iScsiName(), poolUUID, cmd.getContextParam(DiskTO.PROTOCOL_TYPE)); + Pair poolUUIDandChainInfo = getNewPoolUUIDAndChainInfoInDatastoreCluster(vmMo, path, chainInfo, managed, cmd.get_iScsiName(), poolUUID, cmd.getContextParam(DiskTO.PROTOCOL_TYPE)); + + if (pathAndChainInfo != null) { + volumePathChangeObserved = true; + path = pathAndChainInfo.first(); + chainInfo = pathAndChainInfo.second(); } - VirtualDisk disk = vdisk.first(); - if ((VirtualDiskFlatVer2BackingInfo) disk.getBacking() != null && ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent() != null) { - s_logger.error("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid()); - throw new Exception("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid()); + + if (poolUUIDandChainInfo != null) { + datastoreChangeObserved = true; + poolUUID = poolUUIDandChainInfo.first(); + chainInfo = poolUUIDandChainInfo.second(); } + + // OfflineVmwareMigration: 5. ignore/replace the rest of the try-block; It is the functional bit + VirtualDisk disk = getDiskAfterResizeDiskValidations(vmMo, path); String vmdkAbsFile = getAbsoluteVmdkFile(disk); if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) { @@ -922,7 +901,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception("Failed to configure VM to resize disk. vmName: " + vmName); } - return new ResizeVolumeAnswer(cmd, true, "success", newSize * 1024); + ResizeVolumeAnswer answer = new ResizeVolumeAnswer(cmd, true, "success", newSize * 1024); + if (datastoreChangeObserved) { + answer.setContextParam("datastoreUUID", poolUUID); + answer.setContextParam("chainInfo", chainInfo); + } + + if (volumePathChangeObserved) { + answer.setContextParam("volumePath", path); + answer.setContextParam("chainInfo", chainInfo); + } + return answer; } catch (Exception e) { s_logger.error("Unable to resize volume", e); @@ -944,6 +933,79 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + private VirtualDisk getDiskAfterResizeDiskValidations(VirtualMachineMO vmMo, String volumePath) throws Exception { + Pair vdisk = vmMo.getDiskDevice(volumePath); + if (vdisk == null) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("resize volume done (failed)"); + } + throw new Exception("No such disk device: " + volumePath); + } + + // IDE virtual disk cannot be re-sized if VM is running + if (vdisk.second() != null && vdisk.second().contains("ide")) { + throw new Exception("Re-sizing a virtual disk over an IDE controller is not supported in the VMware hypervisor. " + + "Please re-try when virtual disk is attached to a VM using a SCSI controller."); + } + + if (vdisk.second() != null && !vdisk.second().toLowerCase().startsWith("scsi")) { + s_logger.error("Unsupported disk device bus " + vdisk.second()); + throw new Exception("Unsupported disk device bus " + vdisk.second()); + } + VirtualDisk disk = vdisk.first(); + if ((VirtualDiskFlatVer2BackingInfo) disk.getBacking() != null && ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent() != null) { + s_logger.error("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid()); + throw new Exception("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid()); + } + return disk; + } + + private Pair getNewPathAndChainInfoInDatastoreCluster(VirtualMachineMO vmMo, String path, String chainInfo, boolean managed, String iscsiName, String poolUUID, String poolType) throws Exception { + VmwareContext context = getServiceContext(); + VmwareHypervisorHost hyperHost = getHyperHost(context); + if (poolType != null && poolType.equalsIgnoreCase(Storage.StoragePoolType.DatastoreCluster.toString())) { + VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); + VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, path, chainInfo, managed, iscsiName, poolUUID, hyperHost, context); + if (diskInfoBuilder != null && matchingExistingDisk != null) { + String[] diskChain = matchingExistingDisk.getDiskChain(); + DatastoreFile file = new DatastoreFile(diskChain[0]); + if (!file.getFileBaseName().equalsIgnoreCase(path)) { + if (s_logger.isInfoEnabled()) + s_logger.info("Detected disk-chain top file change on volume: " + path + " -> " + file.getFileBaseName()); + path = file.getFileBaseName(); + chainInfo = _gson.toJson(matchingExistingDisk); + return new Pair<>(path, chainInfo); + } + } + } + return null; + } + + private Pair getNewPoolUUIDAndChainInfoInDatastoreCluster(VirtualMachineMO vmMo, String path, String chainInfo, boolean managed, String iscsiName, String poolUUID, String poolType) throws Exception { + VmwareContext context = getServiceContext(); + VmwareHypervisorHost hyperHost = getHyperHost(context); + if (poolType != null && poolType.equalsIgnoreCase(Storage.StoragePoolType.DatastoreCluster.toString())) { + VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); + VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, path, chainInfo, managed, iscsiName, poolUUID, hyperHost, context); + if (diskInfoBuilder != null && matchingExistingDisk != null) { + String[] diskChain = matchingExistingDisk.getDiskChain(); + DatastoreFile file = new DatastoreFile(diskChain[0]); + DatacenterMO dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter()); + DatastoreMO diskDatastoreMofromVM = new DatastoreMO(context, dcMo.findDatastore(file.getDatastoreName())); + if (diskDatastoreMofromVM != null) { + String actualPoolUuid = diskDatastoreMofromVM.getCustomFieldValue(CustomFieldConstants.CLOUD_UUID); + if (!actualPoolUuid.equalsIgnoreCase(poolUUID)) { + s_logger.warn(String.format("Volume %s found to be in a different storage pool %s", path, actualPoolUuid)); + poolUUID = actualPoolUuid; + chainInfo = _gson.toJson(matchingExistingDisk); + return new Pair<>(poolUUID, chainInfo); + } + } + } + } + return null; + } + protected Answer execute(CheckNetworkCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource CheckNetworkCommand " + _gson.toJson(cmd)); @@ -1911,7 +1973,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.error(msg); throw new Exception(msg); } - if (rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) { + if (rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase(Storage.StoragePoolType.DatastoreCluster.toString())) { if (diskInfoBuilder != null) { DatastoreMO diskDatastoreMofromVM = getDataStoreWhereDiskExists(hyperHost, context, diskInfoBuilder, rootDisk, diskDatastores); if (diskDatastoreMofromVM != null) { @@ -3254,70 +3316,82 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa nicIndex++; } } + private VirtualMachineDiskInfo getMatchingExistingDiskWithVolumeDetails(VirtualMachineDiskInfoBuilder diskInfoBuilder, String volumePath, + String chainInfo, boolean isManaged, String iScsiName, String datastoreUUID, + VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { - private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context) - throws Exception { - if (diskInfoBuilder != null) { - VolumeObjectTO volume = (VolumeObjectTO) vol.getData(); + Pair dsNameAndFileName = getVMDiskInfo(volumePath, isManaged, iScsiName, datastoreUUID, hyperHost, context); + String dsName = dsNameAndFileName.first(); + String diskBackingFileBaseName = dsNameAndFileName.second(); - String dsName = null; - String diskBackingFileBaseName = null; - - Map details = vol.getDetails(); - boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - - if (isManaged) { - String iScsiName = details.get(DiskTO.IQN); - - // if the storage is managed, iScsiName should not be null - dsName = VmwareResource.getDatastoreName(iScsiName); - - diskBackingFileBaseName = new DatastoreFile(volume.getPath()).getFileBaseName(); - } else { - ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, volume.getDataStore().getUuid()); - DatastoreMO dsMo = new DatastoreMO(context, morDs); - - dsName = dsMo.getName(); - - diskBackingFileBaseName = volume.getPath(); - } - - VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName); - if (diskInfo != null) { - s_logger.info("Found existing disk info from volume path: " + volume.getPath()); - return diskInfo; - } else { - String chainInfo = volume.getChainInfo(); - if (chainInfo != null) { - VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); - if (infoInChain != null) { - String[] disks = infoInChain.getDiskChain(); - if (disks.length > 0) { - for (String diskPath : disks) { - DatastoreFile file = new DatastoreFile(diskPath); - diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName(), dsName); - if (diskInfo != null) { - s_logger.info("Found existing disk from chain info: " + diskPath); - return diskInfo; - } - } - } - - if (diskInfo == null) { - diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName()); + VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName); + if (diskInfo != null) { + s_logger.info("Found existing disk info from volume path: " + volumePath); + return diskInfo; + } else { + if (chainInfo != null) { + VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); + if (infoInChain != null) { + String[] disks = infoInChain.getDiskChain(); + if (disks.length > 0) { + for (String diskPath : disks) { + DatastoreFile file = new DatastoreFile(diskPath); + diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName(), dsName); if (diskInfo != null) { - s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName()); + s_logger.info("Found existing disk from chain info: " + diskPath); return diskInfo; } } } + + if (diskInfo == null) { + diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName()); + if (diskInfo != null) { + s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName()); + return diskInfo; + } + } } } } - return null; } + private Pair getVMDiskInfo(String volumePath, boolean isManaged, String iScsiName, String datastoreUUID, + VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { + String dsName = null; + String diskBackingFileBaseName = null; + + if (isManaged) { + // if the storage is managed, iScsiName should not be null + dsName = VmwareResource.getDatastoreName(iScsiName); + diskBackingFileBaseName = new DatastoreFile(volumePath).getFileBaseName(); + } else { + ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, datastoreUUID); + DatastoreMO dsMo = new DatastoreMO(context, morDs); + dsName = dsMo.getName(); + diskBackingFileBaseName = volumePath; + } + + return new Pair<>(dsName, diskBackingFileBaseName); + } + + private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context) + throws Exception { + if (diskInfoBuilder != null) { + VolumeObjectTO volume = (VolumeObjectTO) vol.getData(); + String chainInfo = volume.getChainInfo(); + Map details = vol.getDetails(); + boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + String iScsiName = details.get(DiskTO.IQN); + String datastoreUUID = volume.getDataStore().getUuid(); + + return getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, volume.getPath(), chainInfo, isManaged, iScsiName, datastoreUUID, hyperHost, context); + } else { + return null; + } + } + private String getDiskController(VirtualMachineMO vmMo, VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, Pair controllerInfo, boolean deployAsIs) throws Exception { DiskControllerType controllerType = DiskControllerType.none; if (deployAsIs && matchingExistingDisk != null) { @@ -4791,7 +4865,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // OfflineVmwareMigration: refactor to be able to handle a detached volume private Answer execute(MigrateVolumeCommand cmd) { String volumePath = cmd.getVolumePath(); + String chainInfo = cmd.getChainInfo(); StorageFilerTO poolTo = cmd.getPool(); + VolumeObjectTO volumeObjectTO = (VolumeObjectTO)cmd.getSrcData(); if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd)); @@ -4838,6 +4914,22 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } DatastoreMO targetDsMo = new DatastoreMO(srcHyperHost.getContext(), morDs); + if (cmd.getContextParam(DiskTO.PROTOCOL_TYPE) != null && cmd.getContextParam(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) { + VmwareContext context = getServiceContext(); + VmwareHypervisorHost hyperHost = getHyperHost(context); + VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); + VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, volumePath, chainInfo, false, null, poolTo.getUuid(), hyperHost, context); + if (diskInfoBuilder != null && matchingExistingDisk != null) { + String[] diskChain = matchingExistingDisk.getDiskChain(); + DatastoreFile file = new DatastoreFile(diskChain[0]); + if (!file.getFileBaseName().equalsIgnoreCase(volumePath)) { + if (s_logger.isInfoEnabled()) + s_logger.info("Detected disk-chain top file change on volume: " + volumePath + " -> " + file.getFileBaseName()); + volumePath = file.getFileBaseName(); + } + } + } + String fullVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(targetDsMo, vmName, volumePath + VMDK_EXTENSION); Pair diskInfo = getVirtualDiskInfo(vmMo, appendFileType(volumePath, VMDK_EXTENSION)); String vmdkAbsFile = getAbsoluteVmdkFile(diskInfo.first()); @@ -4892,7 +4984,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); - String chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName())); + chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName())); MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath); answer.setVolumeChainInfo(chainInfo); return answer; diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index 04111bc3b6b..9c4188584ec 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -26,6 +26,8 @@ import java.util.Map; import javax.inject.Inject; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.storage.Storage; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; @@ -247,7 +249,10 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { , vm != null ? vm.getInstanceName() : null , sourcePool , targetPool - , hostIdForVmAndHostGuidInTargetCluster.second()); + , hostIdForVmAndHostGuidInTargetCluster.second(), ((VolumeObjectTO) srcData.getTO()).getChainInfo()); + if (sourcePool.getParent() != 0) { + cmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); + } Answer answer; if (hostId != null) { answer = agentMgr.easySend(hostId, cmd); diff --git a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index 93269461e49..fff15fd0ca9 100644 --- a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -26,6 +26,8 @@ import java.util.UUID; import javax.inject.Inject; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.storage.VolumeVO; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; @@ -408,7 +410,10 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(), resizeParameter.newSize, resizeParameter.shrinkOk, - resizeParameter.instanceName); + resizeParameter.instanceName, vol.getChainInfo()); + if (pool.getParent() != 0) { + resizeCmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); + } CreateCmdResult result = new CreateCmdResult(null, null); try { ResizeVolumeAnswer answer = (ResizeVolumeAnswer) storageMgr.sendToPool(pool, resizeParameter.hosts, resizeCmd); @@ -418,6 +423,8 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri vol.setSize(finalSize); vol.update(); + + updateVolumePathDetails(vol, answer); } else if (answer != null) { result.setResult(answer.getDetails()); } else { @@ -433,6 +440,31 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri callback.complete(result); } + private void updateVolumePathDetails(VolumeObject vol, ResizeVolumeAnswer answer) { + VolumeVO volumeVO = volumeDao.findById(vol.getId()); + String datastoreUUID = answer.getContextParam("datastoreUUID"); + if (datastoreUUID != null) { + StoragePoolVO storagePoolVO = primaryStoreDao.findByUuid(datastoreUUID); + if (storagePoolVO != null) { + volumeVO.setPoolId(storagePoolVO.getId()); + } else { + s_logger.warn(String.format("Unable to find datastore %s while updating the new datastore of the volume %d", datastoreUUID, vol.getId())); + } + } + + String volumePath = answer.getContextParam("volumePath"); + if (volumePath != null) { + volumeVO.setPath(volumePath); + } + + String chainInfo = answer.getContextParam("chainInfo"); + if (chainInfo != null) { + volumeVO.setChainInfo(chainInfo); + } + + volumeDao.update(volumeVO.getId(), volumeVO); + } + @Override public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {}