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

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


The following commit(s) were added to refs/heads/master by this push:
     new a3cdd1f  Allow deploy Admin VMs and VRs in disabled 
zones/pods/clusters (#3600)
a3cdd1f is described below

commit a3cdd1f836e40a4b4444af738780a337ee7aac1d
Author: Gabriel Beims Bräscher <[email protected]>
AuthorDate: Fri May 28 05:45:30 2021 -0300

    Allow deploy Admin VMs and VRs in disabled zones/pods/clusters (#3600)
---
 .../cloud/deploy/DeploymentPlanningManager.java    |   8 +
 .../src/main/java/com/cloud/host/dao/HostDao.java  |  13 ++
 .../main/java/com/cloud/host/dao/HostDaoImpl.java  |  20 +-
 .../src/main/java/com/cloud/vm/VMInstanceVO.java   |   2 +-
 .../allocator/impl/RecreateHostAllocator.java      |  15 --
 .../deploy/DeploymentPlanningManagerImpl.java      | 153 +++++++++++---
 .../java/com/cloud/deploy/FirstFitPlanner.java     |  39 ----
 .../DeploymentPlanningManagerImplTest.java         | 221 ++++++++++++++++++++-
 8 files changed, 372 insertions(+), 99 deletions(-)

diff --git 
a/engine/components-api/src/main/java/com/cloud/deploy/DeploymentPlanningManager.java
 
b/engine/components-api/src/main/java/com/cloud/deploy/DeploymentPlanningManager.java
index 2266cd5..d3a5f7f 100644
--- 
a/engine/components-api/src/main/java/com/cloud/deploy/DeploymentPlanningManager.java
+++ 
b/engine/components-api/src/main/java/com/cloud/deploy/DeploymentPlanningManager.java
@@ -22,9 +22,17 @@ import com.cloud.exception.AffinityConflictException;
 import com.cloud.exception.InsufficientServerCapacityException;
 import com.cloud.utils.component.Manager;
 import com.cloud.vm.VirtualMachineProfile;
+import org.apache.cloudstack.framework.config.ConfigKey;
 
 public interface DeploymentPlanningManager extends Manager {
 
+
+    static final ConfigKey<Boolean> allowRouterOnDisabledResource = new 
ConfigKey<Boolean>("Advanced", Boolean.class, 
"allow.router.on.disabled.resources", "false",
+            "Allow deploying VR in disabled Zones, Pods, and Clusters", true);
+
+    static final ConfigKey<Boolean> allowAdminVmOnDisabledResource = new 
ConfigKey<Boolean>("Advanced", Boolean.class, 
"allow.admin.vm.on.disabled.resources", "false",
+            "Allow deploying VMs owned by the admin account in disabled 
Clusters, Pods, and Zones", true);
+
     /**
      * Manages vm deployment stages: First Process Affinity/Anti-affinity - 
Call
      * the chain of AffinityGroupProcessor adapters to set deploymentplan scope
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java 
b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
index 3d76c8b..af06fcc 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
@@ -83,8 +83,21 @@ public interface HostDao extends GenericDao<HostVO, Long>, 
StateDao<Status, Stat
 
     List<HostVO> findByClusterId(Long clusterId);
 
+    /**
+     * Returns hosts that are 'Up' and 'Enabled' from the given Data 
Center/Zone
+     */
     List<HostVO> listByDataCenterId(long id);
 
+    /**
+     * Returns hosts that are from the given Data Center/Zone and at a given 
state (e.g. Creating, Enabled, Disabled, etc).
+     */
+    List<HostVO> listByDataCenterIdAndState(long id, ResourceState state);
+
+    /**
+     * Returns hosts that are 'Up' and 'Disabled' from the given Data 
Center/Zone
+     */
+    List<HostVO> listDisabledByDataCenterId(long id);
+
     List<HostVO> listByDataCenterIdAndHypervisorType(long zoneId, 
Hypervisor.HypervisorType hypervisorType);
 
     List<Long> listAllHosts(long zoneId);
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java 
b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
index e931f65..e58df1d 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
@@ -463,13 +463,27 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, 
Long> implements HostDao
 
     @Override
     public List<HostVO> listByDataCenterId(long id) {
+        return listByDataCenterIdAndState(id, ResourceState.Enabled);
+    }
+
+    @Override
+    public List<HostVO> listByDataCenterIdAndState(long id, ResourceState 
state) {
+        SearchCriteria<HostVO> sc = scHostsFromZoneUpRouting(id);
+        sc.setParameters("resourceState", state);
+        return listBy(sc);
+    }
+
+    @Override
+    public List<HostVO> listDisabledByDataCenterId(long id) {
+        return listByDataCenterIdAndState(id, ResourceState.Disabled);
+    }
+
+    private SearchCriteria<HostVO> scHostsFromZoneUpRouting(long id) {
         SearchCriteria<HostVO> sc = DcSearch.create();
         sc.setParameters("dc", id);
         sc.setParameters("status", Status.Up);
         sc.setParameters("type", Host.Type.Routing);
-        sc.setParameters("resourceState", ResourceState.Enabled);
-
-        return listBy(sc);
+        return sc;
     }
 
     @Override
diff --git a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java 
b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java
index 47932c9..0e8dd4e 100644
--- a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java
+++ b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java
@@ -238,7 +238,7 @@ public class VMInstanceVO implements VirtualMachine, 
FiniteStateObject<State, Vi
         this.diskOfferingId = diskOfferingId;
     }
 
-    protected VMInstanceVO() {
+    public VMInstanceVO() {
     }
 
     public Date getRemoved() {
diff --git 
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
index a4797c1..be6f401 100644
--- 
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
@@ -45,7 +45,6 @@ import com.cloud.deploy.DeploymentPlanner.ExcludeList;
 import com.cloud.host.Host;
 import com.cloud.host.Host.Type;
 import com.cloud.host.dao.HostDao;
-import com.cloud.org.Grouping;
 import com.cloud.resource.ResourceManager;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.VolumeDao;
@@ -122,21 +121,7 @@ public class RecreateHostAllocator extends 
FirstFitRoutingAllocator {
         }
 
         for (PodCluster p : pcs) {
-            if (p.getPod().getAllocationState() != 
Grouping.AllocationState.Enabled) {
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Pod name: " + p.getPod().getName() + ", 
podId: " + p.getPod().getId() + " is in " + 
p.getPod().getAllocationState().name() +
-                        " state, skipping this and trying other pods");
-                }
-                continue;
-            }
             Long clusterId = p.getCluster() == null ? null : 
p.getCluster().getId();
-            if (p.getCluster() != null && p.getCluster().getAllocationState() 
!= Grouping.AllocationState.Enabled) {
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Cluster name: " + p.getCluster().getName() 
+ ", clusterId: " + clusterId + " is in " + 
p.getCluster().getAllocationState().name() +
-                        " state, skipping this and trying other pod-clusters");
-                }
-                continue;
-            }
             DataCenterDeployment newPlan = new 
DataCenterDeployment(plan.getDataCenterId(), p.getPod().getId(), clusterId, 
null, null, null);
             hosts = super.allocateTo(vm, newPlan, type, avoid, returnUpTo);
             if (hosts != null && !hosts.isEmpty()) {
diff --git 
a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java 
b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
index fed29aa..7a939ae 100644
--- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -31,6 +31,20 @@ import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
 import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.StringUtils;
+import com.cloud.exception.StorageUnavailableException;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.fsm.StateMachine2;
+
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.log4j.Logger;
 import org.apache.cloudstack.affinity.AffinityGroupProcessor;
 import org.apache.cloudstack.affinity.AffinityGroupService;
 import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
@@ -50,9 +64,6 @@ import 
org.apache.cloudstack.managed.context.ManagedContextTimerTask;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.MapUtils;
-import org.apache.log4j.Logger;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
@@ -84,7 +95,6 @@ import com.cloud.deploy.dao.PlannerHostReservationDao;
 import com.cloud.exception.AffinityConflictException;
 import com.cloud.exception.ConnectionException;
 import com.cloud.exception.InsufficientServerCapacityException;
-import com.cloud.exception.StorageUnavailableException;
 import com.cloud.gpu.GPU;
 import com.cloud.host.DetailVO;
 import com.cloud.host.Host;
@@ -97,7 +107,6 @@ import com.cloud.offering.ServiceOffering;
 import com.cloud.org.Cluster;
 import com.cloud.org.Grouping;
 import com.cloud.resource.ResourceManager;
-import com.cloud.resource.ResourceState;
 import com.cloud.service.ServiceOfferingDetailsVO;
 import com.cloud.service.dao.ServiceOfferingDetailsDao;
 import com.cloud.storage.DiskOfferingVO;
@@ -107,31 +116,26 @@ import com.cloud.storage.Storage;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolHostVO;
-import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.GuestOSCategoryDao;
 import com.cloud.storage.dao.GuestOSDao;
 import com.cloud.storage.dao.StoragePoolHostDao;
-import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.user.AccountManager;
 import com.cloud.utils.DateUtil;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
-import com.cloud.utils.StringUtils;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionCallback;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.StateListener;
-import com.cloud.utils.fsm.StateMachine2;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
@@ -144,12 +148,14 @@ import com.cloud.vm.dao.VMInstanceDao;
 import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
 
 public class DeploymentPlanningManagerImpl extends ManagerBase implements 
DeploymentPlanningManager, Manager, Listener,
-StateListener<State, VirtualMachine.Event, VirtualMachine> {
+StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
 
     private static final Logger s_logger = 
Logger.getLogger(DeploymentPlanningManagerImpl.class);
     @Inject
     AgentManager _agentMgr;
     @Inject
+    private AccountDao accountDao;
+    @Inject
     protected UserVmDao _vmDao;
     @Inject
     protected VMInstanceDao _vmInstanceDao;
@@ -177,6 +183,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
     @Inject
     private VMTemplateDao templateDao;
 
+    private static final long ADMIN_ACCOUNT_ROLE_ID = 1l;
     private static final long INITIAL_RESERVATION_RELEASE_CHECKER_DELAY = 30L 
* 1000L; // thirty seconds expressed in milliseconds
     protected long _nodeId = -1;
 
@@ -283,6 +290,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
             s_logger.debug("Is ROOT volume READY (pool already allocated)?: " 
+ (plan.getPoolId() != null ? "Yes" : "No"));
         }
 
+        avoidDisabledResources(vmProfile, dc, avoids);
+
         String haVmTag = 
(String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag);
         String uefiFlag = 
(String)vmProfile.getParameter(VirtualMachineProfile.Param.UefiFlag);
 
@@ -311,17 +320,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> 
{
                 }
 
                 Pod pod = _podDao.findById(host.getPodId());
-                // check if the cluster or the pod is disabled
-                if (pod.getAllocationState() != 
Grouping.AllocationState.Enabled) {
-                    s_logger.warn("The Pod containing this host is in disabled 
state, PodId= " + pod.getId());
-                    return null;
-                }
 
                 Cluster cluster = _clusterDao.findById(host.getClusterId());
-                if (cluster.getAllocationState() != 
Grouping.AllocationState.Enabled) {
-                    s_logger.warn("The Cluster containing this host is in 
disabled state, PodId= " + cluster.getId());
-                    return null;
-                }
 
                 boolean displayStorage = 
getDisplayStorageFromVmProfile(vmProfile);
                 if (vm.getHypervisorType() == HypervisorType.BareMetal) {
@@ -422,8 +422,15 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> 
{
                     s_logger.debug("The last host of this VM does not have 
required GPU devices available");
                 }
             } else {
-                if (host.getStatus() == Status.Up && host.getResourceState() 
== ResourceState.Enabled) {
-                    if (checkVmProfileAndHost(vmProfile, host)) {
+                if (host.getStatus() == Status.Up) {
+                    boolean hostTagsMatch = true;
+                    if(offering.getHostTag() != null){
+                        _hostDao.loadHostTags(host);
+                        if (!(host.getHostTags() != null && 
host.getHostTags().contains(offering.getHostTag()))) {
+                            hostTagsMatch = false;
+                        }
+                    }
+                    if (hostTagsMatch) {
                         long cluster_id = host.getClusterId();
                         ClusterDetailsVO cluster_detail_cpu = 
_clusterDetailsDao.findDetail(cluster_id,
                                 "cpuOvercommitRatio");
@@ -573,6 +580,86 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> 
{
         return vmProfile == null || vmProfile.getTemplate() == null || 
!vmProfile.getTemplate().isDeployAsIs();
     }
 
+        /**
+         * Adds disabled resources (Data centers, Pods, Clusters, and hosts) 
to exclude list (avoid) in case of disabled state.
+         */
+        public void avoidDisabledResources(VirtualMachineProfile vmProfile, 
DataCenter dc, ExcludeList avoids) {
+            if (vmProfile.getType().isUsedBySystem() && 
isRouterDeployableInDisabledResources()) {
+                return;
+            }
+
+            VMInstanceVO vm = _vmInstanceDao.findById(vmProfile.getId());
+            AccountVO owner = accountDao.findById(vm.getAccountId());
+            boolean isOwnerRoleIdAdmin = false;
+
+            if (owner != null && owner.getRoleId() != null && 
owner.getRoleId() == ADMIN_ACCOUNT_ROLE_ID) {
+                isOwnerRoleIdAdmin = true;
+            }
+
+            if (isOwnerRoleIdAdmin && 
isAdminVmDeployableInDisabledResources()) {
+                return;
+            }
+
+            avoidDisabledDataCenters(dc, avoids);
+            avoidDisabledPods(dc, avoids);
+            avoidDisabledClusters(dc, avoids);
+            avoidDisabledHosts(dc, avoids);
+        }
+
+    /**
+     * Returns the value of the ConfigKey 'allow.router.on.disabled.resources'.
+     * @note this method allows mocking and testing with the respective 
ConfigKey parameter.
+     */
+    protected boolean isRouterDeployableInDisabledResources() {
+        return allowRouterOnDisabledResource.value();
+    }
+
+    /**
+     * Returns the value of the ConfigKey 
'allow.admin.vm.on.disabled.resources'.
+     * @note this method allows mocking and testing with the respective 
ConfigKey parameter.
+     */
+    protected boolean isAdminVmDeployableInDisabledResources() {
+        return allowAdminVmOnDisabledResource.value();
+    }
+
+    /**
+     * Adds disabled Hosts to the ExcludeList in order to avoid them at the 
deployment planner.
+     */
+    protected void avoidDisabledHosts(DataCenter dc, ExcludeList avoids) {
+        List<HostVO> disabledHosts = 
_hostDao.listDisabledByDataCenterId(dc.getId());
+        for (HostVO host : disabledHosts) {
+            avoids.addHost(host.getId());
+        }
+    }
+
+    /**
+     * Adds disabled Clusters to the ExcludeList in order to avoid them at the 
deployment planner.
+     */
+    protected void avoidDisabledClusters(DataCenter dc, ExcludeList avoids) {
+        List<Long> pods = _podDao.listAllPods(dc.getId());
+        for (Long podId : pods) {
+            List<Long> disabledClusters = 
_clusterDao.listDisabledClusters(dc.getId(), podId);
+            avoids.addClusterList(disabledClusters);
+        }
+    }
+
+    /**
+     * Adds disabled Pods to the ExcludeList in order to avoid them at the 
deployment planner.
+     */
+    protected void avoidDisabledPods(DataCenter dc, ExcludeList avoids) {
+        List<Long> disabledPods = _podDao.listDisabledPods(dc.getId());
+        avoids.addPodList(disabledPods);
+    }
+
+    /**
+     * Adds disabled Data Centers (Zones) to the ExcludeList in order to avoid 
them at the deployment planner.
+     */
+    protected void avoidDisabledDataCenters(DataCenter dc, ExcludeList avoids) 
{
+        if (dc.getAllocationState() == Grouping.AllocationState.Disabled) {
+            avoids.addDataCenter(dc.getId());
+        }
+    }
+
     @Override
     public DeploymentPlanner getDeploymentPlannerByName(String plannerName) {
         if (plannerName != null) {
@@ -1092,11 +1179,6 @@ StateListener<State, VirtualMachine.Event, 
VirtualMachine> {
         for (Long clusterId : clusterList) {
             ClusterVO clusterVO = _clusterDao.findById(clusterId);
 
-            if (clusterVO.getAllocationState() == 
Grouping.AllocationState.Disabled && !plan.isMigrationPlan()) {
-                s_logger.debug("Cannot deploy in disabled cluster " + 
clusterId + ", skipping this cluster");
-                avoid.addCluster(clusterVO.getId());
-            }
-
             if (clusterVO.getHypervisorType() != 
vmProfile.getHypervisorType()) {
                 s_logger.debug("Cluster: " + clusterId + " has HyperVisorType 
that does not match the VM, skipping this cluster");
                 avoid.addCluster(clusterVO.getId());
@@ -1110,7 +1192,9 @@ StateListener<State, VirtualMachine.Event, 
VirtualMachine> {
                     new DataCenterDeployment(plan.getDataCenterId(), 
clusterVO.getPodId(), clusterVO.getId(), null, plan.getPoolId(), null, 
plan.getReservationContext());
 
             Pod pod = _podDao.findById(clusterVO.getPodId());
-            if (pod.getAllocationState() == Grouping.AllocationState.Enabled ) 
{
+            if (CollectionUtils.isNotEmpty(avoid.getPodsToAvoid()) && 
avoid.getPodsToAvoid().contains(pod.getId())) {
+                s_logger.debug("The cluster is in a disabled pod : " + 
pod.getId());
+            } else {
                 // find suitable hosts under this cluster, need as many hosts 
as we
                 // get.
                 List<Host> suitableHosts = findSuitableHosts(vmProfile, 
potentialPlan, avoid, HostAllocator.RETURN_UPTO_ALL);
@@ -1151,9 +1235,6 @@ StateListener<State, VirtualMachine.Event, 
VirtualMachine> {
                     s_logger.debug("No suitable hosts found under this 
Cluster: " + clusterId);
                 }
             }
-            else {
-                s_logger.debug("The cluster is in a disabled pod : " + 
pod.getId());
-            }
 
             if (canAvoidCluster(clusterVO, avoid, plannerAvoidOutput, 
vmProfile)) {
                 avoid.addCluster(clusterVO.getId());
@@ -1739,4 +1820,14 @@ StateListener<State, VirtualMachine.Event, 
VirtualMachine> {
       }
       return true;
     }
+
+    @Override
+    public ConfigKey<?>[] getConfigKeys() {
+        return new ConfigKey<?>[] {allowRouterOnDisabledResource, 
allowAdminVmOnDisabledResource};
+    }
+
+    @Override
+    public String getConfigComponentName() {
+        return DeploymentPlanningManager.class.getSimpleName();
+    }
 }
diff --git a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java 
b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
index a93da71..dbcfe4d 100644
--- a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
+++ b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
@@ -260,15 +260,6 @@ public class FirstFitPlanner extends AdapterBase 
implements DeploymentClusterPla
                 }
                 podsWithCapacity.removeAll(avoid.getPodsToAvoid());
             }
-            if (!isRootAdmin(vmProfile)) {
-                List<Long> disabledPods = 
listDisabledPods(plan.getDataCenterId());
-                if (!disabledPods.isEmpty()) {
-                    if (s_logger.isDebugEnabled()) {
-                        s_logger.debug("Removing from the podId list these 
pods that are disabled: " + disabledPods);
-                    }
-                    podsWithCapacity.removeAll(disabledPods);
-                }
-            }
         } else {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("No pods found having a host with enough 
capacity, returning.");
@@ -402,21 +393,6 @@ public class FirstFitPlanner extends AdapterBase 
implements DeploymentClusterPla
                 prioritizedClusterIds.removeAll(avoid.getClustersToAvoid());
             }
 
-            if (!isRootAdmin(vmProfile)) {
-                List<Long> disabledClusters = new ArrayList<Long>();
-                if (isZone) {
-                    disabledClusters = 
listDisabledClusters(plan.getDataCenterId(), null);
-                } else {
-                    disabledClusters = 
listDisabledClusters(plan.getDataCenterId(), id);
-                }
-                if (!disabledClusters.isEmpty()) {
-                    if (s_logger.isDebugEnabled()) {
-                        s_logger.debug("Removing from the clusterId list these 
clusters that are disabled/clusters under disabled pods: " + disabledClusters);
-                    }
-                    prioritizedClusterIds.removeAll(disabledClusters);
-                }
-            }
-
             removeClustersCrossingThreshold(prioritizedClusterIds, avoid, 
vmProfile, plan);
             String hostTagOnOffering = offering.getHostTag();
             if (hostTagOnOffering != null) {
@@ -465,21 +441,6 @@ public class FirstFitPlanner extends AdapterBase 
implements DeploymentClusterPla
         return podIdsByCapacity;
     }
 
-    private List<Long> listDisabledClusters(long zoneId, Long podId) {
-        List<Long> disabledClusters = clusterDao.listDisabledClusters(zoneId, 
podId);
-        if (podId == null) {
-            //list all disabled clusters under this zone + clusters under any 
disabled pod of this zone
-            List<Long> clustersWithDisabledPods = 
clusterDao.listClustersWithDisabledPods(zoneId);
-            disabledClusters.addAll(clustersWithDisabledPods);
-        }
-        return disabledClusters;
-    }
-
-    private List<Long> listDisabledPods(long zoneId) {
-        List<Long> disabledPods = podDao.listDisabledPods(zoneId);
-        return disabledPods;
-    }
-
     protected Pair<List<Long>, Map<Long, Double>> listClustersByCapacity(long 
id, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone) {
         //look at the aggregate available cpu and ram per cluster
         //although an aggregate value may be false indicator that a cluster 
can host a vm, it will at the least eliminate those clusters which definitely 
cannot
diff --git 
a/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java 
b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java
similarity index 64%
rename from 
server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java
rename to 
server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java
index d356570..ab73e63 100644
--- a/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java
+++ 
b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java
@@ -14,7 +14,7 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-package com.cloud.vm;
+package com.cloud.deploy;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -28,18 +28,30 @@ import java.util.List;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.dc.DataCenter;
 import com.cloud.host.Host;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Type;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachineProfileImpl;
 import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
+import org.apache.commons.collections.CollectionUtils;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
 import org.mockito.Matchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.ComponentScan.Filter;
@@ -73,15 +85,8 @@ import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.DedicatedResourceDao;
 import com.cloud.dc.dao.HostPodDao;
-import com.cloud.deploy.DataCenterDeployment;
-import com.cloud.deploy.DeployDestination;
-import com.cloud.deploy.DeploymentClusterPlanner;
-import com.cloud.deploy.DeploymentPlanner;
 import com.cloud.deploy.DeploymentPlanner.ExcludeList;
 import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage;
-import com.cloud.deploy.DeploymentPlanningManagerImpl;
-import com.cloud.deploy.FirstFitPlanner;
-import com.cloud.deploy.PlannerHostReservationVO;
 import com.cloud.deploy.dao.PlannerHostReservationDao;
 import com.cloud.exception.AffinityConflictException;
 import com.cloud.exception.InsufficientServerCapacityException;
@@ -90,6 +95,7 @@ import com.cloud.host.dao.HostDao;
 import com.cloud.host.dao.HostTagsDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.resource.ResourceManager;
+import com.cloud.org.Grouping.AllocationState;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDetailsDao;
 import com.cloud.storage.Storage.ProvisioningType;
@@ -110,7 +116,8 @@ import com.cloud.host.dao.HostDetailsDao;
 @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
 public class DeploymentPlanningManagerImplTest {
 
-    @Inject
+    @Spy
+    @InjectMocks
     DeploymentPlanningManagerImpl _dpm;
 
     @Inject
@@ -120,6 +127,12 @@ public class DeploymentPlanningManagerImplTest {
     VirtualMachineProfileImpl vmProfile;
 
     @Inject
+    private AccountDao accountDao;
+
+    @Inject
+    private VMInstanceDao vmInstanceDao;
+
+    @Inject
     AffinityGroupVMMapDao _affinityGroupVMMapDao;
 
     @Inject
@@ -146,11 +159,15 @@ public class DeploymentPlanningManagerImplTest {
     @Inject
     VMTemplateDao templateDao;
 
+    @Inject
+    HostPodDao hostPodDao;
+
     @Mock
     Host host;
 
     private static long dataCenterId = 1L;
     private static long hostId = 1l;
+    private static final long ADMIN_ACCOUNT_ROLE_ID = 1l;
 
     @BeforeClass
     public static void setUp() throws ConfigurationException {
@@ -189,6 +206,7 @@ public class DeploymentPlanningManagerImplTest {
         _dpm.setPlanners(planners);
 
         Mockito.when(host.getId()).thenReturn(hostId);
+        Mockito.doNothing().when(_dpm).avoidDisabledResources(vmProfile, dc, 
avoids);
     }
 
     @Test
@@ -259,6 +277,184 @@ public class DeploymentPlanningManagerImplTest {
         assertFalse(_dpm.checkAffinity(host, Arrays.asList(3l, 4l, 2l)));
     }
 
+    @Test
+    public void routerInDisabledResourceAssertFalse() {
+        
Assert.assertFalse(DeploymentPlanningManager.allowRouterOnDisabledResource.value());
+    }
+
+    @Test
+    public void adminVmInDisabledResourceAssertFalse() {
+        
Assert.assertFalse(DeploymentPlanningManager.allowAdminVmOnDisabledResource.value());
+    }
+
+    @Test
+    public void avoidDisabledResourcesTestAdminAccount() {
+        Type[] vmTypes = VirtualMachine.Type.values();
+        for (int i = 0; i < vmTypes.length - 1; ++i) {
+            Mockito.when(vmProfile.getType()).thenReturn(vmTypes[i]);
+            if (vmTypes[i].isUsedBySystem()) {
+                prepareAndVerifyAvoidDisabledResourcesTest(1, 0, 0, 
ADMIN_ACCOUNT_ROLE_ID, vmTypes[i], true, false);
+            } else {
+                prepareAndVerifyAvoidDisabledResourcesTest(0, 1, 1, 
ADMIN_ACCOUNT_ROLE_ID, vmTypes[i], true, false);
+            }
+        }
+    }
+
+    @Test
+    public void 
avoidDisabledResourcesTestUserAccounAdminCannotDeployOnDisabled() {
+        Type[] vmTypes = VirtualMachine.Type.values();
+        for (int i = 0; i < vmTypes.length - 1; ++i) {
+            Mockito.when(vmProfile.getType()).thenReturn(vmTypes[i]);
+            long userAccountId = ADMIN_ACCOUNT_ROLE_ID + 1;
+            if (vmTypes[i].isUsedBySystem()) {
+                prepareAndVerifyAvoidDisabledResourcesTest(1, 0, 0, 
userAccountId, vmTypes[i], true, false);
+            } else {
+                prepareAndVerifyAvoidDisabledResourcesTest(0, 0, 1, 
userAccountId, vmTypes[i], true, false);
+            }
+        }
+    }
+
+    @Test
+    public void avoidDisabledResourcesTestUserAccounAdminCanDeployOnDisabled() 
{
+        Type[] vmTypes = VirtualMachine.Type.values();
+        for (int i = 0; i < vmTypes.length - 1; ++i) {
+            Mockito.when(vmProfile.getType()).thenReturn(vmTypes[i]);
+            long userAccountId = ADMIN_ACCOUNT_ROLE_ID + 1;
+            if (vmTypes[i].isUsedBySystem()) {
+                prepareAndVerifyAvoidDisabledResourcesTest(1, 0, 0, 
userAccountId, vmTypes[i], true, true);
+            } else {
+                prepareAndVerifyAvoidDisabledResourcesTest(0, 0, 1, 
userAccountId, vmTypes[i], true, true);
+            }
+        }
+    }
+
+    private void prepareAndVerifyAvoidDisabledResourcesTest(int timesRouter, 
int timesAdminVm, int timesDisabledResource, long roleId, Type vmType, boolean 
isSystemDepolyable,
+            boolean isAdminVmDeployable) {
+        
Mockito.doReturn(isSystemDepolyable).when(_dpm).isRouterDeployableInDisabledResources();
+        
Mockito.doReturn(isAdminVmDeployable).when(_dpm).isAdminVmDeployableInDisabledResources();
+
+        VirtualMachineProfile vmProfile = 
Mockito.mock(VirtualMachineProfile.class);
+        DataCenter dc = Mockito.mock(DataCenter.class);
+        ExcludeList avoids = Mockito.mock(ExcludeList.class);
+
+        Mockito.when(vmProfile.getType()).thenReturn(vmType);
+        Mockito.when(vmProfile.getId()).thenReturn(1l);
+
+        Mockito.doNothing().when(_dpm).avoidDisabledDataCenters(dc, avoids);
+        Mockito.doNothing().when(_dpm).avoidDisabledPods(dc, avoids);
+        Mockito.doNothing().when(_dpm).avoidDisabledClusters(dc, avoids);
+        Mockito.doNothing().when(_dpm).avoidDisabledHosts(dc, avoids);
+
+        VMInstanceVO vmInstanceVO = Mockito.mock(VMInstanceVO.class);
+        
Mockito.when(vmInstanceDao.findById(Mockito.anyLong())).thenReturn(vmInstanceVO);
+        AccountVO owner = Mockito.mock(AccountVO.class);
+        Mockito.when(owner.getRoleId()).thenReturn(roleId);
+        Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(owner);
+
+        _dpm.avoidDisabledResources(vmProfile, dc, avoids);
+
+        Mockito.verify(_dpm, 
Mockito.times(timesRouter)).isRouterDeployableInDisabledResources();
+        Mockito.verify(_dpm, 
Mockito.times(timesAdminVm)).isAdminVmDeployableInDisabledResources();
+        Mockito.verify(_dpm, 
Mockito.times(timesDisabledResource)).avoidDisabledDataCenters(dc, avoids);
+        Mockito.verify(_dpm, 
Mockito.times(timesDisabledResource)).avoidDisabledPods(dc, avoids);
+        Mockito.verify(_dpm, 
Mockito.times(timesDisabledResource)).avoidDisabledClusters(dc, avoids);
+        Mockito.verify(_dpm, 
Mockito.times(timesDisabledResource)).avoidDisabledHosts(dc, avoids);
+        Mockito.reset(_dpm);
+    }
+
+    @Test
+    public void avoidDisabledDataCentersTest() {
+        DataCenter dc = Mockito.mock(DataCenter.class);
+        Mockito.when(dc.getId()).thenReturn(123l);
+
+        ExcludeList avoids = new ExcludeList();
+        AllocationState[] allocationStates = AllocationState.values();
+        for (int i = 0; i < allocationStates.length - 1; ++i) {
+            
Mockito.when(dc.getAllocationState()).thenReturn(allocationStates[i]);
+
+            _dpm.avoidDisabledDataCenters(dc, avoids);
+
+            if (allocationStates[i] == AllocationState.Disabled) {
+                assertAvoidIsEmpty(avoids, false, true, true, true);
+                Assert.assertTrue(avoids.getDataCentersToAvoid().size() == 1);
+                
Assert.assertTrue(avoids.getDataCentersToAvoid().contains(dc.getId()));
+            } else {
+                assertAvoidIsEmpty(avoids, true, true, true, true);
+            }
+        }
+    }
+
+    @Test
+    public void avoidDisabledPodsTestNoDisabledPod() {
+        DataCenter dc = Mockito.mock(DataCenter.class);
+        List<Long> podIds = new ArrayList<>();
+        long expectedPodId = 123l;
+        podIds.add(expectedPodId);
+        Mockito.doReturn(new 
ArrayList<>()).when(hostPodDao).listDisabledPods(Mockito.anyLong());
+        ExcludeList avoids = new ExcludeList();
+
+        _dpm.avoidDisabledPods(dc, avoids);
+        assertAvoidIsEmpty(avoids, true, true, true, true);
+    }
+
+    @Test
+    public void avoidDisabledPodsTestHasDisabledPod() {
+        DataCenter dc = Mockito.mock(DataCenter.class);
+        List<Long> podIds = new ArrayList<>();
+        long expectedPodId = 123l;
+        podIds.add(expectedPodId);
+        
Mockito.doReturn(podIds).when(hostPodDao).listDisabledPods(Mockito.anyLong());
+
+        ExcludeList avoids = new ExcludeList();
+
+        _dpm.avoidDisabledPods(dc, avoids);
+        assertAvoidIsEmpty(avoids, true, false, true, true);
+        Assert.assertTrue(avoids.getPodsToAvoid().size() == 1);
+        Assert.assertTrue(avoids.getPodsToAvoid().contains(expectedPodId));
+    }
+
+    @Test
+    public void avoidDisabledClustersTestNoDisabledCluster() {
+        DataCenter dc = prepareAvoidDisabledTests();
+        Mockito.doReturn(new 
ArrayList<>()).when(_clusterDao).listDisabledClusters(Mockito.anyLong(), 
Mockito.anyLong());
+        ExcludeList avoids = new ExcludeList();
+
+        _dpm.avoidDisabledClusters(dc, avoids);
+        assertAvoidIsEmpty(avoids, true, true, true, true);
+    }
+
+    @Test
+    public void avoidDisabledClustersTestHasDisabledCluster() {
+        DataCenter dc = prepareAvoidDisabledTests();
+        long expectedClusterId = 123l;
+        List<Long> disabledClusters = new ArrayList<>();
+        disabledClusters.add(expectedClusterId);
+        
Mockito.doReturn(disabledClusters).when(_clusterDao).listDisabledClusters(Mockito.anyLong(),
 Mockito.anyLong());
+        ExcludeList avoids = new ExcludeList();
+
+        _dpm.avoidDisabledClusters(dc, avoids);
+
+        assertAvoidIsEmpty(avoids, true, true, false, true);
+        Assert.assertTrue(avoids.getClustersToAvoid().size() == 1);
+        
Assert.assertTrue(avoids.getClustersToAvoid().contains(expectedClusterId));
+    }
+
+    private DataCenter prepareAvoidDisabledTests() {
+        DataCenter dc = Mockito.mock(DataCenter.class);
+        Mockito.when(dc.getId()).thenReturn(123l);
+        List<Long> podIds = new ArrayList<>();
+        podIds.add(1l);
+        
Mockito.doReturn(podIds).when(hostPodDao).listAllPods(Mockito.anyLong());
+        return dc;
+    }
+
+    private void assertAvoidIsEmpty(ExcludeList avoids, boolean isDcEmpty, 
boolean isPodsEmpty, boolean isClustersEmpty, boolean isHostsEmpty) {
+        Assert.assertEquals(isDcEmpty, 
CollectionUtils.isEmpty(avoids.getDataCentersToAvoid()));
+        Assert.assertEquals(isPodsEmpty, 
CollectionUtils.isEmpty(avoids.getPodsToAvoid()));
+        Assert.assertEquals(isClustersEmpty, 
CollectionUtils.isEmpty(avoids.getClustersToAvoid()));
+        Assert.assertEquals(isHostsEmpty, 
CollectionUtils.isEmpty(avoids.getHostsToAvoid()));
+    }
+
     @Configuration
     @ComponentScan(basePackageClasses = {DeploymentPlanningManagerImpl.class}, 
includeFilters = {@Filter(value = TestConfiguration.Library.class,
                                                                                
                          type = FilterType.CUSTOM)}, useDefaultFilters = false)
@@ -461,11 +657,16 @@ public class DeploymentPlanningManagerImplTest {
         }
 
         @Bean
-        public HostGpuGroupsDao hostGpuGroupsDap() {
+        public HostGpuGroupsDao hostGpuGroupsDao() {
             return Mockito.mock(HostGpuGroupsDao.class);
         }
 
         @Bean
+        public AccountDao accountDao() {
+            return Mockito.mock(AccountDao.class);
+        }
+
+        @Bean
         public VMTemplateDao vmTemplateDao() {
             return Mockito.mock(VMTemplateDao.class);
         }

Reply via email to