Skip to content

Commit abc778e

Browse files
committed
Add guest OS rule feature
1 parent 1e91276 commit abc778e

File tree

28 files changed

+336
-89
lines changed

28 files changed

+336
-89
lines changed

api/src/main/java/com/cloud/host/Host.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ public static String[] toStrings(Host.Type... types) {
5656
public static final String HOST_UEFI_ENABLE = "host.uefi.enable";
5757
public static final String HOST_VOLUME_ENCRYPTION = "host.volume.encryption";
5858
public static final String HOST_INSTANCE_CONVERSION = "host.instance.conversion";
59+
String GUEST_OS_CATEGORY_ID = "guest.os.category.id";
60+
String GUEST_OS_RULE = "guest.os.rule";
5961

6062
/**
6163
* @return name of the machine.

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ public class ApiConstants {
362362
public static final String OS_NAME_FOR_HYPERVISOR = "osnameforhypervisor";
363363
public static final String GUEST_OS_LIST = "guestoslist";
364364
public static final String GUEST_OS_COUNT = "guestoscount";
365+
public static final String GUEST_OS_RULE = "guestosrule";
365366
public static final String OS_MAPPING_CHECK_ENABLED = "osmappingcheckenabled";
366367
public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
367368
public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";

api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,14 @@ public class UpdateHostCmd extends BaseCmd {
4747
@Parameter(name = ApiConstants.OS_CATEGORY_ID,
4848
type = CommandType.UUID,
4949
entityType = GuestOSCategoryResponse.class,
50-
description = "the id of Os category to update the host with")
50+
description = "the ID of OS category used to prioritize VMs with matching OS category during the allocation process." +
51+
" It cannot be used alongside the `guestosrule` parameter.")
5152
private Long osCategoryId;
5253

54+
@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." +
55+
"It cannot be used alongside the `oscategoryid` parameter.")
56+
private String guestOsRule;
57+
5358
@Parameter(name = ApiConstants.ALLOCATION_STATE,
5459
type = CommandType.STRING,
5560
description = "Change resource state of host, valid values are [Enable, Disable]. Operation may failed if host in states not allowing Enable/Disable")
@@ -83,6 +88,10 @@ public Long getOsCategoryId() {
8388
return osCategoryId;
8489
}
8590

91+
public String getGuestOsRule() {
92+
return guestOsRule;
93+
}
94+
8695
public String getAllocationState() {
8796
return allocationState;
8897
}

api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
6363
@Param(description = "the OS category name of the host")
6464
private String osCategoryName;
6565

66+
@SerializedName(ApiConstants.GUEST_OS_RULE)
67+
@Param(description = "the guest OS rule")
68+
private String guestOsRule;
69+
6670
@SerializedName(ApiConstants.IP_ADDRESS)
6771
@Param(description = "the IP address of the host")
6872
private String ipAddress;
@@ -870,4 +874,8 @@ public Boolean getEncryptionSupported() {
870874
public Boolean getInstanceConversionSupported() {
871875
return instanceConversionSupported;
872876
}
877+
878+
public void setGuestOsRule(String guestOsRule) {
879+
this.guestOsRule = guestOsRule;
880+
}
873881
}

engine/schema/src/main/java/com/cloud/host/HostVO.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
import com.cloud.cpu.CPU;
4646
import org.apache.cloudstack.util.CPUArchConverter;
4747
import org.apache.cloudstack.util.HypervisorTypeConverter;
48-
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
48+
import org.apache.cloudstack.utils.jsinterpreter.GenericRuleHelper;
4949
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
5050
import org.apache.commons.collections.CollectionUtils;
5151
import org.apache.commons.lang.BooleanUtils;
@@ -832,7 +832,8 @@ public boolean checkHostServiceOfferingTags(ServiceOffering serviceOffering) {
832832
}
833833

834834
if (BooleanUtils.isTrue(this.getIsTagARule())) {
835-
return TagAsRuleHelper.interpretTagAsRule(this.getHostTags().get(0), serviceOffering.getHostTag(), HostTagsDao.hostTagRuleExecutionTimeout.value());
835+
return GenericRuleHelper.interpretTagAsRule(this.getHostTags().get(0), serviceOffering.getHostTag(), HostTagsDao.hostTagRuleExecutionTimeout.value(),
836+
HostTagsDao.hostTagRuleExecutionTimeout.key());
836837
}
837838

838839
if (StringUtils.isEmpty(serviceOffering.getHostTag())) {

engine/schema/src/main/java/com/cloud/host/dao/HostDao.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,17 @@
2929
import com.cloud.resource.ResourceState;
3030
import com.cloud.utils.db.GenericDao;
3131
import com.cloud.utils.fsm.StateDao;
32+
import org.apache.cloudstack.framework.config.ConfigKey;
3233

3334
/**
3435
* Data Access Object for server
3536
*
3637
*/
3738
public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Status.Event, Host> {
39+
40+
ConfigKey<Long> guestOsRuleExecutionTimeout = new ConfigKey<>("Advanced", Long.class, "guest.os.rule.execution.timeout", "3000", "The maximum runtime, in milliseconds, " +
41+
"to execute a guest OS rule; if it is reached, a timeout will happen.", true);
42+
3843
long countBy(long clusterId, ResourceState... states);
3944

4045
Integer countAllByType(final Host.Type type);
@@ -171,4 +176,6 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
171176
List<Long> findClustersThatMatchHostTagRule(String computeOfferingTags);
172177

173178
List<Long> listSsvmHostsWithPendingMigrateJobsOrderedByJobCount();
179+
180+
List<HostVO> findHostsWithGuestOsRulesThatDidNotMatchOsOfGuestVm(String templateGuestOSName);
174181
}

engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
import javax.inject.Inject;
3535
import javax.persistence.TableGenerator;
3636

37-
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
37+
import org.apache.cloudstack.framework.config.ConfigKey;
38+
import org.apache.cloudstack.framework.config.Configurable;
39+
import org.apache.cloudstack.utils.jsinterpreter.GenericRuleHelper;
3840
import org.apache.commons.collections.CollectionUtils;
3941

4042
import com.cloud.agent.api.VgpuTypesInfo;
@@ -78,7 +80,7 @@
7880

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

8385
private static final String LIST_HOST_IDS_BY_COMPUTETAGS = "SELECT filtered.host_id, COUNT(filtered.tag) AS tag_count "
8486
+ "FROM (SELECT host_id, tag, is_tag_a_rule FROM host_tags GROUP BY host_id,tag) AS filtered "
@@ -1350,18 +1352,36 @@ private List<Long> findHostByComputeOfferings(String computeOfferingTags){
13501352
}
13511353
}
13521354

