mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Allow deploy Admin VMs and VRs in disabled zones/pods/clusters (#3600)
This commit is contained in:
parent
6531ee5871
commit
a3cdd1f836
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -238,7 +238,7 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
|
||||
this.diskOfferingId = diskOfferingId;
|
||||
}
|
||||
|
||||
protected VMInstanceVO() {
|
||||
public VMInstanceVO() {
|
||||
}
|
||||
|
||||
public Date getRemoved() {
|
||||
|
||||
@ -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()) {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -119,6 +126,12 @@ public class DeploymentPlanningManagerImplTest {
|
||||
@Inject
|
||||
VirtualMachineProfileImpl vmProfile;
|
||||
|
||||
@Inject
|
||||
private AccountDao accountDao;
|
||||
|
||||
@Inject
|
||||
private VMInstanceDao vmInstanceDao;
|
||||
|
||||
@Inject
|
||||
AffinityGroupVMMapDao _affinityGroupVMMapDao;
|
||||
|
||||
@ -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,10 +657,15 @@ 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);
|
||||
Loading…
x
Reference in New Issue
Block a user