Handle detach volume of datastore cluster if the volume name has changed at vCenter level and reconsile the chaininfo

This commit is contained in:
Harikrishna Patnala 2020-10-06 10:47:01 +05:30
parent 588b7a1c90
commit 9b923ba9dc
7 changed files with 144 additions and 51 deletions

View File

@ -1734,9 +1734,9 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
vol.setPath(path);
vol.setChainInfo(chainInfo);
if (updatedDataStoreUUID != null) {
List<StoragePoolVO> pools = _storagePoolDao.listPoolsByLikePath(updatedDataStoreUUID);
if (pools != null && !pools.isEmpty()) {
vol.setPoolId(pools.get(0).getId());
StoragePoolVO pool = _storagePoolDao.findByUuid(updatedDataStoreUUID);
if (pool != null) {
vol.setPoolId(pool.getId());
}
}
_volsDao.update(volumeId, vol);

View File

@ -128,5 +128,4 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
Integer countAll();
public List<StoragePoolVO> listPoolsByLikePath(String path);
}

View File

@ -56,7 +56,6 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
private final SearchBuilder<StoragePoolVO> DeleteLvmSearch;
private final SearchBuilder<StoragePoolVO> DcLocalStorageSearch;
private final GenericSearchBuilder<StoragePoolVO, Long> StatusCountSearch;
private final SearchBuilder<StoragePoolVO> PathLikeSearch;
@Inject
private StoragePoolDetailsDao _detailsDao;
@ -134,16 +133,6 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
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<StoragePoolVO> listPoolsByLikePath(String path) {
SearchCriteria<StoragePoolVO> sc = PathLikeSearch.create();
sc.setParameters("path", "%" + path + "%");
return listBy(sc);
}
@Override

View File

@ -2127,12 +2127,23 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
if (vol.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && vol.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) {
if (diskInfoBuilder != null && matchingExistingDisk == null) {
if (diskInfoBuilder != null && matchingExistingDisk != null) {
String[] diskChain = matchingExistingDisk.getDiskChain();
if (diskChain != null && diskChain.length > 0) {
DatastoreFile file = new DatastoreFile(diskChain[0]);
if (!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) {
if (s_logger.isInfoEnabled())
s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + file.getFileBaseName());
volumeTO.setPath(file.getFileBaseName());
}
}
DatastoreMO diskDatastoreMofromVM = getDataStoreWhereDiskExists(hyperHost, context, diskInfoBuilder, vol, diskDatastores);
if (diskDatastoreMofromVM != null) {
String actualPoolUuid = diskDatastoreMofromVM.getCustomFieldValue(CustomFieldConstants.CLOUD_UUID);
if (!actualPoolUuid.equalsIgnoreCase(primaryStore.getUuid())) {
if (actualPoolUuid != null && !actualPoolUuid.equalsIgnoreCase(primaryStore.getUuid())) {
volumeDsDetails = new Pair<>(diskDatastoreMofromVM.getMor(), diskDatastoreMofromVM);
if (s_logger.isInfoEnabled())
s_logger.info("Detected datastore uuid change on volume: " + volumeTO.getId() + " " + primaryStore.getUuid() + " -> " + actualPoolUuid);
((PrimaryDataStoreTO)primaryStore).setUuid(actualPoolUuid);
}
}
@ -3322,8 +3333,9 @@ 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());
if (vol.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && vol.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) {
volInSpec.setUpdatedDataStoreUUID(volumeTO.getDataStore().getUuid());
}
}
volInSpec.setChainInfo(_gson.toJson(diskInfo));
}

View File