1355+
@Override
13531356
public List<HostVO> findHostsWithTagRuleThatMatchComputeOfferingTags(String computeOfferingTags) {
13541357
List<HostTagVO> hostTagVOList = _hostTagsDao.findHostRuleTags();
13551358
List<HostVO> result = new ArrayList<>();
13561359
for (HostTagVO rule: hostTagVOList) {
1357-
if (TagAsRuleHelper.interpretTagAsRule(rule.getTag(), computeOfferingTags, HostTagsDao.hostTagRuleExecutionTimeout.value())) {
1360+
if (GenericRuleHelper.interpretTagAsRule(rule.getTag(), computeOfferingTags, HostTagsDao.hostTagRuleExecutionTimeout.value(),
1361+
HostTagsDao.hostTagRuleExecutionTimeout.key())) {
13581362
result.add(findById(rule.getHostId()));
13591363
}
13601364
}
13611365

13621366
return result;
13631367
}
13641368

1369+
@Override
1370+
public List<HostVO> findHostsWithGuestOsRulesThatDidNotMatchOsOfGuestVm(String templateGuestOSName) {
1371+
List<DetailVO> hostIdsWithGuestOsRule = _detailsDao.findByName(Host.GUEST_OS_RULE);
1372+
List<HostVO> hostsWithIncompatibleRules = new ArrayList<>();
1373+
for (DetailVO guestOsRule : hostIdsWithGuestOsRule) {
1374+
if (!GenericRuleHelper.interpretGuestOsRule(guestOsRule.getValue(), templateGuestOSName, HostDao.guestOsRuleExecutionTimeout.value(),
1375+
HostDao.guestOsRuleExecutionTimeout.key())) {
1376+
logger.trace("The guest OS rule [{}] of the host with ID [{}] is incompatible with the OS of the VM.", guestOsRule.getHostId(), guestOsRule.getValue());
1377+
hostsWithIncompatibleRules.add(findById(guestOsRule.getHostId()));
1378+
}
1379+
}
1380+
logger.trace("The hosts with the following IDs [{}] are incompatible with the VM considering their guest OS rule.", hostsWithIncompatibleRules);
1381+
return hostsWithIncompatibleRules;
1382+
}
1383+
1384+
@Override
13651385
public List<Long> findClustersThatMatchHostTagRule(String computeOfferingTags) {
13661386
Set<Long> result = new HashSet<>();
13671387
List<HostVO> hosts = findHostsWithTagRuleThatMatchComputeOfferingTags(computeOfferingTags);
@@ -1602,4 +1622,14 @@ private String createSqlFindHostToExecuteCommand(boolean useDisabledHosts) {
16021622
}
16031623
return String.format(sqlFindHostInZoneToExecuteCommand, hostResourceStatus);
16041624
}
1625+
1626+
@Override
1627+
public ConfigKey<?>[] getConfigKeys() {
1628+
return new ConfigKey<?>[] {guestOsRuleExecutionTimeout};
1629+
}
1630+
1631+
@Override
1632+
public String getConfigComponentName() {
1633+
return HostDaoImpl.class.getSimpleName();
1634+
}
16051635
}

