From 9543fd6e6abd976fd1cc2d49b913daf5431fa7b2 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 29 Sep 2020 00:49:35 +0530 Subject: [PATCH] Fix startcommand on Datastore cluster when the volume datastore in CloudStack mismatches with vCenter datastore. Volume could have migrated with in datastore cluster which caused the mismatch Fix dettach volume when volume is not on CloudStack intended datastore --- .../storage/to/PrimaryDataStoreTO.java | 6 +- .../cloudstack/storage/to/VolumeObjectTO.java | 10 ++ .../service/VolumeOrchestrationService.java | 2 +- .../cloud/vm/VirtualMachineManagerImpl.java | 4 +- .../orchestration/VolumeOrchestrator.java | 20 ++- .../datastore/db/PrimaryDataStoreDao.java | 2 + .../datastore/db/PrimaryDataStoreDaoImpl.java | 12 ++ .../vmware/resource/VmwareResource.java | 164 ++++++++++-------- .../resource/VmwareStorageProcessor.java | 61 +++++++ .../cloud/storage/VolumeApiServiceImpl.java | 27 +++ .../vmware/mo/VirtualMachineMO.java | 2 +- 11 files changed, 233 insertions(+), 77 deletions(-) diff --git a/core/src/main/java/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index 1572efe621a..7dab8d9da03 100644 --- a/core/src/main/java/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/core/src/main/java/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -39,7 +39,7 @@ public class PrimaryDataStoreTO implements DataStoreTO { public static final String REMOVE_AFTER_COPY = PrimaryDataStore.REMOVE_AFTER_COPY; public static final String VOLUME_SIZE = PrimaryDataStore.VOLUME_SIZE; - private final String uuid; + private String uuid; private final String name; private String type; private final long id; @@ -75,6 +75,10 @@ public class PrimaryDataStoreTO implements DataStoreTO { return this.uuid; } + public void setUuid(String uuid) { + this.uuid = uuid; + } + @Override public String getUrl() { return this.url; diff --git a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java index 6d613ab1269..f7e17f7bc14 100644 --- a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java +++ b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java @@ -63,6 +63,7 @@ public class VolumeObjectTO implements DataTO { private MigrationOptions migrationOptions; private boolean directDownload; private boolean deployAsIs; + private String updatedDataStoreUUID; public VolumeObjectTO() { @@ -319,4 +320,13 @@ public class VolumeObjectTO implements DataTO { public boolean isDeployAsIs() { return deployAsIs; } + + public String getUpdatedDataStoreUUID() { + return updatedDataStoreUUID; + } + + public void setUpdatedDataStoreUUID(String updatedDataStoreUUID) { + this.updatedDataStoreUUID = updatedDataStoreUUID; + } + } diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index 9baea60f29f..44e993f53b2 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -134,7 +134,7 @@ public interface VolumeOrchestrationService { StoragePool findStoragePool(DiskProfile dskCh, DataCenter dc, Pod pod, Long clusterId, Long hostId, VirtualMachine vm, Set avoid); - void updateVolumeDiskChain(long volumeId, String path, String chainInfo); + void updateVolumeDiskChain(long volumeId, String path, String chainInfo, String updatedDataStoreUUID); /** * Imports an existing volume for a VM into database. Useful while ingesting an unmanaged VM. diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 02ceef276bf..e8a96f1d6fb 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1491,9 +1491,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac // Before doing this, in a certain situation, getPath() from VolumeObjectTO // returned null instead of an actual path (because it was out of date with the DB). if(vol.getPath() != null) { - volumeMgr.updateVolumeDiskChain(vol.getId(), vol.getPath(), vol.getChainInfo()); + volumeMgr.updateVolumeDiskChain(vol.getId(), vol.getPath(), vol.getChainInfo(), vol.getUpdatedDataStoreUUID()); } else { - volumeMgr.updateVolumeDiskChain(vol.getId(), volume.getPath(), vol.getChainInfo()); + volumeMgr.updateVolumeDiskChain(vol.getId(), volume.getPath(), vol.getChainInfo(), vol.getUpdatedDataStoreUUID()); } } } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index a51aae7c8f4..b4d662d449c 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -1238,9 +1238,15 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati details.put(DiskTO.MOUNT_POINT, volumeInfo.get_iScsiName()); VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); - details.put(DiskTO.PROTOCOL_TYPE, (volume.getPoolType() != null) ? volume.getPoolType().toString() : null); + if (volume.getPoolId() != null) { + StoragePoolVO poolVO = _storagePoolDao.findById(volume.getPoolId()); + if (poolVO.getParent() != 0L) { + details.put(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); + } + } + ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore); if (chapInfo != null) { @@ -1704,7 +1710,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati } @Override - public void updateVolumeDiskChain(long volumeId, String path, String chainInfo) { + public void updateVolumeDiskChain(long volumeId, String path, String chainInfo, String updatedDataStoreUUID) { VolumeVO vol = _volsDao.findById(volumeId); boolean needUpdate = false; // Volume path is not getting updated in the DB, need to find reason and fix the issue. @@ -1719,10 +1725,20 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati needUpdate = true; } + if (updatedDataStoreUUID != null) { + needUpdate = true; + } + if (needUpdate) { s_logger.info("Update volume disk chain info. vol: " + vol.getId() + ", " + vol.getPath() + " -> " + path + ", " + vol.getChainInfo() + " -> " + chainInfo); vol.setPath(path); vol.setChainInfo(chainInfo); + if (updatedDataStoreUUID != null) { + List pools = _storagePoolDao.listPoolsByLikePath(updatedDataStoreUUID); + if (pools != null && !pools.isEmpty()) { + vol.setPoolId(pools.get(0).getId()); + } + } _volsDao.update(volumeId, vol); } } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java index 5712411a48e..0cbd0e14f28 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java @@ -127,4 +127,6 @@ public interface PrimaryDataStoreDao extends GenericDao { List listChildStoragePoolsInDatastoreCluster(long poolId); Integer countAll(); + + public List listPoolsByLikePath(String path); } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java index 1d1e0a0198d..315f698c099 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java @@ -56,6 +56,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase private final SearchBuilder DeleteLvmSearch; private final SearchBuilder DcLocalStorageSearch; private final GenericSearchBuilder StatusCountSearch; + private final SearchBuilder PathLikeSearch; @Inject private StoragePoolDetailsDao _detailsDao; @@ -132,6 +133,17 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase DcLocalStorageSearch.and("path", DcLocalStorageSearch.entity().getPath(), SearchCriteria.Op.EQ); DcLocalStorageSearch.and("scope", DcLocalStorageSearch.entity().getScope(), SearchCriteria.Op.EQ); DcLocalStorageSearch.done(); + + PathLikeSearch = createSearchBuilder(); + PathLikeSearch.and("path", PathLikeSearch.entity().getPath(), SearchCriteria.Op.LIKE); + PathLikeSearch.done(); + } + + @Override + public List listPoolsByLikePath(String path) { + SearchCriteria sc = PathLikeSearch.create(); + sc.setParameters("path", "%" + path + "%"); + return listBy(sc); } @Override 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 a7c82914867..a3990bb4f90 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 @@ -1791,13 +1791,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception(msg); } - DatastoreMO dsRootVolumeIsOn = getDatastoreThatRootDiskIsOn(dataStoresDetails, disks); - if (dsRootVolumeIsOn == null) { - String msg = "Unable to locate datastore details of root volume"; - s_logger.error(msg); - throw new Exception(msg); - } - VirtualMachineDiskInfoBuilder diskInfoBuilder = null; VirtualDevice[] nicDevices = null; VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); @@ -1806,12 +1799,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa int numScsiControllerForSystemVm = 1; boolean hasSnapshot = false; + List> diskDatastores = null; if (vmMo != null) { s_logger.info("VM " + vmInternalCSName + " already exists, tear down devices for reconfiguration"); if (getVmPowerState(vmMo) != PowerState.PowerOff) vmMo.safePowerOff(_shutdownWaitMs); // retrieve disk information before we tear down + diskDatastores = vmMo.getAllDiskDatastores(); diskInfoBuilder = vmMo.getDiskInfoBuilder(); hasSnapshot = vmMo.hasSnapshot(); nicDevices = vmMo.getNicDevices(); @@ -1836,6 +1831,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa diskInfoBuilder = vmMo.getDiskInfoBuilder(); hasSnapshot = vmMo.hasSnapshot(); + diskDatastores = vmMo.getAllDiskDatastores(); tearDownVmDevices(vmMo, hasSnapshot, deployAsIs); ensureDiskControllersInternal(vmMo, systemVm, controllerInfo, systemVmScsiControllerType, @@ -1866,32 +1862,33 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } mapSpecDisksToClonedDisks(vmMo, vmInternalCSName, specDisks); } else { - Pair rootDiskDataStoreDetails = null; + DiskTO rootDisk = null; for (DiskTO vol : disks) { if (vol.getType() == Volume.Type.ROOT) { - Map details = vol.getDetails(); - boolean managed = false; - - if (details != null) { - managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - } - - if (managed) { - String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); - - rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); - } else { - DataStoreTO primaryStore = vol.getData().getDataStore(); - - rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + rootDisk = vol; + } + } + Pair rootDiskDataStoreDetails = getDatastoreThatDiskIsOn(dataStoresDetails, rootDisk); + assert (vmSpec.getMinSpeed() != null) && (rootDiskDataStoreDetails != null); + DatastoreMO dsRootVolumeIsOn = rootDiskDataStoreDetails.second(); + if (dsRootVolumeIsOn == null) { + String msg = "Unable to locate datastore details of root volume"; + 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 (diskInfoBuilder != null) { + DatastoreMO diskDatastoreMofromVM = getDataStoreWhereDiskExists(hyperHost, context, diskInfoBuilder, rootDisk, diskDatastores); + if (diskDatastoreMofromVM != null) { + String actualPoolUuid = diskDatastoreMofromVM.getCustomFieldValue(CustomFieldConstants.CLOUD_UUID); + if (!actualPoolUuid.equalsIgnoreCase(rootDisk.getData().getDataStore().getUuid())) { + dsRootVolumeIsOn = diskDatastoreMofromVM; + } } } } - assert (vmSpec.getMinSpeed() != null) && (rootDiskDataStoreDetails != null); - - boolean vmFolderExists = rootDiskDataStoreDetails.second().folderExists(String.format("[%s]", rootDiskDataStoreDetails.second().getName()), vmNameOnVcenter); - String vmxFileFullPath = dsRootVolumeIsOn.searchFileInSubFolders(vmNameOnVcenter + ".vmx", false, VmwareManager.s_vmwareSearchExcludeFolder.value()); + boolean vmFolderExists = dsRootVolumeIsOn.folderExists(String.format("[%s]", dsRootVolumeIsOn.getName()), vmNameOnVcenter); String vmxFileFullPath = dsRootVolumeIsOn.searchFileInSubFolders(vmNameOnVcenter + ".vmx", false, VmwareManager.s_vmwareSearchExcludeFolder.value()); if (vmFolderExists && vmxFileFullPath != null) { // VM can be registered only if .vmx is present. registerVm(vmNameOnVcenter, dsRootVolumeIsOn); vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); @@ -2121,13 +2118,30 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa iScsiName = details.get(DiskTO.IQN); } + String primaryStoreUuid = primaryStore.getUuid(); // if the storage is managed, iScsiName should not be null - String datastoreName = managed ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); + String datastoreName = managed ? VmwareResource.getDatastoreName(iScsiName) : primaryStoreUuid; Pair volumeDsDetails = dataStoresDetails.get(datastoreName); assert (volumeDsDetails != null); + if (volumeDsDetails == null) { + throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host."); + } - String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec, vol, matchingExistingDisk, dataStoresDetails); + if (vol.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && vol.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) { + if (diskInfoBuilder != null && matchingExistingDisk == null) { + DatastoreMO diskDatastoreMofromVM = getDataStoreWhereDiskExists(hyperHost, context, diskInfoBuilder, vol, diskDatastores); + if (diskDatastoreMofromVM != null) { + String actualPoolUuid = diskDatastoreMofromVM.getCustomFieldValue(CustomFieldConstants.CLOUD_UUID); + if (!actualPoolUuid.equalsIgnoreCase(primaryStore.getUuid())) { + volumeDsDetails = new Pair<>(diskDatastoreMofromVM.getMor(), diskDatastoreMofromVM); + ((PrimaryDataStoreTO)primaryStore).setUuid(actualPoolUuid); + } + } + } + } + + String[] diskChain = syncDiskChain(dcMo, vmMo, vol, matchingExistingDisk, volumeDsDetails.second()); int deviceNumber = -1; if (controllerKey == vmMo.getIDEControllerKey(ideUnitNumber)) { @@ -2872,31 +2886,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } // return the finalized disk chain for startup, from top to bottom - private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO vol, VirtualMachineDiskInfo diskInfo, - HashMap> dataStoresDetails) throws Exception { + private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, DiskTO vol, VirtualMachineDiskInfo diskInfo, + DatastoreMO dsMo) throws Exception { VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); - DataStoreTO primaryStore = volumeTO.getDataStore(); Map details = vol.getDetails(); boolean isManaged = false; - String iScsiName = null; if (details != null) { isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - iScsiName = details.get(DiskTO.IQN); } - // if the storage is managed, iScsiName should not be null - String datastoreName = isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); - Pair volumeDsDetails = dataStoresDetails.get(datastoreName); - - if (volumeDsDetails == null) { - throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host."); - } - - DatastoreMO dsMo = volumeDsDetails.second(); String datastoreDiskPath; - if (dsMo.getDatastoreType().equalsIgnoreCase("VVOL")) { datastoreDiskPath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk"); if (!dsMo.fileExists(datastoreDiskPath)) { @@ -3327,6 +3328,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa volInSpec.setPath(datastoreVolumePath); } else { volInSpec.setPath(file.getFileBaseName()); + if (!file.getDatastoreName().equals(volumeTO.getDataStore().getUuid())) + volInSpec.setUpdatedDataStoreUUID(file.getDatastoreName()); } volInSpec.setChainInfo(_gson.toJson(diskInfo)); } @@ -3462,6 +3465,41 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return path.substring(0, endIndex).trim(); } + private DatastoreMO getDataStoreWhereDiskExists(VmwareHypervisorHost hyperHost, VmwareContext context, + VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO disk, List> diskDatastores) throws Exception { + VolumeObjectTO volume = (VolumeObjectTO) disk.getData(); + String diskBackingFileBaseName = volume.getPath(); + for (Pair diskDatastore : diskDatastores) { + DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), diskDatastore.second()); + String dsName = dsMo.getName(); + + VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName); + if (diskInfo != null) { + s_logger.info("Found existing disk info from volume path: " + volume.getPath()); + return dsMo; + } 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 dsMo; + } + } + } + } + } + } + } + return null; + } + private HashMap> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, DiskTO[] disks, Command cmd) throws Exception { HashMap> mapIdToMors = new HashMap<>(); @@ -3534,39 +3572,25 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return mapIdToMors; } - private DatastoreMO getDatastoreThatRootDiskIsOn(HashMap> dataStoresDetails, DiskTO disks[]) { + private Pair getDatastoreThatDiskIsOn(HashMap> dataStoresDetails, DiskTO vol) { Pair rootDiskDataStoreDetails = null; - for (DiskTO vol : disks) { - if (vol.getType() == Volume.Type.ROOT) { - Map details = vol.getDetails(); - boolean managed = false; + Map details = vol.getDetails(); + boolean managed = false; - if (details != null) { - managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - } - - if (managed) { - String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); - - rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); - - break; - } else { - DataStoreTO primaryStore = vol.getData().getDataStore(); - - rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); - - break; - } - } + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); } - if (rootDiskDataStoreDetails != null) { - return rootDiskDataStoreDetails.second(); + if (managed) { + String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); + rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); + } else { + DataStoreTO primaryStore = vol.getData().getDataStore(); + rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); } - return null; + return rootDiskDataStoreDetails; } private String getPvlanInfo(NicTO nicTo) { diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java index 35f77e2e358..5eb5c3e0d6a 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -35,6 +35,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import com.cloud.hypervisor.vmware.mo.VirtualStorageObjectManagerMO; +import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder; import com.vmware.vim25.BaseConfigInfoDiskFileBackingInfo; import com.vmware.vim25.VStorageObject; import com.vmware.vim25.VirtualDiskType; @@ -2081,6 +2082,7 @@ public class VmwareStorageProcessor implements StorageProcessor { DatastoreMO dsMo = new DatastoreMO(context, morDs); String datastoreVolumePath; + boolean datastoreChangeObserved = false; if (isAttach) { if (isManaged) { @@ -2106,6 +2108,25 @@ public class VmwareStorageProcessor implements StorageProcessor { if (isManaged) { datastoreVolumePath = dsMo.getDatastorePath((vmdkPath != null ? vmdkPath : dsMo.getName()) + ".vmdk"); } else { + String datastoreUUID = primaryStore.getUuid(); + if (disk.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && disk.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) { + DatastoreMO diskDatastoreMoFromVM = getDiskDatastoreMofromVM(hyperHost, context, vmMo, disk); + if (diskDatastoreMoFromVM != null) { + String actualPoolUuid = diskDatastoreMoFromVM.getCustomFieldValue(CustomFieldConstants.CLOUD_UUID); + if (!actualPoolUuid.equalsIgnoreCase(primaryStore.getUuid())) { + s_logger.warn(String.format("Volume %s found to be in a different storage pool %s", volumeTO.getPath(), actualPoolUuid)); + datastoreChangeObserved = true; + datastoreUUID = actualPoolUuid; + } + } + } + if (storagePort == DEFAULT_NFS_PORT) { + morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(diskUuid) : datastoreUUID); + } else { + morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : datastoreUUID); + } + dsMo = new DatastoreMO(context, morDs); + datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk"); if (!dsMo.fileExists(datastoreVolumePath)) { datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk"); @@ -2147,6 +2168,8 @@ public class VmwareStorageProcessor implements StorageProcessor { VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath(), vmName, VmwareManager.s_vmwareSearchExcludeFolder.value()); } } + if (datastoreChangeObserved) + answer.setContextParam("datastoreName", dsMo.getName()); } return answer; @@ -2172,6 +2195,44 @@ public class VmwareStorageProcessor implements StorageProcessor { } } + private DatastoreMO getDiskDatastoreMofromVM(VmwareHypervisorHost hyperHost, VmwareContext context, + VirtualMachineMO vmMo, DiskTO disk) throws Exception { + assert (hyperHost != null) && (context != null); + List> diskDatastores = vmMo.getAllDiskDatastores(); + VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); + VolumeObjectTO volume = (VolumeObjectTO) disk.getData(); + String diskBackingFileBaseName = volume.getPath(); + for (Pair diskDatastore : diskDatastores) { + DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), diskDatastore.second()); + String dsName = dsMo.getName(); + + VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName); + if (diskInfo != null) { + s_logger.info("Found existing disk info from volume path: " + volume.getPath()); + return dsMo; + } 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 dsMo; + } + } + } + } + } + } + } + return null; + } + private boolean expandVirtualDisk(VirtualMachineMO vmMo, String datastoreVolumePath, long currentSizeInBytes) throws Exception { long currentSizeInKB = currentSizeInBytes / 1024; diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index 4127b9f5fcc..3fdf534b7f4 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -2025,6 +2025,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic DataTO volTO = volFactory.getVolume(volume.getId()).getTO(); DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType()); + Map details = new HashMap(); + disk.setDetails(details); + if (volume.getPoolId() != null) { + StoragePoolVO poolVO = _storagePoolDao.findById(volume.getPoolId()); + if (poolVO.getParent() != 0L) { + details.put(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); + } + } DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); @@ -2045,6 +2053,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic if (!sendCommand || (answer != null && answer.getResult())) { // Mark the volume as detached _volsDao.detachVolume(volume.getId()); + String datastoreName = answer.getContextParam("datastoreName"); + if (datastoreName != null) { + List storagePoolVOS = _storagePoolDao.listPoolsByLikePath(datastoreName); + if (storagePoolVOS != null && !storagePoolVOS.isEmpty()) { + VolumeVO volumeVO = _volsDao.findById(volumeId); + volumeVO.setPoolId(storagePoolVOS.get(0).getId()); + _volsDao.update(volumeVO.getId(), volumeVO); + } else { + s_logger.warn(String.format("Unable to find datastore %s while updating the new datastore of the volume %d", datastoreName, volumeId)); + } + } // volume.getPoolId() should be null if the VM we are detaching the disk from has never been started before if (volume.getPoolId() != null) { @@ -3041,6 +3060,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic details.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); details.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); } + + if (volumeToAttach.getPoolId() != null) { + StoragePoolVO poolVO = _storagePoolDao.findById(volumeToAttach.getPoolId()); + if (poolVO.getParent() != 0L) { + details.put(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); + } + } + _userVmDao.loadDetails(vm); Map controllerInfo = new HashMap(); controllerInfo.put(VmDetailConstants.ROOT_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER)); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index f99c8f70393..44eb47b93d1 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -2637,7 +2637,7 @@ public class VirtualMachineMO extends BaseMO { VirtualDeviceBackingInfo backingInfo = ((VirtualDisk)device).getBacking(); if (backingInfo instanceof VirtualDiskFlatVer2BackingInfo) { VirtualDiskFlatVer2BackingInfo diskBackingInfo = (VirtualDiskFlatVer2BackingInfo)backingInfo; - disks.add(new Pair(new Integer(device.getKey()), diskBackingInfo.getDatastore())); + disks.add(new Pair(new Integer(device.getUnitNumber()), diskBackingInfo.getDatastore())); } } }