@ -2041,8 +2041,9 @@ public class VmwareStorageProcessor implements StorageProcessor {
String storageHost, int storagePort, Map<String, String> controllerInfo) {
VolumeObjectTO volumeTO = (VolumeObjectTO)disk.getData();
DataStoreTO primaryStore = volumeTO.getDataStore();
String volumePath = volumeTO.getPath();
String vmdkPath = isManaged ? resource.getVmdkPath(volumeTO.getPath()) : null;
String vmdkPath = isManaged ? resource.getVmdkPath(volumePath) : null;
try {
VmwareContext context = hostService.getServiceContext(null);
@ -2091,25 +2092,27 @@ public class VmwareStorageProcessor implements StorageProcessor {
DatastoreMO dsMo = new DatastoreMO(context, morDs);
String datastoreVolumePath;
boolean datastoreChangeObserved = false;
boolean volumePathChangeObserved = false;
String chainInfo = null;
if (isAttach) {
if (isManaged) {
datastoreVolumePath = dsMo.getDatastorePath((vmdkPath != null ? vmdkPath : dsMo.getName()) + ".vmdk");
} else {
if (dsMo.getDatastoreType().equalsIgnoreCase("VVOL")) {
datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumePath + ".vmdk");
if (!dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumePath + ".vmdk");
}
if (!dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmName) || !dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath(), volumeTO.getPath() + ".vmdk");
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, volumePath, volumePath + ".vmdk");
}
if (!dsMo.folderExists(String.format("[%s]", dsMo.getName()), volumeTO.getPath()) || !dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = dsMo.searchFileInSubFolders(volumeTO.getPath() + ".vmdk", true, null);
if (!dsMo.folderExists(String.format("[%s]", dsMo.getName()), volumePath) || !dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = dsMo.searchFileInSubFolders(volumePath + ".vmdk", true, null);
}
} else {
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo, volumeTO.getPath(), VmwareManager.s_vmwareSearchExcludeFolder.value());
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo, volumePath, VmwareManager.s_vmwareSearchExcludeFolder.value());
}
}
} else {
@ -2118,13 +2121,30 @@ public class VmwareStorageProcessor implements StorageProcessor {
} 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;
VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(hyperHost, context, vmMo, disk);
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
if (diskInfoBuilder != null && matchingExistingDisk != null) {
String[] diskChain = matchingExistingDisk.getDiskChain();
assert (diskChain.length > 0);
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: " + volumeTO.getId() + " " + volumePath + " -> " + file.getFileBaseName());
volumePathChangeObserved = true;
volumePath = file.getFileBaseName();
volumeTO.setPath(volumePath);
chainInfo = _gson.toJson(matchingExistingDisk);
}
DatastoreMO diskDatastoreMofromVM = getDiskDatastoreMofromVM(hyperHost, context, vmMo, disk, diskInfoBuilder);
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", volumePath, actualPoolUuid));
datastoreChangeObserved = true;
datastoreUUID = actualPoolUuid;
chainInfo = _gson.toJson(matchingExistingDisk);
}
}
}
}
@ -2135,15 +2155,15 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
dsMo = new DatastoreMO(context, morDs);
datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumePath + ".vmdk");
if (!dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumePath + ".vmdk");
}
if (!dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmName) || !dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath(), volumeTO.getPath() + ".vmdk");
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, volumePath, volumePath + ".vmdk");
}
if (!dsMo.folderExists(String.format("[%s]", dsMo.getName()), volumeTO.getPath()) || !dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = dsMo.searchFileInSubFolders(volumeTO.getPath() + ".vmdk", true, null);
if (!dsMo.folderExists(String.format("[%s]", dsMo.getName()), volumePath) || !dsMo.fileExists(datastoreVolumePath)) {
datastoreVolumePath = dsMo.searchFileInSubFolders(volumePath + ".vmdk", true, null);
}
}
}
@ -2176,11 +2196,18 @@ public class VmwareStorageProcessor implements StorageProcessor {
handleDatastoreAndVmdkDetachManaged(cmd, diskUuid, iScsiName, storageHost, storagePort);
} else {
if (!dsMo.getDatastoreType().equalsIgnoreCase("VVOL")) {
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath(), vmName, VmwareManager.s_vmwareSearchExcludeFolder.value());
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumePath, vmName, VmwareManager.s_vmwareSearchExcludeFolder.value());
}
}
if (datastoreChangeObserved)
answer.setContextParam("datastoreName", dsMo.getName());
if (datastoreChangeObserved) {
answer.setContextParam("datastoreName", dsMo.getCustomFieldValue(CustomFieldConstants.CLOUD_UUID));
answer.setContextParam("chainInfo", chainInfo);
}
if (volumePathChangeObserved) {
answer.setContextParam("volumePath", volumePath);
answer.setContextParam("chainInfo", chainInfo);
}
}
return answer;
@ -2206,11 +2233,58 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
}
private VirtualMachineDiskInfo getMatchingExistingDisk(VmwareHypervisorHost hyperHost, VmwareContext context, VirtualMachineMO vmMo, DiskTO vol)
throws Exception {
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
if (diskInfoBuilder != null) {
VolumeObjectTO volume = (VolumeObjectTO) vol.getData();
ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, volume.getDataStore().getUuid());
DatastoreMO dsMo = new DatastoreMO(context, morDs);
String dsName = dsMo.getName();
String 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());
if (diskInfo != null) {
s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName());
return diskInfo;
}
}
}
}
}
}
return null;
}
private DatastoreMO getDiskDatastoreMofromVM(VmwareHypervisorHost hyperHost, VmwareContext context,
VirtualMachineMO vmMo, DiskTO disk) throws Exception {
VirtualMachineMO vmMo, DiskTO disk, VirtualMachineDiskInfoBuilder diskInfoBuilder) throws Exception {
assert (hyperHost != null) && (context != null);
List<Pair<Integer, ManagedObjectReference>> diskDatastores = vmMo.getAllDiskDatastores();
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
VolumeObjectTO volume = (VolumeObjectTO) disk.getData();
String diskBackingFileBaseName = volume.getPath();
for (Pair<Integer, ManagedObjectReference> diskDatastore : diskDatastores) {

View File

@ -2055,16 +2055,29 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
_volsDao.detachVolume(volume.getId());
String datastoreName = answer.getContextParam("datastoreName");
if (datastoreName != null) {
List<StoragePoolVO> storagePoolVOS = _storagePoolDao.listPoolsByLikePath(datastoreName);
if (storagePoolVOS != null && !storagePoolVOS.isEmpty()) {
StoragePoolVO storagePoolVO = _storagePoolDao.findByUuid(datastoreName);
if (storagePoolVO != null) {
VolumeVO volumeVO = _volsDao.findById(volumeId);
volumeVO.setPoolId(storagePoolVOS.get(0).getId());
volumeVO.setPoolId(storagePoolVO.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));
}
}
String volumePath = answer.getContextParam("volumePath");
if (volumePath != null) {
VolumeVO volumeVO = _volsDao.findById(volumeId);
volumeVO.setPath(volumePath);
_volsDao.update(volumeVO.getId(), volumeVO);
}
String chainInfo = answer.getContextParam("chainInfo");
if (chainInfo != null) {
VolumeVO volumeVO = _volsDao.findById(volumeId);
volumeVO.setChainInfo(chainInfo);
_volsDao.update(volumeVO.getId(), volumeVO);
}
// volume.getPoolId() should be null if the VM we are detaching the disk from has never been started before
if (volume.getPoolId() != null) {
DataStore dataStore = dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary);

View File

@ -2896,14 +2896,20 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
s_logger.debug("Found no ongoing snapshots on volume of type ROOT, for the vm with id " + vmId);
List<VolumeVO> volumes = getVolumesFromIds(cmd);
List<VolumeVO> volumesToBeDeleted = getVolumesFromIds(cmd);
checkForUnattachedVolumes(vmId, volumes);
validateVolumes(volumes);
checkForUnattachedVolumes(vmId, volumesToBeDeleted);
validateVolumes(volumesToBeDeleted);
stopVirtualMachine(vmId, VmDestroyForcestop.value());
detachVolumesFromVm(volumes);
if (vm.getHypervisorType() == HypervisorType.VMware) {
List<VolumeVO> allVolumes = _volsDao.findByInstance(vm.getId());
allVolumes.removeIf(vol -> vol.getVolumeType() == Volume.Type.ROOT);
detachVolumesFromVm(allVolumes);
} else {
detachVolumesFromVm(volumesToBeDeleted);
}
UserVm destroyedVm = destroyVm(vmId, expunge);
if (expunge) {
@ -2912,7 +2918,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
deleteVolumesFromVm(volumes);
deleteVolumesFromVm(volumesToBeDeleted);
return destroyedVm;
}