mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Improve logs when adding components to avoid set (#7214)
Co-authored-by: SadiJr <sadi@scclouds.com.br> Co-authored-by: GaOrtiga <49285692+GaOrtiga@users.noreply.github.com> Co-authored-by: João Jandre <48719461+JoaoJandre@users.noreply.github.com>
This commit is contained in:
parent
c8a4575bcd
commit
6f27b1f459
@ -21,8 +21,12 @@ import java.util.Collection;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
import com.cloud.dc.Pod;
|
import com.cloud.dc.Pod;
|
||||||
|
import com.cloud.exception.CloudException;
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
import com.cloud.exception.InsufficientServerCapacityException;
|
import com.cloud.exception.InsufficientServerCapacityException;
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
@ -75,7 +79,7 @@ public interface DeploymentPlanner extends Adapter {
|
|||||||
|
|
||||||
public static class ExcludeList implements Serializable {
|
public static class ExcludeList implements Serializable {
|
||||||
private static final long serialVersionUID = -482175549460148301L;
|
private static final long serialVersionUID = -482175549460148301L;
|
||||||
|
protected static Logger LOGGER = LogManager.getLogger(ExcludeList.class);
|
||||||
private Set<Long> _dcIds;
|
private Set<Long> _dcIds;
|
||||||
private Set<Long> _podIds;
|
private Set<Long> _podIds;
|
||||||
private Set<Long> _clusterIds;
|
private Set<Long> _clusterIds;
|
||||||
@ -104,13 +108,26 @@ public interface DeploymentPlanner extends Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logAvoid(Class<?> scope, CloudException e) {
|
||||||
|
Long id = null;
|
||||||
|
if (e instanceof InsufficientCapacityException) {
|
||||||
|
id = ((InsufficientCapacityException) e).getId();
|
||||||
|
} else if (e instanceof ResourceUnavailableException) {
|
||||||
|
id = ((ResourceUnavailableException) e).getResourceId();
|
||||||
|
} else {
|
||||||
|
LOGGER.debug("Failed to log avoided component due to unexpected exception type [{}].", e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOGGER.debug("Adding {} [{}] to the avoid set due to [{}].", scope.getSimpleName(), id, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
public boolean add(InsufficientCapacityException e) {
|
public boolean add(InsufficientCapacityException e) {
|
||||||
Class<?> scope = e.getScope();
|
Class<?> scope = e.getScope();
|
||||||
|
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
logAvoid(scope, e);
|
||||||
if (Host.class.isAssignableFrom(scope)) {
|
if (Host.class.isAssignableFrom(scope)) {
|
||||||
addHost(e.getId());
|
addHost(e.getId());
|
||||||
} else if (Pod.class.isAssignableFrom(scope)) {
|
} else if (Pod.class.isAssignableFrom(scope)) {
|
||||||
@ -128,13 +145,14 @@ public interface DeploymentPlanner extends Adapter {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean add(ResourceUnavailableException e) {
|
public boolean add(ResourceUnavailableException e) {
|
||||||
Class<?> scope = e.getScope();
|
Class<?> scope = e.getScope();
|
||||||
|
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
logAvoid(scope, e);
|
||||||
if (Host.class.isAssignableFrom(scope)) {
|
if (Host.class.isAssignableFrom(scope)) {
|
||||||
addHost(e.getResourceId());
|
addHost(e.getResourceId());
|
||||||
} else if (Pod.class.isAssignableFrom(scope)) {
|
} else if (Pod.class.isAssignableFrom(scope)) {
|
||||||
|
|||||||
@ -165,6 +165,7 @@ import com.cloud.deploy.DeploymentPlan;
|
|||||||
import com.cloud.deploy.DeploymentPlanner;
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||||
import com.cloud.deploy.DeploymentPlanningManager;
|
import com.cloud.deploy.DeploymentPlanningManager;
|
||||||
|
import com.cloud.deploy.DeploymentPlanningManagerImpl;
|
||||||
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
|
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
|
||||||
import com.cloud.event.EventTypes;
|
import com.cloud.event.EventTypes;
|
||||||
import com.cloud.event.UsageEventUtils;
|
import com.cloud.event.UsageEventUtils;
|
||||||
@ -237,6 +238,7 @@ import com.cloud.user.User;
|
|||||||
import com.cloud.uservm.UserVm;
|
import com.cloud.uservm.UserVm;
|
||||||
import com.cloud.utils.DateUtil;
|
import com.cloud.utils.DateUtil;
|
||||||
import com.cloud.utils.Journal;
|
import com.cloud.utils.Journal;
|
||||||
|
import com.cloud.utils.LogUtils;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.Predicate;
|
import com.cloud.utils.Predicate;
|
||||||
import com.cloud.utils.ReflectionUse;
|
import com.cloud.utils.ReflectionUse;
|
||||||
@ -1093,6 +1095,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
|
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
|
||||||
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
|
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
|
||||||
|
|
||||||
|
logger.debug(() -> LogUtils.logGsonWithoutException("Trying to start VM [%s] using plan [%s] and planner [%s].", vmUuid, planToDeploy, planner));
|
||||||
final CallContext cctxt = CallContext.current();
|
final CallContext cctxt = CallContext.current();
|
||||||
final Account account = cctxt.getCallingAccount();
|
final Account account = cctxt.getCallingAccount();
|
||||||
final User caller = cctxt.getCallingUser();
|
final User caller = cctxt.getCallingUser();
|
||||||
@ -1116,10 +1119,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
|
|
||||||
DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null, ctx);
|
DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null, ctx);
|
||||||
if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
|
if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
|
||||||
if (logger.isDebugEnabled()) {
|
VMInstanceVO finalVm = vm;
|
||||||
logger.debug("advanceStart: DeploymentPlan is provided, using dcId:" + planToDeploy.getDataCenterId() + ", podId: " + planToDeploy.getPodId() +
|
logger.debug(() -> DeploymentPlanningManagerImpl.logDeploymentWithoutException(finalVm, planToDeploy, planToDeploy.getAvoids(), planner));
|
||||||
", clusterId: " + planToDeploy.getClusterId() + ", hostId: " + planToDeploy.getHostId() + ", poolId: " + planToDeploy.getPoolId());
|
|
||||||
}
|
|
||||||
plan =
|
plan =
|
||||||
new DataCenterDeployment(planToDeploy.getDataCenterId(), planToDeploy.getPodId(), planToDeploy.getClusterId(), planToDeploy.getHostId(),
|
new DataCenterDeployment(planToDeploy.getDataCenterId(), planToDeploy.getPodId(), planToDeploy.getClusterId(), planToDeploy.getHostId(),
|
||||||
planToDeploy.getPoolId(), planToDeploy.getPhysicalNetworkId(), ctx);
|
planToDeploy.getPoolId(), planToDeploy.getPhysicalNetworkId(), ctx);
|
||||||
@ -1140,13 +1141,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
|
|
||||||
if (planToDeploy != null) {
|
if (planToDeploy != null) {
|
||||||
avoids = planToDeploy.getAvoids();
|
avoids = planToDeploy.getAvoids();
|
||||||
|
ExcludeList finalAvoids = avoids;
|
||||||
|
logger.debug(() -> LogUtils.logGsonWithoutException("Avoiding components [%s] in deployment of VM [%s].", finalAvoids, vmUuid));
|
||||||
}
|
}
|
||||||
if (avoids == null) {
|
if (avoids == null) {
|
||||||
avoids = new ExcludeList();
|
avoids = new ExcludeList();
|
||||||
}
|
}
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Deploy avoids pods: " + avoids.getPodsToAvoid() + ", clusters: " + avoids.getClustersToAvoid() + ", hosts: " + avoids.getHostsToAvoid());
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean planChangedByVolume = false;
|
boolean planChangedByVolume = false;
|
||||||
boolean reuseVolume = true;
|
boolean reuseVolume = true;
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import javax.naming.ConfigurationException;
|
|||||||
|
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.agent.manager.allocator.HostAllocator;
|
import com.cloud.agent.manager.allocator.HostAllocator;
|
||||||
@ -210,6 +211,10 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
|
|||||||
// add all hosts that we are not considering to the avoid list
|
// add all hosts that we are not considering to the avoid list
|
||||||
List<HostVO> allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);
|
List<HostVO> allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);
|
||||||
allhostsInCluster.removeAll(clusterHosts);
|
allhostsInCluster.removeAll(clusterHosts);
|
||||||
|
|
||||||
|
logger.debug(() -> String.format("Adding hosts [%s] to the avoid set because these hosts do not support HA.",
|
||||||
|
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(allhostsInCluster, "uuid", "name")));
|
||||||
|
|
||||||
for (HostVO host : allhostsInCluster) {
|
for (HostVO host : allhostsInCluster) {
|
||||||
avoid.addHost(host.getId());
|
avoid.addHost(host.getId());
|
||||||
}
|
}
|
||||||
@ -325,10 +330,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
|
|||||||
|
|
||||||
//find number of guest VMs occupying capacity on this host.
|
//find number of guest VMs occupying capacity on this host.
|
||||||
if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) {
|
if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) {
|
||||||
if (logger.isDebugEnabled()) {
|
logger.debug(() -> String.format("Adding host [%s] to the avoid set because this host already has the max number of running (user and/or system) VMs.",
|
||||||
logger.debug("Host name: " + host.getName() + ", hostId: " + host.getId() +
|
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(host, "uuid", "name")));
|
||||||
" already has max Running VMs(count includes system VMs), skipping this and trying other available hosts");
|
|
||||||
}
|
|
||||||
avoid.addHost(host.getId());
|
avoid.addHost(host.getId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -337,7 +340,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
|
|||||||
if ((offeringDetails = _serviceOfferingDetailsDao.findDetail(serviceOfferingId, GPU.Keys.vgpuType.toString())) != null) {
|
if ((offeringDetails = _serviceOfferingDetailsDao.findDetail(serviceOfferingId, GPU.Keys.vgpuType.toString())) != null) {
|
||||||
ServiceOfferingDetailsVO groupName = _serviceOfferingDetailsDao.findDetail(serviceOfferingId, GPU.Keys.pciDevice.toString());
|
ServiceOfferingDetailsVO groupName = _serviceOfferingDetailsDao.findDetail(serviceOfferingId, GPU.Keys.pciDevice.toString());
|
||||||
if(!_resourceMgr.isGPUDeviceAvailable(host.getId(), groupName.getValue(), offeringDetails.getValue())){
|
if(!_resourceMgr.isGPUDeviceAvailable(host.getId(), groupName.getValue(), offeringDetails.getValue())){
|
||||||
logger.info("Host name: " + host.getName() + ", hostId: "+ host.getId() +" does not have required GPU devices available");
|
logger.debug(String.format("Adding host [%s] to avoid set, because this host does not have required GPU devices available.",
|
||||||
|
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(host, "uuid", "name")));
|
||||||
avoid.addHost(host.getId());
|
avoid.addHost(host.getId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,7 +46,9 @@ import com.cloud.utils.fsm.StateMachine2;
|
|||||||
|
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
|
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupService;
|
import org.apache.cloudstack.affinity.AffinityGroupService;
|
||||||
@ -128,6 +130,7 @@ import com.cloud.storage.dao.VolumeDao;
|
|||||||
import com.cloud.template.VirtualMachineTemplate;
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.utils.DateUtil;
|
import com.cloud.utils.DateUtil;
|
||||||
|
import com.cloud.utils.LogUtils;
|
||||||
import com.cloud.utils.NumbersUtil;
|
import com.cloud.utils.NumbersUtil;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.Manager;
|
import com.cloud.utils.component.Manager;
|
||||||
@ -299,25 +302,30 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
@Override
|
@Override
|
||||||
public DeployDestination planDeployment(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids, DeploymentPlanner planner)
|
public DeployDestination planDeployment(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids, DeploymentPlanner planner)
|
||||||
throws InsufficientServerCapacityException, AffinityConflictException {
|
throws InsufficientServerCapacityException, AffinityConflictException {
|
||||||
|
logger.debug(logDeploymentWithoutException(vmProfile.getVirtualMachine(), plan, avoids, planner));
|
||||||
|
|
||||||
ServiceOffering offering = vmProfile.getServiceOffering();
|
ServiceOffering offering = vmProfile.getServiceOffering();
|
||||||
int cpu_requested = offering.getCpu() * offering.getSpeed();
|
int cpuRequested = offering.getCpu() * offering.getSpeed();
|
||||||
long ram_requested = offering.getRamSize() * 1024L * 1024L;
|
long ramRequested = offering.getRamSize() * 1024L * 1024L;
|
||||||
VirtualMachine vm = vmProfile.getVirtualMachine();
|
VirtualMachine vm = vmProfile.getVirtualMachine();
|
||||||
DataCenter dc = _dcDao.findById(vm.getDataCenterId());
|
DataCenter dc = _dcDao.findById(vm.getDataCenterId());
|
||||||
boolean volumesRequireEncryption = anyVolumeRequiresEncryption(_volsDao.findByInstance(vm.getId()));
|
boolean volumesRequireEncryption = anyVolumeRequiresEncryption(_volsDao.findByInstance(vm.getId()));
|
||||||
|
|
||||||
if (vm.getType() == VirtualMachine.Type.User || vm.getType() == VirtualMachine.Type.DomainRouter) {
|
if (vm.getType() == VirtualMachine.Type.User || vm.getType() == VirtualMachine.Type.DomainRouter) {
|
||||||
|
logger.debug("Checking non dedicated resources to deploy VM [{}].", () -> ReflectionToStringBuilderUtils.reflectOnlySelectedFields(vm, "uuid", "type", "instanceName"));
|
||||||
checkForNonDedicatedResources(vmProfile, dc, avoids);
|
checkForNonDedicatedResources(vmProfile, dc, avoids);
|
||||||
}
|
}
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("DeploymentPlanner allocation algorithm: " + planner);
|
|
||||||
|
|
||||||
logger.debug("Trying to allocate a host and storage pools from dc:" + plan.getDataCenterId() + ", pod:" + plan.getPodId() + ",cluster:" +
|
logger.debug(() -> {
|
||||||
plan.getClusterId() + ", requested cpu: " + cpu_requested + ", requested ram: " + toHumanReadableSize(ram_requested));
|
String datacenter = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(dc, "uuid", "name");
|
||||||
|
String podVO = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(_podDao.findById(plan.getPodId()), "uuid", "name");
|
||||||
|
String clusterVO = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(_clusterDao.findById(plan.getClusterId()), "uuid", "name");
|
||||||
|
String vmDetails = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(vm, "uuid", "type", "instanceName");
|
||||||
|
return String.format("Trying to allocate a host and storage pools from datacenter [%s], pod [%s], cluster [%s], to deploy VM [%s] "
|
||||||
|
+ "with requested CPU [%s] and requested RAM [%s].", datacenter, podVO, clusterVO, vmDetails, cpuRequested, toHumanReadableSize(ramRequested));
|
||||||
|
});
|
||||||
|
|
||||||
logger.debug("Is ROOT volume READY (pool already allocated)?: " + (plan.getPoolId() != null ? "Yes" : "No"));
|
logger.debug("ROOT volume [{}] {} to deploy VM [{}].", () -> getRootVolumeUuid(_volsDao.findByInstance(vm.getId())), () -> plan.getPoolId() != null ? "is ready" : "is not ready", vm::getUuid);
|
||||||
}
|
|
||||||
|
|
||||||
avoidDisabledResources(vmProfile, dc, avoids);
|
avoidDisabledResources(vmProfile, dc, avoids);
|
||||||
|
|
||||||
@ -325,81 +333,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
String uefiFlag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.UefiFlag);
|
String uefiFlag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.UefiFlag);
|
||||||
|
|
||||||
if (plan.getHostId() != null && haVmTag == null) {
|
if (plan.getHostId() != null && haVmTag == null) {
|
||||||
Long hostIdSpecified = plan.getHostId();
|
return deployInSpecifiedHostWithoutHA(vmProfile, plan, avoids, planner, vm, dc, uefiFlag);
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("DeploymentPlan has host_id specified, choosing this host: " + hostIdSpecified);
|
|
||||||
}
|
|
||||||
HostVO host = _hostDao.findById(hostIdSpecified);
|
|
||||||
if (host != null && StringUtils.isNotBlank(uefiFlag) && "yes".equalsIgnoreCase(uefiFlag)) {
|
|
||||||
DetailVO uefiHostDetail = _hostDetailsDao.findDetail(host.getId(), Host.HOST_UEFI_ENABLE);
|
|
||||||
if (uefiHostDetail == null || "false".equalsIgnoreCase(uefiHostDetail.getValue())) {
|
|
||||||
logger.debug("Cannot deploy to specified host as host does n't support uefi vm deployment, returning.");
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (host == null) {
|
|
||||||
logger.debug("The specified host cannot be found");
|
|
||||||
} else if (avoids.shouldAvoid(host)) {
|
|
||||||
logger.debug("The specified host is in avoid set");
|
|
||||||
} else {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
"Looking for suitable pools for this host under zone: " + host.getDataCenterId() + ", pod: " + host.getPodId() + ", cluster: " + host.getClusterId());
|
|
||||||
}
|
|
||||||
|
|
||||||
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>(), displayStorage);
|
|
||||||
logger.debug("Returning Deployment Destination: " + dest);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// search for storage under the zone, pod, cluster of the host.
|
|
||||||
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();
|
|
||||||
|
|
||||||
_hostDao.loadDetails(host);
|
|
||||||
if (volumesRequireEncryption && !Boolean.parseBoolean(host.getDetail(Host.HOST_VOLUME_ENCRYPTION))) {
|
|
||||||
logger.warn(String.format("VM's volumes require encryption support, and provided host %s can't handle it", host));
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
logger.debug(String.format("Volume encryption requirements are met by provided host %s", host));
|
|
||||||
}
|
|
||||||
|
|
||||||
// choose the potential pool for this VM for this host
|
|
||||||
if (!suitableVolumeStoragePools.isEmpty()) {
|
|
||||||
List<Host> suitableHosts = new ArrayList<Host>();
|
|
||||||
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();
|
|
||||||
// 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 deploy to specified host, returning.");
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// call affinitygroup chain
|
// call affinitygroup chain
|
||||||
@ -410,11 +344,14 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
processor.process(vmProfile, plan, avoids);
|
processor.process(vmProfile, plan, avoids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logger.debug("DeploymentPlan [{}] has not specified host. Trying to find another destination to deploy VM [{}], avoiding pods [{}], clusters [{}] and hosts [{}].",
|
||||||
|
() -> plan.getClass().getSimpleName(), vmProfile::getUuid, () -> StringUtils.join(avoids.getPodsToAvoid(), ", "), () -> StringUtils.join(avoids.getClustersToAvoid(), ", "),
|
||||||
|
() -> StringUtils.join(avoids.getHostsToAvoid(), ", "));
|
||||||
|
|
||||||
|
|
||||||
|
logger.debug("Deploy avoids pods: {}, clusters: {}, hosts: {}.", avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid());
|
||||||
|
logger.debug("Deploy hosts with priorities {}, hosts have NORMAL priority by default", plan.getHostPriorities());
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Deploy avoids pods: " + avoids.getPodsToAvoid() + ", clusters: " + avoids.getClustersToAvoid() + ", hosts: " + avoids.getHostsToAvoid());
|
|
||||||
logger.debug("Deploy hosts with priorities " + plan.getHostPriorities() + " , hosts have NORMAL priority by default");
|
|
||||||
}
|
|
||||||
|
|
||||||
// call planners
|
// call planners
|
||||||
// DataCenter dc = _dcDao.findById(vm.getDataCenterId());
|
// DataCenter dc = _dcDao.findById(vm.getDataCenterId());
|
||||||
@ -448,108 +385,11 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
|
|
||||||
HostVO host = _hostDao.findById(vm.getLastHostId());
|
HostVO host = _hostDao.findById(vm.getLastHostId());
|
||||||
lastHost = host;
|
lastHost = host;
|
||||||
_hostDao.loadHostTags(host);
|
|
||||||
_hostDao.loadDetails(host);
|
|
||||||
ServiceOfferingDetailsVO offeringDetails = null;
|
|
||||||
if (host == null) {
|
|
||||||
logger.debug("The last host of this VM cannot be found");
|
|
||||||
} else if (avoids.shouldAvoid(host)) {
|
|
||||||
logger.debug("The last host of this VM is in avoid set");
|
|
||||||
} else if (plan.getClusterId() != null && host.getClusterId() != null
|
|
||||||
&& !plan.getClusterId().equals(host.getClusterId())) {
|
|
||||||
logger.debug("The last host of this VM cannot be picked as the plan specifies different clusterId: "
|
|
||||||
+ plan.getClusterId());
|
|
||||||
} else if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) {
|
|
||||||
logger.debug("The last Host, hostId: " + host.getId() +
|
|
||||||
" already has max Running VMs(count includes system VMs), skipping this and trying other available hosts");
|
|
||||||
} else if ((offeringDetails = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString())) != null) {
|
|
||||||
ServiceOfferingDetailsVO groupName = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.pciDevice.toString());
|
|
||||||
if(!_resourceMgr.isGPUDeviceAvailable(host.getId(), groupName.getValue(), offeringDetails.getValue())){
|
|
||||||
logger.debug("The last host of this VM does not have required GPU devices available");
|
|
||||||
}
|
|
||||||
} else if (volumesRequireEncryption && !Boolean.parseBoolean(host.getDetail(Host.HOST_VOLUME_ENCRYPTION))) {
|
|
||||||
logger.warn(String.format("The last host of this VM %s does not support volume encryption, which is required by this VM.", host));
|
|
||||||
} else {
|
|
||||||
if (host.getStatus() == Status.Up) {
|
|
||||||
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;
|
DeployDestination deployDestination = deployInVmLastHost(vmProfile, plan, avoids, planner, vm, dc, offering, cpuRequested, ramRequested, volumesRequireEncryption);
|
||||||
hostHasCpuCapability = _capacityMgr.checkIfHostHasCpuCapability(host.getId(), offering.getCpu(), offering.getSpeed());
|
if (deployDestination != null) {
|
||||||
|
return deployDestination;
|
||||||
if (hostHasCpuCapability) {
|
|
||||||
// first check from reserved capacity
|
|
||||||
hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, cpuOvercommitRatio, memoryOvercommitRatio, true);
|
|
||||||
|
|
||||||
// if not reserved, check the free capacity
|
|
||||||
if (!hostHasCapacity)
|
|
||||||
hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, cpuOvercommitRatio, memoryOvercommitRatio, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayStorage = getDisplayStorageFromVmProfile(vmProfile);
|
|
||||||
if (hostHasCapacity
|
|
||||||
&& hostHasCpuCapability) {
|
|
||||||
logger.debug("The last host of this VM is UP and has enough capacity");
|
|
||||||
logger.debug("Now checking for suitable pools under zone: " + host.getDataCenterId()
|
|
||||||
+ ", pod: " + host.getPodId() + ", cluster: " + 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);
|
|
||||||
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()) {
|
|
||||||
List<Host> suitableHosts = new ArrayList<Host>();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.debug("The last host of this VM does not have enough capacity");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.debug("The last host of this VM is not UP or is not enabled, host status is: " + host.getStatus().name() + ", host resource state is: " +
|
|
||||||
host.getResourceState());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("Cannot choose the last host to deploy this VM ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
avoidOtherClustersForDeploymentIfMigrationDisabled(vm, lastHost, avoids);
|
avoidOtherClustersForDeploymentIfMigrationDisabled(vm, lastHost, avoids);
|
||||||
@ -614,6 +454,208 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
return dest;
|
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());
|
||||||
|
_hostDao.loadHostTags(host);
|
||||||
|
_hostDao.loadDetails(host);
|
||||||
|
|
||||||
|
if (canUseLastHost(host, avoids, plan, vm, offering, volumesRequireEncryption)) {
|
||||||
|
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);
|
||||||
|
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>();
|
||||||
|
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>(),
|
||||||
|
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>();
|
||||||
|
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) {
|
protected boolean anyVolumeRequiresEncryption(List<? extends Volume> volumes) {
|
||||||
for (Volume volume : volumes) {
|
for (Volume volume : volumes) {
|
||||||
if (volume.getPassphraseId() != null) {
|
if (volume.getPassphraseId() != null) {
|
||||||
@ -637,7 +679,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds disabled resources (Data centers, Pods, Clusters, and hosts) to exclude list (avoid) in case of disabled state.
|
* 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) {
|
public void avoidDisabledResources(VirtualMachineProfile vmProfile, DataCenter dc, ExcludeList avoids) {
|
||||||
if (vmProfile.getType().isUsedBySystem() && isRouterDeployableInDisabledResources()) {
|
if (vmProfile.getType().isUsedBySystem() && isRouterDeployableInDisabledResources()) {
|
||||||
@ -646,11 +689,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
|
|
||||||
VMInstanceVO vm = _vmInstanceDao.findById(vmProfile.getId());
|
VMInstanceVO vm = _vmInstanceDao.findById(vmProfile.getId());
|
||||||
AccountVO owner = accountDao.findById(vm.getAccountId());
|
AccountVO owner = accountDao.findById(vm.getAccountId());
|
||||||
boolean isOwnerRoleIdAdmin = false;
|
boolean isOwnerRoleIdAdmin = owner != null && owner.getRoleId() != null && owner.getRoleId() == ADMIN_ACCOUNT_ROLE_ID;
|
||||||
|
|
||||||
if (owner != null && owner.getRoleId() != null && owner.getRoleId() == ADMIN_ACCOUNT_ROLE_ID) {
|
|
||||||
isOwnerRoleIdAdmin = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOwnerRoleIdAdmin && isAdminVmDeployableInDisabledResources()) {
|
if (isOwnerRoleIdAdmin && isAdminVmDeployableInDisabledResources()) {
|
||||||
return;
|
return;
|
||||||
@ -683,6 +722,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
*/
|
*/
|
||||||
protected void avoidDisabledHosts(DataCenter dc, ExcludeList avoids) {
|
protected void avoidDisabledHosts(DataCenter dc, ExcludeList avoids) {
|
||||||
List<HostVO> disabledHosts = _hostDao.listDisabledByDataCenterId(dc.getId());
|
List<HostVO> disabledHosts = _hostDao.listDisabledByDataCenterId(dc.getId());
|
||||||
|
logger.debug(() -> String.format("Adding hosts [%s] of datacenter [%s] to the avoid set, because these hosts are in the Disabled state.",
|
||||||
|
disabledHosts.stream().map(HostVO::getUuid).collect(Collectors.joining(", ")), dc.getUuid()));
|
||||||
for (HostVO host : disabledHosts) {
|
for (HostVO host : disabledHosts) {
|
||||||
avoids.addHost(host.getId());
|
avoids.addHost(host.getId());
|
||||||
}
|
}
|
||||||
@ -695,6 +736,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
List<Long> pods = _podDao.listAllPods(dc.getId());
|
List<Long> pods = _podDao.listAllPods(dc.getId());
|
||||||
for (Long podId : pods) {
|
for (Long podId : pods) {
|
||||||
List<Long> disabledClusters = _clusterDao.listDisabledClusters(dc.getId(), podId);
|
List<Long> disabledClusters = _clusterDao.listDisabledClusters(dc.getId(), podId);
|
||||||
|
logger.debug(() -> String.format("Adding clusters [%s] of pod [%s] to the void set because these clusters are in the Disabled state.", StringUtils.join(disabledClusters, ", "), podId));
|
||||||
avoids.addClusterList(disabledClusters);
|
avoids.addClusterList(disabledClusters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -704,6 +746,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
*/
|
*/
|
||||||
protected void avoidDisabledPods(DataCenter dc, ExcludeList avoids) {
|
protected void avoidDisabledPods(DataCenter dc, ExcludeList avoids) {
|
||||||
List<Long> disabledPods = _podDao.listDisabledPods(dc.getId());
|
List<Long> disabledPods = _podDao.listDisabledPods(dc.getId());
|
||||||
|
logger.debug(() -> String.format("Adding pods [%s] to the avoid set because these pods are in the Disabled state.", StringUtils.join(disabledPods, ", ")));
|
||||||
avoids.addPodList(disabledPods);
|
avoids.addPodList(disabledPods);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,6 +755,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
*/
|
*/
|
||||||
protected void avoidDisabledDataCenters(DataCenter dc, ExcludeList avoids) {
|
protected void avoidDisabledDataCenters(DataCenter dc, ExcludeList avoids) {
|
||||||
if (dc.getAllocationState() == Grouping.AllocationState.Disabled) {
|
if (dc.getAllocationState() == Grouping.AllocationState.Disabled) {
|
||||||
|
logger.debug("Adding datacenter [{}] to the avoid set because this datacenter is in Disabled state.", dc.getUuid());
|
||||||
avoids.addDataCenter(dc.getId());
|
avoids.addDataCenter(dc.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -765,6 +809,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
if (dedicatedZone != null && !_accountMgr.isRootAdmin(vmProfile.getOwner().getId())) {
|
if (dedicatedZone != null && !_accountMgr.isRootAdmin(vmProfile.getOwner().getId())) {
|
||||||
long accountDomainId = vmProfile.getOwner().getDomainId();
|
long accountDomainId = vmProfile.getOwner().getDomainId();
|
||||||
long accountId = vmProfile.getOwner().getAccountId();
|
long accountId = vmProfile.getOwner().getAccountId();
|
||||||
|
logger.debug("Zone [{}] is dedicated. Checking if account [{}] in domain [{}] can use this zone to deploy VM [{}].",
|
||||||
|
dedicatedZone.getUuid(), accountId, accountDomainId, vmProfile.getUuid());
|
||||||
|
|
||||||
// If a zone is dedicated to an account then all hosts in this zone
|
// If a zone is dedicated to an account then all hosts in this zone
|
||||||
// will be explicitly dedicated to
|
// will be explicitly dedicated to
|
||||||
@ -784,7 +830,6 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
if (!_affinityGroupService.isAffinityGroupAvailableInDomain(dedicatedZone.getAffinityGroupId(), accountDomainId)) {
|
if (!_affinityGroupService.isAffinityGroupAvailableInDomain(dedicatedZone.getAffinityGroupId(), accountDomainId)) {
|
||||||
throw new CloudRuntimeException("Failed to deploy VM, Zone " + dc.getName() + " not available for the user domain " + vmProfile.getOwner());
|
throw new CloudRuntimeException("Failed to deploy VM, Zone " + dc.getName() + " not available for the user domain " + vmProfile.getOwner());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check affinity group of type Explicit dedication exists. If No put
|
// check affinity group of type Explicit dedication exists. If No put
|
||||||
@ -809,109 +854,97 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
|
|
||||||
//Only when the type is instance VM and not explicitly dedicated.
|
//Only when the type is instance VM and not explicitly dedicated.
|
||||||
if (vm.getType() == VirtualMachine.Type.User && !isExplicit) {
|
if (vm.getType() == VirtualMachine.Type.User && !isExplicit) {
|
||||||
//add explicitly dedicated resources in avoidList
|
findAvoidSetForNonExplicitUserVM(avoids, vm, allPodsInDc, allClustersInDc, allHostsInDc);
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding pods to avoid lists for non-explicit VM deployment: " + allPodsInDc);
|
|
||||||
}
|
|
||||||
avoids.addPodList(allPodsInDc);
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding clusters to avoid lists for non-explicit VM deployment: " + allClustersInDc);
|
|
||||||
}
|
|
||||||
avoids.addClusterList(allClustersInDc);
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding hosts to avoid lists for non-explicit VM deployment: " + allHostsInDc);
|
|
||||||
}
|
|
||||||
avoids.addHostList(allHostsInDc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Handle the Virtual Router Case
|
//Handle the Virtual Router Case
|
||||||
//No need to check the isExplicit. As both the cases are handled.
|
//No need to check the isExplicit. As both the cases are handled.
|
||||||
if (vm.getType() == VirtualMachine.Type.DomainRouter) {
|
if (vm.getType() == VirtualMachine.Type.DomainRouter) {
|
||||||
|
findAvoiSetForRouterVM(avoids, vm, allPodsInDc, allClustersInDc, allHostsInDc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findAvoiSetForRouterVM(ExcludeList avoids, VirtualMachine vm, List<Long> allPodsInDc, List<Long> allClustersInDc, List<Long> allHostsInDc) {
|
||||||
long vmAccountId = vm.getAccountId();
|
long vmAccountId = vm.getAccountId();
|
||||||
long vmDomainId = vm.getDomainId();
|
long vmDomainId = vm.getDomainId();
|
||||||
|
|
||||||
//Lists all explicitly dedicated resources from vm account ID or domain ID.
|
|
||||||
List<Long> allPodsFromDedicatedID = new ArrayList<Long>();
|
List<Long> allPodsFromDedicatedID = new ArrayList<Long>();
|
||||||
List<Long> allClustersFromDedicatedID = new ArrayList<Long>();
|
List<Long> allClustersFromDedicatedID = new ArrayList<Long>();
|
||||||
List<Long> allHostsFromDedicatedID = 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<AffinityGroupDomainMapVO> domainGroupMappings = _affinityGroupDomainMapDao.listByDomain(vmDomainId);
|
||||||
|
|
||||||
//For temporary storage and indexing.
|
|
||||||
List<DedicatedResourceVO> tempStorage;
|
List<DedicatedResourceVO> tempStorage;
|
||||||
|
|
||||||
if (domainGroupMappings == null || domainGroupMappings.isEmpty()) {
|
if (domainGroupMappings == null || domainGroupMappings.isEmpty()) {
|
||||||
//The dedicated resource belongs to VM Account ID.
|
tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, vmAccountId, null,
|
||||||
|
new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
||||||
|
|
||||||
tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
for (DedicatedResourceVO vo : tempStorage) {
|
||||||
|
|
||||||
for(DedicatedResourceVO vo : tempStorage) {
|
|
||||||
allPodsFromDedicatedID.add(vo.getPodId());
|
allPodsFromDedicatedID.add(vo.getPodId());
|
||||||
}
|
}
|
||||||
|
|
||||||
tempStorage.clear();
|
tempStorage.clear();
|
||||||
tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, vmAccountId, null,
|
||||||
|
new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
||||||
|
|
||||||
for(DedicatedResourceVO vo : tempStorage) {
|
for (DedicatedResourceVO vo : tempStorage) {
|
||||||
allClustersFromDedicatedID.add(vo.getClusterId());
|
allClustersFromDedicatedID.add(vo.getClusterId());
|
||||||
}
|
}
|
||||||
|
|
||||||
tempStorage.clear();
|
tempStorage.clear();
|
||||||
tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, vmAccountId, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, vmAccountId, null,
|
||||||
|
new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
||||||
|
|
||||||
for(DedicatedResourceVO vo : tempStorage) {
|
for (DedicatedResourceVO vo : tempStorage) {
|
||||||
allHostsFromDedicatedID.add(vo.getHostId());
|
allHostsFromDedicatedID.add(vo.getHostId());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove the dedicated ones from main list
|
|
||||||
allPodsInDc.removeAll(allPodsFromDedicatedID);
|
allPodsInDc.removeAll(allPodsFromDedicatedID);
|
||||||
allClustersInDc.removeAll(allClustersFromDedicatedID);
|
allClustersInDc.removeAll(allClustersFromDedicatedID);
|
||||||
allHostsInDc.removeAll(allHostsFromDedicatedID);
|
allHostsInDc.removeAll(allHostsFromDedicatedID);
|
||||||
}
|
} else {
|
||||||
else {
|
tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, null, null,
|
||||||
//The dedicated resource belongs to VM Domain ID or No dedication.
|
new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
||||||
|
|
||||||
tempStorage = _dedicatedDao.searchDedicatedPods(null, vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
for (DedicatedResourceVO vo : tempStorage) {
|
||||||
|
|
||||||
for(DedicatedResourceVO vo : tempStorage) {
|
|
||||||
allPodsFromDedicatedID.add(vo.getPodId());
|
allPodsFromDedicatedID.add(vo.getPodId());
|
||||||
}
|
}
|
||||||
|
|
||||||
tempStorage.clear();
|
tempStorage.clear();
|
||||||
tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
tempStorage = _dedicatedDao.searchDedicatedClusters(null, vmDomainId, null, null,
|
||||||
|
new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
||||||
|
|
||||||
for(DedicatedResourceVO vo : tempStorage) {
|
for (DedicatedResourceVO vo : tempStorage) {
|
||||||
allClustersFromDedicatedID.add(vo.getClusterId());
|
allClustersFromDedicatedID.add(vo.getClusterId());
|
||||||
}
|
}
|
||||||
|
|
||||||
tempStorage.clear();
|
tempStorage.clear();
|
||||||
tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, null, null, new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
tempStorage = _dedicatedDao.searchDedicatedHosts(null, vmDomainId, null, null,
|
||||||
|
new Filter(DedicatedResourceVO.class, "id", true, 0L, 1L)).first();
|
||||||
|
|
||||||
for(DedicatedResourceVO vo : tempStorage) {
|
for (DedicatedResourceVO vo : tempStorage) {
|
||||||
allHostsFromDedicatedID.add(vo.getHostId());
|
allHostsFromDedicatedID.add(vo.getHostId());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove the dedicated ones from main list
|
|
||||||
allPodsInDc.removeAll(allPodsFromDedicatedID);
|
allPodsInDc.removeAll(allPodsFromDedicatedID);
|
||||||
allClustersInDc.removeAll(allClustersFromDedicatedID);
|
allClustersInDc.removeAll(allClustersFromDedicatedID);
|
||||||
allHostsInDc.removeAll(allHostsFromDedicatedID);
|
allHostsInDc.removeAll(allHostsFromDedicatedID);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add in avoid list or no addition if no dedication
|
logger.debug(() -> LogUtils.logGsonWithoutException("Adding pods [%s], clusters [%s] and hosts [%s] to the avoid list in the deploy process of VR VM [%s], "
|
||||||
if (logger.isDebugEnabled()) {
|
+ "because this VM is not dedicated to this components.", allPodsInDc, allClustersInDc, allHostsInDc, vm.getUuid()));
|
||||||
logger.debug("Adding pods to avoid lists: " + allPodsInDc);
|
|
||||||
}
|
|
||||||
avoids.addPodList(allPodsInDc);
|
avoids.addPodList(allPodsInDc);
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding clusters to avoid lists: " + allClustersInDc);
|
|
||||||
}
|
|
||||||
avoids.addClusterList(allClustersInDc);
|
avoids.addClusterList(allClustersInDc);
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding hosts to avoid lists: " + allHostsInDc);
|
|
||||||
}
|
|
||||||
avoids.addHostList(allHostsInDc);
|
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) {
|
private void resetAvoidSet(ExcludeList avoidSet, ExcludeList removeSet) {
|
||||||
@ -1246,14 +1279,15 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
DeploymentPlanner.PlannerResourceUsage resourceUsageRequired, ExcludeList plannerAvoidOutput) {
|
DeploymentPlanner.PlannerResourceUsage resourceUsageRequired, ExcludeList plannerAvoidOutput) {
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("ClusterId List to consider: " + clusterList);
|
logger.trace("ClusterId List to consider: {}.", clusterList);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Long clusterId : clusterList) {
|
for (Long clusterId : clusterList) {
|
||||||
ClusterVO clusterVO = _clusterDao.findById(clusterId);
|
ClusterVO clusterVO = _clusterDao.findById(clusterId);
|
||||||
|
|
||||||
if (clusterVO.getHypervisorType() != vmProfile.getHypervisorType()) {
|
if (clusterVO.getHypervisorType() != vmProfile.getHypervisorType()) {
|
||||||
logger.debug("Cluster: " + clusterId + " has HyperVisorType that does not match the VM, skipping this cluster");
|
logger.debug("Adding cluster [{}] to the avoid set because the cluster's hypervisor [{}] does not match the VM [{}] hypervisor: [{}]. Skipping this cluster.",
|
||||||
|
clusterVO.getUuid(), clusterVO.getHypervisorType().name(), vmProfile.getUuid(), vmProfile.getHypervisorType().name());
|
||||||
avoid.addCluster(clusterVO.getId());
|
avoid.addCluster(clusterVO.getId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1564,14 +1598,17 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
|
|
||||||
boolean hostHasEncryption = Boolean.parseBoolean(potentialHostVO.getDetail(Host.HOST_VOLUME_ENCRYPTION));
|
boolean hostHasEncryption = Boolean.parseBoolean(potentialHostVO.getDetail(Host.HOST_VOLUME_ENCRYPTION));
|
||||||
boolean hostMeetsEncryptionRequirements = !anyVolumeRequiresEncryption(new ArrayList<>(volumesOrderBySizeDesc)) || hostHasEncryption;
|
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) {
|
if (hostCanAccessPool && haveEnoughSpace && hostAffinityCheck && hostMeetsEncryptionRequirements && hostFitsPlannerUsage) {
|
||||||
logger.debug("Found a potential host " + "id: " + potentialHost.getId() + " name: " + potentialHost.getName() +
|
logger.debug("Found a potential host " + "id: " + potentialHost.getId() + " name: " + potentialHost.getName() +
|
||||||
" and associated storage pools for this VM");
|
" and associated storage pools for this VM");
|
||||||
volumeAllocationMap.clear();
|
volumeAllocationMap.clear();
|
||||||
return new Pair<Host, Map<Volume, StoragePool>>(potentialHost, storage);
|
return new Pair<Host, Map<Volume, StoragePool>>(potentialHost, storage);
|
||||||
} else {
|
} 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) {
|
if (!hostMeetsEncryptionRequirements) {
|
||||||
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");
|
||||||
}
|
}
|
||||||
@ -1668,12 +1705,12 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
// There should be at least the ROOT volume of the VM in usable state
|
// There should be at least the ROOT volume of the VM in usable state
|
||||||
if (volumesTobeCreated.isEmpty()) {
|
if (volumesTobeCreated.isEmpty()) {
|
||||||
// OfflineVmwareMigration: find out what is wrong with the id of the vm we try to start
|
// OfflineVmwareMigration: find out what is wrong with the id of the vm we try to start
|
||||||
throw new CloudRuntimeException("Unable to create deployment, no usable volumes found for the VM: " + vmProfile.getId());
|
throw new CloudRuntimeException("Unable to create deployment, no usable volumes found for the VM: " + vmProfile.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't allow to start vm that doesn't have a root volume
|
// don't allow to start vm that doesn't have a root volume
|
||||||
if (_volsDao.findByInstanceAndType(vmProfile.getId(), Volume.Type.ROOT).isEmpty()) {
|
if (_volsDao.findByInstanceAndType(vmProfile.getId(), Volume.Type.ROOT).isEmpty()) {
|
||||||
throw new CloudRuntimeException("Unable to prepare volumes for vm as ROOT volume is missing");
|
throw new CloudRuntimeException(String.format("Unable to deploy VM [%s] because the ROOT volume is missing.", vmProfile.getUuid()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each volume find list of suitable storage pools by calling the
|
// for each volume find list of suitable storage pools by calling the
|
||||||
@ -1685,7 +1722,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
Set<Long> poolsToAvoidOutput = new HashSet<>(originalAvoidPoolSet);
|
Set<Long> poolsToAvoidOutput = new HashSet<>(originalAvoidPoolSet);
|
||||||
|
|
||||||
for (VolumeVO toBeCreated : volumesTobeCreated) {
|
for (VolumeVO toBeCreated : volumesTobeCreated) {
|
||||||
logger.debug("Checking suitable pools for volume (Id, Type): (" + toBeCreated.getId() + "," + toBeCreated.getVolumeType().name() + ")");
|
logger.debug("Checking suitable pools for volume [{}, {}] of VM [{}].", toBeCreated.getUuid(), toBeCreated.getVolumeType().name(), vmProfile.getUuid());
|
||||||
|
|
||||||
if (toBeCreated.getState() == Volume.State.Allocated && toBeCreated.getPoolId() != null) {
|
if (toBeCreated.getState() == Volume.State.Allocated && toBeCreated.getPoolId() != null) {
|
||||||
toBeCreated.setPoolId(null);
|
toBeCreated.setPoolId(null);
|
||||||
@ -1701,71 +1738,17 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
// volume is ready and the pool should be reused.
|
// volume is ready and the pool should be reused.
|
||||||
// In this case, also check if rest of the volumes are ready and can
|
// In this case, also check if rest of the volumes are ready and can
|
||||||
// be reused.
|
// be reused.
|
||||||
if (plan.getPoolId() != null || (toBeCreated.getVolumeType() == Volume.Type.DATADISK && toBeCreated.getPoolId() != null && toBeCreated.getState() == Volume.State.Ready)) {
|
if ((plan.getPoolId() != null || (toBeCreated.getVolumeType() == Volume.Type.DATADISK && toBeCreated.getPoolId() != null && toBeCreated.getState() == Volume.State.Ready)) &&
|
||||||
logger.debug("Volume has pool already allocated, checking if pool can be reused, poolId: " + toBeCreated.getPoolId());
|
checkIfPoolCanBeReused(vmProfile, plan, avoid, suitableVolumeStoragePools, readyAndReusedVolumes, toBeCreated)) {
|
||||||
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
|
|
||||||
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)) {
|
|
||||||
long exstPoolDcId = pool.getDataCenterId();
|
|
||||||
long exstPoolPodId = pool.getPodId() != null ? pool.getPodId() : -1;
|
|
||||||
long exstPoolClusterId = pool.getClusterId() != null ? pool.getClusterId() : -1;
|
|
||||||
boolean canReusePool = false;
|
|
||||||
if (plan.getDataCenterId() == exstPoolDcId && plan.getPodId() == exstPoolPodId && plan.getClusterId() == exstPoolClusterId) {
|
|
||||||
canReusePool = true;
|
|
||||||
} else if (plan.getDataCenterId() == exstPoolDcId) {
|
|
||||||
DataStore dataStore = dataStoreMgr.getPrimaryDataStore(pool.getId());
|
|
||||||
if (dataStore != null && dataStore.getScope() != null && dataStore.getScope().getScopeType() == ScopeType.ZONE) {
|
|
||||||
canReusePool = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.debug("Pool of the volume does not fit the specified plan, need to reallocate a pool for this volume");
|
|
||||||
canReusePool = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canReusePool) {
|
|
||||||
logger.debug("Planner need not allocate a pool for this volume since its READY");
|
|
||||||
suitablePools.add(pool);
|
|
||||||
suitableVolumeStoragePools.put(toBeCreated, suitablePools);
|
|
||||||
if (!(toBeCreated.getState() == Volume.State.Allocated || toBeCreated.getState() == Volume.State.Creating)) {
|
|
||||||
readyAndReusedVolumes.add(toBeCreated);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
logger.debug("Pool of the volume is in avoid set, need to reallocate a pool for this volume");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.debug("Pool of the volume is in maintenance, need to reallocate a pool for this volume");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (!isRootAdmin(vmProfile) && !isEnabledForAllocation(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId())) {
|
||||||
logger.debug("We need to allocate new storagepool for this volume");
|
logger.debug(String.format("Cannot find new storage pool to deploy volume [{}] of VM [{}] in cluster [{}] because allocation state is disabled. Returning.",
|
||||||
}
|
toBeCreated.getUuid(), vmProfile.getUuid(), plan.getClusterId()));
|
||||||
if (!isRootAdmin(vmProfile)) {
|
|
||||||
if (!isEnabledForAllocation(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId())) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Cannot allocate new storagepool for this volume in this cluster, allocation state is disabled");
|
|
||||||
logger.debug("Cannot deploy to this specified plan, allocation state is disabled, returning.");
|
|
||||||
}
|
|
||||||
// Cannot find suitable storage pools under this cluster for
|
|
||||||
// this volume since allocation_state is disabled.
|
|
||||||
// - remove any suitable pools found for other volumes.
|
|
||||||
// All volumes should get suitable pools under this cluster;
|
|
||||||
// else we can't use this cluster.
|
|
||||||
suitableVolumeStoragePools.clear();
|
suitableVolumeStoragePools.clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Calling StoragePoolAllocators to find suitable pools");
|
|
||||||
|
|
||||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(toBeCreated.getDiskOfferingId());
|
DiskOfferingVO diskOffering = _diskOfferingDao.findById(toBeCreated.getDiskOfferingId());
|
||||||
|
|
||||||
@ -1783,16 +1766,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
useLocalStorage = diskOffering.isUseLocalStorage();
|
useLocalStorage = diskOffering.isUseLocalStorage();
|
||||||
}
|
}
|
||||||
diskProfile.setUseLocalStorage(useLocalStorage);
|
diskProfile.setUseLocalStorage(useLocalStorage);
|
||||||
|
logger.debug(String.format("Calling StoragePoolAllocators to find suitable pools to allocate volume [{}] necessary to deploy VM [{}].", toBeCreated.getUuid(), vmProfile.getUuid()));
|
||||||
boolean foundPotentialPools = false;
|
boolean foundPotentialPools = tryToFindPotentialPoolsToAlocateVolume(vmProfile, plan, avoid, returnUpTo, suitableVolumeStoragePools, toBeCreated, diskProfile);
|
||||||
for (StoragePoolAllocator allocator : _storagePoolAllocators) {
|
|
||||||
final List<StoragePool> suitablePools = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid, returnUpTo);
|
|
||||||
if (suitablePools != null && !suitablePools.isEmpty()) {
|
|
||||||
checkForPreferredStoragePool(suitablePools, vmProfile.getVirtualMachine(), suitableVolumeStoragePools, toBeCreated);
|
|
||||||
foundPotentialPools = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avoid.getPoolsToAvoid() != null) {
|
if (avoid.getPoolsToAvoid() != null) {
|
||||||
poolsToAvoidOutput.addAll(avoid.getPoolsToAvoid());
|
poolsToAvoidOutput.addAll(avoid.getPoolsToAvoid());
|
||||||
@ -1800,7 +1775,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!foundPotentialPools) {
|
if (!foundPotentialPools) {
|
||||||
logger.debug("No suitable pools found for volume: " + toBeCreated + " under cluster: " + plan.getClusterId());
|
logger.debug(String.format("No suitable pools found for volume [{}] used by VM [{}] under cluster: [{}].", toBeCreated.getUuid(), vmProfile.getUuid(), plan.getClusterId()));
|
||||||
// No suitable storage pools found under this cluster for this
|
// No suitable storage pools found under this cluster for this
|
||||||
// volume. - remove any suitable pools found for other volumes.
|
// volume. - remove any suitable pools found for other volumes.
|
||||||
// All volumes should get suitable pools under this cluster;
|
// All volumes should get suitable pools under this cluster;
|
||||||
@ -1829,6 +1804,75 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
return new Pair<Map<Volume, List<StoragePool>>, List<Volume>>(suitableVolumeStoragePools, readyAndReusedVolumes);
|
return new Pair<Map<Volume, List<StoragePool>>, List<Volume>>(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>();
|
||||||
|
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,
|
private void checkForPreferredStoragePool(List<StoragePool> suitablePools,
|
||||||
VirtualMachine vm,
|
VirtualMachine vm,
|
||||||
Map<Volume, List<StoragePool>> suitableVolumeStoragePools,
|
Map<Volume, List<StoragePool>> suitableVolumeStoragePools,
|
||||||
@ -1972,6 +2016,9 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String logDeploymentWithoutException(VirtualMachine vm, DeploymentPlan plan, ExcludeList avoids, DeploymentPlanner planner) {
|
||||||
|
return LogUtils.logGsonWithoutException("Trying to deploy VM [%s] and details: Plan [%s]; avoid list [%s] and planner: [%s].", vm, plan, avoids, planner);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[] {allowRouterOnDisabledResource, allowAdminVmOnDisabledResource};
|
return new ConfigKey<?>[] {allowRouterOnDisabledResource, allowAdminVmOnDisabledResource};
|
||||||
|
|||||||
@ -252,7 +252,9 @@ public class DeploymentPlanningManagerImplTest {
|
|||||||
Mockito.when(template.isDeployAsIs()).thenReturn(false);
|
Mockito.when(template.isDeployAsIs()).thenReturn(false);
|
||||||
Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(template);
|
Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(template);
|
||||||
|
|
||||||
VMInstanceVO vm = new VMInstanceVO();
|
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
|
||||||
|
Mockito.when(vm.getType()).thenReturn(Type.Instance);
|
||||||
|
Mockito.when(vm.getLastHostId()).thenReturn(null);
|
||||||
Mockito.when(vmProfile.getVirtualMachine()).thenReturn(vm);
|
Mockito.when(vmProfile.getVirtualMachine()).thenReturn(vm);
|
||||||
Mockito.when(vmProfile.getId()).thenReturn(instanceId);
|
Mockito.when(vmProfile.getId()).thenReturn(instanceId);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user