This is an automated email from the ASF dual-hosted git repository.

rohit 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 b2db897  server: fix for respecting secondary storage threshold limit 
(#3480)
b2db897 is described below

commit b2db8979f2249b0b6c0d8d0dfe40e05ba9ef9649
Author: Abhishek Kumar <[email protected]>
AuthorDate: Wed Jul 31 15:37:59 2019 +0530

    server: fix for respecting secondary storage threshold limit (#3480)
    
    Retrieval of an image store using ImageStoreProviderManager has been 
refactored by introducing three different methods,
    DataStore getRandomImageStore(List<DataStore> imageStores);
    To get an image store for reading purpose. Threshold capacity check will 
not be used here.
    DataStore getImageStoreWithFreeCapacity(List<DataStore> imageStores);
    To get an image store for reading purpose. Threshold capacity check will be 
used here and the store with max free space will be returned. If no store with 
filled storage less than the threshold is found, the NULL value will be 
returned.
    List<DataStore> listImageStoresWithFreeCapacity(List<DataStore> 
imageStores);
    To get a list of image stores for writing purpose which fulfills threshold 
capacity check.
    
    Correspondingly DataStoreManager methods have been refactored to return 
similar values for a given zone.
    
    Fixes #3287 - NULL value will be returned when secondary storage is needed 
for writing but there is not store with free space.
    Fixes #3041 - Rather than returning random secondary storage for writing, 
storage with max. free space will be returned.
    Fixes #3478 - For migration on VMware, all writable secondary storage will 
be mounted while preparation.
    
    Signed-off-by: Abhishek Kumar <[email protected]>
---
 .../subsystem/api/storage/DataStoreManager.java    |  6 ++-
 .../allocator/StorageCacheRandomAllocator.java     |  4 +-
 .../storage/motion/AncientDataMotionStrategy.java  |  4 +-
 .../KvmNonManagedStorageDataMotionStrategy.java    | 30 ++++++-----
 .../KvmNonManagedStorageSystemDataMotionTest.java  | 22 ++++----
 .../manager/ImageStoreProviderManagerImpl.java     | 58 ++++++++++++++++----
 .../storage/snapshot/SnapshotServiceImpl.java      |  4 +-
 .../storage/datastore/DataStoreManagerImpl.java    | 24 +++++++--
 .../image/datastore/ImageStoreProviderManager.java | 35 ++++++++++++-
 .../hyperv/manager/HypervManagerImpl.java          |  2 +-
 .../hypervisor/vmware/manager/VmwareManager.java   | 13 +++--
 .../vmware/manager/VmwareManagerImpl.java          | 31 ++++++++++-
 .../hypervisor/vmware/resource/VmwareResource.java | 61 +++++++++++++---------
 .../network/element/ConfigDriveNetworkElement.java | 19 +++++--
 .../main/java/com/cloud/server/StatsCollector.java | 12 +++++
 .../com/cloud/storage/VolumeApiServiceImpl.java    |  5 +-
 .../cloud/storage/upload/UploadMonitorImpl.java    |  6 ++-
 .../cloud/template/HypervisorTemplateAdapter.java  |  4 +-
 .../com/cloud/template/TemplateManagerImpl.java    |  8 +--
 .../element/ConfigDriveNetworkElementTest.java     |  2 +-
 .../SecondaryStorageManagerImpl.java               |  9 ++--
 21 files changed, 262 insertions(+), 97 deletions(-)

diff --git 
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java
 
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java
index 5ebef03..ad5b162 100644
--- 
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java
+++ 
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java
@@ -33,7 +33,11 @@ public interface DataStoreManager {
 
     List<DataStore> getImageStoresByScope(ZoneScope scope);
 
-    DataStore getImageStore(long zoneId);
+    DataStore getRandomImageStore(long zoneId);
+
+    DataStore getImageStoreWithFreeCapacity(long zoneId);
+
+    List<DataStore> listImageStoresWithFreeCapacity(long zoneId);
 
     List<DataStore> getImageCacheStores(Scope scope);
 
diff --git 
a/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java
 
b/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java
index c9832bf..22b3f46 100644
--- 
a/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java
+++ 
b/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java
@@ -62,7 +62,7 @@ public class StorageCacheRandomAllocator implements 
StorageCacheAllocator {
             return null;
         }
 
-        return imageStoreMgr.getImageStore(cacheStores);
+        return imageStoreMgr.getImageStoreWithFreeCapacity(cacheStores);
     }
 
     @Override
@@ -88,6 +88,6 @@ public class StorageCacheRandomAllocator implements 
StorageCacheAllocator {
                 }
             }
         }
-        return imageStoreMgr.getImageStore(cacheStores);
+        return imageStoreMgr.getImageStoreWithFreeCapacity(cacheStores);
     }
 }
