diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java index c9254814f46..a03f82a4358 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -34,6 +34,7 @@ import javax.naming.ConfigurationException; import com.cloud.user.Account; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.quota.activationrule.presetvariables.Configuration; import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable; import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper; import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariables; @@ -467,6 +468,11 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { } + Configuration configuration = presetVariables.getConfiguration(); + if (configuration != null) { + jsInterpreter.injectVariable("configuration", configuration.toString()); + } + jsInterpreter.injectStringVariable("resourceType", presetVariables.getResourceType()); jsInterpreter.injectVariable("value", presetVariables.getValue().toString()); jsInterpreter.injectVariable("zone", presetVariables.getZone().toString()); diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/ComputeOffering.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/ComputeOffering.java index 1d294276d47..09182711ca8 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/ComputeOffering.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/ComputeOffering.java @@ -17,10 +17,15 @@ package org.apache.cloudstack.quota.activationrule.presetvariables; +import org.apache.cloudstack.quota.constant.QuotaTypes; + public class ComputeOffering extends GenericPresetVariable { @PresetVariableDefinition(description = "A boolean informing if the compute offering is customized or not.") private boolean customized; + @PresetVariableDefinition(description = "A boolean informing if the compute offering offers HA or not.", supportedTypes = {QuotaTypes.RUNNING_VM}) + private boolean offerHa; + public boolean isCustomized() { return customized; } @@ -30,4 +35,13 @@ public class ComputeOffering extends GenericPresetVariable { fieldNamesToIncludeInToString.add("customized"); } + public boolean offerHa() { + return offerHa; + } + + public void setOfferHa(boolean offerHa) { + this.offerHa = offerHa; + fieldNamesToIncludeInToString.add("offerHa"); + } + } diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Configuration.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Configuration.java new file mode 100644 index 00000000000..e59f78af8d9 --- /dev/null +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Configuration.java @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.quota.activationrule.presetvariables; + +import org.apache.cloudstack.quota.constant.QuotaTypes; + +public class Configuration extends GenericPresetVariable{ + + @PresetVariableDefinition(description = "A boolean informing if the cluster configuration force.ha is enabled or not.", supportedTypes = {QuotaTypes.RUNNING_VM}) + private boolean forceHa; + + public boolean getForceHa() { + return forceHa; + } + + public void setForceHa(boolean forceHa) { + this.forceHa = forceHa; + fieldNamesToIncludeInToString.add("forceHa"); + } +} diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelper.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelper.java index b94b7de1b7b..05b75f4f64d 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelper.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelper.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; import com.cloud.host.HostTagVO; import com.cloud.network.dao.NetworkVO; import com.cloud.network.vpc.VpcVO; @@ -37,6 +39,7 @@ import org.apache.cloudstack.acl.dao.RoleDao; import org.apache.cloudstack.backup.BackupOfferingVO; import org.apache.cloudstack.backup.dao.BackupOfferingDao; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.quota.constant.QuotaTypes; import org.apache.cloudstack.quota.dao.NetworkDao; import org.apache.cloudstack.quota.dao.VmTemplateDao; @@ -51,6 +54,7 @@ import org.apache.cloudstack.usage.UsageTypes; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; import org.apache.cloudstack.utils.jsinterpreter.JsInterpreter; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.springframework.stereotype.Component; @@ -181,6 +185,11 @@ public class PresetVariableHelper { @Inject VpcDao vpcDao; + @Inject + ConfigurationDao configDao; + + @Inject + ClusterDetailsDao clusterDetailsDao; protected boolean backupSnapshotAfterTakingSnapshot = SnapshotInfo.BackupSnapshotAfterTakingSnapshot.value(); @@ -194,6 +203,7 @@ public class PresetVariableHelper { presetVariables.setAccount(getPresetVariableAccount(usageRecord.getAccountId())); setPresetVariableProject(presetVariables); + setPresetVariableConfiguration(presetVariables, usageRecord); presetVariables.setDomain(getPresetVariableDomain(usageRecord.getDomainId())); presetVariables.setResourceType(usageRecord.getType()); @@ -272,6 +282,39 @@ public class PresetVariableHelper { return zone; } + protected void setPresetVariableConfiguration(PresetVariables presetVariables, UsageVO usageRecord) { + if (usageRecord.getUsageType() != UsageTypes.RUNNING_VM) { + return; + } + + Configuration configuration = new Configuration(); + setForceHaInConfiguration(configuration, usageRecord); + + presetVariables.setConfiguration(configuration); + } + + protected void setForceHaInConfiguration(Configuration configuration, UsageVO usageRecord) { + Long vmId = usageRecord.getUsageId(); + VMInstanceVO vmVo = vmInstanceDao.findByIdIncludingRemoved(vmId); + validateIfObjectIsNull(vmVo, vmId, "VM"); + + Long hostId = ObjectUtils.defaultIfNull(vmVo.getHostId(), vmVo.getLastHostId()); + + HostVO hostVo = hostDao.findByIdIncludingRemoved(hostId); + validateIfObjectIsNull(hostVo, hostId, "host"); + ClusterDetailsVO forceHa = clusterDetailsDao.findDetail(hostVo.getClusterId(), "force.ha"); + + String forceHaValue; + + if (forceHa != null) { + forceHaValue = forceHa.getValue(); + } else { + forceHaValue = configDao.getValue("force.ha"); + } + + configuration.setForceHa((Boolean.parseBoolean(forceHaValue))); + } + protected Value getPresetVariableValue(UsageVO usageRecord) { Long accountId = usageRecord.getAccountId(); int usageType = usageRecord.getUsageType(); @@ -390,12 +433,16 @@ public class PresetVariableHelper { return guestOsVo.getDisplayName(); } - protected ComputeOffering getPresetVariableValueComputeOffering(ServiceOfferingVO serviceOfferingVo) { + protected ComputeOffering getPresetVariableValueComputeOffering(ServiceOfferingVO serviceOfferingVo, int usageType) { ComputeOffering computeOffering = new ComputeOffering(); computeOffering.setId(serviceOfferingVo.getUuid()); computeOffering.setName(serviceOfferingVo.getName()); computeOffering.setCustomized(serviceOfferingVo.isDynamic()); + if (usageType == UsageTypes.RUNNING_VM) { + computeOffering.setOfferHa(serviceOfferingVo.isOfferHA()); + } + return computeOffering; } @@ -404,7 +451,7 @@ public class PresetVariableHelper { long computeOfferingId = vmVo.getServiceOfferingId(); ServiceOfferingVO serviceOfferingVo = serviceOfferingDao.findByIdIncludingRemoved(computeOfferingId); validateIfObjectIsNull(serviceOfferingVo, computeOfferingId, "compute offering"); - value.setComputeOffering(getPresetVariableValueComputeOffering(serviceOfferingVo)); + value.setComputeOffering(getPresetVariableValueComputeOffering(serviceOfferingVo, usageType)); if (usageType == UsageTypes.RUNNING_VM) { value.setComputingResources(getPresetVariableValueComputingResource(vmVo, serviceOfferingVo)); diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariables.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariables.java index 6dab6604e91..1f8b88ca4cd 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariables.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariables.java @@ -39,6 +39,9 @@ public class PresetVariables { @PresetVariableDefinition(description = "Zone where the resource is.") private GenericPresetVariable zone; + @PresetVariableDefinition(description = "Configurations of the resource.") + private Configuration configuration; + @PresetVariableDefinition(description = "A list containing the tariffs ordered by the field 'position'.") private List lastTariffs; @@ -90,6 +93,14 @@ public class PresetVariables { this.zone = zone; } + public Configuration getConfiguration() { + return configuration; + } + + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + public List getLastTariffs() { return lastTariffs; } diff --git a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaManagerImplTest.java b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaManagerImplTest.java index 5dfc12f7ef8..c62f80d4a44 100644 --- a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaManagerImplTest.java +++ b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaManagerImplTest.java @@ -270,6 +270,7 @@ public class QuotaManagerImplTest { Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("account"), Mockito.anyString()); Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("domain"), Mockito.anyString()); Mockito.verify(jsInterpreterMock, Mockito.never()).injectVariable(Mockito.eq("project"), Mockito.anyString()); + Mockito.verify(jsInterpreterMock, Mockito.never()).injectVariable(Mockito.eq("configuration"), Mockito.anyString()); Mockito.verify(jsInterpreterMock).injectStringVariable(Mockito.eq("resourceType"), Mockito.anyString()); Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("value"), Mockito.anyString()); Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("zone"), Mockito.anyString()); diff --git a/framework/quota/src/test/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelperTest.java b/framework/quota/src/test/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelperTest.java index 660bf8ba205..e2be3acbbb5 100644 --- a/framework/quota/src/test/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelperTest.java +++ b/framework/quota/src/test/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelperTest.java @@ -27,6 +27,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; import com.cloud.host.HostTagVO; import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.StoragePoolTagVO; @@ -123,6 +125,9 @@ public class PresetVariableHelperTest { @Mock HostTagsDao hostTagsDaoMock; + @Mock + ClusterDetailsDao clusterDetailsDaoMock; + @Mock ImageStoreDao imageStoreDaoMock; @@ -234,6 +239,7 @@ public class PresetVariableHelperTest { computeOffering.setId("compute_offering_id"); computeOffering.setName("compute_offering_name"); computeOffering.setCustomized(false); + computeOffering.setOfferHa(false); return computeOffering; } @@ -245,6 +251,14 @@ public class PresetVariableHelperTest { return host; } + private Configuration getConfigurationForTests() { + Configuration configuration = new Configuration(); + configuration.setId("config_id"); + configuration.setName("config_name"); + configuration.setForceHa(false); + return configuration; + } + private List getHostTagsForTests() { return Arrays.asList(new HostTagVO(1, "tag1", false), new HostTagVO(1, "tag2", false)); } @@ -338,6 +352,7 @@ public class PresetVariableHelperTest { Mockito.doReturn(expected.getAccount()).when(presetVariableHelperSpy).getPresetVariableAccount(Mockito.anyLong()); Mockito.doNothing().when(presetVariableHelperSpy).setPresetVariableProject(Mockito.any()); + Mockito.doNothing().when(presetVariableHelperSpy).setPresetVariableConfiguration(Mockito.any(), Mockito.any()); Mockito.doReturn(expected.getDomain()).when(presetVariableHelperSpy).getPresetVariableDomain(Mockito.anyLong()); Mockito.doReturn(expected.getValue()).when(presetVariableHelperSpy).getPresetVariableValue(Mockito.any(UsageVO.class)); Mockito.doReturn(expected.getZone()).when(presetVariableHelperSpy).getPresetVariableZone(Mockito.anyLong()); @@ -361,6 +376,35 @@ public class PresetVariableHelperTest { Assert.assertNull(result.getProject()); } + @Test + public void setPresetVariableConfigurationTestQuotaTypeDifferentFromRunningVmDoNothing() { + getQuotaTypesForTests(UsageTypes.RUNNING_VM).forEach(type -> { + PresetVariables result = new PresetVariables(); + Mockito.doReturn(type.getKey()).when(usageVoMock).getUsageType(); + presetVariableHelperSpy.setPresetVariableConfiguration(result, usageVoMock); + + Assert.assertNull(result.getConfiguration()); + }); + } + + @Test + public void setPresetVariableConfigurationTestQuotaTypeIsRunningVmSetConfiguration() { + PresetVariables result = new PresetVariables(); + Configuration expectedConfig = getConfigurationForTests(); + HostVO hostVoMock = Mockito.mock(HostVO.class); + ClusterDetailsVO clusterDetailsVoMock = Mockito.mock(ClusterDetailsVO.class); + + Mockito.doReturn(vmInstanceVoMock).when(vmInstanceDaoMock).findByIdIncludingRemoved(Mockito.anyLong()); + Mockito.doReturn(hostVoMock).when(hostDaoMock).findByIdIncludingRemoved(Mockito.anyLong()); + Mockito.doReturn(1L).when(vmInstanceVoMock).getHostId(); + Mockito.doReturn(1).when(usageVoMock).getUsageType(); + Mockito.doReturn(clusterDetailsVoMock).when(clusterDetailsDaoMock).findDetail(Mockito.anyLong(), Mockito.anyString()); + presetVariableHelperSpy.setPresetVariableConfiguration(result, usageVoMock); + + Assert.assertNotNull(result.getConfiguration()); + Assert.assertEquals(expectedConfig.getForceHa(), result.getConfiguration().getForceHa()); + } + @Test public void setPresetVariableProjectTestAccountWithoutRoleSetAsProject() { PresetVariables result = new PresetVariables(); @@ -636,19 +680,36 @@ public class PresetVariableHelperTest { } @Test - public void getPresetVariableValueComputeOfferingTestSetFieldsAndReturnObject() { + public void getPresetVariableValueComputeOfferingForTestSetFieldsAndReturnObjectForRunningVm() { + ComputeOffering expected = getComputeOfferingForTests(); + Mockito.doReturn(expected.getId()).when(serviceOfferingVoMock).getUuid(); + Mockito.doReturn(expected.getName()).when(serviceOfferingVoMock).getName(); + Mockito.doReturn(expected.isCustomized()).when(serviceOfferingVoMock).isDynamic(); + Mockito.doReturn(expected.offerHa()).when(serviceOfferingVoMock).isOfferHA(); + + ComputeOffering result = presetVariableHelperSpy.getPresetVariableValueComputeOffering(serviceOfferingVoMock, UsageTypes.RUNNING_VM); + + assertPresetVariableIdAndName(expected, result); + Assert.assertEquals(expected.isCustomized(), result.isCustomized()); + Assert.assertEquals(expected.offerHa(), result.offerHa()); + validateFieldNamesToIncludeInToString(Arrays.asList("id", "name", "customized", "offerHa"), result); + } + + @Test + public void getPresetVariableValueComputeOfferingForTestSetFieldsAndReturnObjectForAllocatedVm() { ComputeOffering expected = getComputeOfferingForTests(); Mockito.doReturn(expected.getId()).when(serviceOfferingVoMock).getUuid(); Mockito.doReturn(expected.getName()).when(serviceOfferingVoMock).getName(); Mockito.doReturn(expected.isCustomized()).when(serviceOfferingVoMock).isDynamic(); - ComputeOffering result = presetVariableHelperSpy.getPresetVariableValueComputeOffering(serviceOfferingVoMock); + ComputeOffering result = presetVariableHelperSpy.getPresetVariableValueComputeOffering(serviceOfferingVoMock, UsageTypes.ALLOCATED_VM); assertPresetVariableIdAndName(expected, result); Assert.assertEquals(expected.isCustomized(), result.isCustomized()); validateFieldNamesToIncludeInToString(Arrays.asList("id", "name", "customized"), result); } + @Test public void getPresetVariableValueTemplateTestSetValuesAndReturnObject() { VMTemplateVO vmTemplateVoMock = Mockito.mock(VMTemplateVO.class); @@ -1127,7 +1188,7 @@ public class PresetVariableHelperTest { Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findByIdIncludingRemoved(Mockito.anyLong()); mockMethodValidateIfObjectIsNull(); - Mockito.doReturn(expected.getComputeOffering()).when(presetVariableHelperSpy).getPresetVariableValueComputeOffering(Mockito.any()); + Mockito.doReturn(expected.getComputeOffering()).when(presetVariableHelperSpy).getPresetVariableValueComputeOffering(Mockito.any(), Mockito.anyInt()); Mockito.doReturn(expected.getComputingResources()).when(presetVariableHelperSpy).getPresetVariableValueComputingResource(Mockito.any(), Mockito.any()); QuotaTypes.listQuotaTypes().forEach((typeInt, value) -> {