Skip to content
Open
Show file tree
Hide file tree
Changes from all 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