diff --git 
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
 
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 7b52645..39851b4 100644
--- 
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ 
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -328,8 +328,8 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
         if (cacheStore == null) {
             // need to find a nfs or cifs image store, assuming that can't 
copy volume
             // directly to s3
-            ImageStoreEntity imageStore = 
(ImageStoreEntity)dataStoreMgr.getImageStore(destScope.getScopeId());
-            if (!imageStore.getProtocol().equalsIgnoreCase("nfs") && 
!imageStore.getProtocol().equalsIgnoreCase("cifs")) {
+            ImageStoreEntity imageStore = 
(ImageStoreEntity)dataStoreMgr.getImageStoreWithFreeCapacity(destScope.getScopeId());
+            if (imageStore == null || 
!imageStore.getProtocol().equalsIgnoreCase("nfs") && 
!imageStore.getProtocol().equalsIgnoreCase("cifs")) {
                 s_logger.debug("can't find a nfs (or cifs) image store to 
satisfy the need for a staging store");
                 return null;
             }
diff --git 
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java
 
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java
index e42715a..e6b5c85 100644
--- 
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java
+++ 
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java
@@ -24,18 +24,17 @@ import java.util.Set;
 
 import javax.inject.Inject;
 
-import com.cloud.storage.ScopeType;
-import com.cloud.storage.Storage;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import 
org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
-import 
org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.datastore.DataStoreManagerImpl;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 
@@ -47,6 +46,8 @@ import com.cloud.exception.OperationTimedoutException;
 import com.cloud.host.Host;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.ScopeType;
+import com.cloud.storage.Storage;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePool;
@@ -56,7 +57,6 @@ import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.VMTemplatePoolDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VirtualMachineManager;
-import org.apache.commons.collections.MapUtils;
 
 /**
  * Extends {@link StorageSystemDataMotionStrategy}, allowing KVM hosts to 
migrate VMs with the ROOT volume on a non managed local storage pool.
@@ -197,19 +197,21 @@ public class KvmNonManagedStorageDataMotionStrategy 
extends StorageSystemDataMot
             Host destHost) {
         VMTemplateStoragePoolVO sourceVolumeTemplateStoragePoolVO = 
vmTemplatePoolDao.findByPoolTemplate(destStoragePool.getId(), 
srcVolumeInfo.getTemplateId());
         if (sourceVolumeTemplateStoragePoolVO == null && 
destStoragePool.getPoolType() == StoragePoolType.Filesystem) {
-            DataStore sourceTemplateDataStore = 
dataStoreManagerImpl.getImageStore(srcVolumeInfo.getDataCenterId());
-            TemplateInfo sourceTemplateInfo = 
templateDataFactory.getTemplate(srcVolumeInfo.getTemplateId(), 
sourceTemplateDataStore);
-            TemplateObjectTO sourceTemplate = new 
TemplateObjectTO(sourceTemplateInfo);
+            DataStore sourceTemplateDataStore = 
dataStoreManagerImpl.getRandomImageStore(srcVolumeInfo.getDataCenterId());
+            if (sourceTemplateDataStore != null) {
+                TemplateInfo sourceTemplateInfo = 
templateDataFactory.getTemplate(srcVolumeInfo.getTemplateId(), 
sourceTemplateDataStore);
+                TemplateObjectTO sourceTemplate = new 
TemplateObjectTO(sourceTemplateInfo);
 
-            LOGGER.debug(String.format("Could not find template [id=%s, 
name=%s] on the storage pool [id=%s]; copying the template to the target 
storage pool.",
-                    srcVolumeInfo.getTemplateId(), 
sourceTemplateInfo.getName(), destDataStore.getId()));
+                LOGGER.debug(String.format("Could not find template [id=%s, 
name=%s] on the storage pool [id=%s]; copying the template to the target 
storage pool.",
+                        srcVolumeInfo.getTemplateId(), 
sourceTemplateInfo.getName(), destDataStore.getId()));
 
-            TemplateInfo destTemplateInfo = 
templateDataFactory.getTemplate(srcVolumeInfo.getTemplateId(), destDataStore);
-            final TemplateObjectTO destTemplate = new 
TemplateObjectTO(destTemplateInfo);
-            Answer copyCommandAnswer = sendCopyCommand(destHost, 
sourceTemplate, destTemplate, destDataStore);
+                TemplateInfo destTemplateInfo = 
templateDataFactory.getTemplate(srcVolumeInfo.getTemplateId(), destDataStore);
+                final TemplateObjectTO destTemplate = new 
TemplateObjectTO(destTemplateInfo);
+                Answer copyCommandAnswer = sendCopyCommand(destHost, 
sourceTemplate, destTemplate, destDataStore);
 
-            if (copyCommandAnswer != null && copyCommandAnswer.getResult()) {
-                updateTemplateReferenceIfSuccessfulCopy(srcVolumeInfo, 
srcStoragePool, destTemplateInfo, destDataStore);
+                if (copyCommandAnswer != null && 
copyCommandAnswer.getResult()) {
+                    updateTemplateReferenceIfSuccessfulCopy(srcVolumeInfo, 
srcStoragePool, destTemplateInfo, destDataStore);
+                }
             }
         }
     }
diff --git 
a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java
 
b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java
index 5b8d3af..3dfc4af 100644
--- 
a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java
+++ 
b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java
@@ -18,13 +18,12 @@
  */
 package org.apache.cloudstack.storage.motion;
 
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
 import java.util.HashMap;
 import java.util.Map;
 
-import com.cloud.host.Host;
-import com.cloud.hypervisor.Hypervisor;
-import com.cloud.storage.ScopeType;
-import com.cloud.storage.Storage;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
@@ -58,21 +57,22 @@ import com.cloud.agent.api.MigrateCommand;
 import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.CloudException;
 import com.cloud.exception.OperationTimedoutException;
+import com.cloud.host.Host;
 import com.cloud.host.HostVO;
+import com.cloud.hypervisor.Hypervisor;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.DataStoreRole;
-import com.cloud.storage.StoragePool;
-import com.cloud.storage.VMTemplateStoragePoolVO;
+import com.cloud.storage.ScopeType;
+import com.cloud.storage.Storage;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.VMTemplateStoragePoolVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.VMTemplatePoolDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VirtualMachineManager;
 
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
-
 @RunWith(MockitoJUnitRunner.class)
 public class KvmNonManagedStorageSystemDataMotionTest {
 
@@ -353,7 +353,7 @@ public class KvmNonManagedStorageSystemDataMotionTest {
         
Mockito.when(sourceTemplateInfo.getHypervisorType()).thenReturn(HypervisorType.KVM);
 
         Mockito.when(vmTemplatePoolDao.findByPoolTemplate(Mockito.anyLong(), 
Mockito.anyLong())).thenReturn(vmTemplateStoragePoolVO);
-        
Mockito.when(dataStoreManagerImpl.getImageStore(Mockito.anyLong())).thenReturn(sourceTemplateDataStore);
+        
Mockito.when(dataStoreManagerImpl.getRandomImageStore(Mockito.anyLong())).thenReturn(sourceTemplateDataStore);
         Mockito.when(templateDataFactory.getTemplate(Mockito.anyLong(), 
Mockito.eq(sourceTemplateDataStore))).thenReturn(sourceTemplateInfo);
         Mockito.when(templateDataFactory.getTemplate(Mockito.anyLong(), 
Mockito.eq(destDataStore))).thenReturn(sourceTemplateInfo);
         
kvmNonManagedStorageDataMotionStrategy.copyTemplateToTargetFilesystemStorageIfNeeded(srcVolumeInfo,
 srcStoragePool, destDataStore, destStoragePool, destHost);
@@ -362,7 +362,7 @@ public class KvmNonManagedStorageSystemDataMotionTest {
 
         InOrder verifyInOrder = Mockito.inOrder(vmTemplatePoolDao, 
dataStoreManagerImpl, templateDataFactory, 
kvmNonManagedStorageDataMotionStrategy);
         verifyInOrder.verify(vmTemplatePoolDao, 
Mockito.times(1)).findByPoolTemplate(Mockito.anyLong(), Mockito.anyLong());
-        verifyInOrder.verify(dataStoreManagerImpl, 
Mockito.times(times)).getImageStore(Mockito.anyLong());
+        verifyInOrder.verify(dataStoreManagerImpl, 
Mockito.times(times)).getRandomImageStore(Mockito.anyLong());
         verifyInOrder.verify(templateDataFactory, 
Mockito.times(times)).getTemplate(Mockito.anyLong(), 
Mockito.eq(sourceTemplateDataStore));
         verifyInOrder.verify(templateDataFactory, 
Mockito.times(times)).getTemplate(Mockito.anyLong(), Mockito.eq(destDataStore));
         verifyInOrder.verify(kvmNonManagedStorageDataMotionStrategy, 
Mockito.times(times)).sendCopyCommand(Mockito.eq(destHost), 
Mockito.any(TemplateObjectTO.class),
diff --git 
a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
 
b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
index cb9a97e..80e5b38 100644
--- 
a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
+++ 
b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
@@ -20,17 +20,14 @@ package org.apache.cloudstack.storage.image.manager;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import 
org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.ImageStoreProvider;
@@ -42,6 +39,8 @@ import org.apache.cloudstack.storage.image.ImageStoreDriver;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager;
 import org.apache.cloudstack.storage.image.store.ImageStoreImpl;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
 
 import com.cloud.server.StatsCollector;
 import com.cloud.storage.ScopeType;
@@ -144,19 +143,56 @@ public class ImageStoreProviderManagerImpl implements 
ImageStoreProviderManager
     }
 
     @Override
-    public DataStore getImageStore(List<DataStore> imageStores) {
+    public DataStore getRandomImageStore(List<DataStore> imageStores) {
+        if (imageStores.size() > 1) {
+            Collections.shuffle(imageStores);
+        }
+        return imageStores.get(0);
+    }
+
+    @Override
+    public DataStore getImageStoreWithFreeCapacity(List<DataStore> 
imageStores) {
         if (imageStores.size() > 1) {
-            Collections.shuffle(imageStores); // Randomize image store list.
-            Iterator<DataStore> i = imageStores.iterator();
-            DataStore imageStore = null;
-            while(i.hasNext()) {
-                imageStore = i.next();
+            imageStores.sort(new Comparator<DataStore>() { // Sort data stores 
based on free capacity
+                @Override
+                public int compare(DataStore store1, DataStore store2) {
+                    return 
Long.compare(_statsCollector.imageStoreCurrentFreeCapacity(store1),
+                            
_statsCollector.imageStoreCurrentFreeCapacity(store2));
+                }
+            });
+            for (DataStore imageStore : imageStores) {
                 // Return image store if used percentage is less then 
threshold value i.e. 90%.
                 if (_statsCollector.imageStoreHasEnoughCapacity(imageStore)) {
                     return imageStore;
                 }
             }
+        } else if (imageStores.size() == 1) {
+            if 
(_statsCollector.imageStoreHasEnoughCapacity(imageStores.get(0))) {
+                return imageStores.get(0);
+            }
         }
-        return imageStores.get(0);
+
+        // No store with space found
+        s_logger.error(String.format("Can't find an image storage in zone with 
less than %d usage",
+                
Math.round(_statsCollector.getImageStoreCapacityThreshold()*100)));
+        return null;
+    }
+
+    @Override
+    public List<DataStore> listImageStoresWithFreeCapacity(List<DataStore> 
imageStores) {
+        List<DataStore> stores = new ArrayList<>();
+        for (DataStore imageStore : imageStores) {
+            // Return image store if used percentage is less then threshold 
value i.e. 90%.
+            if (_statsCollector.imageStoreHasEnoughCapacity(imageStore)) {
+                stores.add(imageStore);
+            }
+        }
+
+        // No store with space found
+        if (stores.isEmpty()) {
+            s_logger.error(String.format("Can't find image storage in zone 
with less than %d usage",
+                    
Math.round(_statsCollector.getImageStoreCapacityThreshold() * 100)));
+        }
+        return stores;
     }
 }
diff --git 
a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
 
b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
index 9c51370..51a2741 100644
--- 
a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
+++ 
b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
@@ -240,7 +240,7 @@ public class SnapshotServiceImpl implements SnapshotService 
{
             fullSnapshot = snapshotFullBackup;
         }
         if (fullSnapshot) {
-            return dataStoreMgr.getImageStore(snapshot.getDataCenterId());
+            return 
dataStoreMgr.getImageStoreWithFreeCapacity(snapshot.getDataCenterId());
         } else {
             SnapshotInfo parentSnapshot = snapshot.getParent();
             // Note that DataStore information in parentSnapshot is for primary
@@ -251,7 +251,7 @@ public class SnapshotServiceImpl implements SnapshotService 
{
                 parentSnapshotOnBackupStore = 
_snapshotStoreDao.findBySnapshot(parentSnapshot.getId(), DataStoreRole.Image);
             }
             if (parentSnapshotOnBackupStore == null) {
-                return dataStoreMgr.getImageStore(snapshot.getDataCenterId());
+                return 
dataStoreMgr.getImageStoreWithFreeCapacity(snapshot.getDataCenterId());
             }
             return 
dataStoreMgr.getDataStore(parentSnapshotOnBackupStore.getDataStoreId(), 
parentSnapshotOnBackupStore.getRole());
         }
diff --git 
a/engine/storage/src/main/java/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java
 
b/engine/storage/src/main/java/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java
index f640376..51421e4 100644
--- 
a/engine/storage/src/main/java/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java
+++ 
b/engine/storage/src/main/java/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java
@@ -73,12 +73,30 @@ public class DataStoreManagerImpl implements 
DataStoreManager {
     }
 
     @Override
-    public DataStore getImageStore(long zoneId) {
+    public DataStore getRandomImageStore(long zoneId) {
         List<DataStore> stores = getImageStoresByScope(new ZoneScope(zoneId));
         if (stores == null || stores.size() == 0) {
             return null;
         }
-        return imageDataStoreMgr.getImageStore(stores);
+        return imageDataStoreMgr.getRandomImageStore(stores);
+    }
+
+    @Override
+    public DataStore getImageStoreWithFreeCapacity(long zoneId) {
+        List<DataStore> stores = getImageStoresByScope(new ZoneScope(zoneId));
+        if (stores == null || stores.size() == 0) {
+            return null;
+        }
+        return imageDataStoreMgr.getImageStoreWithFreeCapacity(stores);
+    }
+
+    @Override
+    public List<DataStore> listImageStoresWithFreeCapacity(long zoneId) {
+        List<DataStore> stores = getImageStoresByScope(new ZoneScope(zoneId));
+        if (stores == null || stores.size() == 0) {
+            return null;
+        }
+        return imageDataStoreMgr.listImageStoresWithFreeCapacity(stores);
     }
 
     @Override
@@ -110,7 +128,7 @@ public class DataStoreManagerImpl implements 
DataStoreManager {
         if (stores == null || stores.size() == 0) {
             return null;
         }
-        return imageDataStoreMgr.getImageStore(stores);
+        return imageDataStoreMgr.getImageStoreWithFreeCapacity(stores);
     }
 
     @Override
diff --git 
a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/datastore/ImageStoreProviderManager.java
 
b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/datastore/ImageStoreProviderManager.java
index 70b7a7c..01f2100 100644
--- 
a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/datastore/ImageStoreProviderManager.java
+++ 
b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/datastore/ImageStoreProviderManager.java
@@ -42,5 +42,38 @@ public interface ImageStoreProviderManager {
 
     boolean registerDriver(String uuid, ImageStoreDriver driver);
 
-    DataStore getImageStore(List<DataStore> imageStores);
+    /**
+     * Return a random DataStore from the a list of DataStores.
+     *
+     * @param imageStores the list of image stores from which a random store
+     *                    to be returned
+     * @return            random DataStore
+     */
+    DataStore getRandomImageStore(List<DataStore> imageStores);
+
+    /**
+     * Return a DataStore which has free capacity. Stores will be sorted
+     * based on their free space and capacity check will be done based on
+     * the predefined threshold value. If a store is full beyond the
+     * threshold it won't be considered for response. First store in the
+     * sorted list free capacity will be returned. When there is no store
+     * with free capacity in the list a null value will be returned.
+     *
+     * @param imageStores the list of image stores from which stores with free
+     *                    capacity stores to be returned
+     * @return            the DataStore which has free capacity
+     */
+    DataStore getImageStoreWithFreeCapacity(List<DataStore> imageStores);
+
+    /**
+     * Return a list of DataStore which have free capacity. Free capacity check
+     * will be done based on the predefined threshold value. If a store is full
+     * beyond the threshold it won't be considered for response. An empty list
+     * will be returned when no store in the parameter list has free capacity.
+     *
+     * @param imageStores the list of image stores from which stores with free
+     *                    capacity stores to be returned
+     * @return            the list of DataStore which have free capacity
+     */
+    List<DataStore> listImageStoresWithFreeCapacity(List<DataStore> 
imageStores);
 }
diff --git 
a/plugins/hypervisors/hyperv/src/main/java/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
 
b/plugins/hypervisors/hyperv/src/main/java/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
index 9d63726..09e4544 100644
--- 
a/plugins/hypervisors/hyperv/src/main/java/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
+++ 
b/plugins/hypervisors/hyperv/src/main/java/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
@@ -137,7 +137,7 @@ public class HypervManagerImpl implements HypervManager {
 
     private String getSecondaryStorageStoreUrl(long zoneId) {
         String secUrl = null;
-        DataStore secStore = _dataStoreMgr.getImageStore(zoneId);
+        DataStore secStore = 
_dataStoreMgr.getImageStoreWithFreeCapacity(zoneId);
         if (secStore != null) {
             secUrl = secStore.getUri();
         }
diff --git 
a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManager.java
 
b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManager.java
index efdbc72..8cc328a 100644
--- 
a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManager.java
+++ 
b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManager.java
@@ -16,16 +16,17 @@
 // under the License.
 package com.cloud.hypervisor.vmware.manager;
 
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cloudstack.framework.config.ConfigKey;
+
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.vmware.mo.HostMO;
 import com.cloud.hypervisor.vmware.util.VmwareContext;
 import com.cloud.utils.Pair;
 import com.vmware.vim25.ManagedObjectReference;
-import org.apache.cloudstack.framework.config.ConfigKey;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
 
 public interface VmwareManager {
     public final String CONTEXT_STOCK_NAME = "vmwareMgr";
@@ -65,6 +66,8 @@ public interface VmwareManager {
 
     Pair<String, Long> getSecondaryStorageStoreUrlAndId(long dcId);
 
+    List<Pair<String, Long>> getSecondaryStorageStoresUrlAndIdList(long dcId);
+
     File getSystemVMKeyFile();
 
     VmwareStorageManager getStorageManager();
diff --git 
a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
 
b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
index 23758d5..1d3c1ad 100644
--- 
a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
+++ 
b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
@@ -48,10 +48,12 @@ import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.framework.jobs.impl.AsyncJobManagerImpl;
+import org.apache.cloudstack.management.ManagementServerHost;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
 import org.apache.log4j.Logger;
 
+import com.amazonaws.util.CollectionUtils;
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
 import com.cloud.agent.api.AgentControlAnswer;
@@ -62,7 +64,6 @@ import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StartupRoutingCommand;
 import com.cloud.api.query.dao.TemplateJoinDao;
 import com.cloud.cluster.ClusterManager;
-import org.apache.cloudstack.management.ManagementServerHost;
 import com.cloud.cluster.dao.ManagementServerHostPeerDao;
 import com.cloud.configuration.Config;
 import com.cloud.dc.ClusterDetailsDao;
@@ -492,7 +493,7 @@ public class VmwareManagerImpl extends ManagerBase 
implements VmwareManager, Vmw
 
         String secUrl = null;
         Long secId = null;
-        DataStore secStore = _dataStoreMgr.getImageStore(dcId);
+        DataStore secStore = _dataStoreMgr.getImageStoreWithFreeCapacity(dcId);
         if (secStore != null) {
             secUrl = secStore.getUri();
             secId = secStore.getId();
@@ -514,6 +515,32 @@ public class VmwareManagerImpl extends ManagerBase 
implements VmwareManager, Vmw
     }
 
     @Override
+    public List<Pair<String, Long>> getSecondaryStorageStoresUrlAndIdList(long 
dcId) {
+        List<Pair<String, Long>> urlIdList = new ArrayList<>();
+        List<DataStore> secStores = 
_dataStoreMgr.listImageStoresWithFreeCapacity(dcId);
+        if (!CollectionUtils.isNullOrEmpty(secStores)) {
+            for (DataStore secStore : secStores) {
+                if (secStore != null) {
+                    urlIdList.add(new Pair<>(secStore.getUri(), 
secStore.getId()));
+                }
+            }
+        }
+
+        if (urlIdList.isEmpty()) {
+            // we are using non-NFS image store, then use cache storage instead
+            s_logger.info("Secondary storage is not NFS, we need to use 
staging storage");
+            DataStore cacheStore = _dataStoreMgr.getImageCacheStore(dcId);
+            if (cacheStore != null) {
+                urlIdList.add(new Pair<>(cacheStore.getUri(), 
cacheStore.getId()));
+            } else {
+                s_logger.warn("No staging storage is found when non-NFS 
secondary storage is used");
+            }
+        }
+
+        return urlIdList;
+    }
+
+    @Override
     public String getServiceConsolePortGroupName() {
         return _serviceConsoleName;
     }
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 141f2f6..834900f 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
@@ -3868,19 +3868,24 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
                 prepareNetworkFromNicInfo(new HostMO(getServiceContext(), 
_morHyperHost), nic, false, cmd.getVirtualMachine().getType());
             }
 
-            Pair<String, Long> secStoreUrlAndId = 
mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId));
-            String secStoreUrl = secStoreUrlAndId.first();
-            Long secStoreId = secStoreUrlAndId.second();
-            if (secStoreUrl == null) {
-                String msg = "secondary storage for dc " + _dcId + " is not 
ready yet?";
-                throw new Exception(msg);
-            }
-            mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId);
+            List<Pair<String, Long>> secStoreUrlAndIdList = 
mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(_dcId));
+            for (Pair<String, Long> secStoreUrlAndId : secStoreUrlAndIdList) {
+                String secStoreUrl = secStoreUrlAndId.first();
+                Long secStoreId = secStoreUrlAndId.second();
+                if (secStoreUrl == null) {
+                    String msg = String.format("Secondary storage for dc %s is 
not ready yet?", _dcId);
+                    throw new Exception(msg);
+                }
 
-            ManagedObjectReference morSecDs = 
prepareSecondaryDatastoreOnHost(secStoreUrl);
-            if (morSecDs == null) {
-                String msg = "Failed to prepare secondary storage on host, 
secondary store url: " + secStoreUrl;
-                throw new Exception(msg);
+                if (vm.getType() != VirtualMachine.Type.User) {
+                    mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId);
+                }
+
+                ManagedObjectReference morSecDs = 
prepareSecondaryDatastoreOnHost(secStoreUrl);
+                if (morSecDs == null) {
+                    String msg = "Failed to prepare secondary storage on host, 
secondary store url: " + secStoreUrl;
+                    throw new Exception(msg);
+                }
             }
             return new PrepareForMigrationAnswer(cmd);
         } catch (Throwable e) {
@@ -4247,19 +4252,25 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
                 prepareNetworkFromNicInfo(new HostMO(getServiceContext(), 
morTgtHost), nic, false, vmTo.getType());
             }
 
-            // Ensure secondary storage mounted on target host
-            Pair<String, Long> secStoreUrlAndId = 
mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId));
-            String secStoreUrl = secStoreUrlAndId.first();
-            Long secStoreId = secStoreUrlAndId.second();
-            if (secStoreUrl == null) {
-                String msg = "secondary storage for dc " + _dcId + " is not 
ready yet?";
-                throw new Exception(msg);
-            }
-            mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId);
-            ManagedObjectReference morSecDs = 
prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, tgtHyperHost);
-            if (morSecDs == null) {
-                String msg = "Failed to prepare secondary storage on host, 
secondary store url: " + secStoreUrl;
-                throw new Exception(msg);
+            // Ensure all secondary storage mounted on target host
+            List<Pair<String, Long>> secStoreUrlAndIdList = 
mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(_dcId));
+            for (Pair<String, Long> secStoreUrlAndId : secStoreUrlAndIdList) {
+                String secStoreUrl = secStoreUrlAndId.first();
+                Long secStoreId = secStoreUrlAndId.second();
+                if (secStoreUrl == null) {
+                    String msg = String.format("Secondary storage for dc %s is 
not ready yet?", _dcId);
+                    throw new Exception(msg);
+                }
+
+                if (vmTo.getType() != VirtualMachine.Type.User) {
+                    mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId);
+                }
+
+                ManagedObjectReference morSecDs = 
prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, tgtHyperHost);
+                if (morSecDs == null) {
+                    String msg = "Failed to prepare secondary storage on host, 
secondary store url: " + secStoreUrl;
+                    throw new Exception(msg);
+                }
             }
 
             if (srcHostApiVersion.compareTo("5.1") < 0) {
diff --git 
a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java 
b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java
index 76e4fc0..e2c3ca7 100644
--- 
a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java
+++ 
b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java
@@ -23,7 +23,6 @@ import java.util.Set;
 
 import javax.inject.Inject;
 
-import com.cloud.storage.StoragePool;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
@@ -59,6 +58,7 @@ import com.cloud.offering.NetworkOffering;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Storage;
+import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.GuestOSCategoryDao;
@@ -308,7 +308,12 @@ public class ConfigDriveNetworkElement extends AdapterBase 
implements NetworkEle
         if (nic.isDefaultNic() && 
_networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.ConfigDrive))
 {
             LOG.trace(String.format("[prepareMigration] for vm: %s", 
vm.getInstanceName()));
             final DataStore dataStore = findDataStore(vm, dest);
-            addConfigDriveDisk(vm, dataStore);
+
+            try {
+                addConfigDriveDisk(vm, dataStore);
+            } catch (ResourceUnavailableException e) {
+                LOG.error("Failed to add config disk drive due to: ", e);
+            }
             return false;
         }
         else return  true;
@@ -332,7 +337,7 @@ public class ConfigDriveNetworkElement extends AdapterBase 
implements NetworkEle
                 dataStore = pickExistingRootVolumeFromDataStore(profile, 
dataStore);
             }
         } else {
-            dataStore = 
_dataStoreMgr.getImageStore(dest.getDataCenter().getId());
+            dataStore = 
_dataStoreMgr.getImageStoreWithFreeCapacity(dest.getDataCenter().getId());
         }
         return dataStore;
     }
@@ -444,7 +449,7 @@ public class ConfigDriveNetworkElement extends AdapterBase 
implements NetworkEle
     }
 
     private boolean deleteConfigDriveIso(final VirtualMachine vm) throws 
