You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2024/06/18 17:59:01 UTC

(cloudstack) branch main updated (a9caee3c6f8 -> 373f0170020)

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

dahn pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


    from a9caee3c6f8 add readratemax and writeratemax (#9227)
     add ed86dc973b1 protect against missing service offering (#9235)
     add 00fe25ab01c Fix allocation of VMs with multiple clusters (#8611)
     add 96288ecf1fa fix: domain limits tab ui is now able to present 0 to the user (#9166)
     add bb0c1f93afe Add volume encryption checks during the disk offering change (#9209)
     add 7e71e505788 [Quota] Improve Quota balance calculation flow (#8581)
     add f360f7048da vmware: do not tear down vm disks if deploy-as-is vm has vm snapshots (#9243)
     add 591cc4f0027 Add action button to enable/disable Oauth provider (#9242)
     add a10eee25b34 Add method for decrypting values accordingly (#9088)
     add 75341963614 UI: Fix Userdata registration from UI (#8791)
     add 6c7426e3a7e Prevent network disruption on adding a VPC tier for redundant VRs (#9251)
     add 4e7c6682fd4 While starting VM with considerlasthost enabled, don't load host tags/details for the last host when it doesn't exist (#9037)
     add 56b69b157ea prevent duplicate ip table rules in SSVM (#8530)
     add 7c5b7ca0777 Extra parameter for UpdateImageStore (#8941)
     add 050ee44137a Merge branch '4.18' into 4.19
     new 373f0170020 Merge branch '4.19'

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../network/VpcVirtualNetworkApplianceService.java |  22 ++-
 .../java/com/cloud/storage/StorageService.java     |   3 +
 .../command/admin/storage/UpdateImageStoreCmd.java |  21 ++-
 .../api/response/ImageStoreResponse.java           |  14 +-
 .../agent/resource/virtualnetwork/VRScripts.java   |   1 +
 .../virtualnetwork/VirtualRoutingResource.java     |  19 ++
 .../agent/routing/ManageServiceCommand.java}       |  26 +--
 .../subsystem/api/storage/VolumeService.java       |   2 +
 .../java/com/cloud/storage/StorageManager.java     |   2 +
 .../com/cloud/domain/dao/DomainDetailsDao.java     |   2 +
 .../com/cloud/domain/dao/DomainDetailsDaoImpl.java |  15 +-
 .../com/cloud/service/dao/ServiceOfferingDao.java  |   4 +-
 .../cloud/service/dao/ServiceOfferingDaoImpl.java  |   4 +-
 .../java/com/cloud/user/AccountDetailsDao.java     |   2 +
 .../java/com/cloud/user/AccountDetailsDaoImpl.java |  15 +-
 .../storage/volume/VolumeServiceImpl.java          |  80 +++++----
 .../storage/volume/VolumeServiceTest.java          |  72 ++++++--
 .../apache/cloudstack/quota/QuotaManagerImpl.java  | 102 +++++------
 .../manager/allocator/impl/RandomAllocator.java    |  16 +-
 .../hypervisor/vmware/resource/VmwareResource.java |   4 +-
 .../cloudstack/oauth2/OAuth2AuthManagerImpl.java   |  12 +-
 .../manager/allocator/impl/FirstFitAllocator.java  |  46 +++--
 .../allocator/impl/RecreateHostAllocator.java      |   3 +-
 server/src/main/java/com/cloud/api/ApiDBUtils.java |   4 +-
 .../java/com/cloud/api/query/QueryManagerImpl.java |   2 +-
 .../com/cloud/api/query/dao/VolumeJoinDaoImpl.java |  24 ++-
 .../deploy/DeploymentPlanningManagerImpl.java      |  61 ++++---
 .../java/com/cloud/deploy/FirstFitPlanner.java     |  18 +-
 .../network/element/VpcVirtualRouterElement.java   |  91 +++++-----
 .../VpcVirtualNetworkApplianceManagerImpl.java     |  50 ++++++
 .../com/cloud/server/ManagementServerImpl.java     | 103 ++++++-----
 .../main/java/com/cloud/server/StatsCollector.java |  17 +-
 .../java/com/cloud/storage/StorageManagerImpl.java |  75 ++++----
 .../com/cloud/storage/VolumeApiServiceImpl.java    |   4 +-
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  |   7 +-
 .../java/com/cloud/vm/UserVmManagerImplTest.java   |  42 -----
 .../vpc/MockVpcVirtualNetworkApplianceManager.java |  14 ++
 .../SecondaryStorageManagerImpl.java               |   4 +-
 .../storage/resource/IpTablesHelper.java           |  67 ++++++++
 .../resource/NfsSecondaryStorageResource.java      |  24 +--
 .../storage/template/DownloadManagerImpl.java      |  40 ++---
 systemvm/debian/opt/cloud/bin/cs/CsHelper.py       |   2 +-
 .../debian/opt/cloud/bin/manage_service.sh         |   6 +-
 .../plugins/quota/test_quota_balance.py            | 191 +++++++++++++++++++++
 ui/public/locales/en.json                          |   1 +
 ui/src/components/view/ResourceLimitTab.vue        |   1 +
 ui/src/config/section/config.js                    |  20 ++-
 ui/src/config/section/infra/secondaryStorages.js   |  17 +-
 ui/src/utils/plugins.js                            |  12 +-
 ui/src/views/AutogenView.vue                       |   1 -
 ui/src/views/compute/RegisterUserData.vue          |   9 +-
 .../java/com/cloud/usage/UsageManagerImpl.java     |   7 +-
 .../main/java/com/cloud/utils/script/Script.java   |  11 +-
 53 files changed, 955 insertions(+), 457 deletions(-)
 copy core/src/main/java/{com/cloud/agent/api/CheckS2SVpnConnectionsCommand.java => org/apache/cloudstack/agent/routing/ManageServiceCommand.java} (67%)
 create mode 100644 services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/IpTablesHelper.java
 copy core/src/main/resources/META-INF/cloudstack/allocator/module.properties => systemvm/debian/opt/cloud/bin/manage_service.sh (95%)
 mode change 100644 => 100755
 create mode 100644 test/integration/plugins/quota/test_quota_balance.py


(cloudstack) 01/01: Merge branch '4.19'

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 373f0170020ace41ca3e0c3362a932a903a67218
Merge: a9caee3c6f8 050ee44137a
Author: Daan Hoogland <da...@onecht.net>
AuthorDate: Tue Jun 18 19:58:43 2024 +0200

    Merge branch '4.19'

 .../network/VpcVirtualNetworkApplianceService.java |  22 ++-
 .../java/com/cloud/storage/StorageService.java     |   3 +
 .../command/admin/storage/UpdateImageStoreCmd.java |  21 ++-
 .../api/response/ImageStoreResponse.java           |  14 +-
 .../agent/resource/virtualnetwork/VRScripts.java   |   1 +
 .../virtualnetwork/VirtualRoutingResource.java     |  19 ++
 .../agent/routing/ManageServiceCommand.java        |  35 ++--
 .../subsystem/api/storage/VolumeService.java       |   2 +
 .../java/com/cloud/storage/StorageManager.java     |   2 +
 .../com/cloud/domain/dao/DomainDetailsDao.java     |   2 +
 .../com/cloud/domain/dao/DomainDetailsDaoImpl.java |  15 +-
 .../com/cloud/service/dao/ServiceOfferingDao.java  |   4 +-
 .../cloud/service/dao/ServiceOfferingDaoImpl.java  |   4 +-
 .../java/com/cloud/user/AccountDetailsDao.java     |   2 +
 .../java/com/cloud/user/AccountDetailsDaoImpl.java |  15 +-
 .../storage/volume/VolumeServiceImpl.java          |  80 +++++----
 .../storage/volume/VolumeServiceTest.java          |  72 ++++++--
 .../apache/cloudstack/quota/QuotaManagerImpl.java  | 102 +++++------
 .../manager/allocator/impl/RandomAllocator.java    |  16 +-
 .../hypervisor/vmware/resource/VmwareResource.java |   4 +-
 .../cloudstack/oauth2/OAuth2AuthManagerImpl.java   |  12 +-
 .../manager/allocator/impl/FirstFitAllocator.java  |  46 +++--
 .../allocator/impl/RecreateHostAllocator.java      |   3 +-
 server/src/main/java/com/cloud/api/ApiDBUtils.java |   4 +-
 .../java/com/cloud/api/query/QueryManagerImpl.java |   2 +-
 .../com/cloud/api/query/dao/VolumeJoinDaoImpl.java |  24 ++-
 .../deploy/DeploymentPlanningManagerImpl.java      |  61 ++++---
 .../java/com/cloud/deploy/FirstFitPlanner.java     |  18 +-
 .../network/element/VpcVirtualRouterElement.java   |  91 +++++-----
 .../VpcVirtualNetworkApplianceManagerImpl.java     |  50 ++++++
 .../com/cloud/server/ManagementServerImpl.java     | 103 ++++++-----
 .../main/java/com/cloud/server/StatsCollector.java |  17 +-
 .../java/com/cloud/storage/StorageManagerImpl.java |  75 ++++----
 .../com/cloud/storage/VolumeApiServiceImpl.java    |   4 +-
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  |   7 +-
 .../java/com/cloud/vm/UserVmManagerImplTest.java   |  42 -----
 .../vpc/MockVpcVirtualNetworkApplianceManager.java |  14 ++
 .../SecondaryStorageManagerImpl.java               |   4 +-
 .../storage/resource/IpTablesHelper.java           |  67 ++++++++
 .../resource/NfsSecondaryStorageResource.java      |  24 +--
 .../storage/template/DownloadManagerImpl.java      |  40 ++---
 systemvm/debian/opt/cloud/bin/cs/CsHelper.py       |   2 +-
 systemvm/debian/opt/cloud/bin/manage_service.sh    |  19 ++
 .../plugins/quota/test_quota_balance.py            | 191 +++++++++++++++++++++
 ui/public/locales/en.json                          |   1 +
 ui/src/components/view/ResourceLimitTab.vue        |   1 +
 ui/src/config/section/config.js                    |  20 ++-
 ui/src/config/section/infra/secondaryStorages.js   |  17 +-
 ui/src/utils/plugins.js                            |  12 +-
 ui/src/views/AutogenView.vue                       |   1 -
 ui/src/views/compute/RegisterUserData.vue          |   9 +-
 .../java/com/cloud/usage/UsageManagerImpl.java     |   7 +-
 .../main/java/com/cloud/utils/script/Script.java   |  11 +-
 53 files changed, 983 insertions(+), 451 deletions(-)

diff --cc engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java
index d086ad1dac1,3b6fa8fa103..48e63d8e2b5
--- a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java
+++ b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java
@@@ -54,7 -54,5 +54,7 @@@ public interface ServiceOfferingDao ext
  
      List<ServiceOfferingVO> listPublicByCpuAndMemory(Integer cpus, Integer memory);
  
-     ServiceOfferingVO findServiceOfferingByComputeOnlyDiskOffering(long diskOfferingId);
- 
 +    List<ServiceOfferingVO> listByHostTag(String tag);
++
+     ServiceOfferingVO findServiceOfferingByComputeOnlyDiskOffering(long diskOfferingId, boolean includingRemoved);
  }
diff --cc engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index 24a0db0b74a,a47cb41a323..136134698a9
--- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@@ -32,7 -32,10 +32,6 @@@ import java.util.concurrent.ExecutionEx
  
  import javax.inject.Inject;
  
 -import com.cloud.exception.InvalidParameterValueException;
 -import com.cloud.storage.DiskOfferingVO;
--import com.cloud.storage.VolumeApiServiceImpl;
 -import com.cloud.storage.dao.DiskOfferingDao;
  import org.apache.cloudstack.annotation.AnnotationService;
  import org.apache.cloudstack.annotation.dao.AnnotationDao;
  import org.apache.cloudstack.api.command.user.volume.CheckAndRepairVolumeCmd;
@@@ -105,6 -107,6 +104,7 @@@ import com.cloud.configuration.Resource
  import com.cloud.dc.dao.ClusterDao;
  import com.cloud.event.EventTypes;
  import com.cloud.event.UsageEventUtils;
++import com.cloud.exception.InvalidParameterValueException;
  import com.cloud.exception.ResourceAllocationException;
  import com.cloud.exception.StorageAccessException;
  import com.cloud.host.Host;
@@@ -118,6 -120,6 +118,7 @@@ import com.cloud.org.Grouping.Allocatio
  import com.cloud.resource.ResourceState;
  import com.cloud.server.ManagementService;
  import com.cloud.storage.CheckAndRepairVolumePayload;
++import com.cloud.storage.DiskOfferingVO;
  import com.cloud.storage.DataStoreRole;
  import com.cloud.storage.RegisterVolumePayload;
  import com.cloud.storage.ScopeType;
@@@ -130,6 -132,6 +131,7 @@@ import com.cloud.storage.VMTemplateStor
  import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
  import com.cloud.storage.VMTemplateVO;
  import com.cloud.storage.Volume;
++import com.cloud.storage.VolumeApiServiceImpl;
  import com.cloud.storage.Volume.State;
  import com.cloud.storage.VolumeDetailVO;
  import com.cloud.storage.VolumeVO;
@@@ -290,12 -291,12 +292,12 @@@ public class VolumeServiceImpl implemen
  
      @Override
      public AsyncCallFuture<VolumeApiResult> createVolumeAsync(VolumeInfo volume, DataStore dataStore) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          DataObject volumeOnStore = dataStore.create(volume);
          volumeOnStore.processEvent(Event.CreateOnlyRequested);
  
          try {
--            CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore, future);
++            CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<>(null, volumeOnStore, future);
              AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context);
  
@@@ -371,12 -372,12 +373,12 @@@
      @DB
      @Override
      public AsyncCallFuture<VolumeApiResult> expungeVolumeAsync(VolumeInfo volume) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          VolumeApiResult result = new VolumeApiResult(volume);
          if (volume.getDataStore() == null) {
 -            s_logger.info("Expunge volume with no data store specified");
 +            logger.info("Expunge volume with no data store specified");
              if (canVolumeBeRemoved(volume.getId())) {
 -                s_logger.info("Volume " + volume.getId() + " is not referred anywhere, remove it from volumes table");
 +                logger.info("Volume " + volume.getId() + " is not referred anywhere, remove it from volumes table");
                  volDao.remove(volume.getId());
              }
              future.complete(result);
@@@ -427,7 -428,7 +429,7 @@@
              volume.processEvent(Event.ExpungeRequested);
          }
  
--        DeleteVolumeContext<VolumeApiResult> context = new DeleteVolumeContext<VolumeApiResult>(null, vo, future);
++        DeleteVolumeContext<VolumeApiResult> context = new DeleteVolumeContext<>(null, vo, future);
          AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
          caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null)).setContext(context);
  
@@@ -636,7 -637,7 +638,7 @@@
              }
          }
          long templatePoolRefId = templatePoolRef.getId();
--        CreateBaseImageContext<CreateCmdResult> context = new CreateBaseImageContext<CreateCmdResult>(null, volume, dataStore, template, future, templateOnPrimaryStoreObj, templatePoolRefId);
++        CreateBaseImageContext<CreateCmdResult> context = new CreateBaseImageContext<>(null, volume, dataStore, template, future, templateOnPrimaryStoreObj, templatePoolRefId);
          AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
          caller.setCallback(caller.getTarget().copyBaseImageCallback(null, null)).setContext(context);
  
@@@ -806,7 -807,7 +808,7 @@@
          DataObject volumeOnPrimaryStorage = pd.create(volume, volume.getDeployAsIsConfiguration());
          volumeOnPrimaryStorage.processEvent(Event.CreateOnlyRequested);
  
--        CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volumeOnPrimaryStorage, pd, templateOnPrimaryStore, future, null, volume.getDeployAsIsConfiguration());
++        CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<>(null, volumeOnPrimaryStorage, pd, templateOnPrimaryStore, future, null, volume.getDeployAsIsConfiguration());
          AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
          caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null));
          caller.setContext(context);
@@@ -1174,7 -1175,7 +1176,7 @@@
              // Refresh the volume info from the DB.
              volumeInfo = volFactory.getVolume(volumeInfo.getId(), destPrimaryDataStore);
  
--            Map<String, String> details = new HashMap<String, String>();
++            Map<String, String> details = new HashMap<>();
              details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString());
              details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress());
              details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort()));
@@@ -1278,12 -1279,12 +1280,12 @@@
              // Refresh the volume info from the DB.
              volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore);
  
--            ManagedCreateBaseImageContext<CreateCmdResult> context = new ManagedCreateBaseImageContext<CreateCmdResult>(null, volumeInfo, primaryDataStore, srcTemplateInfo, future);
++            ManagedCreateBaseImageContext<CreateCmdResult> context = new ManagedCreateBaseImageContext<>(null, volumeInfo, primaryDataStore, srcTemplateInfo, future);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
  
              caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context);
  
--            Map<String, String> details = new HashMap<String, String>();
++            Map<String, String> details = new HashMap<>();
  
              details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString());
              details.put(PrimaryDataStore.STORAGE_HOST, primaryDataStore.getHostAddress());
@@@ -1639,14 -1641,14 +1641,14 @@@
  
      @Override
      public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(VolumeInfo volume, DataStore store, SnapshotInfo snapshot) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
  
          try {
              DataObject volumeOnStore = store.create(volume);
              volumeOnStore.processEvent(Event.CreateOnlyRequested);
              _volumeDetailsDao.addDetail(volume.getId(), SNAPSHOT_ID, Long.toString(snapshot.getId()), false);
  
--            CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volume, store, volumeOnStore, future, snapshot, null);
++            CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<>(null, volume, store, volumeOnStore, future, snapshot, null);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null)).setContext(context);
              motionSrv.copyAsync(snapshot, volumeOnStore, caller);
@@@ -1733,7 -1735,7 +1735,7 @@@
      }
  
      protected AsyncCallFuture<VolumeApiResult> copyVolumeFromImageToPrimary(VolumeInfo srcVolume, DataStore destStore) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          VolumeApiResult res = new VolumeApiResult(srcVolume);
          VolumeInfo destVolume = null;
          try {
@@@ -1741,7 -1743,7 +1743,7 @@@
              destVolume.processEvent(Event.CopyingRequested);
              srcVolume.processEvent(Event.CopyingRequested);
  
--            CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume, destVolume, destStore);
++            CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<>(null, future, srcVolume, destVolume, destStore);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().copyVolumeFromImageToPrimaryCallback(null, null)).setContext(context);
  