engine/schema/src/main/resources/META-INF/db/views/cloud.host_view.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ SELECT
6060
guest_os_category.id guest_os_category_id,
6161
guest_os_category.uuid guest_os_category_uuid,
6262
guest_os_category.name guest_os_category_name,
63+
(SELECT `value` FROM `cloud`.`host_details` `hd` WHERE `hd`.`host_id` = `cloud`.`host`.`id` AND `hd`.`name` = 'guest.os.rule') AS `guest_os_rule`,
6364
mem_caps.used_capacity memory_used_capacity,
6465
mem_caps.reserved_capacity memory_reserved_capacity,
6566
cpu_caps.used_capacity cpu_used_capacity,

framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO
311311

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

314-
try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value())) {
314+
try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value(), QuotaConfig.QuotaActivationRuleTimeout.key())) {
315315
for (UsageVO usageRecord : usageRecords) {
316316
int usageType = usageRecord.getUsageType();
317317

server/src/main/java/com/cloud/agent/manager/allocator/impl/BaseAllocator.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
package com.cloud.agent.manager.allocator.impl;
1818

1919
import com.cloud.agent.manager.allocator.HostAllocator;
20+
import com.cloud.api.ApiDBUtils;
2021
import com.cloud.capacity.CapacityManager;
2122
import com.cloud.host.Host;
2223
import com.cloud.host.HostVO;
2324
import com.cloud.host.dao.HostDao;
2425
import com.cloud.offering.ServiceOffering;
26+
import com.cloud.storage.VMTemplateVO;
2527
import com.cloud.utils.Pair;
2628
import com.cloud.utils.component.AdapterBase;
2729
import org.apache.commons.collections.CollectionUtils;
@@ -69,6 +71,29 @@ protected void addHostsBasedOnTagRules(String hostTagOnOffering, List<HostVO> cl
6971
clusterHosts.addAll(hostsWithTagRules);
7072
}
7173

74+
protected void filterHostsBasedOnGuestOsRules(VMTemplateVO vmTemplate, List<? extends Host> clusterHosts) {
75+
if (clusterHosts.isEmpty()) {
76+
logger.info("Will not filter hosts based on guest OS as there is no available hosts left to verify.");
77+
return;
78+
}
79+
80+
String templateGuestOSName = ApiDBUtils.getTemplateGuestOSName(vmTemplate);
81+
List<HostVO> incompatibleHosts = hostDao.findHostsWithGuestOsRulesThatDidNotMatchOsOfGuestVm(templateGuestOSName);
82+
83+
if (incompatibleHosts.isEmpty()) {
84+
logger.info("No incompatible hosts found with guest OS rules matching the VM guest OS [{}].", templateGuestOSName);
85+
return;
86+
}
87+
88+
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.",
89+
incompatibleHosts, templateGuestOSName);
90+
clusterHosts.removeAll(incompatibleHosts);
91+
92+
if (clusterHosts.isEmpty()) {
93+
logger.info("After filtering by guest OS rules, no compatible hosts were found for VM with OS [{}].", templateGuestOSName);
94+
}
95+
}
96+
7297
/**
7398
* Adds hosts with enough CPU capability and enough CPU capacity to the suitable hosts list.
7499
*/

0 commit comments

Comments
 (0)