cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bhais...@apache.org
Subject [cloudstack] branch master updated: CLOUDSTACK-9956: File search on the vmware datastore may select wrong file if there are multiple files with same name (#2153)
Date Tue, 19 Sep 2017 09:42:21 GMT
This is an automated email from the ASF dual-hosted git repository.

bhaisaab pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new 3f69c83  CLOUDSTACK-9956: File search on the vmware datastore may select wrong file
if there are multiple files with same name (#2153)
3f69c83 is described below

commit 3f69c83f96f927f4a84b2d4b29bce168caf0530d
Author: SudharmaJain <sudharma.jain@accelerite.com>
AuthorDate: Tue Sep 19 15:12:17 2017 +0530

    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.
---
 .../src/com/cloud/hypervisor/guru/VMwareGuru.java  |   1 +
 .../hypervisor/vmware/manager/VmwareManager.java   |   3 +
 .../vmware/manager/VmwareManagerImpl.java          |   2 +-
 .../vmware/manager/VmwareStorageManagerImpl.java   |  11 +-
 .../hypervisor/vmware/resource/VmwareResource.java |  14 +--
 .../resource/VmwareStorageLayoutHelper.java        |  35 +++++--
 .../storage/resource/VmwareStorageProcessor.java   |  23 +++--
 .../cloud/hypervisor/vmware/mo/DatastoreMO.java    |  28 ++++-
 .../hypervisor/vmware/mo/DatastoreMOTest.java      | 114 +++++++++++++++++++++
 9 files changed, 199 insertions(+), 32 deletions(-)

diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
index 7b6accf..d8076fd 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
@@ -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());
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java
b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java
index 65963eb..4a4d2ea 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java
@@ -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();
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
index c003b44..53e3239 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
@@ -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
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
index 3158ad4..00298ce 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
@@ -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());
         }
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index b8a3495..ccb5d0f 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -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
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java
b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java
index 4096333..fc79a4b 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java
@@ -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);
         }
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
index 8026575..012556e 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -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) {
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
index 290e1a0..1152ba5 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
@@ -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();
diff --git a/vmware-base/test/com/cloud/hypervisor/vmware/mo/DatastoreMOTest.java b/vmware-base/test/com/cloud/hypervisor/vmware/mo/DatastoreMOTest.java
new file mode 100644
index 0000000..394d199
--- /dev/null
+++ b/vmware-base/test/com/cloud/hypervisor/vmware/mo/DatastoreMOTest.java
@@ -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" );
+    }
+
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
['"commits@cloudstack.apache.org" <commits@cloudstack.apache.org>'].

Mime
View raw message