@@@ -1787,7 -1789,7 +1789,7 @@@
      }
  
      protected AsyncCallFuture<VolumeApiResult> copyVolumeFromPrimaryToImage(VolumeInfo srcVolume, DataStore destStore) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          VolumeApiResult res = new VolumeApiResult(srcVolume);
          VolumeInfo destVolume = null;
          try {
@@@ -1795,7 -1797,7 +1797,7 @@@
              srcVolume.processEvent(Event.MigrationRequested);    // this is just used for locking that src volume record in DB to avoid using lock
              destVolume.processEventOnly(Event.CreateOnlyRequested);
  
--            CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume, destVolume, destStore);
++            CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<>(null, future, srcVolume, destVolume, destStore);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().copyVolumeFromPrimaryToImageCallback(null, null)).setContext(context);
  
@@@ -1868,7 -1870,7 +1870,7 @@@
  
          // OfflineVmwareMigration: aren't we missing secondary to secondary in this logic?
  
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          VolumeApiResult res = new VolumeApiResult(srcVolume);
          try {
              if (!snapshotMgr.canOperateOnVolume(srcVolume)) {
@@@ -1884,7 -1886,7 +1886,7 @@@
              destVolume.processEvent(Event.MigrationCopyRequested);
              srcVolume.processEvent(Event.MigrationRequested);
  
--            CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume, destVolume, destStore);
++            CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<>(null, future, srcVolume, destVolume, destStore);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().copyVolumeCallBack(null, null)).setContext(context);
              motionSrv.copyAsync(srcVolume, destVolume, caller);
@@@ -2018,7 -2020,7 +2020,7 @@@
      }
  
      private AsyncCallFuture<VolumeApiResult> copyManagedVolume(VolumeInfo srcVolume, DataStore destStore) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          VolumeApiResult res = new VolumeApiResult(srcVolume);
          try {
              if (!snapshotMgr.canOperateOnVolume(srcVolume)) {
@@@ -2035,7 -2037,7 +2037,7 @@@
                  return future;
              }
  
--            List<Long> poolIds = new ArrayList<Long>();
++            List<Long> poolIds = new ArrayList<>();
              poolIds.add(srcVolume.getPoolId());
              poolIds.add(destStore.getId());
  
@@@ -2067,7 -2069,7 +2069,7 @@@
  
              PrimaryDataStore srcPrimaryDataStore = (PrimaryDataStore) srcVolume.getDataStore();
              if (srcPrimaryDataStore.isManaged()) {
--                Map<String, String> srcPrimaryDataStoreDetails = new HashMap<String, String>();
++                Map<String, String> srcPrimaryDataStoreDetails = new HashMap<>();
                  srcPrimaryDataStoreDetails.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString());
                  srcPrimaryDataStoreDetails.put(PrimaryDataStore.STORAGE_HOST, srcPrimaryDataStore.getHostAddress());
                  srcPrimaryDataStoreDetails.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(srcPrimaryDataStore.getPort()));
@@@ -2080,7 -2082,7 +2082,7 @@@
              }
  
              PrimaryDataStore destPrimaryDataStore = (PrimaryDataStore) destStore;
--            Map<String, String> destPrimaryDataStoreDetails = new HashMap<String, String>();
++            Map<String, String> destPrimaryDataStoreDetails = new HashMap<>();
              destPrimaryDataStoreDetails.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString());
              destPrimaryDataStoreDetails.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress());
              destPrimaryDataStoreDetails.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort()));
@@@ -2095,7 -2097,7 +2097,7 @@@
              destVolume.processEvent(Event.CreateRequested);
              srcVolume.processEvent(Event.MigrationRequested);
  
--            CopyManagedVolumeContext<VolumeApiResult> context = new CopyManagedVolumeContext<VolumeApiResult>(null, future, srcVolume, destVolume, hostWithPoolsAccess);
++            CopyManagedVolumeContext<VolumeApiResult> context = new CopyManagedVolumeContext<>(null, future, srcVolume, destVolume, hostWithPoolsAccess);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().copyManagedVolumeCallBack(null, null)).setContext(context);
  
@@@ -2233,7 -2235,7 +2235,7 @@@
  
      @Override
      public AsyncCallFuture<VolumeApiResult> migrateVolume(VolumeInfo srcVolume, DataStore destStore) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          VolumeApiResult res = new VolumeApiResult(srcVolume);
          try {
              if (!snapshotMgr.canOperateOnVolume(srcVolume)) {
@@@ -2245,7 -2247,7 +2247,7 @@@
  
              VolumeInfo destVolume = volFactory.getVolume(srcVolume.getId(), destStore);
              srcVolume.processEvent(Event.MigrationRequested);
--            MigrateVolumeContext<VolumeApiResult> context = new MigrateVolumeContext<VolumeApiResult>(null, future, srcVolume, destVolume, destStore);
++            MigrateVolumeContext<VolumeApiResult> context = new MigrateVolumeContext<>(null, future, srcVolume, destVolume, destStore);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().migrateVolumeCallBack(null, null)).setContext(context);
              motionSrv.copyAsync(srcVolume, destVolume, caller);
@@@ -2298,13 -2300,13 +2300,13 @@@
  
      @Override
      public AsyncCallFuture<CommandResult> migrateVolumes(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost) {
--        AsyncCallFuture<CommandResult> future = new AsyncCallFuture<CommandResult>();
++        AsyncCallFuture<CommandResult> future = new AsyncCallFuture<>();
          CommandResult res = new CommandResult();
          try {
              // Check to make sure there are no snapshot operations on a volume
              // and
              // put it in the migrating state.
--            List<VolumeInfo> volumesMigrating = new ArrayList<VolumeInfo>();
++            List<VolumeInfo> volumesMigrating = new ArrayList<>();
              for (Map.Entry<VolumeInfo, DataStore> entry : volumeMap.entrySet()) {
                  VolumeInfo volume = entry.getKey();
                  if (!snapshotMgr.canOperateOnVolume(volume)) {
@@@ -2324,7 -2326,7 +2326,7 @@@
                  }
              }
  
--            MigrateVmWithVolumesContext<CommandResult> context = new MigrateVmWithVolumesContext<CommandResult>(null, future, volumeMap);
++            MigrateVmWithVolumesContext<CommandResult> context = new MigrateVmWithVolumesContext<>(null, future, volumeMap);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().migrateVmWithVolumesCallBack(null, null)).setContext(context);
              motionSrv.copyAsync(volumeMap, vmTo, srcHost, destHost, caller);
@@@ -2371,13 -2373,13 +2373,13 @@@
      @Override
      public AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataStore store) {
  
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          DataObject volumeOnStore = store.create(volume);
  
          volumeOnStore.processEvent(Event.CreateOnlyRequested);
  
          try {
--            CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore, future);
++            CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<>(null, volumeOnStore, future);
              AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().registerVolumeCallback(null, null));
              caller.setContext(context);
@@@ -2472,7 -2474,7 +2474,7 @@@
  
      @Override
      public AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume) {
--        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
++        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
          VolumeApiResult result = new VolumeApiResult(volume);
          try {
              volume.processEvent(Event.ResizeRequested);
@@@ -2482,7 -2484,7 +2484,7 @@@
              future.complete(result);
              return future;
          }
--        CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volume, future);
++        CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<>(null, volume, future);
          AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
          caller.setCallback(caller.getTarget().resizeVolumeCallback(caller, context)).setContext(context);
  
@@@ -2581,7 -2583,7 +2583,7 @@@
  
                      // find all the db volumes including those with NULL url column to avoid accidentally deleting volumes on image store later.
                      List<VolumeDataStoreVO> dbVolumes = _volumeStoreDao.listByStoreId(storeId);
--                    List<VolumeDataStoreVO> toBeDownloaded = new ArrayList<VolumeDataStoreVO>(dbVolumes);
++                    List<VolumeDataStoreVO> toBeDownloaded = new ArrayList<>(dbVolumes);
                      for (VolumeDataStoreVO volumeStore : dbVolumes) {
                          VolumeVO volume = volDao.findById(volumeStore.getVolumeId());
                          if (volume == null) {
diff --cc engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceTest.java
index 3a7fcfb6338,97ccc37be13..c4241dfbc3a
--- a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceTest.java
+++ b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceTest.java
@@@ -19,7 -19,21 +19,24 @@@
  
  package org.apache.cloudstack.storage.volume;
  
+ import com.cloud.agent.api.storage.CheckAndRepairVolumeAnswer;
+ import com.cloud.agent.api.storage.CheckAndRepairVolumeCommand;
+ import com.cloud.agent.api.to.StorageFilerTO;
+ import com.cloud.exception.InvalidParameterValueException;
+ import com.cloud.exception.StorageUnavailableException;
+ import com.cloud.host.HostVO;
+ import com.cloud.host.dao.HostDao;
+ import com.cloud.storage.CheckAndRepairVolumePayload;
+ import com.cloud.storage.DiskOfferingVO;
++import com.cloud.storage.Storage;
+ import com.cloud.storage.StorageManager;
+ import com.cloud.storage.StoragePool;
+ import com.cloud.storage.VolumeVO;
+ import com.cloud.storage.dao.DiskOfferingDao;
+ import com.cloud.storage.dao.VolumeDao;
+ import com.cloud.storage.snapshot.SnapshotManager;
++import com.cloud.utils.Pair;
 +
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
@@@ -39,23 -55,6 +56,8 @@@ import org.mockito.Mockito
  import org.mockito.Spy;
  import org.mockito.junit.MockitoJUnitRunner;
  
- import com.cloud.agent.api.storage.CheckAndRepairVolumeAnswer;
- import com.cloud.agent.api.storage.CheckAndRepairVolumeCommand;
- import com.cloud.agent.api.to.StorageFilerTO;
- import com.cloud.exception.StorageUnavailableException;
- import com.cloud.host.HostVO;
- import com.cloud.host.dao.HostDao;
- import com.cloud.storage.CheckAndRepairVolumePayload;
- import com.cloud.storage.Storage;
- import com.cloud.storage.StorageManager;
- import com.cloud.storage.StoragePool;
- import com.cloud.storage.VolumeVO;
- import com.cloud.storage.dao.VolumeDao;
- import com.cloud.storage.snapshot.SnapshotManager;
- import com.cloud.utils.Pair;
- 
 +import junit.framework.TestCase;
 +
  @RunWith(MockitoJUnitRunner.class)
  public class VolumeServiceTest extends TestCase{
  
diff --cc framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java
index 9c15a47444a,f222f6596cf..ded35338aea
--- a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java
+++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java
@@@ -49,11 -50,13 +50,12 @@@ import org.apache.cloudstack.usage.Usag
  import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
  import org.apache.cloudstack.utils.jsinterpreter.JsInterpreter;
  import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
 -import org.apache.cloudstack.utils.usage.UsageUtils;
  import org.apache.commons.collections.CollectionUtils;
  import org.apache.commons.lang3.BooleanUtils;
 +import org.apache.commons.lang3.ObjectUtils;
  import org.apache.commons.lang3.StringUtils;
  import org.apache.commons.lang3.math.NumberUtils;
+ import org.apache.commons.lang3.time.DateUtils;
 -import org.apache.log4j.Logger;
  import org.springframework.stereotype.Component;
  
  import com.cloud.usage.UsageVO;
@@@ -145,75 -158,77 +147,77 @@@ public class QuotaManagerImpl extends M
              return;
          }
  
-         QuotaUsageVO firstQuotaUsage = accountQuotaUsages.get(0);
-         Date startDate = firstQuotaUsage.getStartDate();
-         Date endDate = firstQuotaUsage.getStartDate();
+         Date startDate = accountQuotaUsages.get(0).getStartDate();
+         Date endDate = accountQuotaUsages.get(0).getEndDate();
+         Date lastQuotaUsageEndDate = accountQuotaUsages.get(accountQuotaUsages.size() - 1).getEndDate();
  
-         logger.info("Processing quota balance for account [{}] between [{}] and [{}].", accountToString,
-                 DateUtil.displayDateInTimezone(usageAggregationTimeZone, startDate),
-                 DateUtil.displayDateInTimezone(usageAggregationTimeZone, accountQuotaUsages.get(accountQuotaUsages.size() - 1).getEndDate()));
+         LinkedHashSet<Pair<Date, Date>> periods = accountQuotaUsages.stream()
+                 .map(quotaUsageVO -> new Pair<>(quotaUsageVO.getStartDate(), quotaUsageVO.getEndDate()))
+                 .collect(Collectors.toCollection(LinkedHashSet::new));
+ 
 -        s_logger.info(String.format("Processing quota balance for account[%s] between [%s] and [%s].", accountToString, startDate, lastQuotaUsageEndDate));
++        logger.info(String.format("Processing quota balance for account[{}] between [{}] and [{}].", accountToString, startDate, lastQuotaUsageEndDate));
  
-         BigDecimal aggregatedUsage = BigDecimal.ZERO;
          long accountId = accountVo.getAccountId();
          long domainId = accountVo.getDomainId();
+         BigDecimal accountBalance = retrieveBalanceForUsageCalculation(accountId, domainId, startDate, accountToString);
  
-         aggregatedUsage = getUsageValueAccordingToLastQuotaUsageEntryAndLastQuotaBalance(accountId, domainId, startDate, endDate, aggregatedUsage, accountToString);
- 
-         for (QuotaUsageVO quotaUsage : accountQuotaUsages) {
-             Date quotaUsageStartDate = quotaUsage.getStartDate();
-             Date quotaUsageEndDate = quotaUsage.getEndDate();
-             BigDecimal quotaUsed = quotaUsage.getQuotaUsed();
- 
-             if (quotaUsed.equals(BigDecimal.ZERO)) {
-                 aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, quotaUsageStartDate, quotaUsageEndDate, accountToString));
-                 continue;
-             }
- 
-             if (startDate.compareTo(quotaUsageStartDate) == 0) {
-                 aggregatedUsage = aggregatedUsage.subtract(quotaUsed);
-                 continue;
-             }
- 
-             _quotaBalanceDao.saveQuotaBalance(new QuotaBalanceVO(accountId, domainId, aggregatedUsage, endDate));
- 
-             aggregatedUsage = BigDecimal.ZERO;
-             startDate = quotaUsageStartDate;
-             endDate = quotaUsageEndDate;
+         for (Pair<Date, Date> period : periods) {
+             startDate = period.first();
+             endDate = period.second();
  
-             QuotaBalanceVO lastRealBalanceEntry = _quotaBalanceDao.findLastBalanceEntry(accountId, domainId, endDate);
-             Date lastBalanceDate = new Date(0);
+             accountBalance = calculateBalanceConsideringCreditsAddedAndQuotaUsed(accountBalance, accountQuotaUsages, accountId, domainId, startDate, endDate, accountToString);
+             _quotaBalanceDao.saveQuotaBalance(new QuotaBalanceVO(accountId, domainId, accountBalance, endDate));
+         }
+         saveQuotaAccount(accountId, accountBalance, endDate);
+     }
  
-             if (lastRealBalanceEntry != null) {
-                 lastBalanceDate = lastRealBalanceEntry.getUpdatedOn();
-                 aggregatedUsage = aggregatedUsage.add(lastRealBalanceEntry.getCreditBalance());
+     /**
+      * Calculates the balance for the given account considering the specified period. The balance is calculated as follows:
+      * <ol>
+      *     <li>The credits added in this period are added to the balance.</li>
+      *     <li>All quota consumed in this period are subtracted from the account balance.</li>
+      * </ol>
+      */
+     protected BigDecimal calculateBalanceConsideringCreditsAddedAndQuotaUsed(BigDecimal accountBalance, List<QuotaUsageVO> accountQuotaUsages, long accountId, long domainId,
+                                                                              Date startDate, Date endDate, String accountToString) {
+         accountBalance = accountBalance.add(aggregateCreditBetweenDates(accountId, domainId, startDate, endDate, accountToString));
+ 
+         for (QuotaUsageVO quotaUsageVO : accountQuotaUsages) {
+             if (DateUtils.isSameInstant(quotaUsageVO.getStartDate(), startDate)) {
+                 accountBalance = accountBalance.subtract(quotaUsageVO.getQuotaUsed());
              }
- 
-             aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, lastBalanceDate, endDate, accountToString));
-             aggregatedUsage = aggregatedUsage.subtract(quotaUsed);
          }
- 
-         _quotaBalanceDao.saveQuotaBalance(new QuotaBalanceVO(accountId, domainId, aggregatedUsage, endDate));
-         saveQuotaAccount(accountId, aggregatedUsage, endDate);
+         return accountBalance;
      }
  
-     protected BigDecimal getUsageValueAccordingToLastQuotaUsageEntryAndLastQuotaBalance(long accountId, long domainId, Date startDate, Date endDate, BigDecimal aggregatedUsage,
-             String accountToString) {
+     /**
+      * Retrieves the initial balance prior to the period of the quota processing.
+      * <ul>
+      *     <li>
+      *         If it is the first time of processing for the account, the credits prior to the quota processing are added, and the first balance is persisted in the DB.
+      *     </li>
+      *     <li>
+      *         Otherwise, the last real balance of the account is retrieved.
+      *     </li>
+      * </ul>
+      */
+     protected BigDecimal retrieveBalanceForUsageCalculation(long accountId, long domainId, Date startDate, String accountToString) {
+         BigDecimal accountBalance = BigDecimal.ZERO;
          QuotaUsageVO lastQuotaUsage = _quotaUsageDao.findLastQuotaUsageEntry(accountId, domainId, startDate);
  
          if (lastQuotaUsage == null) {
-             aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, new Date(0), startDate, accountToString));
-             QuotaBalanceVO firstBalance = new QuotaBalanceVO(accountId, domainId, aggregatedUsage, startDate);
+             accountBalance = accountBalance.add(aggregateCreditBetweenDates(accountId, domainId, new Date(0), startDate, accountToString));
+             QuotaBalanceVO firstBalance = new QuotaBalanceVO(accountId, domainId, accountBalance, startDate);
  
 -            s_logger.debug(String.format("Persisting the first quota balance [%s] for account [%s].", firstBalance, accountToString));
 +            logger.debug(String.format("Persisting the first quota balance [%s] for account [%s].", firstBalance, accountToString));
              _quotaBalanceDao.saveQuotaBalance(firstBalance);
          } else {
-             QuotaBalanceVO lastRealBalance = _quotaBalanceDao.findLastBalanceEntry(accountId, domainId, endDate);
+             QuotaBalanceVO lastRealBalance = _quotaBalanceDao.findLastBalanceEntry(accountId, domainId, startDate);
  
-             if (lastRealBalance != null) {
-                 aggregatedUsage = aggregatedUsage.add(lastRealBalance.getCreditBalance());
-                 aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, lastRealBalance.getUpdatedOn(), endDate, accountToString));
+             if (lastRealBalance == null) {
 -                s_logger.warn(String.format("Account [%s] has quota usage entries, however it does not have a quota balance.", accountToString));
++                logger.warn("Account [{}] has quota usage entries, however it does not have a quota balance.", accountToString);
              } else {
-                 logger.warn(String.format("Account [%s] has quota usage entries, however it does not have a quota balance.", accountToString));
+                 accountBalance = accountBalance.add(lastRealBalance.getCreditBalance());
              }
          }
  