ResourceUnavailableException {
-        DataStore dataStore = 
_dataStoreMgr.getImageStore(vm.getDataCenterId());
+        DataStore dataStore = 
_dataStoreMgr.getImageStoreWithFreeCapacity(vm.getDataCenterId());
         Long agentId = findAgentIdForImageStore(dataStore);
 
         if (VirtualMachineManager.VmConfigDriveOnPrimaryPool.value()) {
@@ -473,7 +478,7 @@ public class ConfigDriveNetworkElement extends AdapterBase 
implements NetworkEle
         return true;
     }
 
-    private void addConfigDriveDisk(final VirtualMachineProfile profile, final 
DataStore dataStore) {
+    private void addConfigDriveDisk(final VirtualMachineProfile profile, final 
DataStore dataStore) throws ResourceUnavailableException {
         boolean isoAvailable = false;
         final String isoPath = 
ConfigDrive.createConfigDrivePath(profile.getInstanceName());
         for (DiskTO dataTo : profile.getDisks()) {
@@ -484,6 +489,10 @@ public class ConfigDriveNetworkElement extends AdapterBase 
implements NetworkEle
         }
         if (!isoAvailable) {
             TemplateObjectTO dataTO = new TemplateObjectTO();
+            if (dataStore == null) {
+                throw new ResourceUnavailableException("Config drive disk add 
failed, datastore not available",
+                        ConfigDriveNetworkElement.class, 0L);
+            }
             dataTO.setDataStore(dataStore.getTO());
             dataTO.setUuid(profile.getUuid());
             dataTO.setPath(isoPath);
diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java 
b/server/src/main/java/com/cloud/server/StatsCollector.java
index b81507a..b2ccfe2 100644
--- a/server/src/main/java/com/cloud/server/StatsCollector.java
+++ b/server/src/main/java/com/cloud/server/StatsCollector.java
@@ -1362,6 +1362,9 @@ public class StatsCollector extends ManagerBase 
implements ComponentMethodInterc
     }
 
     public boolean imageStoreHasEnoughCapacity(DataStore imageStore) {
+        if (!_storageStats.keySet().contains(imageStore.getId())) { // Stats 
not available for this store yet, can be a new store. Better to assume it has 
enough capacity?
+            return true;
+        }
         StorageStats imageStoreStats = _storageStats.get(imageStore.getId());
         if (imageStoreStats != null && (imageStoreStats.getByteUsed() / 
(imageStoreStats.getCapacityBytes() * 1.0)) <= _imageStoreCapacityThreshold) {
             return true;
@@ -1369,6 +1372,11 @@ public class StatsCollector extends ManagerBase 
implements ComponentMethodInterc
         return false;
     }
 
+    public long imageStoreCurrentFreeCapacity(DataStore imageStore) {
+        StorageStats imageStoreStats = _storageStats.get(imageStore.getId());
+        return imageStoreStats != null ? Math.max(0, 
imageStoreStats.getCapacityBytes() - imageStoreStats.getByteUsed()) : 0;
+    }
+
     /**
      * Sends VMs metrics to the configured graphite host.
      */
@@ -1574,4 +1582,8 @@ public class StatsCollector extends ManagerBase 
implements ComponentMethodInterc
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {vmDiskStatsInterval, 
vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin, 
StatsTimeout, statsOutputUri};
     }
+
+    public double getImageStoreCapacityThreshold() {
+        return _imageStoreCapacityThreshold;
+    }
 }
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java 
b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index 2a3d395..ddd8413 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -2674,7 +2674,10 @@ public class VolumeApiServiceImpl extends ManagerBase 
implements VolumeApiServic
             throw new InvalidParameterValueException("Volume to be extracted 
has been removed or not in right state!");
         }
         // perform extraction
-        ImageStoreEntity secStore = 
(ImageStoreEntity)dataStoreMgr.getImageStore(zoneId);
+        ImageStoreEntity secStore = 
(ImageStoreEntity)dataStoreMgr.getImageStoreWithFreeCapacity(zoneId);
+        if (secStore == null) {
+            throw new InvalidParameterValueException(String.format("Secondary 
storage to satisfy storage needs cannot be found for zone: %d", zoneId));
+        }
         String value = _configDao.getValue(Config.CopyVolumeWait.toString());
         NumbersUtil.parseInt(value, 
Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
 
diff --git 
a/server/src/main/java/com/cloud/storage/upload/UploadMonitorImpl.java 
b/server/src/main/java/com/cloud/storage/upload/UploadMonitorImpl.java
index e8f2980..64ada6d 100644
--- a/server/src/main/java/com/cloud/storage/upload/UploadMonitorImpl.java
+++ b/server/src/main/java/com/cloud/storage/upload/UploadMonitorImpl.java
@@ -176,7 +176,11 @@ public class UploadMonitorImpl extends ManagerBase 
implements UploadMonitor {
 
         Type type = (template.getFormat() == ImageFormat.ISO) ? Type.ISO : 
Type.TEMPLATE;
 
-        DataStore secStore = storeMgr.getImageStore(dataCenterId);
+        DataStore secStore = 
storeMgr.getImageStoreWithFreeCapacity(dataCenterId);
+        if(secStore == null) {
+            s_logger.error("Unable to extract template, secondary storage to 
satisfy storage needs cannot be found!");
+            return null;
+        }
 
         UploadVO uploadTemplateObj = new UploadVO(secStore.getId(), 
template.getId(), new Date(), Upload.Status.NOT_UPLOADED, type, url, 
Mode.FTP_UPLOAD);
         _uploadDao.persist(uploadTemplateObj);
diff --git 
a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java 
b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
index e2db31a..85c4a77 100644
--- a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
+++ b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
@@ -607,7 +607,7 @@ public class HypervisorTemplateAdapter extends 
TemplateAdapterBase {
             throw new InvalidParameterValueException("The DomR template cannot 
be deleted.");
         }
 
-        if (zoneIdList != null && (storeMgr.getImageStore(zoneIdList.get(0)) 
== null)) {
+        if (zoneIdList != null && 
(storeMgr.getImageStoreWithFreeCapacity(zoneIdList.get(0)) == null)) {
             throw new InvalidParameterValueException("Failed to find a 
secondary storage in the specified zone.");
         }
 
@@ -620,7 +620,7 @@ public class HypervisorTemplateAdapter extends 
TemplateAdapterBase {
         List<Long> zoneIdList = profile.getZoneIdList();
 
         if (zoneIdList != null &&
-                (storeMgr.getImageStore(zoneIdList.get(0)) == null)) {
+                (storeMgr.getImageStoreWithFreeCapacity(zoneIdList.get(0)) == 
null)) {
             throw new InvalidParameterValueException("Failed to find a 
secondary storage in the specified zone.");
         }
 
diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java 
b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
index 8d732cb..b81faeb 100755
--- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
@@ -428,7 +428,7 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
         if (storeUuid != null) {
             imageStore = _dataStoreMgr.getDataStore(storeUuid, 
DataStoreRole.Image);
         } else {
-            imageStore = _dataStoreMgr.getImageStore(zoneId);
+            imageStore = _dataStoreMgr.getImageStoreWithFreeCapacity(zoneId);
             if (imageStore == null) {
                 throw new CloudRuntimeException("cannot find an image store 
for zone " + zoneId);
             }
@@ -1356,7 +1356,7 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
             throw new InvalidParameterValueException("Unable to delete iso, as 
it's used by other vms");
         }
 
-        if (zoneId != null && (_dataStoreMgr.getImageStore(zoneId) == null)) {
+        if (zoneId != null && 
(_dataStoreMgr.getImageStoreWithFreeCapacity(zoneId) == null)) {
             throw new InvalidParameterValueException("Failed to find a 
secondary storage store in the specified zone.");
         }
 
@@ -1631,7 +1631,7 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
                 volume = _volumeDao.findById(volumeId);
                 zoneId = volume.getDataCenterId();
             }
-            DataStore store = _dataStoreMgr.getImageStore(zoneId);
+            DataStore store = 
_dataStoreMgr.getImageStoreWithFreeCapacity(zoneId);
             if (store == null) {
                 throw new CloudRuntimeException("cannot find an image store 
for zone " + zoneId);
             }
@@ -1957,7 +1957,7 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
 
     @Override
     public String getSecondaryStorageURL(long zoneId) {
-        DataStore secStore = _dataStoreMgr.getImageStore(zoneId);
+        DataStore secStore = 
_dataStoreMgr.getImageStoreWithFreeCapacity(zoneId);
         if (secStore == null) {
             return null;
         }
diff --git 
a/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java
 
b/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java
index 01713de..d4f96c9 100644
--- 
a/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java
+++ 
b/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java
@@ -156,7 +156,7 @@ public class ConfigDriveNetworkElementTest {
 
         _configDrivesNetworkElement._networkModel = _networkModel;
 
-        when(_dataStoreMgr.getImageStore(DATACENTERID)).thenReturn(dataStore);
+        
when(_dataStoreMgr.getImageStoreWithFreeCapacity(DATACENTERID)).thenReturn(dataStore);
 
         when(_ep.select(dataStore)).thenReturn(endpoint);
         when(_vmDao.findById(VMID)).thenReturn(virtualMachine);
diff --git 
a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
 
b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
index 1d3eba8..8b2ed40 100644
--- 
a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
+++ 
b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
@@ -603,7 +603,7 @@ public class SecondaryStorageManagerImpl extends 
ManagerBase implements Secondar
     }
 
     protected Map<String, Object> createSecStorageVmInstance(long 
dataCenterId, SecondaryStorageVm.Role role) {
-        DataStore secStore = _dataStoreMgr.getImageStore(dataCenterId);
+        DataStore secStore = 
_dataStoreMgr.getImageStoreWithFreeCapacity(dataCenterId);
         if (secStore == null) {
             String msg = "No secondary storage available in zone " + 
dataCenterId + ", cannot create secondary storage vm";
             s_logger.warn(msg);
@@ -1117,8 +1117,11 @@ public class SecondaryStorageManagerImpl extends 
ManagerBase implements Secondar
         Map<String, String> details = 
_vmDetailsDao.listDetailsKeyPairs(vm.getId());
         vm.setDetails(details);
 
-        DataStore secStore = 
_dataStoreMgr.getImageStore(dest.getDataCenter().getId());
-        assert (secStore != null);
+        DataStore secStore = 
_dataStoreMgr.getImageStoreWithFreeCapacity(dest.getDataCenter().getId());
+        if (secStore == null) {
+            s_logger.error(String.format("Unable to finalize virtual machine 
profile as no secondary storage available to satisfy storage needs for zone: 
%s", dest.getDataCenter().getUuid()));
+            return false;
+        }
 
         StringBuilder buf = profile.getBootArgsBuilder();
         buf.append(" template=domP type=secstorage");

Reply via email to