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())); } } }