Number of running and stopped VMs as preset variables for `Network` type Quota tariffs (#11689)

Co-authored-by: Fabricio Duarte <fabricio.duarte.jr@gmail.com>
This commit is contained in:
Henrique Sato 2026-05-01 06:54:40 -03:00 committed by GitHub
parent c45596cca3
commit c07f1fd5d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 112 additions and 5 deletions

View File

@ -35,6 +35,7 @@ import com.cloud.network.vpc.VpcVO;
import javax.inject.Inject;
import com.cloud.storage.StoragePoolTagVO;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleVO;
import org.apache.cloudstack.acl.dao.RoleDao;
import org.apache.cloudstack.backup.BackupOfferingVO;
@ -783,10 +784,21 @@ public class PresetVariableHelper {
value.setId(network.getUuid());
value.setName(network.getName());
value.setState(usageRecord.getState());
value.setResourceCounting(getPresetVariableValueNetworkResourceCounting(networkId));
value.setNetworkOffering(getPresetVariableValueNetworkOffering(network.getNetworkOfferingId()));
}
protected ResourceCounting getPresetVariableValueNetworkResourceCounting(Long networkId) {
ResourceCounting resourceCounting = new ResourceCounting();
List<VMInstanceVO> vmInstancesVO = vmInstanceDao.listNonRemovedVmsByTypeAndNetwork(networkId, VirtualMachine.Type.User);
int runningVms = (int) vmInstancesVO.stream().filter(vm -> vm.getState().equals(VirtualMachine.State.Running)).count();
int stoppedVms = (int) vmInstancesVO.stream().filter(vm -> vm.getState().equals(VirtualMachine.State.Stopped)).count();
resourceCounting.setRunningVms(runningVms);
resourceCounting.setStoppedVms(stoppedVms);
return resourceCounting;
}
protected GenericPresetVariable getPresetVariableValueNetworkOffering(Long networkOfferingId) {
NetworkOfferingVO networkOfferingVo = networkOfferingDao.findByIdIncludingRemoved(networkOfferingId);
validateIfObjectIsNull(networkOfferingVo, networkOfferingId, "network offering");

View File

@ -0,0 +1,52 @@
// 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;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class ResourceCounting {
@PresetVariableDefinition(description = "The number of running user instances.", supportedTypes = {QuotaTypes.NETWORK})
private int runningVms;
@PresetVariableDefinition(description = "The number of stopped user instances.", supportedTypes = {QuotaTypes.NETWORK})
private int stoppedVms;
public int getRunningVms() {
return runningVms;
}
public void setRunningVms(int runningVms) {
this.runningVms = runningVms;
}
public int getStoppedVms() {
return stoppedVms;
}
public void setStoppedVms(int stoppedVms) {
this.stoppedVms = stoppedVms;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}

View File

@ -84,6 +84,9 @@ public class Value extends GenericPresetVariable {
@PresetVariableDefinition(description = "Backup offering of the backup.", supportedTypes = {QuotaTypes.BACKUP})
private BackupOffering backupOffering;
@PresetVariableDefinition(description = "The amount of resources of the usage type.")
private ResourceCounting resourceCounting;
@PresetVariableDefinition(description = "The hypervisor where the resource was deployed. Values can be: XenServer, KVM, VMware, Hyperv, BareMetal, Ovm, Ovm3 and LXC.",
supportedTypes = {QuotaTypes.RUNNING_VM, QuotaTypes.ALLOCATED_VM, QuotaTypes.VM_SNAPSHOT, QuotaTypes.SNAPSHOT})
private String hypervisorType;
@ -262,6 +265,14 @@ public class Value extends GenericPresetVariable {
this.state = state;
}
public ResourceCounting getResourceCounting() {
return resourceCounting;
}
public void setResourceCounting(ResourceCounting resourceCounting) {
this.resourceCounting = resourceCounting;
}
public GenericPresetVariable getNetworkOffering() {
return networkOffering;
}

View File

@ -31,11 +31,13 @@ import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterDetailsVO;
import com.cloud.host.HostTagVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.network.Network;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.vpc.VpcOfferingVO;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcOfferingDao;
import com.cloud.storage.StoragePoolTagVO;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.RoleVO;
import org.apache.cloudstack.acl.dao.RoleDao;
@ -238,6 +240,8 @@ public class PresetVariableHelperTest {
value.setVmSnapshotType(VMSnapshot.Type.Disk.toString());
value.setComputingResources(getComputingResourcesForTests());
value.setVolumeType(Volume.Type.DATADISK.toString());
value.setState(Network.State.Implemented.toString());
value.setResourceCounting(getResourceCountingForTests());
value.setNetworkOffering(getNetworkOfferingForTests());
value.setVpcOffering(getVpcOfferingForTests());
return value;
@ -276,6 +280,13 @@ public class PresetVariableHelperTest {
return configuration;
}
private ResourceCounting getResourceCountingForTests() {
ResourceCounting resourceCounting = new ResourceCounting();
resourceCounting.setRunningVms(1);
resourceCounting.setStoppedVms(1);
return resourceCounting;
}
private List<HostTagVO> getHostTagsForTests() {
return Arrays.asList(new HostTagVO(1, "tag1", false), new HostTagVO(1, "tag2", false));
}
@ -1343,8 +1354,8 @@ public class PresetVariableHelperTest {
Mockito.doReturn(expected.getId()).when(networkVoMock).getUuid();
Mockito.doReturn(expected.getName()).when(networkVoMock).getName();
Mockito.doReturn(expected.getState()).when(usageVoMock).getState();
Mockito.doReturn(expected.getResourceCounting()).when(presetVariableHelperSpy).getPresetVariableValueNetworkResourceCounting(Mockito.anyLong());
Mockito.doReturn(expected.getNetworkOffering()).when(presetVariableHelperSpy).getPresetVariableValueNetworkOffering(Mockito.anyLong());
Mockito.doReturn(UsageTypes.NETWORK).when(usageVoMock).getUsageType();
Value result = new Value();
@ -1352,7 +1363,27 @@ public class PresetVariableHelperTest {
assertPresetVariableIdAndName(expected, result);
Assert.assertEquals(expected.getState(), result.getState());
Assert.assertEquals(expected.getNetworkOffering(), result.getNetworkOffering());
Assert.assertEquals(expected.getResourceCounting(), result.getResourceCounting());
}
@Test
public void getPresetVariableValueNetworkResourceCountingTestSetValueAndReturnObject() {
VMInstanceVO vmInstanceVoMock1 = Mockito.spy(VMInstanceVO.class);
vmInstanceVoMock1.setState(VirtualMachine.State.Stopped);
VMInstanceVO vmInstanceVoMock2 = Mockito.spy(VMInstanceVO.class);
vmInstanceVoMock2.setState(VirtualMachine.State.Running);
Mockito.doReturn(List.of(vmInstanceVoMock1, vmInstanceVoMock2)).when(vmInstanceDaoMock).listNonRemovedVmsByTypeAndNetwork(Mockito.anyLong(), Mockito.any());
mockMethodValidateIfObjectIsNull();
ResourceCounting expected = getResourceCountingForTests();
ResourceCounting result = presetVariableHelperSpy.getPresetVariableValueNetworkResourceCounting(1L);
Assert.assertEquals(expected.getRunningVms(), result.getRunningVms());
Assert.assertEquals(expected.getStoppedVms(), result.getStoppedVms());
}
@Test
@ -1362,7 +1393,7 @@ public class PresetVariableHelperTest {
presetVariableHelperSpy.loadPresetVariableValueForVpc(usageVoMock, null);
});
Mockito.verifyNoInteractions(networkDaoMock);
Mockito.verifyNoInteractions(vpcDaoMock);
}
@Test

View File

@ -98,6 +98,7 @@ import org.apache.cloudstack.quota.activationrule.presetvariables.ComputingResou
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableDefinition;
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariables;
import org.apache.cloudstack.quota.activationrule.presetvariables.ResourceCounting;
import org.apache.cloudstack.quota.activationrule.presetvariables.Value;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.constant.QuotaTypes;
@ -185,7 +186,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
private VolumeDao volumeDao;
private final Class<?>[] assignableClasses = {GenericPresetVariable.class, ComputingResources.class};
private final Class<?>[] assignableClasses = {GenericPresetVariable.class, ComputingResources.class, ResourceCounting.class};
private Set<Account.Type> accountTypesThatCanListAllQuotaSummaries = Sets.newHashSet(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN);