mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-9956: File search on the vmware datastore may select wrong file if there are multiple files with same name (#2153)
If there are multiple files with the same name on vmware datastore, search operation may select any one file during volume related operations. This involves volume attach/detach, volume download, volume snapshot etc. While using NetApp as the backup solution. This has .snapshot folder on the datastore and sometimes files from this folder gets selected during volume operations and the operation fails. Because of wrong selection of file following exception can be observed while volume deletion. 2017-02-23 19:39:05,750 ERROR [c.c.s.r.VmwareStorageProcessor] (DirectAgent-304:ctx-a1dbf5d8 ac.local) delete volume failed due to Exception: java.lang.RuntimeException Message: Cannot delete file [4cbcd46d44c53f5c8244c0aad26a97e1] .snapshot/hourly.2017-02-23_1605/r-97-VM/ROOT-97.vmdk To fix this behavior I have added a global configuration by name vmware.search.exclude.folders which can be comma separated list of folder paths. I have also added a unit test to test the new method.
This commit is contained in:
parent
3bc2341c64
commit
3f69c83f96
@ -531,6 +531,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
||||
// FIXME: Fix long checkPointId2 = _checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(hostDetails.get("guid"), workerName2));
|
||||
cmd.setContextParam("worker2", workerName2);
|
||||
cmd.setContextParam("checkpoint2", String.valueOf(checkPointId2));
|
||||
cmd.setContextParam("searchexludefolders", _vmwareMgr.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
|
||||
return new Pair<Boolean, Long>(Boolean.TRUE, cmdTarget.first().getId());
|
||||
|
||||
@ -39,6 +39,9 @@ public interface VmwareManager {
|
||||
public static final ConfigKey<Boolean> s_vmwareCleanOldWorderVMs = new ConfigKey<Boolean>("Advanced", Boolean.class, "vmware.clean.old.worker.vms", "false",
|
||||
"If a worker vm is older then twice the 'job.expire.minutes' + 'job.cancel.threshold.minutes' , remove it.", true, ConfigKey.Scope.Global);
|
||||
|
||||
static final ConfigKey<String> s_vmwareSearchExcludeFolder = new ConfigKey<String>("Advanced", String.class, "vmware.search.exclude.folders", null,
|
||||
"Comma seperated list of Datastore Folders to exclude from VMWare search", true, ConfigKey.Scope.Global);
|
||||
|
||||
String composeWorkerName();
|
||||
|
||||
String getSystemVMIsoFileNameOnDatastore();
|
||||
|
||||
@ -229,7 +229,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
|
||||
|
||||
@Override
|
||||
public ConfigKey<?>[] getConfigKeys() {
|
||||
return new ConfigKey<?>[] {s_vmwareNicHotplugWaitTimeout, s_vmwareCleanOldWorderVMs, templateCleanupInterval};
|
||||
return new ConfigKey<?>[] {s_vmwareNicHotplugWaitTimeout, s_vmwareCleanOldWorderVMs, templateCleanupInterval, s_vmwareSearchExcludeFolder};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -307,6 +307,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
||||
String snapshotUuid = cmd.getSnapshotUuid(); // not null: Precondition.
|
||||
String prevSnapshotUuid = cmd.getPrevSnapshotUuid();
|
||||
String prevBackupUuid = cmd.getPrevBackupUuid();
|
||||
String searchExcludedFolders = cmd.getContextParam("searchexludefolders");
|
||||
VirtualMachineMO workerVm = null;
|
||||
String workerVMName = null;
|
||||
String volumePath = cmd.getVolumePath();
|
||||
@ -344,7 +345,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
||||
workerVm = vmMo;
|
||||
|
||||
// attach volume to worker VM
|
||||
String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk");
|
||||
String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk", searchExcludedFolders);
|
||||
vmMo.attachDisk(new String[] {datastoreVolumePath}, morDs);
|
||||
}
|
||||
}
|
||||
@ -986,6 +987,8 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
||||
VirtualMachineMO workerVm = null;
|
||||
VirtualMachineMO vmMo = null;
|
||||
String exportName = UUID.randomUUID().toString();
|
||||
String searchExcludedFolders = cmd.getContextParam("searchexludefolders");
|
||||
|
||||
|
||||
try {
|
||||
ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId);
|
||||
@ -1009,7 +1012,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
||||
}
|
||||
|
||||
//attach volume to worker VM
|
||||
String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk");
|
||||
String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk", searchExcludedFolders);
|
||||
workerVm.attachDisk(new String[] {datastoreVolumePath}, morDs);
|
||||
vmMo = workerVm;
|
||||
}
|
||||
@ -1030,8 +1033,8 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
||||
}
|
||||
}
|
||||
|
||||
private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName) throws Exception {
|
||||
String datastoreVolumePath = dsMo.searchFileInSubFolders(volumeFileName, true);
|
||||
private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName, String searchExcludeFolders) throws Exception {
|
||||
String datastoreVolumePath = dsMo.searchFileInSubFolders(volumeFileName, true, searchExcludeFolders);
|
||||
if (datastoreVolumePath == null) {
|
||||
throw new CloudRuntimeException("Unable to find file " + volumeFileName + " in datastore " + dsMo.getName());
|
||||
}
|
||||
|
||||
@ -645,7 +645,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
ManagedObjectReference vmFolderMor = dataCenterMo.getVmFolder();
|
||||
|
||||
//2nd param
|
||||
String vmxFilePath = dsMo.searchFileInSubFolders(vmName + ".vmx", false);
|
||||
String vmxFilePath = dsMo.searchFileInSubFolders(vmName + ".vmx", false, VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
|
||||
// 5th param
|
||||
ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
|
||||
@ -1683,7 +1683,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
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);
|
||||
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);
|
||||
@ -2360,7 +2360,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
DatastoreFile file = new DatastoreFile(disks[i]);
|
||||
if (!isManaged && file.getDir() != null && file.getDir().isEmpty()) {
|
||||
s_logger.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder");
|
||||
disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, file.getFileBaseName());
|
||||
disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, file.getFileBaseName(), VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
}
|
||||
return disks;
|
||||
@ -2370,13 +2370,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
|
||||
if (isManaged) {
|
||||
if (volumeTO.getVolumeType() == Volume.Type.ROOT) {
|
||||
datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getName());
|
||||
datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getName(), VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
else {
|
||||
datastoreDiskPath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
|
||||
}
|
||||
} else {
|
||||
datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getPath());
|
||||
datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getPath(), VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
|
||||
if (!dsMo.fileExists(datastoreDiskPath)) {
|
||||
@ -2802,7 +2802,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
vmFolder = new DatastoreFile(fileInDatastore.getDatastoreName(), fileInDatastore.getDir());
|
||||
DatastoreMO dsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName()));
|
||||
s_logger.debug("Deleting file: " + file.getName());
|
||||
dsMo.deleteFile(file.getName(), dcMo.getMor(), true);
|
||||
dsMo.deleteFile(file.getName(), dcMo.getMor(), true, VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
// Delete files that are present in the VM folder - this will take care of the VM disks as well.
|
||||
DatastoreMO vmFolderDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(vmFolder.getDatastoreName()));
|
||||
@ -2811,7 +2811,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
for (String file : files) {
|
||||
String vmDiskFileFullPath = String.format("%s/%s", vmFolder.getPath(), file);
|
||||
s_logger.debug("Deleting file: " + vmDiskFileFullPath);
|
||||
vmFolderDsMo.deleteFile(vmDiskFileFullPath, dcMo.getMor(), true);
|
||||
vmFolderDsMo.deleteFile(vmDiskFileFullPath, dcMo.getMor(), true, VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
}
|
||||
// Delete VM folder
|
||||
|
||||
@ -67,6 +67,11 @@ public class VmwareStorageLayoutHelper {
|
||||
}
|
||||
|
||||
public static String findVolumeDatastoreFullPath(DatastoreMO dsMo, String vmName, String vmdkFileName) throws Exception {
|
||||
return findVolumeDatastoreFullPath(dsMo, vmName, vmdkFileName, null);
|
||||
}
|
||||
|
||||
public static String findVolumeDatastoreFullPath(DatastoreMO dsMo, String vmName, String vmdkFileName, String excludeFolders) throws Exception {
|
||||
|
||||
if (vmName != null) {
|
||||
String path = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkFileName);
|
||||
if (!dsMo.fileExists(path)) {
|
||||
@ -80,7 +85,7 @@ public class VmwareStorageLayoutHelper {
|
||||
String path = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkFileName);
|
||||
if (!dsMo.fileExists(path)) {
|
||||
// Datastore file movement is not atomic operations, we need to sync and repair
|
||||
path = dsMo.searchFileInSubFolders(vmdkFileName, false);
|
||||
path = dsMo.searchFileInSubFolders(vmdkFileName, false, excludeFolders);
|
||||
|
||||
// to save one call to vCenter, we won't check file existence for this round, so the caller
|
||||
// may still fail with exception, but if that's case, we will let it fail anyway
|
||||
@ -90,6 +95,10 @@ public class VmwareStorageLayoutHelper {
|
||||
}
|
||||
|
||||
public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName, DatastoreMO ds, String vmdkName) throws Exception {
|
||||
return syncVolumeToVmDefaultFolder(dcMo, vmName, ds, vmdkName, null);
|
||||
}
|
||||
|
||||
public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName, DatastoreMO ds, String vmdkName, String excludeFolders) throws Exception {
|
||||
|
||||
assert (ds != null);
|
||||
if (!ds.folderExists(String.format("[%s]", ds.getName()), vmName)) {
|
||||
@ -109,7 +118,7 @@ public class VmwareStorageLayoutHelper {
|
||||
// be left over in its previous owner VM. We will do a fixup synchronization here by moving it to root
|
||||
// again.
|
||||
//
|
||||
syncVolumeToRootFolder(dcMo, ds, vmdkName, vmName);
|
||||
syncVolumeToRootFolder(dcMo, ds, vmdkName, vmName, excludeFolders);
|
||||
}
|
||||
|
||||
if (ds.fileExists(vmdkFullCloneModeLegacyPair[1])) {
|
||||
@ -134,7 +143,11 @@ public class VmwareStorageLayoutHelper {
|
||||
}
|
||||
|
||||
public static void syncVolumeToRootFolder(DatacenterMO dcMo, DatastoreMO ds, String vmdkName, String vmName) throws Exception {
|
||||
String fileDsFullPath = ds.searchFileInSubFolders(vmdkName + ".vmdk", false);
|
||||
syncVolumeToRootFolder(dcMo, ds, vmdkName, null);
|
||||
}
|
||||
|
||||
public static void syncVolumeToRootFolder(DatacenterMO dcMo, DatastoreMO ds, String vmdkName, String vmName, String excludeFolders) throws Exception {
|
||||
String fileDsFullPath = ds.searchFileInSubFolders(vmdkName + ".vmdk", false, excludeFolders);
|
||||
if (fileDsFullPath == null)
|
||||
return;
|
||||
|
||||
@ -259,13 +272,17 @@ public class VmwareStorageLayoutHelper {
|
||||
}
|
||||
|
||||
public static void deleteVolumeVmdkFiles(DatastoreMO dsMo, String volumeName, DatacenterMO dcMo) throws Exception {
|
||||
deleteVolumeVmdkFiles(dsMo, volumeName, dcMo, null);
|
||||
}
|
||||
|
||||
public static void deleteVolumeVmdkFiles(DatastoreMO dsMo, String volumeName, DatacenterMO dcMo, String excludeFolders) throws Exception {
|
||||
|
||||
String fileName = volumeName + ".vmdk";
|
||||
String fileFullPath = getLegacyDatastorePathFromVmdkFileName(dsMo, fileName);
|
||||
if (!dsMo.fileExists(fileFullPath))
|
||||
fileFullPath = dsMo.searchFileInSubFolders(fileName, false);
|
||||
fileFullPath = dsMo.searchFileInSubFolders(fileName, false, excludeFolders);
|
||||
if (fileFullPath != null) {
|
||||
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true);
|
||||
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true, excludeFolders);
|
||||
} else {
|
||||
s_logger.warn("Unable to locate VMDK file: " + fileName);
|
||||
}
|
||||
@ -273,9 +290,9 @@ public class VmwareStorageLayoutHelper {
|
||||
fileName = volumeName + "-flat.vmdk";
|
||||
fileFullPath = getLegacyDatastorePathFromVmdkFileName(dsMo, fileName);
|
||||
if (!dsMo.fileExists(fileFullPath))
|
||||
fileFullPath = dsMo.searchFileInSubFolders(fileName, false);
|
||||
fileFullPath = dsMo.searchFileInSubFolders(fileName, false, excludeFolders);
|
||||
if (fileFullPath != null) {
|
||||
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true);
|
||||
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true, excludeFolders);
|
||||
} else {
|
||||
s_logger.warn("Unable to locate VMDK file: " + fileName);
|
||||
}
|
||||
@ -283,9 +300,9 @@ public class VmwareStorageLayoutHelper {
|
||||
fileName = volumeName + "-delta.vmdk";
|
||||
fileFullPath = getLegacyDatastorePathFromVmdkFileName(dsMo, fileName);
|
||||
if (!dsMo.fileExists(fileFullPath))
|
||||
fileFullPath = dsMo.searchFileInSubFolders(fileName, false);
|
||||
fileFullPath = dsMo.searchFileInSubFolders(fileName, false, excludeFolders);
|
||||
if (fileFullPath != null) {
|
||||
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true);
|
||||
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true, excludeFolders);
|
||||
} else {
|
||||
s_logger.warn("Unable to locate VMDK file: " + fileName);
|
||||
}
|
||||
|
||||
@ -450,6 +450,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
VolumeObjectTO volume = (VolumeObjectTO)destData;
|
||||
DataStoreTO primaryStore = volume.getDataStore();
|
||||
DataStoreTO srcStore = template.getDataStore();
|
||||
String searchExcludedFolders = cmd.getContextParam("searchexludefolders");
|
||||
|
||||
try {
|
||||
VmwareContext context = hostService.getServiceContext(null);
|
||||
@ -481,7 +482,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
String volumeDatastorePath = vmdkFilePair[0];
|
||||
synchronized (this) {
|
||||
s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath);
|
||||
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo);
|
||||
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo, searchExcludedFolders);
|
||||
vmMo.createDisk(volumeDatastorePath, (int)(volume.getSize() / (1024L * 1024L)), morDatastore, -1);
|
||||
vmMo.detachDisk(volumeDatastorePath, false);
|
||||
}
|
||||
@ -527,14 +528,14 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
vmMo.destroy();
|
||||
|
||||
String srcFile = dsMo.getDatastorePath(vmdkName, true);
|
||||
dsMo.deleteFile(srcFile, dcMo.getMor(), true);
|
||||
dsMo.deleteFile(srcFile, dcMo.getMor(), true, searchExcludedFolders);
|
||||
}
|
||||
// restoreVM - move the new ROOT disk into corresponding VM folder
|
||||
VirtualMachineMO restoreVmMo = dcMo.findVm(volume.getVmName());
|
||||
if (restoreVmMo != null) {
|
||||
String vmNameInVcenter = restoreVmMo.getName(); // VM folder name in datastore will be VM's name in vCenter.
|
||||
if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmNameInVcenter)) {
|
||||
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmNameInVcenter, dsMo, vmdkFileBaseName);
|
||||
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmNameInVcenter, dsMo, vmdkFileBaseName, searchExcludedFolders);
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,8 +632,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
|
||||
}
|
||||
|
||||
private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName) throws Exception {
|
||||
String datastoreVolumePath = dsMo.searchFileInSubFolders(volumeFileName, true);
|
||||
private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName, String searchExcludedFolders) throws Exception {
|
||||
String datastoreVolumePath = dsMo.searchFileInSubFolders(volumeFileName, true, searchExcludedFolders);
|
||||
assert (datastoreVolumePath != null) : "Virtual disk file missing from datastore.";
|
||||
return datastoreVolumePath;
|
||||
}
|
||||
@ -642,6 +643,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
VirtualMachineMO workerVm = null;
|
||||
VirtualMachineMO vmMo = null;
|
||||
String exportName = UUID.randomUUID().toString().replace("-", "");
|
||||
String searchExcludedFolders = cmd.getContextParam("searchexludefolders");
|
||||
|
||||
try {
|
||||
ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId);
|
||||
@ -665,7 +667,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
}
|
||||
|
||||
// attach volume to worker VM
|
||||
String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk");
|
||||
String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk", searchExcludedFolders);
|
||||
workerVm.attachDisk(new String[] {datastoreVolumePath}, morDs);
|
||||
vmMo = workerVm;
|
||||
}
|
||||
@ -690,6 +692,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
VolumeObjectTO srcVolume = (VolumeObjectTO)cmd.getSrcTO();
|
||||
VolumeObjectTO destVolume = (VolumeObjectTO)cmd.getDestTO();
|
||||
String vmName = srcVolume.getVmName();
|
||||
String searchExcludedFolders = cmd.getContextParam("searchexludefolders");
|
||||
|
||||
VmwareContext context = hostService.getServiceContext(cmd);
|
||||
try {
|
||||
@ -1380,7 +1383,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
if (isManaged) {
|
||||
datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
|
||||
} else {
|
||||
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo, volumeTO.getPath());
|
||||
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo, volumeTO.getPath(), VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
} else {
|
||||
if (isManaged) {
|
||||
@ -1415,7 +1418,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
if (isManaged) {
|
||||
handleDatastoreAndVmdkDetachManaged(diskUuid, iScsiName, storageHost, storagePort);
|
||||
} else {
|
||||
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath(), vmName);
|
||||
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath(), vmName, VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1591,7 +1594,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
}
|
||||
catch (Exception e) {
|
||||
s_logger.error("Deleting file " + volumeDatastorePath + " due to error: " + e.getMessage());
|
||||
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo);
|
||||
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo, VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
throw new CloudRuntimeException("Unable to create volume due to: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@ -1753,7 +1756,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc));
|
||||
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc), VmwareManager.s_vmwareSearchExcludeFolder.value());
|
||||
|
||||
return new Answer(cmd, true, "Success");
|
||||
} catch (Throwable e) {
|
||||
|
||||
@ -166,6 +166,10 @@ public class DatastoreMO extends BaseMO {
|
||||
}
|
||||
|
||||
public boolean deleteFile(String path, ManagedObjectReference morDc, boolean testExistence) throws Exception {
|
||||
return deleteFile(path, morDc, testExistence, null);
|
||||
}
|
||||
|
||||
public boolean deleteFile(String path, ManagedObjectReference morDc, boolean testExistence, String excludeFolders) throws Exception {
|
||||
String datastoreName = getName();
|
||||
ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager();
|
||||
|
||||
@ -180,7 +184,7 @@ public class DatastoreMO extends BaseMO {
|
||||
|
||||
try {
|
||||
if (testExistence && !fileExists(fullPath)) {
|
||||
String searchResult = searchFileInSubFolders(file.getFileName(), true);
|
||||
String searchResult = searchFileInSubFolders(file.getFileName(), true, excludeFolders);
|
||||
if (searchResult == null) {
|
||||
return true;
|
||||
} else {
|
||||
@ -352,8 +356,13 @@ public class DatastoreMO extends BaseMO {
|
||||
}
|
||||
|
||||
public String searchFileInSubFolders(String fileName, boolean caseInsensitive) throws Exception {
|
||||
return searchFileInSubFolders(fileName,caseInsensitive,null);
|
||||
}
|
||||
|
||||
public String searchFileInSubFolders(String fileName, boolean caseInsensitive, String excludeFolders) throws Exception {
|
||||
String datastorePath = "[" + getName() + "]";
|
||||
String rootDirectoryFilePath = String.format("%s %s", datastorePath, fileName);
|
||||
String[] searchExcludedFolders = getSearchExcludedFolders(excludeFolders);
|
||||
if (fileExists(rootDirectoryFilePath)) {
|
||||
return rootDirectoryFilePath;
|
||||
}
|
||||
@ -380,6 +389,9 @@ public class DatastoreMO extends BaseMO {
|
||||
if (parentFolderPath.endsWith("]"))
|
||||
absoluteFileName += " ";
|
||||
absoluteFileName += fi.getPath();
|
||||
if(isValidCloudStackFolderPath(parentFolderPath, searchExcludedFolders)) {
|
||||
return absoluteFileName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -387,6 +399,20 @@ public class DatastoreMO extends BaseMO {
|
||||
return absoluteFileName;
|
||||
}
|
||||
|
||||
private String[] getSearchExcludedFolders(String excludeFolders) {
|
||||
return excludeFolders != null ? excludeFolders.replaceAll("\\s","").split(",") : new String[] {};
|
||||
}
|
||||
|
||||
private boolean isValidCloudStackFolderPath(String dataStoreFolderPath, String[] searchExcludedFolders) throws Exception {
|
||||
String dsFolder = dataStoreFolderPath.replaceFirst("\\[" + getName() + "\\]", "").trim();
|
||||
for( String excludedFolder : searchExcludedFolders) {
|
||||
if (dsFolder.startsWith(excludedFolder)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAccessibleToHost(String hostValue) throws Exception {
|
||||
boolean isAccessible = true;
|
||||
List<DatastoreHostMount> hostMounts = getHostMounts();
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package com.cloud.hypervisor.vmware.mo;
|
||||
|
||||
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||
import com.vmware.vim25.FileInfo;
|
||||
import com.vmware.vim25.HostDatastoreBrowserSearchResults;
|
||||
import com.vmware.vim25.ManagedObjectReference;
|
||||
import com.vmware.vim25.VimPortType;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Created by sudharma_jain on 6/13/17.
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(DatastoreMO.class)
|
||||
public class DatastoreMOTest {
|
||||
@Mock
|
||||
VmwareContext _context ;
|
||||
@Mock
|
||||
VmwareClient _client;
|
||||
@Mock
|
||||
ManagedObjectReference _mor;
|
||||
@Mock
|
||||
HostDatastoreBrowserMO browserMo;
|
||||
@Mock
|
||||
VimPortType vimPortType;
|
||||
|
||||
DatastoreMO datastoreMO ;
|
||||
String fileName = "ROOT-5.vmdk";
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
datastoreMO = new DatastoreMO(_context, _mor);
|
||||
PowerMockito.whenNew(HostDatastoreBrowserMO.class).withAnyArguments().thenReturn(browserMo);
|
||||
when(_context.getVimClient()).thenReturn(_client);
|
||||
when(_client.getDynamicProperty(any(ManagedObjectReference.class), eq("name"))).thenReturn("252d36c96cfb32f48ce7756ccb79ae37");
|
||||
|
||||
ArrayList<HostDatastoreBrowserSearchResults> results = new ArrayList<>();
|
||||
|
||||
HostDatastoreBrowserSearchResults r1 = new HostDatastoreBrowserSearchResults();
|
||||
FileInfo f1 = new FileInfo();
|
||||
f1.setPath(fileName);
|
||||
r1.getFile().add(f1);
|
||||
r1.setFolderPath("[252d36c96cfb32f48ce7756ccb79ae37] .snapshot/hourly.2017-02-23_1705/i-2-5-VM/");
|
||||
|
||||
HostDatastoreBrowserSearchResults r2 = new HostDatastoreBrowserSearchResults();
|
||||
FileInfo f2 = new FileInfo();
|
||||
f2.setPath(fileName);
|
||||
r2.getFile().add(f2);
|
||||
r2.setFolderPath("[252d36c96cfb32f48ce7756ccb79ae37] .snapshot/hourly.2017-02-23_1605/i-2-5-VM/");
|
||||
|
||||
HostDatastoreBrowserSearchResults r3 = new HostDatastoreBrowserSearchResults();
|
||||
FileInfo f3 = new FileInfo();
|
||||
f3.setPath(fileName);
|
||||
r3.getFile().add(f3);
|
||||
r3.setFolderPath("[252d36c96cfb32f48ce7756ccb79ae37] i-2-5-VM/");
|
||||
|
||||
results.add(r1);
|
||||
results.add(r2);
|
||||
results.add(r3);
|
||||
|
||||
when(browserMo.searchDatastore(any(String.class), any(String.class), eq(true))).thenReturn(null);
|
||||
when(browserMo.searchDatastoreSubFolders(any(String.class),any(String.class), any(Boolean.class) )).thenReturn(results);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchFileInSubFolders() throws Exception {
|
||||
assertEquals("Unexpected Behavior: search should exclude .snapshot folder", "[252d36c96cfb32f48ce7756ccb79ae37] i-2-5-VM/ROOT-5.vmdk", datastoreMO.searchFileInSubFolders(fileName, false, ".snapshot") );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchFileInSubFoldersWithExcludeMultipleFolders() throws Exception {
|
||||
assertEquals("Unexpected Behavior: search should exclude folders", datastoreMO.searchFileInSubFolders(fileName, false, "i-2-5-VM, .snapshot/hourly.2017-02-23_1705"), "[252d36c96cfb32f48ce7756ccb79ae37] .snapshot/hourly.2017-02-23_1605/i-2-5-VM/ROOT-5.vmdk" );
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user