Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/host/Host.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public static String[] toStrings(Host.Type... types) {
String HOST_OVFTOOL_VERSION = "host.ovftool.version";
String HOST_VIRTV2V_VERSION = "host.virtv2v.version";
String HOST_SSH_PORT = "host.ssh.port";
String GUEST_OS_CATEGORY_ID = "guest.os.category.id";
String GUEST_OS_RULE = "guest.os.rule";

int DEFAULT_SSH_PORT = 22;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ public class ApiConstants {
public static final String MAX_VGPU_PER_PHYSICAL_GPU = "maxvgpuperphysicalgpu";
public static final String GUEST_OS_LIST = "guestoslist";
public static final String GUEST_OS_COUNT = "guestoscount";
public static final String GUEST_OS_RULE = "guestosrule";
public static final String OS_MAPPING_CHECK_ENABLED = "osmappingcheckenabled";
public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,14 @@ public class UpdateHostCmd extends BaseCmd {
@Parameter(name = ApiConstants.OS_CATEGORY_ID,
type = CommandType.UUID,
entityType = GuestOSCategoryResponse.class,
description = "The ID of OS category to update the host with")
description = "the ID of OS category used to prioritize VMs with matching OS category during the allocation process. " +
"It cannot be used alongside the 'guestosrule' parameter.")
private Long osCategoryId;

@Parameter(name = ApiConstants.GUEST_OS_RULE, type = CommandType.STRING, description = "the guest OS rule written in JavaScript to match with the OS of the VM." +
"It cannot be used alongside the 'oscategoryid' parameter.")
private String guestOsRule;

@Parameter(name = ApiConstants.ALLOCATION_STATE,
type = CommandType.STRING,
description = "Change resource state of host, valid values are [Enable, Disable]. Operation may failed if host in states not allowing Enable/Disable")
Expand Down Expand Up @@ -96,6 +101,10 @@ public Long getOsCategoryId() {
return osCategoryId;
}

public String getGuestOsRule() {
return guestOsRule;
}

public String getAllocationState() {
return allocationState;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
@Param(description = "The OS category name of the host")
private String osCategoryName;

@SerializedName(ApiConstants.GUEST_OS_RULE)
@Param(description = "the guest OS rule")
private String guestOsRule;

@SerializedName(ApiConstants.IP_ADDRESS)
@Param(description = "The IP address of the host")
private String ipAddress;
Expand Down Expand Up @@ -999,4 +1003,12 @@ public void setExtensionName(String extensionName) {
public String getExtensionName() {
return extensionName;
}

public String getGuestOsRule() {
return guestOsRule;
}

public void setGuestOsRule(String guestOsRule) {
this.guestOsRule = guestOsRule;
}
}
5 changes: 3 additions & 2 deletions engine/schema/src/main/java/com/cloud/host/HostVO.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
import com.cloud.cpu.CPU;
import org.apache.cloudstack.util.CPUArchConverter;
import org.apache.cloudstack.util.HypervisorTypeConverter;
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
import org.apache.cloudstack.utils.jsinterpreter.GenericRuleHelper;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.BooleanUtils;
Expand Down Expand Up @@ -856,7 +856,8 @@ public boolean checkHostServiceOfferingTags(ServiceOffering serviceOffering) {
}

if (BooleanUtils.isTrue(this.getIsTagARule())) {
return TagAsRuleHelper.interpretTagAsRule(this.getHostTags().get(0), serviceOffering.getHostTag(), HostTagsDao.hostTagRuleExecutionTimeout.value());
return GenericRuleHelper.interpretTagAsRule(this.getHostTags().get(0), serviceOffering.getHostTag(), HostTagsDao.hostTagRuleExecutionTimeout.value(),
HostTagsDao.hostTagRuleExecutionTimeout.key());
}

if (StringUtils.isEmpty(serviceOffering.getHostTag())) {
Expand Down
7 changes: 7 additions & 0 deletions engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.fsm.StateDao;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.config.ConfigKey;

/**
* Data Access Object for server
*
*/
public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Status.Event, Host> {

ConfigKey<Long> guestOsRuleExecutionTimeout = new ConfigKey<>("Advanced", Long.class, "guest.os.rule.execution.timeout", "3000", "The maximum runtime, in milliseconds, " +
"to execute a guest OS rule; if it is reached, a timeout will happen.", true);

long countBy(long clusterId, ResourceState... states);

Integer countAllByType(final Host.Type type);
Expand Down Expand Up @@ -220,6 +225,8 @@ int countHostsByMsResourceStateTypeAndHypervisorType(long msId, List<ResourceSta

List<HostVO> findHostsWithTagRuleThatMatchComputeOfferingTags(String computeOfferingTags);

List<HostVO> findHostsWithGuestOsRulesThatDidNotMatchOsOfGuestVm(String templateGuestOSName);

List<Long> findClustersThatMatchHostTagRule(String computeOfferingTags);

List<Long> listSsvmHostsWithPendingMigrateJobsOrderedByJobCount();
Expand Down
37 changes: 34 additions & 3 deletions engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@

import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.utils.jsinterpreter.GenericRuleHelper;
import org.apache.commons.collections.CollectionUtils;

import com.cloud.agent.api.VgpuTypesInfo;
Expand Down Expand Up @@ -84,7 +86,7 @@

@DB
@TableGenerator(name = "host_req_sq", table = "op_host", pkColumnName = "id", valueColumnName = "sequence", allocationSize = 1)
public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao { //FIXME: , ExternalIdDao {
public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao, Configurable {

private static final String LIST_HOST_IDS_BY_HOST_TAGS = "SELECT filtered.host_id, COUNT(filtered.tag) AS tag_count "
+ "FROM (SELECT host_id, tag, is_tag_a_rule FROM host_tags GROUP BY host_id,tag,is_tag_a_rule) AS filtered "
Expand Down Expand Up @@ -1520,18 +1522,37 @@ private List<Long> findHostIdsByHostTags(String hostTags){
}
}

@Override
public List<HostVO> findHostsWithTagRuleThatMatchComputeOfferingTags(String computeOfferingTags) {
List<HostTagVO> hostTagVOList = _hostTagsDao.findHostRuleTags();
List<HostVO> result = new ArrayList<>();
for (HostTagVO rule: hostTagVOList) {
if (TagAsRuleHelper.interpretTagAsRule(rule.getTag(), computeOfferingTags, HostTagsDao.hostTagRuleExecutionTimeout.value())) {
if (GenericRuleHelper.interpretTagAsRule(rule.getTag(), computeOfferingTags, HostTagsDao.hostTagRuleExecutionTimeout.value(),
HostTagsDao.hostTagRuleExecutionTimeout.key())) {
result.add(findById(rule.getHostId()));
}
}

return result;
}

@Override
public List<HostVO> findHostsWithGuestOsRulesThatDidNotMatchOsOfGuestVm(String templateGuestOSName) {
List<DetailVO> hostIdsWithGuestOsRule = _detailsDao.findByName(Host.GUEST_OS_RULE);
List<HostVO> hostsWithIncompatibleRules = new ArrayList<>();
for (DetailVO guestOsRule : hostIdsWithGuestOsRule) {
if (!GenericRuleHelper.interpretGuestOsRule(guestOsRule.getValue(), templateGuestOSName, HostDao.guestOsRuleExecutionTimeout.value(),
HostDao.guestOsRuleExecutionTimeout.key())) {
logger.trace("The guest OS rule [{}] of the host with ID [{}] is incompatible with the OS of the VM.",
guestOsRule.getHostId(), guestOsRule.getValue());
hostsWithIncompatibleRules.add(findById(guestOsRule.getHostId()));
}
}
logger.trace("The hosts with the following IDs [{}] are incompatible with the VM considering their guest OS rule.",
hostsWithIncompatibleRules);
return hostsWithIncompatibleRules;
}

public List<Long> findClustersThatMatchHostTagRule(String computeOfferingTags) {
Set<Long> result = new HashSet<>();
List<HostVO> hosts = findHostsWithTagRuleThatMatchComputeOfferingTags(computeOfferingTags);
Expand Down Expand Up @@ -1984,4 +2005,14 @@ public List<String> listDistinctStorageAccessGroups(String name, String keyword)

return customSearch(sc, null);
}

@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {guestOsRuleExecutionTimeout};
}

@Override
public String getConfigComponentName() {
return HostDaoImpl.class.getSimpleName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ SELECT
guest_os_category.id guest_os_category_id,
guest_os_category.uuid guest_os_category_uuid,
guest_os_category.name guest_os_category_name,
(SELECT `value` FROM `cloud`.`host_details` `hd` WHERE `hd`.`host_id` = `cloud`.`host`.`id` AND `hd`.`name` = 'guest.os.rule') AS `guest_os_rule`,
mem_caps.used_capacity memory_used_capacity,
mem_caps.reserved_capacity memory_reserved_capacity,
cpu_caps.used_capacity cpu_used_capacity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO

List<Pair<UsageVO, QuotaUsageVO>> pairsUsageAndQuotaUsage = new ArrayList<>();

try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value())) {
try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value(), QuotaConfig.QuotaActivationRuleTimeout.key())) {
for (UsageVO usageRecord : usageRecords) {
int usageType = usageRecord.getUsageType();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,7 @@ public QuotaValidateActivationRuleResponse validateActivationRule(QuotaValidateA
addAllPresetVariables(PresetVariables.class, quotaType, usageTypeVariablesAndDescriptions, null);
List<String> usageTypeVariables = usageTypeVariablesAndDescriptions.stream().map(Pair::first).collect(Collectors.toList());

try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value())) {
try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value(), QuotaConfig.QuotaActivationRuleTimeout.key())) {
Map<String, String> newVariables = injectUsageTypeVariables(jsInterpreter, usageTypeVariables);
String scriptToExecute = jsInterpreterHelper.replaceScriptVariables(activationRule, newVariables);
jsInterpreter.executeScript(String.format("new Function(\"%s\")", scriptToExecute.replaceAll("\n", "")));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
package com.cloud.agent.manager.allocator.impl;

import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.api.ApiDBUtils;
import com.cloud.capacity.CapacityManager;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.VMTemplateVO;
import com.cloud.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import org.apache.commons.collections.CollectionUtils;
Expand Down Expand Up @@ -69,6 +71,29 @@ protected void addHostsBasedOnTagRules(String hostTagOnOffering, List<HostVO> cl
clusterHosts.addAll(hostsWithTagRules);
}

protected void filterHostsBasedOnGuestOsRules(VMTemplateVO vmTemplate, List<? extends Host> clusterHosts) {
if (clusterHosts.isEmpty()) {
logger.info("Will not filter hosts based on guest OS as there is no available hosts left to verify.");
return;
}

String templateGuestOSName = ApiDBUtils.getTemplateGuestOSName(vmTemplate);
List<HostVO> incompatibleHosts = hostDao.findHostsWithGuestOsRulesThatDidNotMatchOsOfGuestVm(templateGuestOSName);

if (incompatibleHosts.isEmpty()) {
logger.info("No incompatible hosts found with guest OS rules matching the VM guest OS [{}].", templateGuestOSName);
return;
}

logger.info("Found incompatible hosts {} with guest OS rules that did not match the VM guest OS [{}]. They will be removed from the suitable hosts list.",
incompatibleHosts, templateGuestOSName);
clusterHosts.removeAll(incompatibleHosts);

if (clusterHosts.isEmpty()) {
logger.info("After filtering by guest OS rules, no compatible hosts were found for VM with OS [{}].", templateGuestOSName);
}
}

/**
* Adds hosts with enough CPU capability and enough CPU capacity to the suitable hosts list.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan pla
String hostTagOnTemplate = template.getTemplateTag();
String paramAsStringToLog = String.format("zone [%s], pod [%s], cluster [%s]", dcId, podId, clusterId);

List<HostVO> suitableHosts = retrieveHosts(vmProfile, type, (List<HostVO>) hosts, clusterId, podId, dcId, hostTagOnOffering, hostTagOnTemplate);
List<HostVO> suitableHosts = retrieveHosts(vmProfile, type, (List<HostVO>) hosts, template, clusterId, podId, dcId, hostTagOnOffering, hostTagOnTemplate);

if (suitableHosts.isEmpty()) {
logger.info("No suitable host found for VM [{}] in {}.", vmProfile, paramAsStringToLog);
Expand All @@ -137,8 +137,8 @@ public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan pla
return allocateTo(vmProfile, plan, offering, template, avoid, suitableHosts, returnUpTo, considerReservedCapacity, account);
}

protected List<HostVO> retrieveHosts(VirtualMachineProfile vmProfile, Type type, List<HostVO> hostsToFilter, Long clusterId, Long podId, long dcId, String hostTagOnOffering,
String hostTagOnTemplate) {
protected List<HostVO> retrieveHosts(VirtualMachineProfile vmProfile, Type type, List<HostVO> hostsToFilter, VMTemplateVO template,
Long clusterId, Long podId, long dcId, String hostTagOnOffering, String hostTagOnTemplate) {
String haVmTag = (String) vmProfile.getParameter(VirtualMachineProfile.Param.HaTag);
List<HostVO> clusterHosts;

Expand All @@ -159,6 +159,7 @@ protected List<HostVO> retrieveHosts(VirtualMachineProfile vmProfile, Type type,
filterHostsWithUefiEnabled(type, vmProfile, clusterId, podId, dcId, clusterHosts);

addHostsBasedOnTagRules(hostTagOnOffering, clusterHosts);
filterHostsBasedOnGuestOsRules(template, clusterHosts);

return clusterHosts;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class RandomAllocator extends BaseAllocator {
private ResourceManager _resourceMgr;

protected List<Host> findSuitableHosts(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, List<? extends Host> hosts, int returnUpTo,
boolean considerReservedCapacity) {
boolean considerReservedCapacity) {
if (type == Host.Type.Storage) {
return null;
}
Expand Down Expand Up @@ -115,6 +115,7 @@ protected List<HostVO> retrieveHosts(Type type, List<HostVO> hosts, VMTemplateVO
}

addHostsBasedOnTagRules(offeringHostTag, availableHosts);
filterHostsBasedOnGuestOsRules(template, availableHosts);

return availableHosts;
}
Expand Down
12 changes: 12 additions & 0 deletions server/src/main/java/com/cloud/api/ApiDBUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import javax.inject.Inject;

import com.cloud.cpu.CPU;
import com.cloud.storage.GuestOSVO;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.affinity.AffinityGroup;
Expand Down Expand Up @@ -2345,4 +2346,15 @@ public static SharedFSJoinVO newSharedFSView(SharedFS sharedFS) {
public static List<CPU.CPUArch> listZoneClustersArchs(long zoneId) {
return s_clusterDao.getClustersArchsByZone(zoneId);
}

public static String getTemplateGuestOSName(VMTemplateVO template) {
long guestOSId = template.getGuestOSId();
GuestOSVO guestOS = s_guestOSDao.findById(guestOSId);

if (guestOS == null) {
return null;
}

return guestOS.getDisplayName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ private void setNewHostResponseBase(HostJoinVO host, EnumSet<HostDetails> detail
hostResponse.setHaHost(containsHostHATag(hostTags));
hostResponse.setExplicitHostTags(host.getExplicitTag());
hostResponse.setImplicitHostTags(host.getImplicitTag());
hostResponse.setGuestOsRule(host.getGuestOsRule());

hostResponse.setHypervisorVersion(host.getHypervisorVersion());
if (host.getArch() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
import org.apache.cloudstack.utils.jsinterpreter.GenericRuleHelper;
import org.springframework.stereotype.Component;

import com.cloud.api.ApiDBUtils;
Expand Down Expand Up @@ -398,7 +398,8 @@ public List<StoragePoolVO> findStoragePoolByScopeAndRuleTags(Long datacenterId,
String injectableTag = injectableTagsBuilder.toString();

for (StoragePoolJoinVO storagePoolJoinVO : storagePools) {
if (TagAsRuleHelper.interpretTagAsRule(storagePoolJoinVO.getTag(), injectableTag, VolumeApiServiceImpl.storageTagRuleExecutionTimeout.value())) {
if (GenericRuleHelper.interpretTagAsRule(storagePoolJoinVO.getTag(), injectableTag, VolumeApiServiceImpl.storageTagRuleExecutionTimeout.value(),
VolumeApiServiceImpl.storageTagRuleExecutionTimeout.key())) {
StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolJoinVO.getId());
if (storagePoolVO != null) {
filteredPools.add(storagePoolVO);
Expand Down
7 changes: 7 additions & 0 deletions server/src/main/java/com/cloud/api/query/vo/HostJoinVO.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity
@Column(name = "guest_os_category_name")
private String osCategoryName;

@Column(name = "guest_os_rule")
private String guestOsRule;

@Column(name = "tag")
private String tag;

Expand Down Expand Up @@ -373,6 +376,10 @@ public String getOsCategoryName() {
return osCategoryName;
}

public String getGuestOsRule() {
return guestOsRule;
}

public Long getJobId() {
return jobId;
}
Expand Down
Loading
Loading