This is an automated email from the ASF dual-hosted git repository. harikrishna pushed a commit to branch FixResizeVolumeMigrateVolumeInCaseOfDatastoreCluster in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit cc1833cb71b554ed6d5b78db94cec2d8a608469d Author: Harikrishna Patnala <[email protected]> AuthorDate: Thu Sep 30 12:58:22 2021 +0530 Fix resize volume and migrate volume to update volume path if DRS is applied on volume in datastore cluster --- .../agent/api/storage/MigrateVolumeCommand.java | 14 +- .../agent/api/storage/ResizeVolumeCommand.java | 8 +- .../api/agent/test/CheckNetworkAnswerTest.java | 2 +- .../storage/motion/AncientDataMotionStrategy.java | 9 +- .../motion/StorageSystemDataMotionStrategy.java | 2 +- .../kvm/resource/LibvirtComputingResourceTest.java | 12 +- .../hypervisor/vmware/resource/VmwareResource.java | 211 +++++++++++++-------- .../motion/VmwareStorageMotionStrategy.java | 7 +- .../wrapper/xenbase/CitrixRequestWrapperTest.java | 2 +- .../wrapper/xenbase/XenServer610WrapperTest.java | 2 +- .../CloudStackPrimaryDataStoreDriverImpl.java | 31 ++- .../driver/LinstorPrimaryDataStoreDriverImpl.java | 2 +- 12 files changed, 207 insertions(+), 95 deletions(-) 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 2dd4023..b960e6d 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; @@ -41,22 +42,23 @@ public class MigrateVolumeCommand extends Command { private Map<String, String> srcDetails; private Map<String, String> destDetails; - public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, int timeout) { + public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, int timeout, String chainInfo) { this.volumeId = volumeId; this.volumePath = volumePath; this.pool = new StorageFilerTO(pool); + this.chainInfo = chainInfo; this.setWait(timeout); } - public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout) { - this(volumeId,volumePath,pool,timeout); + public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout, String chainInfo) { + this(volumeId, volumePath, pool, timeout, chainInfo); 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, 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 +136,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 22cff13..161f064 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; @@ -37,7 +38,7 @@ public class ResizeVolumeCommand extends Command { protected ResizeVolumeCommand() { } - public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance) { + public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, String chainInfo) { this.path = path; this.pool = pool; this.currentSize = currentSize; @@ -45,11 +46,12 @@ public class ResizeVolumeCommand extends Command { this.shrinkOk = shrinkOk; this.vmInstance = vmInstance; this.managed = false; + 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); + this(path, pool, currentSize, newSize, shrinkOk, vmInstance, null); this.iScsiName = iScsiName; this.managed = isManaged; @@ -81,6 +83,8 @@ public class ResizeVolumeCommand extends Command { public String get_iScsiName() {return iScsiName; } + public String getChainInfo() {return chainInfo; } + /** * {@inheritDoc} */ diff --git a/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java b/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java index 8b25501..f554cb5 100644 --- a/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java +++ b/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java @@ -209,7 +209,7 @@ public class CheckNetworkAnswerTest { Long newSize = 4194304L; Long currentSize = 1048576L; - ResizeVolumeCommand rv = new ResizeVolumeCommand("dummydiskpath", new StorageFilerTO(dummypool), currentSize, newSize, false, "vmName"); + ResizeVolumeCommand rv = new ResizeVolumeCommand("dummydiskpath", new StorageFilerTO(dummypool), currentSize, newSize, false, "vmName", null); @Test public void testExecuteInSequence() { 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 51e0c97..74de765 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/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index aee1f75..99de054 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -740,7 +740,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destVolumeInfo.getDataStore().getId(), DataStoreRole.Primary); MigrateVolumeCommand command = new MigrateVolumeCommand(srcVolumeInfo.getId(), srcVolumeInfo.getPath(), destPool, srcVolumeInfo.getAttachedVmName(), - srcVolumeInfo.getVolumeType(), waitInterval); + srcVolumeInfo.getVolumeType(), waitInterval, null); Map<String, String> details = new HashMap<>(); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 27399ea..1ef8a9e 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -4836,7 +4836,7 @@ public class LibvirtComputingResourceTest { final boolean shrinkOk = true; final String vmInstance = "Test"; - final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance); + final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance, null); final KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class); final KVMStoragePool storagePool = Mockito.mock(KVMStoragePool.class); @@ -4889,7 +4889,7 @@ public class LibvirtComputingResourceTest { final boolean shrinkOk = false; final String vmInstance = "Test"; - final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance); + final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance, null); final KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class); final KVMStoragePool storagePool = Mockito.mock(KVMStoragePool.class); @@ -4929,7 +4929,7 @@ public class LibvirtComputingResourceTest { final boolean shrinkOk = false; final String vmInstance = "Test"; - final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance); + final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance, null); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -4947,7 +4947,7 @@ public class LibvirtComputingResourceTest { final boolean shrinkOk = true; final String vmInstance = "Test"; - final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance); + final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance, null); final KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class); final KVMStoragePool storagePool = Mockito.mock(KVMStoragePool.class); @@ -4976,7 +4976,7 @@ public class LibvirtComputingResourceTest { final boolean shrinkOk = false; final String vmInstance = "Test"; - final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance); + final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance, null); final KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class); final KVMStoragePool storagePool = Mockito.mock(KVMStoragePool.class); @@ -5024,7 +5024,7 @@ public class LibvirtComputingResourceTest { final boolean shrinkOk = false; final String vmInstance = "Test"; - final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance); + final ResizeVolumeCommand command = new ResizeVolumeCommand(path, pool, currentSize, newSize, shrinkOk, vmInstance, null); final KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class); final KVMStoragePool storagePool = Mockito.mock(KVMStoragePool.class); 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 0e93398..0fd718f 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; @@ -852,26 +856,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<VirtualDisk, String> 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,6 +878,53 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa _storageProcessor.expandDatastore(hostDatastoreSystem, dsMo); } + boolean datastoreChangeObserved = false; + boolean volumePathChangeObserved = false; + + if (cmd.getContextParam(DiskTO.PROTOCOL_TYPE) != null && cmd.getContextParam(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) { + VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); + VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, path, chainInfo, managed, cmd.get_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(); + volumePathChangeObserved = true; + chainInfo = _gson.toJson(matchingExistingDisk); + } + 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)); + datastoreChangeObserved = true; + poolUUID = actualPoolUuid; + chainInfo = _gson.toJson(matchingExistingDisk); + } + } + } + } + + // OfflineVmwareMigration: 5. ignore/replace the rest of the try-block; It is the functional bit + Pair<VirtualDisk, String> 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 (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()); @@ -922,7 +955,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("datastoreName", 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); @@ -1473,7 +1516,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // restore allocation mask in case of exceptions String nicMasksStr = vmMo.getCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK); int nicMasks = Integer.parseInt(nicMasksStr); - nicMasks &= ~(1 << nicIndex); + nicMasks &= ~(1 << nicIndex); vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, String.valueOf(nicMasks)); throw e; @@ -3254,70 +3297,72 @@ 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 { + String dsName = null; + String diskBackingFileBaseName = null; - private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context) - throws Exception { - if (diskInfoBuilder != null) { - VolumeObjectTO volume = (VolumeObjectTO) vol.getData(); - - String dsName = null; - String diskBackingFileBaseName = null; - - Map<String, String> 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 (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; + } - 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 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<String, String> 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<String, String> controllerInfo, boolean deployAsIs) throws Exception { DiskControllerType controllerType = DiskControllerType.none; if (deployAsIs && matchingExistingDisk != null) { @@ -4791,7 +4836,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 +4885,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<VirtualDisk, String> diskInfo = getVirtualDiskInfo(vmMo, appendFileType(volumePath, VMDK_EXTENSION)); String vmdkAbsFile = getAbsoluteVmdkFile(diskInfo.first()); @@ -4892,7 +4955,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 04111bc..9c41885 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/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java index 219c76a..9d18e73 100755 --- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java +++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java @@ -430,7 +430,7 @@ public class CitrixRequestWrapperTest { public void testResizeVolumeCommand() { final StorageFilerTO pool = Mockito.mock(StorageFilerTO.class); - final ResizeVolumeCommand resizeCommand = new ResizeVolumeCommand("Test", pool, 1l, 3l, false, "Tests-1"); + final ResizeVolumeCommand resizeCommand = new ResizeVolumeCommand("Test", pool, 1l, 3l, false, "Tests-1", null); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java index 8fa68f5..e1368d3 100644 --- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java +++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java @@ -486,7 +486,7 @@ public class XenServer610WrapperTest { final Map<String, String> other = new HashMap<String, String>(); other.put("live", "true"); - final MigrateVolumeCommand createStorageCommand = new MigrateVolumeCommand(volumeId, volumePath, pool, timeout); + final MigrateVolumeCommand createStorageCommand = new MigrateVolumeCommand(volumeId, volumePath, pool, timeout, null); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); 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 9326946..1f8d376 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,30 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri vol.setSize(finalSize); vol.update(); + + VolumeVO volumeVO = volumeDao.findById(vol.getId()); + String datastoreName = answer.getContextParam("datastoreName"); + if (datastoreName != null) { + StoragePoolVO storagePoolVO = primaryStoreDao.findByUuid(datastoreName); + 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", datastoreName, 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); + } else if (answer != null) { result.setResult(answer.getDetails()); } else { diff --git a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java index 19cf297..3208603 100644 --- a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java @@ -617,7 +617,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), oldSize, resizeParameter.newSize, resizeParameter.shrinkOk, - resizeParameter.instanceName); + resizeParameter.instanceName, null); CreateCmdResult result = new CreateCmdResult(null, null); try { ResizeVolumeAnswer answer = (ResizeVolumeAnswer) _storageMgr.sendToPool(pool, resizeParameter.hosts, resizeCmd);