diff --cc plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
index f15f3f20001,eb9ab7148b2..a71ae26e670
--- a/plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
+++ b/plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
@@@ -40,10 -38,8 +40,9 @@@ import com.cloud.host.HostVO
  import com.cloud.host.dao.HostDao;
  import com.cloud.offering.ServiceOffering;
  import com.cloud.resource.ResourceManager;
 +import com.cloud.storage.VMTemplateVO;
  import com.cloud.utils.Pair;
  import com.cloud.utils.component.AdapterBase;
- import com.cloud.utils.exception.CloudRuntimeException;
  import com.cloud.vm.VirtualMachine;
  import com.cloud.vm.VirtualMachineProfile;
  
@@@ -88,28 -64,25 +87,28 @@@ public class RandomAllocator extends Ad
          Long podId = plan.getPodId();
          Long clusterId = plan.getClusterId();
          ServiceOffering offering = vmProfile.getServiceOffering();
 +        List<? extends Host> hostsCopy = null;
-         List<Host> suitableHosts = new ArrayList<Host>();
+         List<Host> suitableHosts = new ArrayList<>();
  
          if (type == Host.Type.Storage) {
              return suitableHosts;
          }
 -
 -        String hostTag = offering.getHostTag();
 -        String hostTagToLog = hostTag != null ? String.format("and complying with host tags [%s]", hostTag) : "";
 -        String paramAsStringToLog = String.format("zone [%s], pod [%s], cluster [%s] %s", dcId, podId, clusterId, hostTagToLog);
 -
 -        s_logger.debug(String.format("Looking for hosts in %s.", paramAsStringToLog));
 -
 -        List<? extends Host> hostsCopy;
 -
 +        String offeringHostTag = offering.getHostTag();
 +        VMTemplateVO template = (VMTemplateVO)vmProfile.getTemplate();
 +        String templateTag = template.getTemplateTag();
 +        String hostTag = null;
 +        if (ObjectUtils.anyNull(offeringHostTag, templateTag)) {
 +            hostTag = offeringHostTag;
 +            hostTag = hostTag == null ? templateTag : String.format("%s, %s", hostTag, templateTag);
 +            logger.debug(String.format("Looking for hosts in dc [%s], pod [%s], cluster [%s] and complying with host tag(s): [%s]", dcId, podId, clusterId, hostTag));
 +        } else {
 +            logger.debug("Looking for hosts in dc: " + dcId + "  pod:" + podId + "  cluster:" + clusterId);
 +        }
          if (hosts != null) {
              // retain all computing hosts, regardless of whether they support routing...it's random after all
--            hostsCopy = new ArrayList<Host>(hosts);
 -            if (hostTag != null) {
 -                hostsCopy.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag));
++            hostsCopy = new ArrayList<>(hosts);
 +            if (ObjectUtils.anyNotNull(offeringHostTag, templateTag)) {
 +                hostsCopy.retainAll(listHostsByTags(type, dcId, podId, clusterId, offeringHostTag, templateTag));
              } else {
                  hostsCopy.retainAll(_hostDao.listAllHostsThatHaveNoRuleTag(type, clusterId, podId, dcId));
              }
@@@ -121,17 -94,18 +120,18 @@@
                  hostsCopy = _hostDao.listAllHostsThatHaveNoRuleTag(type, clusterId, podId, dcId);
              }
          }
 -        hostsCopy = ListUtils.union(hostsCopy, _hostDao.findHostsWithTagRuleThatMatchComputeOferringTags(hostTag));
 +        hostsCopy = ListUtils.union(hostsCopy, _hostDao.findHostsWithTagRuleThatMatchComputeOferringTags(offeringHostTag));
  
          if (hostsCopy.isEmpty()) {
-             logger.error(String.format("No suitable host found for vm [%s] with tags [%s].", vmProfile, hostTag));
-             throw new CloudRuntimeException(String.format("No suitable host found for vm [%s].", vmProfile));
 -            s_logger.info(String.format("No suitable host found for VM [%s] in %s.", vmProfile, paramAsStringToLog));
++            logger.info("No suitable host found for VM [{}] in {}.", vmProfile, hostTag);
+             return null;
          }
  
-         logger.debug("Random Allocator found " + hostsCopy.size() + "  hosts");
-         if (hostsCopy.size() == 0) {
 -        s_logger.debug("Random Allocator found " + hostsCopy.size() + "  hosts");
++        logger.debug("Random Allocator found {} hosts", hostsCopy.size());
+         if (hostsCopy.isEmpty()) {
              return suitableHosts;
          }
+ 
          Collections.shuffle(hostsCopy);
          for (Host host : hostsCopy) {
              if (suitableHosts.size() == returnUpTo) {
@@@ -171,10 -145,10 +171,10 @@@
                                   ExcludeList avoid, List<? extends Host> hosts, int returnUpTo,
                                   boolean considerReservedCapacity) {
          if (CollectionUtils.isEmpty(hosts)) {
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Random Allocator found 0 hosts as given host list is empty");
 +            if (logger.isDebugEnabled()) {
 +                logger.debug("Random Allocator found 0 hosts as given host list is empty");
              }
--            return new ArrayList<Host>();
++            return new ArrayList<>();
          }
          return findSuitableHosts(vmProfile, plan, type, avoid, hosts, returnUpTo, considerReservedCapacity);
      }
diff --cc plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index b503610eb3c,830f4e7a25b..6c901795fa2
--- 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
@@@ -782,7 -784,7 +782,7 @@@ public class VmwareResource extends Ser
       */
      protected EnumMap<VmwareStorageProcessorConfigurableFields, Object> examineStorageSubSystemCommandFullCloneFlagForVmware(CopyCommand cmd,
              EnumMap<VmwareStorageProcessorConfigurableFields, Object> params) {
--        EnumMap<VmwareStorageProcessorConfigurableFields, Object> paramsCopy = new EnumMap<VmwareStorageProcessorConfigurableFields, Object>(params);
++        EnumMap<VmwareStorageProcessorConfigurableFields, Object> paramsCopy = new EnumMap<>(params);
          HypervisorType hypervisor = cmd.getDestTO().getHypervisorType();
          if (hypervisor != null && hypervisor.equals(HypervisorType.VMware)) {
              DataStoreTO destDataStore = cmd.getDestTO().getDataStore();
@@@ -2201,8 -2203,8 +2201,8 @@@
                      throw new Exception("Failed to find the newly create or relocated VM. vmName: " + vmInternalCSName);
                  }
              }
-             if (deployAsIs) {
+             if (deployAsIs && !vmMo.hasSnapshot()) {
 -                s_logger.info("Mapping VM disks to spec disks and tearing down datadisks (if any)");
 +                logger.info("Mapping VM disks to spec disks and tearing down datadisks (if any)");
                  mapSpecDisksToClonedDisksAndTearDownDatadisks(vmMo, vmInternalCSName, specDisks);
              }
  
diff --cc server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
index 36330d6685c,18d5d22a8e2..99ac2492e83
--- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
+++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
@@@ -128,12 -128,14 +128,10 @@@ public class FirstFitAllocator extends 
  
          if (type == Host.Type.Storage) {
              // FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of routing or not
--            return new ArrayList<Host>();
++            return new ArrayList<>();
          }
  
-         if (logger.isDebugEnabled()) {
-             logger.debug("Looking for hosts in dc: " + dcId + "  pod:" + podId + "  cluster:" + clusterId);
 -        String paramAsStringToLog = String.format("zone [%s], pod [%s], cluster [%s]", dcId, podId, clusterId);
 -
 -        if (s_logger.isDebugEnabled()) {
 -            s_logger.debug(String.format("Looking for hosts in %s.", paramAsStringToLog));
--        }
++        logger.debug("Looking for hosts in zone [{}], pod [{}], cluster [{}]", dcId, podId, clusterId);
  
          String hostTagOnOffering = offering.getHostTag();
          String hostTagOnTemplate = template.getTemplateTag();
@@@ -142,12 -144,12 +140,12 @@@
          boolean hasSvcOfferingTag = hostTagOnOffering != null ? true : false;
          boolean hasTemplateTag = hostTagOnTemplate != null ? true : false;
  
--        List<HostVO> clusterHosts = new ArrayList<HostVO>();
--        List<HostVO> hostsMatchingUefiTag = new ArrayList<HostVO>();
++        List<HostVO> clusterHosts = new ArrayList<>();
++        List<HostVO> hostsMatchingUefiTag = new ArrayList<>();
          if(isVMDeployedWithUefi){
              hostsMatchingUefiTag = _hostDao.listByHostCapability(type, clusterId, podId, dcId, Host.HOST_UEFI_ENABLE);
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Hosts with tag '" + hostTagUefi + "' are:" + hostsMatchingUefiTag);
 +            if (logger.isDebugEnabled()) {
 +                logger.debug("Hosts with tag '" + hostTagUefi + "' are:" + hostsMatchingUefiTag);
              }
          }
  
@@@ -159,15 -161,15 +157,15 @@@
              if (hostTagOnOffering == null && hostTagOnTemplate == null) {
                  clusterHosts = _resourceMgr.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId);
              } else {
--                List<HostVO> hostsMatchingOfferingTag = new ArrayList<HostVO>();
--                List<HostVO> hostsMatchingTemplateTag = new ArrayList<HostVO>();
++                List<HostVO> hostsMatchingOfferingTag = new ArrayList<>();
++                List<HostVO> hostsMatchingTemplateTag = new ArrayList<>();
                  if (hasSvcOfferingTag) {
 -                    if (s_logger.isDebugEnabled()) {
 -                        s_logger.debug("Looking for hosts having tag specified on SvcOffering:" + hostTagOnOffering);
 +                    if (logger.isDebugEnabled()) {
 +                        logger.debug("Looking for hosts having tag specified on SvcOffering:" + hostTagOnOffering);
                      }
                      hostsMatchingOfferingTag = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnOffering);
 -                    if (s_logger.isDebugEnabled()) {
 -                        s_logger.debug("Hosts with tag '" + hostTagOnOffering + "' are:" + hostsMatchingOfferingTag);
 +                    if (logger.isDebugEnabled()) {
 +                        logger.debug("Hosts with tag '" + hostTagOnOffering + "' are:" + hostsMatchingOfferingTag);
                      }
                  }
                  if (hasTemplateTag) {
@@@ -205,8 -207,8 +203,8 @@@
  
  
          if (clusterHosts.isEmpty()) {
-             logger.error(String.format("No suitable host found for vm [%s] with tags [%s].", vmProfile, hostTagOnOffering));
 -            s_logger.info(String.format("No suitable host found for VM [%s] with tags [%s] in %s.", vmProfile, hostTagOnOffering, paramAsStringToLog));
 -            return null;
++            logger.error("No suitable host found for vm [{}] with tags [{}].", vmProfile, hostTagOnOffering);
 +            throw new CloudRuntimeException(String.format("No suitable host found for vm [%s].", vmProfile));
          }
          // add all hosts that we are not considering to the avoid list
          List<HostVO> allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);
@@@ -231,8 -229,8 +229,8 @@@
          ServiceOffering offering = vmProfile.getServiceOffering();
          VMTemplateVO template = (VMTemplateVO)vmProfile.getTemplate();
          Account account = vmProfile.getOwner();
--        List<Host> suitableHosts = new ArrayList<Host>();
--        List<Host> hostsCopy = new ArrayList<Host>(hosts);
++        List<Host> suitableHosts = new ArrayList<>();
++        List<Host> hostsCopy = new ArrayList<>(hosts);
  
          if (type == Host.Type.Storage) {
              // FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of
@@@ -314,7 -312,7 +312,7 @@@
          }
  
          long serviceOfferingId = offering.getId();
--        List<Host> suitableHosts = new ArrayList<Host>();
++        List<Host> suitableHosts = new ArrayList<>();
          ServiceOfferingDetailsVO offeringDetails = null;
  
          for (Host host : hosts) {
@@@ -383,15 -382,15 +381,15 @@@
          }
  
          //now filter the given list of Hosts by this ordered list
--        Map<Long, Host> hostMap = new HashMap<Long, Host>();
++        Map<Long, Host> hostMap = new HashMap<>();
          for (Host host : hosts) {
              hostMap.put(host.getId(), host);
          }
--        List<Long> matchingHostIds = new ArrayList<Long>(hostMap.keySet());
++        List<Long> matchingHostIds = new ArrayList<>(hostMap.keySet());
  
          hostIdsByFreeCapacity.retainAll(matchingHostIds);
  
--        List<Host> reorderedHosts = new ArrayList<Host>();
++        List<Host> reorderedHosts = new ArrayList<>();
          for(Long id: hostIdsByFreeCapacity){
              reorderedHosts.add(hostMap.get(id));
          }
@@@ -413,15 -412,15 +411,15 @@@
          }
  
          //now filter the given list of Hosts by this ordered list
--        Map<Long, Host> hostMap = new HashMap<Long, Host>();
++        Map<Long, Host> hostMap = new HashMap<>();
          for (Host host : hosts) {
              hostMap.put(host.getId(), host);
          }
--        List<Long> matchingHostIds = new ArrayList<Long>(hostMap.keySet());
++        List<Long> matchingHostIds = new ArrayList<>(hostMap.keySet());
  
          hostIdsByVmCount.retainAll(matchingHostIds);
  
--        List<Host> reorderedHosts = new ArrayList<Host>();
++        List<Host> reorderedHosts = new ArrayList<>();
          for (Long id : hostIdsByVmCount) {
              reorderedHosts.add(hostMap.get(id));
          }
@@@ -444,11 -443,11 +442,11 @@@
          // Determine the guest OS category of the template
          String templateGuestOSCategory = getTemplateGuestOSCategory(template);
  
--        List<Host> prioritizedHosts = new ArrayList<Host>();
--        List<Host> noHvmHosts = new ArrayList<Host>();
++        List<Host> prioritizedHosts = new ArrayList<>();
++        List<Host> noHvmHosts = new ArrayList<>();
  
          // If a template requires HVM and a host doesn't support HVM, remove it from consideration
--        List<Host> hostsToCheck = new ArrayList<Host>();
++        List<Host> hostsToCheck = new ArrayList<>();
          if (template.isRequiresHvm()) {
              for (Host host : hosts) {
                  if (hostSupportsHVM(host)) {
@@@ -468,8 -467,8 +466,8 @@@
          }
          // If a host is tagged with the same guest OS category as the template, move it to a high priority list
          // If a host is tagged with a different guest OS category than the template, move it to a low priority list
--        List<Host> highPriorityHosts = new ArrayList<Host>();
--        List<Host> lowPriorityHosts = new ArrayList<Host>();
++        List<Host> highPriorityHosts = new ArrayList<>();
++        List<Host> lowPriorityHosts = new ArrayList<>();
          for (Host host : hostsToCheck) {
              String hostGuestOSCategory = getHostGuestOSCategory(host);
              if (hostGuestOSCategory == null) {
@@@ -502,7 -501,7 +500,7 @@@
          // if service offering is not GPU enabled then move all the GPU enabled hosts to the end of priority list.
          if (_serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString()) == null) {
  
--            List<Host> gpuEnabledHosts = new ArrayList<Host>();
++            List<Host> gpuEnabledHosts = new ArrayList<>();
              // Check for GPU enabled hosts.
              for (Host host : prioritizedHosts) {
                  if (_resourceMgr.isHostGpuEnabled(host.getId())) {
diff --cc server/src/main/java/com/cloud/agent/manager/allocator/impl/RecreateHostAllocator.java
index 286bef7d39a,77174780405..51b45a2dc98
--- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/RecreateHostAllocator.java
+++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/RecreateHostAllocator.java
@@@ -26,6 -26,8 +26,7 @@@ import java.util.Set
  import javax.inject.Inject;
  import javax.naming.ConfigurationException;
  
+ import org.apache.commons.collections.CollectionUtils;
 -import org.apache.log4j.Logger;
  import org.springframework.stereotype.Component;
  
  import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
diff --cc server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
index 22670c52449,14667c2d47d..784f6451c13
--- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@@ -454,207 -618,6 +454,207 @@@ StateListener<State, VirtualMachine.Eve
          return dest;
      }
  
 +    private DeployDestination deployInVmLastHost(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids,
 +            DeploymentPlanner planner, VirtualMachine vm, DataCenter dc, ServiceOffering offering, int cpuRequested, long ramRequested,
 +            boolean volumesRequireEncryption) throws InsufficientServerCapacityException {
 +        HostVO host = _hostDao.findById(vm.getLastHostId());
 +        if (canUseLastHost(host, avoids, plan, vm, offering, volumesRequireEncryption)) {
 +            _hostDao.loadHostTags(host);
 +            _hostDao.loadDetails(host);
 +            if (host.getStatus() != Status.Up) {
 +                logger.debug("Cannot deploy VM [{}] to the last host [{}] because this host is not in UP state or is not enabled. Host current status [{}] and resource status [{}].",
 +                        vm.getUuid(), host.getUuid(), host.getState().name(), host.getResourceState());
 +                return null;
 +            }
 +            if (checkVmProfileAndHost(vmProfile, host)) {
 +                long cluster_id = host.getClusterId();
 +                ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, "cpuOvercommitRatio");
 +                ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, "memoryOvercommitRatio");
 +                float cpuOvercommitRatio = Float.parseFloat(cluster_detail_cpu.getValue());
 +                float memoryOvercommitRatio = Float.parseFloat(cluster_detail_ram.getValue());
 +
 +                boolean hostHasCpuCapability, hostHasCapacity = false;
 +                hostHasCpuCapability = _capacityMgr.checkIfHostHasCpuCapability(host.getId(), offering.getCpu(), offering.getSpeed());
 +
 +                if (hostHasCpuCapability) {
 +                    // first check from reserved capacity
 +                    hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpuRequested, ramRequested, true, cpuOvercommitRatio, memoryOvercommitRatio, true);
 +
 +                    // if not reserved, check the free capacity
 +                    if (!hostHasCapacity)
 +                        hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpuRequested, ramRequested, false, cpuOvercommitRatio, memoryOvercommitRatio, true);
 +                    }
 +
 +                boolean displayStorage = getDisplayStorageFromVmProfile(vmProfile);
 +                if (!hostHasCapacity || !hostHasCpuCapability) {
 +                    logger.debug("Cannot deploy VM [{}] to the last host [{}] because this host does not have enough capacity to deploy this VM.", vm.getUuid(), host.getUuid());
 +                    return null;
 +                }
 +                logger.debug("Last host [{}] of VM [{}] is UP and has enough capacity. Checking for suitable pools for this host under zone [{}], pod [{}] and cluster [{}].",
 +                        host.getUuid(), vm.getUuid(), host.getDataCenterId(), host.getPodId(), host.getClusterId());
 +
 +                Pod pod = _podDao.findById(host.getPodId());
 +                Cluster cluster = _clusterDao.findById(host.getClusterId());
 +                if (vm.getHypervisorType() == HypervisorType.BareMetal) {
-                     DeployDestination dest = new DeployDestination(dc, pod, cluster, host, new HashMap<Volume, StoragePool>(), displayStorage);
++                    DeployDestination dest = new DeployDestination(dc, pod, cluster, host, new HashMap<>(), displayStorage);
 +                    logger.debug("Returning Deployment Destination: {}.", dest);
 +                    return dest;
 +                }
 +
 +                // search for storage under the zone, pod, cluster
 +                // of
 +                // the last host.
 +                DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(),
 +                        host.getPodId(), host.getClusterId(), host.getId(), plan.getPoolId(), null);
 +                Pair<Map<Volume, List<StoragePool>>, List<Volume>> result = findSuitablePoolsForVolumes(
 +                        vmProfile, lastPlan, avoids, HostAllocator.RETURN_UPTO_ALL);
 +                Map<Volume, List<StoragePool>> suitableVolumeStoragePools = result.first();
 +                List<Volume> readyAndReusedVolumes = result.second();
 +
 +                // choose the potential pool for this VM for this
 +                // host
 +                if (suitableVolumeStoragePools.isEmpty()) {
 +                    logger.debug("Cannot find suitable storage pools in host [{}] to deploy VM [{}]", host.getUuid(), vm.getUuid());
 +                    return null;
 +                }
-                 List<Host> suitableHosts = new ArrayList<Host>();
++                List<Host> suitableHosts = new ArrayList<>();
 +                suitableHosts.add(host);
 +                Pair<Host, Map<Volume, StoragePool>> potentialResources = findPotentialDeploymentResources(
 +                        suitableHosts, suitableVolumeStoragePools, avoids,
 +                        getPlannerUsage(planner, vmProfile, plan, avoids), readyAndReusedVolumes, plan.getPreferredHosts(), vm);
 +                if (potentialResources != null) {
 +                    Map<Volume, StoragePool> storageVolMap = potentialResources.second();
 +                    // remove the reused vol<->pool from
 +                    // destination, since we don't have to
 +                    // prepare
 +                    // this volume.
 +                    for (Volume vol : readyAndReusedVolumes) {
 +                        storageVolMap.remove(vol);
 +                    }
 +                    DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap, displayStorage);
 +                    logger.debug("Returning Deployment Destination: {}", dest);
 +                    return dest;
 +                }
 +            }
 +        }
 +        logger.debug("Cannot choose the last host to deploy this VM {}.", vm);
 +        return null;
 +    }
 +
 +    private boolean canUseLastHost(HostVO host, ExcludeList avoids, DeploymentPlan plan, VirtualMachine vm, ServiceOffering offering, boolean volumesRequireEncryption) {
 +        if (host == null) {
 +            logger.warn("Could not find last host of VM [{}] with id [{}]. Skipping this and trying other available hosts.", vm.getUuid(), vm.getLastHostId());
 +            return false;
 +        }
 +
 +        if (avoids.shouldAvoid(host)) {
 +            logger.warn("The last host [{}] of VM [{}] is in the avoid set. Skipping this and trying other available hosts.", host.getUuid(), vm.getUuid());
 +            return false;
 +        }
 +
 +        if (plan.getClusterId() != null && host.getClusterId() != null && !plan.getClusterId().equals(host.getClusterId())) {
 +            logger.debug(() -> String.format("The last host [%s] of VM [%s] cannot be picked, as the plan [%s] specifies a different cluster [%s] to deploy this VM. Skipping this and trying other available hosts.",
 +                    ReflectionToStringBuilderUtils.reflectOnlySelectedFields(host, "uuid", "clusterId"), vm.getUuid(), plan.getClass().getSimpleName(), plan.getClusterId()));
 +            return false;
 +        }
 +
 +        if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) {
 +            logger.debug("Cannot deploy VM [{}] in the last host [{}] because this host already has the max number of running VMs (users and system VMs). Skipping this and trying other available hosts.",
 +                    vm.getUuid(), host.getUuid());
 +            return false;
 +        }
 +
 +        ServiceOfferingDetailsVO offeringDetails = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString());
 +        ServiceOfferingDetailsVO groupName = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.pciDevice.toString());
 +        if (offeringDetails != null && !_resourceMgr.isGPUDeviceAvailable(host.getId(), groupName.getValue(), offeringDetails.getValue())) {
 +            logger.debug("Cannot deploy VM [{}] in the last host [{}] because this host does not have the required GPU devices available. Skipping this and trying other available hosts.",
 +                    vm.getUuid(), host.getUuid());
 +            return false;
 +        }
 +
 +        if (volumesRequireEncryption && !Boolean.parseBoolean(host.getDetail(Host.HOST_VOLUME_ENCRYPTION))) {
 +            logger.warn("The last host of this VM {} does not support volume encryption, which is required by this VM.", host);
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    private DeployDestination deployInSpecifiedHostWithoutHA(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids,
 +            DeploymentPlanner planner, VirtualMachine vm, DataCenter dc, String uefiFlag)
 +            throws InsufficientServerCapacityException {
 +        Long hostIdSpecified = plan.getHostId();
 +        logger.debug("DeploymentPlan [{}] has specified host [{}] without HA flag. Choosing this host to deploy VM [{}].", plan.getClass().getSimpleName(), hostIdSpecified, vm.getUuid());
 +
 +        HostVO host = _hostDao.findById(hostIdSpecified);
 +        if (host != null && StringUtils.isNotBlank(uefiFlag) && "yes".equalsIgnoreCase(uefiFlag)) {
 +            _hostDao.loadDetails(host);
 +            if (MapUtils.isNotEmpty(host.getDetails()) && host.getDetails().containsKey(Host.HOST_UEFI_ENABLE) && "false".equalsIgnoreCase(host.getDetails().get(Host.HOST_UEFI_ENABLE))) {
 +                logger.debug("Cannot deploy VM [{}] to specified host [{}] because this host does not support UEFI VM deployment, returning.", vm.getUuid(), host.getUuid());
 +                return null;
 +            }
 +        }
 +        if (host == null) {
 +            logger.debug("Cannot deploy VM [{}] to host [{}] because this host cannot be found.", vm.getUuid(), hostIdSpecified);
 +            return null;
 +        }
 +        if (avoids.shouldAvoid(host)) {
 +            logger.debug("Cannot deploy VM [{}] to host [{}] because this host is in the avoid set.", vm.getUuid(), host.getUuid());
 +            return null;
 +        }
 +
 +        logger.debug("Trying to find suitable pools for host [{}] under pod [{}], cluster [{}] and zone [{}], to deploy VM [{}].",
 +                host.getUuid(), host.getDataCenterId(), host.getPodId(), host.getClusterId(), vm.getUuid());
 +
 +        Pod pod = _podDao.findById(host.getPodId());
 +        Cluster cluster = _clusterDao.findById(host.getClusterId());
 +
 +        boolean displayStorage = getDisplayStorageFromVmProfile(vmProfile);
 +        if (vm.getHypervisorType() == HypervisorType.BareMetal) {
-             DeployDestination dest = new DeployDestination(dc, pod, cluster, host, new HashMap<Volume, StoragePool>(),
++            DeployDestination dest = new DeployDestination(dc, pod, cluster, host, new HashMap<>(),
 +                    displayStorage);
 +            logger.debug("Returning Deployment Destination: {}.", dest);
 +            return dest;
 +        }
 +
 +        DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(),
 +                host.getClusterId(), hostIdSpecified, plan.getPoolId(), null, plan.getReservationContext());
 +
 +        Pair<Map<Volume, List<StoragePool>>, List<Volume>> result = findSuitablePoolsForVolumes(vmProfile, lastPlan,
 +                avoids, HostAllocator.RETURN_UPTO_ALL);
 +        Map<Volume, List<StoragePool>> suitableVolumeStoragePools = result.first();
 +        List<Volume> readyAndReusedVolumes = result.second();
 +
 +        if (!suitableVolumeStoragePools.isEmpty()) {
-             List<Host> suitableHosts = new ArrayList<Host>();
++            List<Host> suitableHosts = new ArrayList<>();
 +            suitableHosts.add(host);
 +            Pair<Host, Map<Volume, StoragePool>> potentialResources = findPotentialDeploymentResources(suitableHosts,
 +                    suitableVolumeStoragePools, avoids, getPlannerUsage(planner, vmProfile, plan, avoids),
 +                    readyAndReusedVolumes, plan.getPreferredHosts(), vm);
 +            if (potentialResources != null) {
 +                pod = _podDao.findById(host.getPodId());
 +                cluster = _clusterDao.findById(host.getClusterId());
 +                Map<Volume, StoragePool> storageVolMap = potentialResources.second();
 +                for (Volume vol : readyAndReusedVolumes) {
 +                    storageVolMap.remove(vol);
 +                }
 +                DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap, displayStorage);
 +                logger.debug("Returning Deployment Destination: {}", dest);
 +                return dest;
 +            }
 +        }
 +        logger.debug("Cannot deploy VM [{}] under host [{}], because no suitable pools were found.", vmProfile.getUuid(), host.getUuid());
 +        return null;
 +    }
 +
 +    protected String getRootVolumeUuid(List<? extends Volume> volumes) {
 +        for (Volume volume : volumes) {
 +            if (volume.getVolumeType() == Volume.Type.ROOT) {
 +                return volume.getUuid();
 +            }
 +        }
 +        return null;
 +    }
 +
      protected boolean anyVolumeRequiresEncryption(List<? extends Volume> volumes) {
          for (Volume volume : volumes) {
              if (volume.getPassphraseId() != null) {
@@@ -859,91 -830,91 +859,91 @@@
          //Handle the Virtual Router Case
          //No need to check the isExplicit. As both the cases are handled.
          if (vm.getType() == VirtualMachine.Type.DomainRouter) {
 -            long vmAccountId = vm.getAccountId();
 -            long vmDomainId = vm.getDomainId();
 +            findAvoiSetForRouterVM(avoids, vm, allPodsInDc, allClustersInDc, allHostsInDc);
 +        }
 +    }
  
 -            //Lists all explicitly dedicated resources from vm account ID or domain ID.
 -            List<Long> allPodsFromDedicatedID = new ArrayList<Long>();
 -            List<Long> allClustersFromDedicatedID = new ArrayList<Long>();
 -            List<Long> allHostsFromDedicatedID = new ArrayList<Long>();
 +    private void findAvoiSetForRouterVM(ExcludeList avoids, VirtualMachine vm, List<Long> allPodsInDc, List<Long> allClustersInDc, List<Long> allHostsInDc) {
 +        long vmAccountId = vm.getAccountId();
 +        long vmDomainId = vm.getDomainId();
  
-         List<Long> allPodsFromDedicatedID = new ArrayList<Long>();
-         List<Long> allClustersFromDedicatedID = new ArrayList<Long>();
-         List<Long> allHostsFromDedicatedID = new ArrayList<Long>();
 -            //Whether the dedicated resources belong to Domain or not. If not, it may belongs to Account or no dedication.
 -            List<AffinityGroupDomainMapVO> domainGroupMappings = _affinityGroupDomainMapDao.listByDomain(vmDomainId);
++        List<Long> allPodsFromDedicatedID = new ArrayList<>();
++        List<Long> allClustersFromDedicatedID = new ArrayList<>();
++        List<Long> allHostsFromDedicatedID = new ArrayList<>();
  
 -            //For temporary storage and indexing.
 -            List<DedicatedResourceVO> tempStorage;
 +        List<AffinityGroupDomainMapVO> domainGroupMappings = _affinityGroupDomainMapDao.listByDomain(vmDomainId);
  
 -            if (domainGroupMappings == null || domainGroupMappings.isEmpty()) {
 -                //The dedicated resource belongs to VM Account ID.
 +        List<DedicatedResourceVO> tempStorage;
  
 -                tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
 +        if (domainGroupMappings == null || domainGroupMappings.isEmpty()) {
 +            tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, vmAccountId, null,
 +                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
  
 -                for(DedicatedResourceVO vo : tempStorage) {
 -                    allPodsFromDedicatedID.add(vo.getPodId());
 -                }
 +            for (DedicatedResourceVO vo : tempStorage) {
 +                allPodsFromDedicatedID.add(vo.getPodId());
 +            }
  
 -                tempStorage.clear();
 -                tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
 +            tempStorage.clear();
 +            tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, vmAccountId, null,
 +                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
  
 -                for(DedicatedResourceVO vo : tempStorage) {
 -                    allClustersFromDedicatedID.add(vo.getClusterId());
 -                }
 +            for (DedicatedResourceVO vo : tempStorage) {
 +                allClustersFromDedicatedID.add(vo.getClusterId());
 +            }
  
 -                tempStorage.clear();
 -                tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
 +            tempStorage.clear();
 +            tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, vmAccountId, null,
 +                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
  
 -                for(DedicatedResourceVO vo : tempStorage) {
 -                    allHostsFromDedicatedID.add(vo.getHostId());
 -                }
 -
 -                //Remove the dedicated ones from main list
 -                allPodsInDc.removeAll(allPodsFromDedicatedID);
 -                allClustersInDc.removeAll(allClustersFromDedicatedID);
 -                allHostsInDc.removeAll(allHostsFromDedicatedID);
 +            for (DedicatedResourceVO vo : tempStorage) {
 +                allHostsFromDedicatedID.add(vo.getHostId());
              }
 -            else {
 -                //The dedicated resource belongs to VM Domain ID or No dedication.
  
 -                tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
 +            allPodsInDc.removeAll(allPodsFromDedicatedID);
 +            allClustersInDc.removeAll(allClustersFromDedicatedID);
 +            allHostsInDc.removeAll(allHostsFromDedicatedID);
 +        } else {
 +            tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, null, null,
 +                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
  
 -                for(DedicatedResourceVO vo : tempStorage) {
 -                    allPodsFromDedicatedID.add(vo.getPodId());
 -                }
 +            for (DedicatedResourceVO vo : tempStorage) {
 +                allPodsFromDedicatedID.add(vo.getPodId());
 +            }
  
 -                tempStorage.clear();
 -                tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
 +            tempStorage.clear();
 +            tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, null, null,
 +                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
  
 -                for(DedicatedResourceVO vo : tempStorage) {
 -                    allClustersFromDedicatedID.add(vo.getClusterId());
 -                }
 +            for (DedicatedResourceVO vo : tempStorage) {
 +                allClustersFromDedicatedID.add(vo.getClusterId());
 +            }
  
 -                tempStorage.clear();
 -                tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
 +            tempStorage.clear();
 +            tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, null, null,
 +                    new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
  
 -                for(DedicatedResourceVO vo : tempStorage) {
 -                    allHostsFromDedicatedID.add(vo.getHostId());
 -                }
 -
 -                //Remove the dedicated ones from main list
 -                allPodsInDc.removeAll(allPodsFromDedicatedID);
 -                allClustersInDc.removeAll(allClustersFromDedicatedID);
 -                allHostsInDc.removeAll(allHostsFromDedicatedID);
 +            for (DedicatedResourceVO vo : tempStorage) {
 +                allHostsFromDedicatedID.add(vo.getHostId());
              }
  
 -            //Add in avoid list or no addition if no dedication
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Adding pods to avoid lists: " + allPodsInDc);
 -            }
 -            avoids.addPodList(allPodsInDc);
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Adding clusters to avoid lists: " + allClustersInDc);
 -            }
 -            avoids.addClusterList(allClustersInDc);
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Adding hosts to avoid lists: " + allHostsInDc);
 -            }
 -            avoids.addHostList(allHostsInDc);
 +            allPodsInDc.removeAll(allPodsFromDedicatedID);
 +            allClustersInDc.removeAll(allClustersFromDedicatedID);
 +            allHostsInDc.removeAll(allHostsFromDedicatedID);
          }
 +
 +        logger.debug(() -> LogUtils.logGsonWithoutException("Adding pods [%s], clusters [%s] and hosts [%s] to the avoid list in the deploy process of VR VM [%s], "
 +                        + "because this VM is not dedicated to this components.", allPodsInDc, allClustersInDc, allHostsInDc, vm.getUuid()));
 +        avoids.addPodList(allPodsInDc);
 +        avoids.addClusterList(allClustersInDc);
 +        avoids.addHostList(allHostsInDc);
 +    }
 +
 +    private void findAvoidSetForNonExplicitUserVM(ExcludeList avoids, VirtualMachine vm, List<Long> allPodsInDc, List<Long> allClustersInDc, List<Long> allHostsInDc) {
 +        logger.debug(() -> LogUtils.logGsonWithoutException("Adding pods [%s], clusters [%s] and hosts [%s] to the avoid list in the deploy process of user VM [%s], "
 +                        + "because this VM is not explicitly dedicated to these components.", allPodsInDc, allClustersInDc, allHostsInDc, vm.getUuid()));
 +        avoids.addPodList(allPodsInDc);
 +        avoids.addClusterList(allClustersInDc);
 +        avoids.addHostList(allHostsInDc);
      }
  
      private void resetAvoidSet(ExcludeList avoidSet, ExcludeList removeSet) {
@@@ -999,7 -970,7 +999,7 @@@
                  final PlannerResourceUsage hostResourceTypeFinal = hostResourceType;
                  // reserve the host for required resourceType
                  // let us lock the reservation entry before updating.
--                return Transaction.execute(new TransactionCallback<Boolean>() {
++                return Transaction.execute(new TransactionCallback<>() {
                      @Override
                      public Boolean doInTransaction(TransactionStatus status) {
                          final PlannerHostReservationVO lockedEntry = _plannerHostReserveDao.lockRow(id, true);
@@@ -1091,7 -1062,7 +1091,7 @@@
  
                  final long id = reservationEntry.getId();
  
--                return Transaction.execute(new TransactionCallback<Boolean>() {
++                return Transaction.execute(new TransactionCallback<>() {
                      @Override
                      public Boolean doInTransaction(TransactionStatus status) {
                          final PlannerHostReservationVO lockedEntry = _plannerHostReserveDao.lockRow(id, true);
@@@ -1453,7 -1423,7 +1453,7 @@@
              }
          }
  
--        return new Pair<Boolean, Boolean>(requiresShared, requiresLocal);
++        return new Pair<>(requiresShared, requiresLocal);
      }
  
      protected Pair<Host, Map<Volume, StoragePool>> findPotentialDeploymentResources(List<Host> suitableHosts, Map<Volume, List<StoragePool>> suitableVolumeStoragePools,
@@@ -1465,10 -1435,10 +1465,10 @@@
          boolean hostAffinityCheck = false;
  
          if (readyAndReusedVolumes == null) {
--            readyAndReusedVolumes = new ArrayList<Volume>();
++            readyAndReusedVolumes = new ArrayList<>();
          }
--        Map<Volume, StoragePool> storage = new HashMap<Volume, StoragePool>();
--        TreeSet<Volume> volumesOrderBySizeDesc = new TreeSet<Volume>(new Comparator<Volume>() {
++        Map<Volume, StoragePool> storage = new HashMap<>();
++        TreeSet<Volume> volumesOrderBySizeDesc = new TreeSet<>(new Comparator<>() {
              @Override
              public int compare(Volume v1, Volume v2) {
                  if (v1.getSize() < v2.getSize())
@@@ -1481,7 -1451,7 +1481,7 @@@
          boolean multipleVolume = volumesOrderBySizeDesc.size() > 1;
          boolean deployAsIs = isDeployAsIs(vm);
          for (Host potentialHost : suitableHosts) {
--            Map<StoragePool, List<Volume>> volumeAllocationMap = new HashMap<StoragePool, List<Volume>>();
++            Map<StoragePool, List<Volume>> volumeAllocationMap = new HashMap<>();
              if (deployAsIs) {
                  storage = new HashMap<>();
                  // Find the common suitable pools
@@@ -1553,7 -1523,7 +1553,7 @@@
                                  if (volumeAllocationMap.containsKey(potentialSPool))
                                      requestVolumes = volumeAllocationMap.get(potentialSPool);
                                  else
--                                    requestVolumes = new ArrayList<Volume>();
++                                    requestVolumes = new ArrayList<>();
                                  requestVolumes.add(vol);
                                  List<Pair<Volume, DiskProfile>> volumeDiskProfilePair = getVolumeDiskProfilePairs(requestVolumes);
                                  if (potentialHost.getHypervisorType() == HypervisorType.VMware) {
@@@ -1597,19 -1567,16 +1597,19 @@@
  
              boolean hostHasEncryption = Boolean.parseBoolean(potentialHostVO.getDetail(Host.HOST_VOLUME_ENCRYPTION));
              boolean hostMeetsEncryptionRequirements = !anyVolumeRequiresEncryption(new ArrayList<>(volumesOrderBySizeDesc)) || hostHasEncryption;
 -            boolean plannerUsageFits = checkIfHostFitsPlannerUsage(potentialHost.getId(), resourceUsageRequired);
 +            boolean hostFitsPlannerUsage = checkIfHostFitsPlannerUsage(potentialHost.getId(), resourceUsageRequired);
  
 -            if (hostCanAccessPool && haveEnoughSpace && hostAffinityCheck && hostMeetsEncryptionRequirements && plannerUsageFits) {
 -                s_logger.debug("Found a potential host " + "id: " + potentialHost.getId() + " name: " + potentialHost.getName() +
 +            if (hostCanAccessPool && haveEnoughSpace && hostAffinityCheck && hostMeetsEncryptionRequirements && hostFitsPlannerUsage) {
 +                logger.debug("Found a potential host " + "id: " + potentialHost.getId() + " name: " + potentialHost.getName() +
                          " and associated storage pools for this VM");
                  volumeAllocationMap.clear();
--                return new Pair<Host, Map<Volume, StoragePool>>(potentialHost, storage);
++                return new Pair<>(potentialHost, storage);
              } else {
 +                logger.debug("Adding host [{}] to the avoid set because: can access Pool [{}], has enough space [{}], affinity check [{}], fits planner [{}] usage [{}].",
 +                        potentialHost.getUuid(), hostCanAccessPool, haveEnoughSpace, hostAffinityCheck, resourceUsageRequired.getClass().getSimpleName(), hostFitsPlannerUsage);
 +
                  if (!hostMeetsEncryptionRequirements) {
 -                    s_logger.debug("Potential host " + potentialHost + " did not meet encryption requirements of all volumes");
 +                    logger.debug("Potential host " + potentialHost + " did not meet encryption requirements of all volumes");
                  }
                  avoid.addHost(potentialHost.getId());
              }
@@@ -1655,21 -1622,20 +1655,20 @@@
      }
  
      protected List<Host> findSuitableHosts(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
--        List<Host> suitableHosts = new ArrayList<Host>();
++        List<Host> suitableHosts = new ArrayList<>();
          for (HostAllocator allocator : _hostAllocators) {
              suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, avoid, returnUpTo);
-             if (suitableHosts != null && !suitableHosts.isEmpty()) {
+             if (CollectionUtils.isNotEmpty(suitableHosts)) {
                  break;
              }
          }
  
-         if (suitableHosts.isEmpty()) {
-             logger.debug("No suitable hosts found");
+         if (CollectionUtils.isEmpty(suitableHosts)) {
 -            s_logger.debug("No suitable hosts found.");
++            logger.debug("No suitable hosts found.");
+         } else {
+             reorderHostsByPriority(plan.getHostPriorities(), suitableHosts);
          }
  
-         // re-order hosts by priority
-         reorderHostsByPriority(plan.getHostPriorities(), suitableHosts);
- 
          return suitableHosts;
      }
  
@@@ -1698,8 -1664,8 +1697,8 @@@
      protected Pair<Map<Volume, List<StoragePool>>, List<Volume>> findSuitablePoolsForVolumes(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid,
              int returnUpTo) {
          List<VolumeVO> volumesTobeCreated = _volsDao.findUsableVolumesForInstance(vmProfile.getId());
--        Map<Volume, List<StoragePool>> suitableVolumeStoragePools = new HashMap<Volume, List<StoragePool>>();
--        List<Volume> readyAndReusedVolumes = new ArrayList<Volume>();
++        Map<Volume, List<StoragePool>> suitableVolumeStoragePools = new HashMap<>();
++        List<Volume> readyAndReusedVolumes = new ArrayList<>();
  
          // There should be at least the ROOT volume of the VM in usable state
          if (volumesTobeCreated.isEmpty()) {
@@@ -1784,7 -1812,7 +1783,7 @@@
              }
          }
  
--        HashSet<Long> toRemove = new HashSet<Long>();
++        HashSet<Long> toRemove = new HashSet<>();
          for (List<StoragePool> lsp : suitableVolumeStoragePools.values()) {
              for (StoragePool sp : lsp) {
                  toRemove.add(sp.getId());
@@@ -1797,79 -1825,10 +1796,79 @@@
          }
  
          if (suitableVolumeStoragePools.isEmpty()) {
 -            s_logger.debug("No suitable pools found");
 +            logger.debug("No suitable pools found");
          }
  
--        return new Pair<Map<Volume, List<StoragePool>>, List<Volume>>(suitableVolumeStoragePools, readyAndReusedVolumes);
++        return new Pair<>(suitableVolumeStoragePools, readyAndReusedVolumes);
 +    }
 +
 +    private boolean tryToFindPotentialPoolsToAlocateVolume(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo,
 +            Map<Volume, List<StoragePool>> suitableVolumeStoragePools, VolumeVO toBeCreated, DiskProfile diskProfile) {
 +        for (StoragePoolAllocator allocator : _storagePoolAllocators) {
 +            logger.debug("Trying to find suitable pools to allocate volume [{}] necessary to deploy VM [{}], using StoragePoolAllocator: [{}].",
 +                    toBeCreated.getUuid(), vmProfile.getUuid(), allocator.getClass().getSimpleName());
 +
 +            final List<StoragePool> suitablePools = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid, returnUpTo);
 +            if (suitablePools != null && !suitablePools.isEmpty()) {
 +                logger.debug("StoragePoolAllocator [{}] found {} suitable pools to allocate volume [{}] necessary to deploy VM [{}].",
 +                        allocator.getClass().getSimpleName(), suitablePools.size(), toBeCreated.getUuid(), vmProfile.getUuid());
 +                checkForPreferredStoragePool(suitablePools, vmProfile.getVirtualMachine(), suitableVolumeStoragePools, toBeCreated);
 +                return true;
 +            }
 +        }
 +        return false;
 +    }
 +
 +    private boolean checkIfPoolCanBeReused(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid,
 +            Map<Volume, List<StoragePool>> suitableVolumeStoragePools, List<Volume> readyAndReusedVolumes,
 +            VolumeVO toBeCreated) {
 +        logger.debug("Volume [{}] of VM [{}] has pool [{}] already specified. Checking if this pool can be reused.", toBeCreated.getUuid(), vmProfile.getUuid(), toBeCreated.getPoolId());
-         List<StoragePool> suitablePools = new ArrayList<StoragePool>();
++        List<StoragePool> suitablePools = new ArrayList<>();
 +        StoragePool pool = null;
 +        if (toBeCreated.getPoolId() != null) {
 +            pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(toBeCreated.getPoolId());
 +        } else {
 +            pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(plan.getPoolId());
 +        }
 +
 +        if (!pool.isInMaintenance()) {
 +            if (!avoid.shouldAvoid(pool)) {
 +                return canReusePool(vmProfile, plan, suitableVolumeStoragePools, readyAndReusedVolumes, toBeCreated, suitablePools, pool);
 +            } else {
 +                logger.debug("Pool [{}] of volume [{}] used by VM [{}] is in the avoid set. Need to reallocate a pool for this volume.",
 +                        pool.getUuid(), toBeCreated.getUuid(), vmProfile.getUuid());
 +            }
 +        } else {
 +            logger.debug("Pool [{}] of volume [{}] used by VM [{}] is in maintenance. Need to reallocate a pool for this volume.",
 +                    pool.getUuid(), toBeCreated.getUuid(), vmProfile.getUuid());
 +        }
 +        return false;
 +    }
 +
 +    private boolean canReusePool(VirtualMachineProfile vmProfile, DeploymentPlan plan,
 +            Map<Volume, List<StoragePool>> suitableVolumeStoragePools, List<Volume> readyAndReusedVolumes,
 +            VolumeVO toBeCreated, List<StoragePool> suitablePools, StoragePool pool) {
 +        DataStore dataStore = dataStoreMgr.getPrimaryDataStore(pool.getId());
 +
 +        long exstPoolDcId = pool.getDataCenterId();
 +        long exstPoolPodId = pool.getPodId() != null ? pool.getPodId() : -1;
 +        long exstPoolClusterId = pool.getClusterId() != null ? pool.getClusterId() : -1;
 +
 +        if (plan.getDataCenterId() == exstPoolDcId && ((plan.getPodId() == exstPoolPodId && plan.getClusterId() == exstPoolClusterId) ||
 +                (dataStore != null && dataStore.getScope() != null && dataStore.getScope().getScopeType() == ScopeType.ZONE))) {
 +            logger.debug("Pool [{}] of volume [{}] used by VM [{}] fits the specified plan. No need to reallocate a pool for this volume.",
 +                    pool.getUuid(), toBeCreated.getUuid(), vmProfile.getUuid());
 +            suitablePools.add(pool);
 +            suitableVolumeStoragePools.put(toBeCreated, suitablePools);
 +            if (!(toBeCreated.getState() == Volume.State.Allocated || toBeCreated.getState() == Volume.State.Creating)) {
 +                readyAndReusedVolumes.add(toBeCreated);
 +            }
 +            return true;
 +        }
 +
 +        logger.debug("Pool [{}] of volume [{}] used by VM [{}] does not fit the specified plan. Need to reallocate a pool for this volume.",
 +                pool.getUuid(), toBeCreated.getUuid(), vmProfile.getUuid());
 +        return false;
      }
  
      private void checkForPreferredStoragePool(List<StoragePool> suitablePools,
@@@ -1951,7 -1910,7 +1950,7 @@@
          final VirtualMachine vm = vmProfile.getVirtualMachine();
          final long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
  
--        return Transaction.execute(new TransactionCallback<String>() {
++        return Transaction.execute(new TransactionCallback<>() {
              @Override
              public String doInTransaction(TransactionStatus status) {
                  boolean saveReservation = true;
@@@ -1977,7 -1936,7 +1976,7 @@@
                      if (planner != null) {
                          vmReservation.setDeploymentPlanner(planner.getName());
                      }
--                    Map<Long, Long> volumeReservationMap = new HashMap<Long, Long>();
++                    Map<Long, Long> volumeReservationMap = new HashMap<>();
  
                      if (vm.getHypervisorType() != HypervisorType.BareMetal) {
                          for (Volume vo : plannedDestination.getStorageForDisks().keySet()) {
diff --cc server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
index 22b9a33f65b,b812b5dbf66..46e6c369c33
--- a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
+++ b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
@@@ -138,10 -140,10 +138,10 @@@ public class FirstFitPlanner extends Ad
              return null;
          }
  
--        List<Long> clusterList = new ArrayList<Long>();
++        List<Long> clusterList = new ArrayList<>();
          if (plan.getClusterId() != null) {
              Long clusterIdSpecified = plan.getClusterId();
 -            s_logger.debug("Searching resources only under specified Cluster: " + clusterIdSpecified);
 +            logger.debug("Searching resources only under specified Cluster: " + clusterIdSpecified);
              ClusterVO cluster = clusterDao.findById(plan.getClusterId());
              if (cluster != null) {
                  if (avoid.shouldAvoid(cluster)) {
@@@ -209,7 -211,7 +209,7 @@@
      }
  
      private void reorderClustersBasedOnImplicitTags(List<Long> clusterList, int requiredCpu, long requiredRam) {
--            final HashMap<Long, Long> UniqueTagsInClusterMap = new HashMap<Long, Long>();
++            final HashMap<Long, Long> UniqueTagsInClusterMap = new HashMap<>();
              Long uniqueTags;
              for (Long clusterId : clusterList) {
                  uniqueTags = (long) 0;
@@@ -220,7 -222,7 +220,7 @@@
                  }
                  UniqueTagsInClusterMap.put(clusterId, uniqueTags);
              }
--            Collections.sort(clusterList, new Comparator<Long>() {
++            Collections.sort(clusterList, new Comparator<>() {
                  @Override
                  public int compare(Long o1, Long o2) {
                      Long t1 = UniqueTagsInClusterMap.get(o1);
@@@ -249,7 -251,7 +249,7 @@@
          int requiredCpu = offering.getCpu() * offering.getSpeed();
          long requiredRam = offering.getRamSize() * 1024L * 1024L;
          //list pods under this zone by cpu and ram capacity
--        List<Long> prioritizedPodIds = new ArrayList<Long>();
++        List<Long> prioritizedPodIds;
          Pair<List<Long>, Map<Long, Double>> podCapacityInfo = listPodsByCapacity(plan.getDataCenterId(), requiredCpu, requiredRam);
          List<Long> podsWithCapacity = podCapacityInfo.first();
  
@@@ -277,10 -279,10 +277,10 @@@
                  return null;
              }
  
--            List<Long> clusterList = new ArrayList<Long>();
++            List<Long> clusterList = new ArrayList<>();
              //loop over pods
              for (Long podId : prioritizedPodIds) {
 -                s_logger.debug("Checking resources under Pod: " + podId);
 +                logger.debug("Checking resources under Pod: " + podId);
                  List<Long> clustersUnderPod = scanClustersForDestinationInZoneOrPod(podId, false, vmProfile, plan, avoid);
                  if (clustersUnderPod != null) {
                      clusterList.addAll(clustersUnderPod);
@@@ -298,7 -300,7 +298,7 @@@
      private Map<Short, Float> getCapacityThresholdMap() {
          // Lets build this real time so that the admin won't have to restart MS
          // if anyone changes these values
--        Map<Short, Float> disableThresholdMap = new HashMap<Short, Float>();
++        Map<Short, Float> disableThresholdMap = new HashMap<>();
  
          String cpuDisableThresholdString = ClusterCPUCapacityDisableThreshold.value().toString();
          float cpuDisableThreshold = NumbersUtil.parseFloat(cpuDisableThresholdString, 0.85F);
@@@ -312,7 -314,7 +312,7 @@@
      }
  
      private List<Short> getCapacitiesForCheckingThreshold() {
--        List<Short> capacityList = new ArrayList<Short>();
++        List<Short> capacityList = new ArrayList<>();
          capacityList.add(Capacity.CAPACITY_TYPE_CPU);
          capacityList.add(Capacity.CAPACITY_TYPE_MEMORY);
          return capacityList;
@@@ -339,7 -341,7 +339,7 @@@
          }
  
          List<Short> capacityList = getCapacitiesForCheckingThreshold();
--        List<Long> clustersCrossingThreshold = new ArrayList<Long>();
++        List<Long> clustersCrossingThreshold = new ArrayList<>();
  
          ServiceOffering offering = vmProfile.getServiceOffering();
          int cpu_requested = offering.getCpu() * offering.getSpeed();
@@@ -523,7 -525,7 +523,7 @@@
          matchingClusters.addAll(hostDao.findClustersThatMatchHostTagRule(hostTagOnOffering));
  
          if (matchingClusters.isEmpty()) {
-             logger.error(String.format("No suitable host found for the following compute offering tags [%s].", hostTagOnOffering));
 -            s_logger.error(String.format("No suitable host found in any cluster for the following compute offering tags [%s].", hostTagOnOffering));
++            logger.error("No suitable host found for the following compute offering tags [{}].", hostTagOnOffering);
              throw new CloudRuntimeException("No suitable host found.");
          }
  
diff --cc server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java
index 0a1114b8307,86b4af63668..841f6221182
--- a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java
+++ b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java
@@@ -149,7 -151,7 +149,7 @@@ public class VpcVirtualRouterElement ex
      public boolean implementVpc(final Vpc vpc, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException,
      InsufficientCapacityException {
  
--        final Map<VirtualMachineProfile.Param, Object> params = new HashMap<VirtualMachineProfile.Param, Object>(1);
++        final Map<VirtualMachineProfile.Param, Object> params = new HashMap<>(1);
          params.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true);
  
          if (vpc.isRollingRestart()) {
@@@ -194,7 -196,7 +194,7 @@@
              return false;
          }
  
--        final Map<VirtualMachineProfile.Param, Object> params = new HashMap<VirtualMachineProfile.Param, Object>(1);
++        final Map<VirtualMachineProfile.Param, Object> params = new HashMap<>(1);
          params.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true);
  
          if (network.isRollingRestart()) {
@@@ -221,24 -223,57 +221,58 @@@
          return true;
      }
  
-     protected void configureGuestNetwork(final Network network, final List<DomainRouterVO> routers )
+     protected boolean configureGuestNetworkForRouter(final Network network,
+             final DomainRouterVO router) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
+         if (!_networkMdl.isVmPartOfNetwork(router.getId(), network.getId())) {
 -            final Map<VirtualMachineProfile.Param, Object> paramsForRouter = new HashMap<VirtualMachineProfile.Param, Object>(1);
++            final Map<VirtualMachineProfile.Param, Object> paramsForRouter = new HashMap<>(1);
+             if (network.getState() == State.Setup) {
+                 paramsForRouter.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true);
+             }
+             if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, paramsForRouter)) {
 -                s_logger.error("Failed to add VPC router " + router + " to guest network " + network);
++                logger.error("Failed to add VPC router {} to guest network {}", router, network);
+                 return false;
+             } else {
 -                s_logger.debug("Successfully added VPC router " + router + " to guest network " + network);
++                logger.debug("Successfully added VPC router {} to guest network {}", router, network);
+                 return true;
+             }
+         }
+         return true;
+     }
+ 
+     protected void configureGuestNetwork(final Network network, final List<DomainRouterVO> routers)
              throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
 -        s_logger.info("Adding VPC routers to Guest Network: " + routers.size() + " to be added!");
 +
-         logger.info("Adding VPC routers to Guest Network: " + routers.size() + " to be added!");
++        logger.info("Adding VPC routers to Guest Network: {} to be added!", routers.size());
  
-         for (final DomainRouterVO router : routers) {
+         List<DomainRouterVO> backupRouters = new ArrayList<>();
+         List<DomainRouterVO> remainingRouters = new ArrayList<>();
+         for (DomainRouterVO router : routers) {
              if (!_networkMdl.isVmPartOfNetwork(router.getId(), network.getId())) {
-                 final Map<VirtualMachineProfile.Param, Object> paramsForRouter = new HashMap<VirtualMachineProfile.Param, Object>(1);
-                 if (network.getState() == State.Setup) {
-                     paramsForRouter.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true);
+                 if (router.getRedundantState().equals(DomainRouterVO.RedundantState.BACKUP)) {
+                     backupRouters.add(router);
+                 } else {
+                     remainingRouters.add(router);
                  }
-                 if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, paramsForRouter)) {
-                     logger.error("Failed to add VPC router " + router + " to guest network " + network);
+             }
+         }
+ 
+         for (final DomainRouterVO router : backupRouters) {
+             if (network.getState() != State.Setup) {
+                 if (!_vpcRouterMgr.stopKeepAlivedOnRouter(router, network)) {
 -                    s_logger.error("Failed to stop keepalived on VPC router " + router + " to guest network " + network);
++                    logger.error("Failed to stop keepalived on VPC router {} to guest network {}", router, network);
                  } else {
-                     logger.debug("Successfully added VPC router " + router + " to guest network " + network);
 -                    s_logger.debug("Successfully stopped keepalived on VPC router " + router + " to guest network " + network);
++                    logger.debug("Successfully stopped keepalived on VPC router {} to guest network {}", router, network);
                  }
              }
          }
+         for (final DomainRouterVO router : remainingRouters) {
+             configureGuestNetworkForRouter(network, router);
+         }
+         for (final DomainRouterVO router : backupRouters) {
+             if (!configureGuestNetworkForRouter(network, router) && !_vpcRouterMgr.startKeepAlivedOnRouter(router, network)) {
 -                s_logger.error("Failed to start keepalived on VPC router " + router + " to guest network " + network);
++                logger.error("Failed to start keepalived on VPC router {} to guest network {}", router, network);
+             }
+         }
      }
  
      @Override
@@@ -258,7 -293,7 +292,7 @@@
          }
  
          if (vm.getType() == VirtualMachine.Type.User) {
--            final Map<VirtualMachineProfile.Param, Object> params = new HashMap<VirtualMachineProfile.Param, Object>(1);
++            final Map<VirtualMachineProfile.Param, Object> params = new HashMap<>(1);
              params.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true);
  
              final RouterDeploymentDefinition routerDeploymentDefinition = routerDeploymentDefinitionBuilder.create()
@@@ -385,16 -397,16 +396,16 @@@
      }
  
      private static Map<Service, Map<Capability, String>> setCapabilities() {
--        final Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
++        final Map<Service, Map<Capability, String>> capabilities = new HashMap<>();
          capabilities.putAll(VirtualRouterElement.capabilities);
  
--        final Map<Capability, String> sourceNatCapabilities = new HashMap<Capability, String>();
++        final Map<Capability, String> sourceNatCapabilities = new HashMap<>();
          sourceNatCapabilities.putAll(capabilities.get(Service.SourceNat));
          // TODO This kind of logic is already placed in the DB
          sourceNatCapabilities.put(Capability.RedundantRouter, "true");
          capabilities.put(Service.SourceNat, sourceNatCapabilities);
  
--        final Map<Capability, String> vpnCapabilities = new HashMap<Capability, String>();
++        final Map<Capability, String> vpnCapabilities = new HashMap<>();
          vpnCapabilities.putAll(capabilities.get(Service.Vpn));
          vpnCapabilities.put(Capability.VpnTypes, "s2svpn");
          capabilities.put(Service.Vpn, vpnCapabilities);
@@@ -667,7 -674,7 +678,7 @@@
          final NetworkTopology networkTopology = networkTopologyContext.retrieveNetworkTopology(dcVO);
  
          String[] result = null;
--        final List<String> combinedResults = new ArrayList<String>();
++        final List<String> combinedResults = new ArrayList<>();
          for (final DomainRouterVO domainRouterVO : routers) {
              result = networkTopology.applyVpnUsers(vpn, users, domainRouterVO);
              combinedResults.addAll(Arrays.asList(result));
diff --cc server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
index f45386ca8a7,b6dc9183b49..4156c85f880
--- a/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
@@@ -28,9 -27,10 +28,11 @@@ import java.util.Objects
  import javax.inject.Inject;
  import javax.naming.ConfigurationException;
  
 +import com.cloud.network.dao.NetworkDao;
 +import com.cloud.network.vpc.dao.VpcDao;
+ import org.apache.cloudstack.agent.routing.ManageServiceCommand;
+ import com.cloud.agent.api.routing.NetworkElementCommand;
  import org.apache.commons.collections.CollectionUtils;
 -import org.apache.log4j.Logger;
  import org.springframework.stereotype.Component;
  
  import com.cloud.agent.api.Answer;
@@@ -231,6 -228,53 +233,54 @@@ public class VpcVirtualNetworkAppliance
          return result;
      }
  
+     @Override
+     public boolean stopKeepAlivedOnRouter(VirtualRouter router,
+             Network network) throws ConcurrentOperationException, ResourceUnavailableException {
+         return manageKeepalivedServiceOnRouter(router, network, "stop");
+     }
+ 
+     @Override
+     public boolean startKeepAlivedOnRouter(VirtualRouter router,
+             Network network) throws ConcurrentOperationException, ResourceUnavailableException {
+         return manageKeepalivedServiceOnRouter(router, network, "start");
+     }
+ 
+     private boolean manageKeepalivedServiceOnRouter(VirtualRouter router,
+             Network network, String action) throws ConcurrentOperationException, ResourceUnavailableException {
+         if (network.getTrafficType() != TrafficType.Guest) {
 -            s_logger.warn("Network " + network + " is not of type " + TrafficType.Guest);
++            logger.warn("Network {} is not of type {}", network, TrafficType.Guest);
+             return false;
+         }
+         boolean result = true;
+         try {
+             if (router.getState() == State.Running) {
+                 final ManageServiceCommand stopCommand = new ManageServiceCommand("keepalived", action);
+                 stopCommand.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
+ 
+                 final Commands cmds = new Commands(Command.OnError.Stop);
+                 cmds.addCommand("manageKeepalived", stopCommand);
+                 _nwHelper.sendCommandsToRouter(router, cmds);
+ 
+                 final Answer setupAnswer = cmds.getAnswer("manageKeepalived");
+                 if (!(setupAnswer != null && setupAnswer.getResult())) {
 -                    s_logger.warn("Unable to " + action + " keepalived on router " + router);
++                    logger.warn("Unable to {} keepalived on router {}", action, router);
+                     result = false;
+                 }
+             } else if (router.getState() == State.Stopped || router.getState() == State.Stopping) {
 -                s_logger.debug("Router " + router.getInstanceName() + " is in " + router.getState() + ", so not sending command to the backend");
++                logger.debug("Router {} is in {}, so not sending command to the backend", router.getInstanceName(), router.getState());
+             } else {
+                 String message = "Unable to " + action + " keepalived on virtual router [" + router + "] is not in the right state " + router.getState();
 -                s_logger.warn(message);
++                logger.warn(message);
+                 throw new ResourceUnavailableException(message, DataCenter.class, router.getDataCenterId());
+             }
+         } catch (final Exception ex) {
 -            s_logger.warn("Failed to " + action + "  keepalived on router " + router + " to network " + network + " due to ", ex);
++            logger.warn("Failed to {}  keepalived on router {} to network {} due to {}", action, router, network, ex.getLocalizedMessage());
++            logger.debug("Failed to {}  keepalived on router {} to network {}", action, router, network, ex);
+             result = false;
+         }
+         return result;
+     }
+ 
      protected boolean setupVpcGuestNetwork(final Network network, final VirtualRouter router, final boolean add, final NicProfile guestNic) throws ConcurrentOperationException,
      ResourceUnavailableException {
  
diff --cc server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 15a52d3f750,28140d843ad..81ab2524bd6
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@@ -841,13 -839,13 +841,13 @@@ import com.cloud.vm.dao.UserVmDetailsDa
  import com.cloud.vm.dao.VMInstanceDao;
  
  public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable {
 -    public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName());
      protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
  
 -    static final ConfigKey<Integer> vmPasswordLength = new ConfigKey<Integer>("Advanced", Integer.class, "vm.password.length", "6", "Specifies the length of a randomly generated password", false);
 -    static final ConfigKey<Integer> sshKeyLength = new ConfigKey<Integer>("Advanced", Integer.class, "ssh.key.length", "2048", "Specifies custom SSH key length (bit)", true, ConfigKey.Scope.Global);
 -    static final ConfigKey<Boolean> humanReadableSizes = new ConfigKey<Boolean>("Advanced", Boolean.class, "display.human.readable.sizes", "true", "Enables outputting human readable byte sizes to logs and usage records.", false, ConfigKey.Scope.Global);
 -    public static final ConfigKey<String> customCsIdentifier = new ConfigKey<String>("Advanced", String.class, "custom.cs.identifier", UUID.randomUUID().toString().split("-")[0].substring(4), "Custom identifier for the cloudstack installation", true, ConfigKey.Scope.Global);
 +    static final String FOR_SYSTEMVMS = "forsystemvms";
-     static final ConfigKey<Integer> vmPasswordLength = new ConfigKey<Integer>("Advanced", Integer.class, "vm.password.length", "6", "Specifies the length of a randomly generated password", false);
-     static final ConfigKey<Integer> sshKeyLength = new ConfigKey<Integer>("Advanced", Integer.class, "ssh.key.length", "2048", "Specifies custom SSH key length (bit)", true, ConfigKey.Scope.Global);
-     static final ConfigKey<Boolean> humanReadableSizes = new ConfigKey<Boolean>("Advanced", Boolean.class, "display.human.readable.sizes", "true", "Enables outputting human readable byte sizes to logs and usage records.", false, ConfigKey.Scope.Global);
-     public static final ConfigKey<String> customCsIdentifier = new ConfigKey<String>("Advanced", String.class, "custom.cs.identifier", UUID.randomUUID().toString().split("-")[0].substring(4), "Custom identifier for the cloudstack installation", true, ConfigKey.Scope.Global);
++    static final ConfigKey<Integer> vmPasswordLength = new ConfigKey<>("Advanced", Integer.class, "vm.password.length", "6", "Specifies the length of a randomly generated password", false);
++    static final ConfigKey<Integer> sshKeyLength = new ConfigKey<>("Advanced", Integer.class, "ssh.key.length", "2048", "Specifies custom SSH key length (bit)", true, ConfigKey.Scope.Global);
++    static final ConfigKey<Boolean> humanReadableSizes = new ConfigKey<>("Advanced", Boolean.class, "display.human.readable.sizes", "true", "Enables outputting human readable byte sizes to logs and usage records.", false, ConfigKey.Scope.Global);
++    public static final ConfigKey<String> customCsIdentifier = new ConfigKey<>("Advanced", String.class, "custom.cs.identifier", UUID.randomUUID().toString().split("-")[0].substring(4), "Custom identifier for the cloudstack installation", true, ConfigKey.Scope.Global);
      private static final VirtualMachine.Type []systemVmTypes = { VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.ConsoleProxy};
      private static final List<HypervisorType> LIVE_MIGRATION_SUPPORTING_HYPERVISORS = List.of(HypervisorType.Hyperv, HypervisorType.KVM,
              HypervisorType.LXC, HypervisorType.Ovm, HypervisorType.Ovm3, HypervisorType.Simulator, HypervisorType.VMware, HypervisorType.XenServer);
@@@ -1034,7 -1022,7 +1034,7 @@@
  
      protected List<DeploymentPlanner> _planners;
  
--    private final List<HypervisorType> supportedHypervisors = new ArrayList<HypervisorType>();
++    private final List<HypervisorType> supportedHypervisors = new ArrayList<>();
  
      public List<DeploymentPlanner> getPlanners() {
          return _planners;
@@@ -1112,7 -1106,7 +1112,7 @@@
          }
  
          final String[] availableIds = TimeZone.getAvailableIDs();
--        _availableIdsMap = new HashMap<String, Boolean>(availableIds.length);
++        _availableIdsMap = new HashMap<>(availableIds.length);
          for (final String id : availableIds) {
              _availableIdsMap.put(id, true);
          }
@@@ -1196,7 -1190,7 +1196,7 @@@
          final Account caller = getCaller();
          final List<Long> ids = cmd.getIds();
          boolean result = true;
--        List<Long> permittedAccountIds = new ArrayList<Long>();
++        List<Long> permittedAccountIds = new ArrayList<>();
  
          if (_accountService.isNormalUser(caller.getId()) || caller.getType() == Account.Type.PROJECT) {
              permittedAccountIds.add(caller.getId());
@@@ -1211,8 -1205,8 +1211,7 @@@
          _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, false, sameOwnerEvents);
  
          if (ids != null && events.size() < ids.size()) {
--            result = false;
--            return result;
++            return false;
          }
          _eventDao.archiveEvents(events);
          return result;
@@@ -1223,7 -1217,7 +1222,7 @@@
          final Account caller = getCaller();
          final List<Long> ids = cmd.getIds();
          boolean result = true;
--        List<Long> permittedAccountIds = new ArrayList<Long>();
++        List<Long> permittedAccountIds = new ArrayList<>();
  
          if (_accountMgr.isNormalUser(caller.getId()) || caller.getType() == Account.Type.PROJECT) {
              permittedAccountIds.add(caller.getId());
@@@ -1238,8 -1232,8 +1237,7 @@@
          _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, false, sameOwnerEvents);
  
          if (ids != null && events.size() < ids.size()) {
--            result = false;
--            return result;
++            return false;
          }
          for (final EventVO event : events) {
              _eventDao.remove(event.getId());
@@@ -1322,7 -1316,7 +1320,7 @@@
          }
  
          final Pair<List<ClusterVO>, Integer> result = _clusterDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends Cluster>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      private HypervisorType getHypervisorType(VMInstanceVO vm, StoragePool srcVolumePool) {
@@@ -1362,7 -1356,7 +1360,7 @@@
  
          final Pair<List<HostVO>, Integer> result = searchForServers(cmd.getStartIndex(), cmd.getPageSizeVal(), name, type, state, zoneId, pod,
              cluster, id, keyword, resourceState, haHosts, null, null);
--        return new Pair<List<? extends Host>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      protected Pair<Boolean, List<HostVO>> filterUefiHostsForMigration(List<HostVO> allHosts, List<HostVO> filteredHosts, VirtualMachine vm) {
@@@ -1601,15 -1595,12 +1599,12 @@@
              }
          }
  
-         // re-order hosts by priority
          _dpMgr.reorderHostsByPriority(plan.getHostPriorities(), suitableHosts);
  
-         if (logger.isDebugEnabled()) {
-             if (suitableHosts.isEmpty()) {
-                 logger.debug("No suitable hosts found");
-             } else {
-                 logger.debug("Hosts having capacity and suitable for migration: " + suitableHosts);
-             }
+         if (suitableHosts.isEmpty()) {
 -            s_logger.warn("No suitable hosts found.");
++            logger.warn("No suitable hosts found.");
+         } else {
 -            s_logger.debug("Hosts having capacity and suitable for migration: " + suitableHosts);
++            logger.debug("Hosts having capacity and suitable for migration: {}", suitableHosts);
          }
  
          return new Ternary<>(otherHosts, suitableHosts, requiresStorageMotion);
@@@ -1660,9 -1651,9 +1655,9 @@@
              StoragePool datastoreCluster = _poolDao.findById(srcVolumePool.getParent());
              avoidPools.add(datastoreCluster);
          }
--        abstractDataStoreClustersList((List<StoragePool>) allPools, new ArrayList<StoragePool>());
++        abstractDataStoreClustersList((List<StoragePool>) allPools, new ArrayList<>());
          abstractDataStoreClustersList((List<StoragePool>) suitablePools, avoidPools);
--        return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
++        return new Pair<>(allPools, suitablePools);
      }
  
      @Override
@@@ -1694,13 -1685,13 +1689,13 @@@
          }
  
          // Volume must be attached to an instance for live migration.
--        List<? extends StoragePool> allPools = new ArrayList<StoragePool>();
--        List<? extends StoragePool> suitablePools = new ArrayList<StoragePool>();
++        List<? extends StoragePool> allPools = new ArrayList<>();
++        List<? extends StoragePool> suitablePools = new ArrayList<>();
  
          // Volume must be in Ready state to be migrated.
          if (!Volume.State.Ready.equals(volume.getState())) {
 -            s_logger.info("Volume " + volume + " must be in ready state for migration.");
 -            return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
 +            logger.info("Volume " + volume + " must be in ready state for migration.");
-             return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
++            return new Pair<>(allPools, suitablePools);
          }
  
          final Long instanceId = volume.getInstanceId();
@@@ -1735,8 -1726,8 +1730,8 @@@
              }
  
              if (!storageMotionSupported) {
 -                s_logger.info("Volume " + volume + " is attached to a running vm and the hypervisor doesn't support" + " storage motion.");
 -                return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
 +                logger.info("Volume " + volume + " is attached to a running vm and the hypervisor doesn't support" + " storage motion.");
-                 return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
++                return new Pair<>(allPools, suitablePools);
              }
          }
  
@@@ -1759,7 -1750,7 +1754,7 @@@
          }
          removeDataStoreClusterParents((List<StoragePool>) allPools);
          removeDataStoreClusterParents((List<StoragePool>) suitablePools);
--        return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
++        return new Pair<>(allPools, suitablePools);
      }
  
      private void removeDataStoreClusterParents(List<StoragePool> storagePools) {
@@@ -2034,7 -2025,7 +2029,7 @@@
          }
  
          final Pair<List<HostPodVO>, Integer> result = _hostPodDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends Pod>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -2172,7 -2163,7 +2167,7 @@@
          }
  
          final Pair<List<VlanVO>, Integer> result = _vlanDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends Vlan>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -2305,7 -2296,7 +2300,7 @@@
  
          if (scope != null && !scope.isEmpty()) {
              // Populate values corresponding the resource id
--            final List<ConfigurationVO> configVOList = new ArrayList<ConfigurationVO>();
++            final List<ConfigurationVO> configVOList = new ArrayList<>();
              for (final ConfigurationVO param : result.first()) {
                  final ConfigurationVO configVo = _configDao.findByName(param.getName());
                  if (configVo != null) {
@@@ -2327,10 -2318,10 +2322,10 @@@
                  }
              }
  
--            return new Pair<List<? extends Configuration>, Integer>(configVOList, configVOList.size());
++            return new Pair<>(configVOList, configVOList.size());
          }
  
--        return new Pair<List<? extends Configuration>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -2344,7 -2335,7 +2339,7 @@@
          }
  
          final Pair<List<ConfigurationGroupVO>, Integer> result = _configGroupDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends ConfigurationGroup>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -2556,7 -2547,7 +2551,7 @@@
          Collections.sort(addrs, Comparator.comparing(IPAddressVO::getAddress));
          List<? extends IpAddress> wPagination = com.cloud.utils.StringUtils.applyPagination(addrs, cmd.getStartIndex(), cmd.getPageSizeVal());
          if (wPagination != null) {
--            return new Pair<List<? extends IpAddress>, Integer>(wPagination, addrs.size());
++            return new Pair<>(wPagination, addrs.size());
          }
          return new Pair<>(addrs, addrs.size());
      }
@@@ -2728,7 -2716,7 +2723,7 @@@
          }
  
          final Pair<List<GuestOSCategoryVO>, Integer> result = _guestOSCategoryDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends GuestOsCategory>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -2781,7 -2769,7 +2776,7 @@@
          }
  
          final Pair<List<GuestOSHypervisorVO>, Integer> result = _guestOSHypervisorDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends GuestOSHypervisor>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -3146,12 -3134,12 +3141,12 @@@
      @Override
      public Pair<String, Integer> getVncPort(final VirtualMachine vm) {
          if (vm.getHostId() == null) {
 -            s_logger.warn("VM " + vm.getHostName() + " does not have host, return -1 for its VNC port");
 -            return new Pair<String, Integer>(null, -1);
 +            logger.warn("VM " + vm.getHostName() + " does not have host, return -1 for its VNC port");
-             return new Pair<String, Integer>(null, -1);
++            return new Pair<>(null, -1);
          }
  
 -        if (s_logger.isTraceEnabled()) {
 -            s_logger.trace("Trying to retrieve VNC port from agent about VM " + vm.getHostName());
 +        if (logger.isTraceEnabled()) {
 +            logger.trace("Trying to retrieve VNC port from agent about VM " + vm.getHostName());
          }
  
          GetVncPortAnswer answer = null;
@@@ -3161,10 -3149,10 +3156,10 @@@
              answer = (GetVncPortAnswer)_agentMgr.easySend(vm.getHostId(), new GetVncPortCommand(vm.getId(), vm.getInstanceName()));
          }
          if (answer != null && answer.getResult()) {
--            return new Pair<String, Integer>(answer.getAddress(), answer.getPort());
++            return new Pair<>(answer.getAddress(), answer.getPort());
          }
  
--        return new Pair<String, Integer>(null, -1);
++        return new Pair<>(null, -1);
      }
  
      @Override
@@@ -3202,92 -3190,21 +3197,90 @@@
  
          sc.addAnd("archived", SearchCriteria.Op.EQ, false);
          final Pair<List<AlertVO>, Integer> result = _alertDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends Alert>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
      public boolean archiveAlerts(final ArchiveAlertsCmd cmd) {
          final Long zoneId = _accountMgr.checkAccessAndSpecifyAuthority(CallContext.current().getCallingAccount(), null);
--        final boolean result = _alertDao.archiveAlert(cmd.getIds(), cmd.getType(), cmd.getStartDate(), cmd.getEndDate(), zoneId);
--        return result;
++        return _alertDao.archiveAlert(cmd.getIds(), cmd.getType(), cmd.getStartDate(), cmd.getEndDate(), zoneId);
      }
  
      @Override
      public boolean deleteAlerts(final DeleteAlertsCmd cmd) {
          final Long zoneId = _accountMgr.checkAccessAndSpecifyAuthority(CallContext.current().getCallingAccount(), null);
--        final boolean result = _alertDao.deleteAlert(cmd.getIds(), cmd.getType(), cmd.getStartDate(), cmd.getEndDate(), zoneId);
--        return result;
++        return _alertDao.deleteAlert(cmd.getIds(), cmd.getType(), cmd.getStartDate(), cmd.getEndDate(), zoneId);
 +    }
 +
 +    Pair<Boolean, List<Long>> getHostIdsForCapacityListing(Long zoneId, Long podId, Long clusterId, Integer capacityType, String tag) {
 +        if (StringUtils.isEmpty(tag)) {
 +            return new Pair<>(true, null);
 +        }
 +        Short type = capacityType == null ? null : capacityType.shortValue();
 +        if (type != null && Capacity.STORAGE_CAPACITY_TYPES.contains(type)) {
 +            return new Pair<>(false, null);
 +        }
 +        List<Long> hostIds = null;
 +        try {
 +            List<HostVO> hosts = _hostDao.listByHostTag(Type.Routing, clusterId, podId, zoneId, tag);
 +            hostIds = hosts.stream().map(HostVO::getId).collect(Collectors.toList());
 +        } catch (CloudRuntimeException ignored) {}
 +        return new Pair<>(CollectionUtils.isNotEmpty(hostIds), hostIds);
 +    }
 +
 +    protected List<String> getResourceLimitTagsForCapacityListing() {
 +        List<String> tags = new ArrayList<>();
 +        tags.add(null);
 +        tags.addAll(resourceLimitService.getResourceLimitHostTags());
 +        tags.addAll(resourceLimitService.getResourceLimitStorageTags());
 +        tags = tags.stream().distinct().collect(Collectors.toList());
 +        return tags;
 +    }
 +
 +    protected Pair<Boolean, List<Long>> getStoragePoolIdsForCapacityListing(Integer capacityType, String tag) {
 +        if (StringUtils.isEmpty(tag)) {
 +            return new Pair<>(true, null);
 +        }
 +        Short type = capacityType == null ? null : capacityType.shortValue();
 +        if (type != null && !Capacity.STORAGE_CAPACITY_TYPES.contains(type)) {
 +            return new Pair<>(false, null);
 +        }
 +        List<Long> storagePoolIds = storagePoolTagsDao.listPoolIdsByTag(tag);
 +        return new Pair<>(CollectionUtils.isNotEmpty(storagePoolIds), storagePoolIds);
 +    }
 +
 +    protected List<SummedCapacity> getCapacitiesWithDetails(final Long zoneId, final Long podId, Long clusterId,
 +            final Integer capacityType, final String tag, int level, Long pageSize) {
 +        List<String> tags = new ArrayList<>();
 +        if (StringUtils.isNotEmpty(tag)) {
 +            tags.add(tag);
 +        } else {
 +            tags = getResourceLimitTagsForCapacityListing();
 +        }
 +        List<SummedCapacity> summedCapacities = new ArrayList<>();
 +        for (String t : tags) {
 +            List<SummedCapacity> taggedSummedCapacities = new ArrayList<>();
 +            Pair<Boolean, List<Long>> hostIdsForCapacity = getHostIdsForCapacityListing(zoneId, podId, clusterId, capacityType, t);
 +            Pair<Boolean, List<Long>> storagePoolIdsForCapacity = getStoragePoolIdsForCapacityListing(capacityType, t);
 +            if (hostIdsForCapacity.first() || storagePoolIdsForCapacity.first()) {
 +                final List<SummedCapacity> summedHostCapacities = _capacityDao.listCapacitiesGroupedByLevelAndType(
 +                        capacityType, zoneId, podId, clusterId, level, hostIdsForCapacity.second(),
 +                        storagePoolIdsForCapacity.second(), pageSize);
 +                if (summedHostCapacities != null) {
 +                    taggedSummedCapacities.addAll(summedHostCapacities);
 +                }
 +            }
 +            if (storagePoolIdsForCapacity.first()) {
 +                List<SummedCapacity> summedStorageCapacities = getStorageCapacities(clusterId, podId, zoneId,
 +                        storagePoolIdsForCapacity.second(), capacityType == null ? null : capacityType.shortValue());
 +                if (summedStorageCapacities != null) {
 +                    taggedSummedCapacities.addAll(summedStorageCapacities);
 +                }
 +            }
 +            taggedSummedCapacities.forEach(x -> x.setTag(t));
 +            summedCapacities.addAll(taggedSummedCapacities);
 +        }
 +        return summedCapacities;
      }
  
      @Override
@@@ -3482,7 -3390,7 +3475,7 @@@
  
      @Override
      public List<Class<?>> getCommands() {
--        final List<Class<?>> cmdList = new ArrayList<Class<?>>();
++        final List<Class<?>> cmdList = new ArrayList<>();
          cmdList.add(CreateAccountCmd.class);
          cmdList.add(DeleteAccountCmd.class);
          cmdList.add(DisableAccountCmd.class);
@@@ -4251,7 -4158,7 +4244,7 @@@
          }
  
          final Pair<List<VMInstanceVO>, Integer> result = _vmInstanceDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends VirtualMachine>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -4414,10 -4321,10 +4407,10 @@@
              final String input = cloudIdentifier;
              signature = signRequest(input, secretKey);
          } catch (final Exception e) {
 -            s_logger.warn("Exception whilst creating a signature:" + e);
 +            logger.warn("Exception whilst creating a signature:" + e);
          }
  
--        final ArrayList<String> cloudParams = new ArrayList<String>();
++        final ArrayList<String> cloudParams = new ArrayList<>();
          cloudParams.add(cloudIdentifier);
          cloudParams.add(signature);
  
@@@ -4426,7 -4333,7 +4419,7 @@@
  
      @Override
      public Map<String, Object> listCapabilities(final ListCapabilitiesCmd cmd) {
--        final Map<String, Object> capabilities = new HashMap<String, Object>();
++        final Map<String, Object> capabilities = new HashMap<>();
  
          final Account caller = getCaller();
          boolean securityGroupsEnabled = false;
@@@ -4598,7 -4505,7 +4591,7 @@@
  
      @Override
      public List<String> getHypervisors(final Long zoneId) {
--        final List<String> result = new ArrayList<String>();
++        final List<String> result = new ArrayList<>();
          final String hypers = _configDao.getValue(Config.HypervisorList.key());
          final String[] hypervisors = hypers.split(",");
  
@@@ -4810,9 -4717,9 +4803,9 @@@
          final String keyword = cmd.getKeyword();
  
          final Account caller = getCaller();
--        final List<Long> permittedAccounts = new ArrayList<Long>();
++        final List<Long> permittedAccounts = new ArrayList<>();
  
--        final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
++        final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
          _accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
          final Long domainId = domainIdRecursiveListProject.first();
          final Boolean isRecursive = domainIdRecursiveListProject.second();
@@@ -5155,7 -5062,7 +5148,7 @@@
          }
  
          final Pair<List<HypervisorCapabilitiesVO>, Integer> result = _hypervisorCapabilitiesDao.searchAndCount(sc, searchFilter);
--        return new Pair<List<? extends HypervisorCapabilities>, Integer>(result.first(), result.second());
++        return new Pair<>(result.first(), result.second());
      }
  
      @Override
@@@ -5302,7 -5209,7 +5295,7 @@@
  
      @Override
      public List<String> listDeploymentPlanners() {
--        final List<String> plannersAvailable = new ArrayList<String>();
++        final List<String> plannersAvailable = new ArrayList<>();
          for (final DeploymentPlanner planner : _planners) {
              plannersAvailable.add(planner.getName());
          }
diff --cc server/src/main/java/com/cloud/server/StatsCollector.java
index 2c8b79500ba,5aa6dd0a214..86b8b0c682c
--- a/server/src/main/java/com/cloud/server/StatsCollector.java
+++ b/server/src/main/java/com/cloud/server/StatsCollector.java
@@@ -1687,10 -1689,10 +1687,10 @@@ public class StatsCollector extends Man
                      Answer answer = ssAhost.sendMessage(command);
                      if (answer != null && answer.getResult()) {
                          storageStats.put(storeId, (StorageStats)answer);
 -                        LOGGER.trace("HostId: " + storeId + " Used: " + toHumanReadableSize(((StorageStats)answer).getByteUsed()) + " Total Available: " + toHumanReadableSize(((StorageStats)answer).getCapacityBytes()));
 +                        logger.trace("HostId: " + storeId + " Used: " + toHumanReadableSize(((StorageStats)answer).getByteUsed()) + " Total Available: " + toHumanReadableSize(((StorageStats)answer).getCapacityBytes()));
                      }
                  }
-                 _storageStats = storageStats;
+                 updateStorageStats(storageStats);
                  ConcurrentHashMap<Long, StorageStats> storagePoolStats = new ConcurrentHashMap<Long, StorageStats>();
  
                  List<StoragePoolVO> storagePools = _storagePoolDao.listAll();
@@@ -1737,9 -1739,22 +1737,22 @@@
                  }
                  _storagePoolStats = storagePoolStats;
              } catch (Throwable t) {
 -                LOGGER.error("Error trying to retrieve storage stats", t);
 +                logger.error("Error trying to retrieve storage stats", t);
              }
          }
+ 
+         private void updateStorageStats(ConcurrentHashMap<Long, StorageStats> storageStats) {
+             for (Long storeId : storageStats.keySet()) {
+                 if (_storageStats.containsKey(storeId)
+                         && (_storageStats.get(storeId).getCapacityBytes() == 0l
+                         || _storageStats.get(storeId).getCapacityBytes() != storageStats.get(storeId).getCapacityBytes())) {
+                         // get add to DB rigorously
+                         _storageManager.updateImageStoreStatus(storeId, null, null, storageStats.get(storeId).getCapacityBytes());
+                 }
+             }
+             // if in _storageStats and not in storageStats it gets discarded
+             _storageStats = storageStats;
+         }
      }
  
      class AutoScaleMonitor extends ManagedContextRunnable {
diff --cc server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index f3f0c5dc7e4,02edd02fa94..a25dadacf44
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@@ -138,7 -139,7 +139,6 @@@ import org.apache.commons.collections.C
  import org.apache.commons.collections.MapUtils;
  import org.apache.commons.lang.time.DateUtils;
  import org.apache.commons.lang3.EnumUtils;
- import org.apache.commons.lang3.StringUtils;
 -import org.apache.log4j.Logger;
  import org.springframework.stereotype.Component;
  
  import com.cloud.agent.AgentManager;
@@@ -407,7 -410,7 +408,7 @@@ public class StorageManagerImpl extend
      int _downloadUrlExpirationInterval;
      private long _serverId;
  
--    private final Map<String, HypervisorHostListener> hostListeners = new HashMap<String, HypervisorHostListener>();
++    private final Map<String, HypervisorHostListener> hostListeners = new HashMap<>();
  
      public boolean share(VMInstanceVO vm, List<VolumeVO> vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException {
  
@@@ -465,7 -470,7 +466,7 @@@
      @Override
      public List<StoragePoolVO> ListByDataCenterHypervisor(long datacenterId, HypervisorType type) {
          List<StoragePoolVO> pools = _storagePoolDao.listByDataCenterId(datacenterId);
--        List<StoragePoolVO> retPools = new ArrayList<StoragePoolVO>();
++        List<StoragePoolVO> retPools = new ArrayList<>();
          for (StoragePoolVO pool : pools) {
              if (pool.getStatus() != StoragePoolStatus.Up) {
                  continue;
@@@ -571,7 -576,7 +572,7 @@@
          DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
          DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
          PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver) storeDriver;
--        HashMap<String, VolumeStatsEntry> statEntry = new HashMap<String, VolumeStatsEntry>();
++        HashMap<String, VolumeStatsEntry> statEntry = new HashMap<>();
          GetVolumeStatsCommand getVolumeStatsCommand = (GetVolumeStatsCommand) cmd;
          for (String volumeUuid : getVolumeStatsCommand.getVolumeUuids()) {
              Pair<Long, Long> volumeStats = primaryStoreDriver.getVolumeStats(pool, volumeUuid);
@@@ -793,7 -798,7 +794,7 @@@
              DataStoreProvider provider = _dataStoreProviderMgr.getDefaultPrimaryDataStoreProvider();
              DataStoreLifeCycle lifeCycle = provider.getDataStoreLifeCycle();
              if (pool == null) {
--                Map<String, Object> params = new HashMap<String, Object>();
++                Map<String, Object> params = new HashMap<>();
                  String name = pInfo.getName() != null ? pInfo.getName() : createLocalStoragePoolName(host, pInfo);
                  params.put("zoneId", host.getDataCenterId());
                  params.put("clusterId", host.getClusterId());
@@@ -909,7 -914,7 +910,7 @@@
              throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId);
          }
  
--        Map<String, Object> params = new HashMap<String, Object>();
++        Map<String, Object> params = new HashMap<>();
          params.put("zoneId", zone.getId());
          params.put("clusterId", clusterId);
          params.put("podId", podId);
@@@ -1031,7 -1036,7 +1032,7 @@@
      }
  
      private Map<String, String> extractApiParamAsMap(Map ds) {
--        Map<String, String> details = new HashMap<String, String>();
++        Map<String, String> details = new HashMap<>();
          if (ds != null) {
              Collection detailsCollection = ds.values();
              Iterator it = detailsCollection.iterator();
@@@ -1442,17 -1447,17 +1443,17 @@@
          }
          for (Long hostId : hostIds) {
              try {
--                List<Answer> answers = new ArrayList<Answer>();
++                List<Answer> answers = new ArrayList<>();
                  Command[] cmdArray = cmds.toCommands();
                  for (Command cmd : cmdArray) {
                      long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(hostId, cmd);
                      answers.add(_agentMgr.send(targetHostId, cmd));
                  }
--                return new Pair<Long, Answer[]>(hostId, answers.toArray(new Answer[answers.size()]));
++                return new Pair<>(hostId, answers.toArray(new Answer[answers.size()]));
              } catch (AgentUnavailableException e) {
 -                s_logger.debug("Unable to send storage pool command to " + pool + " via " + hostId, e);
 +                logger.debug("Unable to send storage pool command to " + pool + " via " + hostId, e);
              } catch (OperationTimedoutException e) {
 -                s_logger.debug("Unable to send storage pool command to " + pool + " via " + hostId, e);
 +                logger.debug("Unable to send storage pool command to " + pool + " via " + hostId, e);
              }
          }
  
@@@ -1463,7 -1468,7 +1464,7 @@@
      public Pair<Long, Answer> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Command cmd) throws StorageUnavailableException {
          Commands cmds = new Commands(cmd);
          Pair<Long, Answer[]> result = sendToPool(pool, hostIdsToTryFirst, hostIdsToAvoid, cmds);
--        return new Pair<Long, Answer>(result.first(), result.second()[0]);
++        return new Pair<>(result.first(), result.second()[0]);
      }
  
      private void cleanupInactiveTemplates() {
@@@ -1785,7 -1789,7 +1786,7 @@@
      @DB
      List<Long> findAllVolumeIdInSnapshotTable(Long storeId) {
          String sql = "SELECT volume_id from snapshots, snapshot_store_ref WHERE snapshots.id = snapshot_store_ref.snapshot_id and store_id=? GROUP BY volume_id";
--        List<Long> list = new ArrayList<Long>();
++        List<Long> list = new ArrayList<>();
          try {
              TransactionLegacy txn = TransactionLegacy.currentTxn();
              ResultSet rs = null;
@@@ -1813,7 -1817,7 +1814,7 @@@
              pstmt = txn.prepareAutoCloseStatement(sql);
              pstmt.setLong(1, volumeId);
              rs = pstmt.executeQuery();
--            List<String> list = new ArrayList<String>();
++            List<String> list = new ArrayList<>();
              while (rs.next()) {
                  list.add(rs.getString(1));
              }
@@@ -2062,7 -2066,7 +2063,7 @@@
              }
  
              if (!answer.getResult()) {
--                throw new CloudRuntimeException(String.format("Unable to process ModifyStoragePoolCommand for pool %s on the host %s due to ", pool.getUuid(), hostId, answer.getDetails()));
++                throw new CloudRuntimeException(String.format("Unable to process ModifyStoragePoolCommand for pool %s on the host %s due to %s", pool.getUuid(), hostId, answer.getDetails()));
              }
  
              assert (answer instanceof ModifyStoragePoolAnswer) : "Well, now why won't you actually return the ModifyStoragePoolAnswer when it's ModifyStoragePoolCommand? Pool=" +
@@@ -2297,7 -2301,7 +2298,7 @@@
                  // Prepare for the syncvolumepath command
                  DataTO volTO = volFactory.getVolume(volume.getId()).getTO();
                  DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType());
--                Map<String, String> details = new HashMap<String, String>();
++                Map<String, String> details = new HashMap<>();
                  details.put(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
                  disk.setDetails(details);
  
@@@ -2416,7 -2420,7 +2417,7 @@@
              sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId);
          }
  
--        List<Long> hosts = new ArrayList<Long>();
++        List<Long> hosts = new ArrayList<>();
          if (hostId != null) {
              hosts.add(hostId);
          } else {
@@@ -2571,11 -2565,11 +2572,7 @@@
          DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
          DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
  
--        if (storeDriver instanceof PrimaryDataStoreDriver && ((PrimaryDataStoreDriver)storeDriver).canHostAccessStoragePool(host, pool)) {
--            return true;
--        }
--
--        return false;
++        return (storeDriver instanceof PrimaryDataStoreDriver && ((PrimaryDataStoreDriver)storeDriver).canHostAccessStoragePool(host, pool));
      }
  
      @Override
@@@ -2894,7 -2826,7 +2891,7 @@@
          if (CollectionUtils.isEmpty(volumes)) {
              return false;
          }
--        List<Pair<Volume, Answer>> answers = new ArrayList<Pair<Volume, Answer>>();
++        List<Pair<Volume, Answer>> answers = new ArrayList<>();
  
          for (Pair<Volume, DiskProfile> volumeDiskProfilePair : volumes) {
              Volume volume = volumeDiskProfilePair.first();
@@@ -3232,7 -3190,7 +3229,7 @@@
                      // Check if it's the only/first store in the zone
                      if (stores.size() == 0) {
                          List<HypervisorType> hypervisorTypes = _clusterDao.getAvailableHypervisorInZone(zoneId);
--                        Set<HypervisorType> hypSet = new HashSet<HypervisorType>(hypervisorTypes);
++                        Set<HypervisorType> hypSet = new HashSet<>(hypervisorTypes);
                          TransactionLegacy txn = TransactionLegacy.open("AutomaticTemplateRegister");
                          SystemVmTemplateRegistration systemVmTemplateRegistration = new SystemVmTemplateRegistration();
                          String filePath = null;
@@@ -3292,7 -3250,7 +3289,7 @@@
      public ImageStore migrateToObjectStore(String name, String url, String providerName, Map<String, String> details) throws DiscoveryException, InvalidParameterValueException {
          // check if current cloud is ready to migrate, we only support cloud with only NFS secondary storages
          List<ImageStoreVO> imgStores = _imageStoreDao.listImageStores();
--        List<ImageStoreVO> nfsStores = new ArrayList<ImageStoreVO>();
++        List<ImageStoreVO> nfsStores = new ArrayList<>();
          if (imgStores != null && imgStores.size() > 0) {
              for (ImageStoreVO store : imgStores) {
                  if (!store.getProviderName().equals(DataStoreProvider.NFS_IMAGE)) {
@@@ -3380,7 -3356,7 +3395,7 @@@
          }
  
          // find the host
--        List<Long> poolIds = new ArrayList<Long>();
++        List<Long> poolIds = new ArrayList<>();
          poolIds.add(pool.getId());
          List<Long> hosts = _storagePoolHostDao.findHostsConnectedToPools(poolIds);
          if (hosts.size() > 0) {
@@@ -3417,7 -3393,7 +3432,7 @@@
          VMTemplateZoneVO tmpltZone;
  
          List<VMTemplateVO> allTemplates = _vmTemplateDao.listAll();
--        List<Long> dcIds = new ArrayList<Long>();
++        List<Long> dcIds = new ArrayList<>();
          if (zoneId != null) {
              dcIds.add(zoneId);
          } else {
@@@ -3534,7 -3510,7 +3549,7 @@@
              throw ex;
          }
  
--        Map<String, Object> params = new HashMap<String, Object>();
++        Map<String, Object> params = new HashMap<>();
          params.put("zoneId", dcId);
          params.put("url", cmd.getUrl());
          params.put("name", cmd.getUrl());
@@@ -3622,8 -3598,8 +3637,8 @@@
  
          // Cleanup expired volume URLs
          List<VolumeDataStoreVO> volumesOnImageStoreList = _volumeStoreDao.listVolumeDownloadUrls();
--        HashSet<Long> expiredVolumeIds = new HashSet<Long>();
--        HashSet<Long> activeVolumeIds = new HashSet<Long>();
++        HashSet<Long> expiredVolumeIds = new HashSet<>();
++        HashSet<Long> activeVolumeIds = new HashSet<>();
          for (VolumeDataStoreVO volumeOnImageStore : volumesOnImageStoreList) {
  
              long volumeId = volumeOnImageStore.getVolumeId();
diff --cc services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/IpTablesHelper.java
index 00000000000,b9f0d2fdc77..a130f11a82a
mode 000000,100644..100644
--- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/IpTablesHelper.java
+++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/IpTablesHelper.java
@@@ -1,0 -1,66 +1,67 @@@
+ //
+ // 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 org.apache.cloudstack.storage.resource;
+ 
+ import com.cloud.utils.script.Script;
 -import org.apache.log4j.Logger;
++import org.apache.logging.log4j.Logger;
++import org.apache.logging.log4j.LogManager;
+ 
+ public class IpTablesHelper {
 -    public static final Logger LOGGER = Logger.getLogger(IpTablesHelper.class);
++    public static final Logger LOGGER = LogManager.getLogger(IpTablesHelper.class);
+ 
+     public static final String OUTPUT_CHAIN = "OUTPUT";
+     public static final String INPUT_CHAIN = "INPUT";
+     public static final String INSERT = " -I ";
+     public static final String APPEND = " -A ";
+ 
+     public static boolean needsAdding(String chain, String rule) {
+         Script command = new Script("/bin/bash", LOGGER);
+         command.add("-c");
+         command.add("iptables -C " + chain + " " + rule);
+ 
+         String commandOutput = command.execute();
+         boolean needsAdding = (commandOutput != null && commandOutput.contains("iptables: Bad rule (does a matching rule exist in that chain?)."));
+         LOGGER.debug(String.format("Rule [%s], %s need adding to [%s] : %s",
+                 rule,
+                 needsAdding ? "does indeed" : "doesn't",
+                 chain,
+                 commandOutput
+         ));
+         return needsAdding;
+     }
+ 
+     public static String addConditionally(String chain, boolean insert, String rule, String errMsg) {
+         LOGGER.info(String.format("Adding rule [%s] to [%s] if required.", rule, chain));
+         if (needsAdding(chain, rule)) {
+             Script command = new Script("/bin/bash", LOGGER);
+             command.add("-c");
+             command.add("iptables" + (insert ? INSERT : APPEND) + chain + " " + rule);
+             String result = command.execute();
+             LOGGER.debug(String.format("Executed [%s] with result [%s]", command, result));
+             if (result != null) {
+                 LOGGER.warn(String.format("%s , err = %s", errMsg, result));
+                 return errMsg + result;
+             }
+         } else {
+             LOGGER.warn("Rule already defined in SVM: " + rule);
+         }
+         return null;
+     }
+ }
diff --cc services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
index 6f2d4d23cf1,41cf11025a1..26b9e3ea65e
--- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
+++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
@@@ -247,11 -246,11 +247,11 @@@ public class NfsSecondaryStorageResourc
      private String _storageNetmask;
      private String _storageGateway;
      private String _nfsVersion;
--    private final List<String> nfsIps = new ArrayList<String>();
++    private final List<String> nfsIps = new ArrayList<>();
      protected String _parent = "/mnt/SecStorage";
      final private String _tmpltpp = "template.properties";
      protected String createTemplateFromSnapshotXenScript;
--    private HashMap<String, UploadEntity> uploadEntityStateMap = new HashMap<String, UploadEntity>();
++    private HashMap<String, UploadEntity> uploadEntityStateMap = new HashMap<>();
      private String _ssvmPSK = null;
      private long processTimeout;
  
@@@ -2330,15 -2329,14 +2330,14 @@@
          if (!_inSystemVM) {
              return null;
          }
-         Script command = new Script("/bin/bash", logger);
          String intf = "eth1";
-         command.add("-c");
-         command.add("iptables -I OUTPUT -o " + intf + " -d " + destCidr + " -p tcp -m state --state NEW -m tcp  -j ACCEPT");
+         String rule =  String.format("-o %s -d %s -p tcp -m state --state NEW -m tcp -j ACCEPT", intf, destCidr);
+         String errMsg = String.format("Error in allowing outgoing to %s", destCidr);
  
-         String result = command.execute();
 -        s_logger.info(String.format("Adding rule if required: " + rule));
++        logger.info("Adding rule if required: {}", rule);
+         String result = IpTablesHelper.addConditionally(IpTablesHelper.OUTPUT_CHAIN, true, rule, errMsg);
          if (result != null) {
-             logger.warn("Error in allowing outgoing to " + destCidr + ", err=" + result);
-             return "Error in allowing outgoing to " + destCidr + ", err=" + result;
+             return result;
          }
  
          addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, destCidr);
@@@ -2873,15 -2871,10 +2872,10 @@@
          command.add("ssh");
          String result = command.execute();
          if (result != null) {
 -            s_logger.warn("Error in starting sshd service err=" + result);
 +            logger.warn("Error in starting sshd service err=" + result);
          }
-         command = new Script("/bin/bash", logger);
-         command.add("-c");
-         command.add("iptables -I INPUT -i eth1 -p tcp -m state --state NEW -m tcp --dport 3922 -j ACCEPT");
-         result = command.execute();
-         if (result != null) {
-             logger.warn("Error in opening up ssh port err=" + result);
-         }
+         String rule = "-i eth1 -p tcp -m state --state NEW -m tcp --dport 3922 -j ACCEPT";
+         IpTablesHelper.addConditionally(IpTablesHelper.INPUT_CHAIN, true, rule, "Error in opening up ssh port");
      }
  
      private void addRouteToInternalIpOrCidr(String localgw, String eth1ip, String eth1mask, String destIpOrCidr) {
diff --cc services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
index fd5c9e43ac6,11878ae6400..ad73a9bc708
--- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
+++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
@@@ -1260,19 -1257,21 +1258,21 @@@ public class DownloadManagerImpl extend
          command.add("apache2");
          String result = command.execute();
          if (result != null) {
 -            LOGGER.warn("Error in stopping httpd service err=" + result);
 +            logger.warn("Error in stopping httpd service err=" + result);
          }
-         String port = Integer.toString(TemplateConstants.DEFAULT_TMPLT_COPY_PORT);
-         String intf = TemplateConstants.DEFAULT_TMPLT_COPY_INTF;
  
-         command = new Script("/bin/bash", logger);
-         command.add("-c");
-         command.add("iptables -I INPUT -i " + intf + " -p tcp -m state --state NEW -m tcp --dport " + port + " -j ACCEPT;" + "iptables -I INPUT -i " + intf +
-                 " -p tcp -m state --state NEW -m tcp --dport " + "443" + " -j ACCEPT;");
- 
-         result = command.execute();
+         result = IpTablesHelper.addConditionally(IpTablesHelper.INPUT_CHAIN
+                 , true
+                 , "-i " + TemplateConstants.DEFAULT_TMPLT_COPY_INTF + " -p tcp -m state --state NEW -m tcp --dport " + TemplateConstants.DEFAULT_TMPLT_COPY_PORT + " -j ACCEPT"
+                 , "Error in opening up apache2 port " + TemplateConstants.TMPLT_COPY_INTF_PRIVATE);
+         if (result != null) {
+             return;
+         }
+         result = IpTablesHelper.addConditionally(IpTablesHelper.INPUT_CHAIN
+                 , true
+                 , "-i " + TemplateConstants.DEFAULT_TMPLT_COPY_INTF + " -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT;"
+                 , "Error in opening up apache2 port 443");
          if (result != null) {
-             logger.warn("Error in opening up apache2 port err=" + result);
              return;
          }
  
diff --cc ui/src/components/view/ResourceLimitTab.vue
index eba6b79cb7d,875d2cc3b40..a54adf83eae
--- a/ui/src/components/view/ResourceLimitTab.vue
+++ b/ui/src/components/view/ResourceLimitTab.vue
@@@ -135,13 -112,7 +135,14 @@@ export default 
          this.formLoading = true
          this.dataResource = await this.listResourceLimits(params)
          this.dataResource.forEach(item => {
 +          this.resourceTypeIdNames[item.resourcetype] = item.resourcetypename
 +          item.key = item.tag ? (item.resourcetype + '-' + item.tag) : item.resourcetype
 +          form[item.key] = item.max || -1
 +          item.taggedresource.forEach(subItem => {
 +            subItem.key = subItem.tag ? (subItem.resourcetype + '-' + subItem.tag) : subItem.resourcetype
 +            form[subItem.key] = subItem.max || -1
 +          })
+           form[item.resourcetype] = item.max == null ? -1 : item.max
          })
          this.form = form
          this.formRef.value.resetFields()