Skip to content

Commit ac581d1

Browse files
authored
New feature: Resource count (CPU/RAM) take only running vms into calculation (#3760)
* marvin: check resource count of more types * New feature: add flag resource.count.running.vms.only to count resource consumption of only running vms Stopped VMs do not use CPU/RAM actually. A new global configuration resource.count.running.vms.only is added to determine whether resource (cpu/memory) of only running vms (including Starting/Stopping) will be taken into calculation of resource consumption. * Add integration test for resource count of only running vms
1 parent 518ed53 commit ac581d1

14 files changed

Lines changed: 1168 additions & 62 deletions

File tree

api/src/main/java/com/cloud/vm/UserVmService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffe
396396
* @throws ResourceUnavailableException
397397
* if the resources required the deploy the VM is not currently available.
398398
*/
399-
UserVm startVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException;
399+
UserVm startVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException;
400400

401401
/**
402402
* Creates a vm group.

api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,9 @@ public void execute() {
588588
} catch (ResourceUnavailableException ex) {
589589
s_logger.warn("Exception: ", ex);
590590
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
591+
} catch (ResourceAllocationException ex) {
592+
s_logger.warn("Exception: ", ex);
593+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
591594
} catch (ConcurrentOperationException ex) {
592595
s_logger.warn("Exception: ", ex);
593596
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());

api/src/main/java/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public Long getInstanceId() {
154154
}
155155

156156
@Override
157-
public void execute() throws ResourceUnavailableException, ResourceAllocationException {
157+
public void execute() {
158158
try {
159159
CallContext.current().setEventDetails("Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, getId()));
160160

@@ -177,6 +177,12 @@ public void execute() throws ResourceUnavailableException, ResourceAllocationExc
177177
} catch (ExecutionException ex) {
178178
s_logger.warn("Exception: ", ex);
179179
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
180+
} catch (ResourceUnavailableException ex) {
181+
s_logger.warn("Exception: ", ex);
182+
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
183+
} catch (ResourceAllocationException ex) {
184+
s_logger.warn("Exception: ", ex);
185+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
180186
} catch (InsufficientCapacityException ex) {
181187
StringBuilder message = new StringBuilder(ex.getMessage());
182188
if (ex instanceof InsufficientServerCapacityException) {

engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public interface VirtualMachineManager extends Manager {
5858
ConfigKey<Boolean> VmConfigDriveOnPrimaryPool = new ConfigKey<>("Advanced", Boolean.class, "vm.configdrive.primarypool.enabled", "false",
5959
"If config drive need to be created and hosted on primary storage pool. Currently only supported for KVM.", true);
6060

61+
ConfigKey<Boolean> ResoureCountRunningVMsonly = new ConfigKey<Boolean>("Advanced", Boolean.class, "resource.count.running.vms.only", "false",
62+
"Count the resources of only running VMs in resource limitation.", true);
63+
6164
interface Topics {
6265
String VM_POWER_STATE = "vm.powerstate";
6366
}

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
import com.cloud.agent.manager.allocator.HostAllocator;
123123
import com.cloud.alert.AlertManager;
124124
import com.cloud.capacity.CapacityManager;
125+
import com.cloud.configuration.Resource.ResourceType;
125126
import com.cloud.dc.ClusterDetailsDao;
126127
import com.cloud.dc.ClusterDetailsVO;
127128
import com.cloud.dc.DataCenter;
@@ -191,6 +192,7 @@
191192
import com.cloud.storage.dao.VolumeDao;
192193
import com.cloud.template.VirtualMachineTemplate;
193194
import com.cloud.user.Account;
195+
import com.cloud.user.ResourceLimitService;
194196
import com.cloud.user.User;
195197
import com.cloud.utils.DateUtil;
196198
import com.cloud.utils.Journal;
@@ -302,6 +304,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
302304
@Inject
303305
private ResourceManager _resourceMgr;
304306
@Inject
307+
private ResourceLimitService _resourceLimitMgr;
308+
@Inject
305309
private VMSnapshotManager _vmSnapshotMgr;
306310
@Inject
307311
private ClusterDetailsDao _clusterDetailsDao;
@@ -970,6 +974,12 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
970974

971975
final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
972976

977+
// check resource count if ResoureCountRunningVMsonly.value() = true
978+
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
979+
if (VirtualMachine.Type.User.equals(vm.type) && ResoureCountRunningVMsonly.value()) {
980+
resourceCountIncrement(owner.getAccountId(),new Long(offering.getCpu()), new Long(offering.getRamSize()));
981+
}
982+
973983
boolean canRetry = true;
974984
ExcludeList avoids = null;
975985
try {
@@ -1045,7 +1055,6 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
10451055
}
10461056
}
10471057

1048-
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
10491058
final VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, owner, params);
10501059
DeployDestination dest = null;
10511060
try {
@@ -1272,6 +1281,9 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
12721281
}
12731282
} finally {
12741283
if (startedVm == null) {
1284+
if (VirtualMachine.Type.User.equals(vm.type) && ResoureCountRunningVMsonly.value()) {
1285+
resourceCountDecrement(owner.getAccountId(),new Long(offering.getCpu()), new Long(offering.getRamSize()));
1286+
}
12751287
if (canRetry) {
12761288
try {
12771289
changeState(vm, Event.OperationFailed, null, work, Step.Done);
@@ -1817,7 +1829,14 @@ private void advanceStop(final VMInstanceVO vm, final boolean cleanUpEvenIfUnabl
18171829
_workDao.update(work.getId(), work);
18181830
}
18191831

1820-
if (!stateTransitTo(vm, Event.OperationSucceeded, null)) {
1832+
boolean result = stateTransitTo(vm, Event.OperationSucceeded, null);
1833+
if (result) {
1834+
if (VirtualMachine.Type.User.equals(vm.type) && ResoureCountRunningVMsonly.value()) {
1835+
//update resource count if stop successfully
1836+
ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
1837+
resourceCountDecrement(vm.getAccountId(),new Long(offering.getCpu()), new Long(offering.getRamSize()));
1838+
}
1839+
} else {
18211840
throw new CloudRuntimeException("unable to stop " + vm);
18221841
}
18231842
} catch (final NoTransitionException e) {
@@ -4218,7 +4237,8 @@ public String getConfigComponentName() {
42184237
public ConfigKey<?>[] getConfigKeys() {
42194238
return new ConfigKey<?>[] {ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait,
42204239
VmOpLockStateRetry,
4221-
VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, HaVmRestartHostUp};
4240+
VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, HaVmRestartHostUp,
4241+
ResoureCountRunningVMsonly };
42224242
}
42234243

42244244
public List<StoragePoolAllocator> getStoragePoolAllocators() {
@@ -5338,4 +5358,17 @@ private VmWorkJobVO createPlaceHolderWork(final long instanceId) {
53385358

53395359
return workJob;
53405360
}
5361+
5362+
protected void resourceCountIncrement (long accountId, Long cpu, Long memory) {
5363+
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.user_vm);
5364+
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.cpu, cpu);
5365+
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.memory, memory);
5366+
}
5367+
5368+
protected void resourceCountDecrement (long accountId, Long cpu, Long memory) {
5369+
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.user_vm);
5370+
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.cpu, cpu);
5371+
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.memory, memory);
5372+
}
5373+
53415374
}

engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public interface UserVmDao extends GenericDao<UserVmVO, Long> {
7777

7878
List<Long> listPodIdsHavingVmsforAccount(long zoneId, long accountId);
7979

80-
public Long countAllocatedVMsForAccount(long accountId);
80+
public Long countAllocatedVMsForAccount(long accountId, boolean runningVMsonly);
8181

8282
Hashtable<Long, UserVmData> listVmDetails(Hashtable<Long, UserVmData> userVmData);
8383

engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -635,11 +635,14 @@ public String getQueryBatchAppender(int count) {
635635
}
636636

637637
@Override
638-
public Long countAllocatedVMsForAccount(long accountId) {
638+
public Long countAllocatedVMsForAccount(long accountId, boolean runningVMsonly) {
639639
SearchCriteria<Long> sc = CountByAccount.create();
640640
sc.setParameters("account", accountId);
641641
sc.setParameters("type", VirtualMachine.Type.User);
642-
sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging});
642+
if (runningVMsonly)
643+
sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging, State.Stopped});
644+
else
645+
sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging});
643646
sc.setParameters("displayVm", 1);
644647
return customSearch(sc, null).get(0);
645648
}

server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,9 @@ private boolean startNewVM(long vmId) {
13761376
} catch (final ResourceUnavailableException ex) {
13771377
s_logger.warn("Exception: ", ex);
13781378
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
1379+
} catch (ResourceAllocationException ex) {
1380+
s_logger.warn("Exception: ", ex);
1381+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
13791382
} catch (ConcurrentOperationException ex) {
13801383
s_logger.warn("Exception: ", ex);
13811384
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());

server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import org.springframework.stereotype.Component;
4545

4646
import com.cloud.alert.AlertManager;
47+
import com.cloud.api.query.dao.UserVmJoinDao;
48+
import com.cloud.api.query.vo.UserVmJoinVO;
4749
import com.cloud.configuration.Config;
4850
import com.cloud.configuration.Resource;
4951
import com.cloud.configuration.Resource.ResourceOwnerType;
@@ -100,6 +102,8 @@
100102
import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
101103
import com.cloud.utils.db.TransactionStatus;
102104
import com.cloud.utils.exception.CloudRuntimeException;
105+
import com.cloud.vm.VirtualMachineManager;
106+
import com.cloud.vm.VirtualMachine.State;
103107
import com.cloud.vm.dao.UserVmDao;
104108
import com.cloud.vm.dao.VMInstanceDao;
105109

@@ -151,6 +155,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
151155
private VlanDao _vlanDao;
152156
@Inject
153157
private SnapshotDataStoreDao _snapshotDataStoreDao;
158+
@Inject
159+
private UserVmJoinDao _userVmJoinDao;
154160

155161
protected GenericSearchBuilder<TemplateDataStoreVO, SumCount> templateSizeSearch;
156162
protected GenericSearchBuilder<SnapshotDataStoreVO, SumCount> snapshotSizeSearch;
@@ -872,7 +878,7 @@ public Long doInTransaction(TransactionStatus status) {
872878
protected long recalculateAccountResourceCount(final long accountId, final ResourceType type) {
873879
final Long newCount;
874880
if (type == Resource.ResourceType.user_vm) {
875-
newCount = _userVmDao.countAllocatedVMsForAccount(accountId);
881+
newCount = _userVmDao.countAllocatedVMsForAccount(accountId, VirtualMachineManager.ResoureCountRunningVMsonly.value());
876882
} else if (type == Resource.ResourceType.volume) {
877883
long virtualRouterCount = _vmDao.findIdsOfAllocatedVirtualRoutersForAccount(accountId).size();
878884
newCount = _volumeDao.countAllocatedVolumesForAccount(accountId) - virtualRouterCount; // don't count the volumes of virtual router
@@ -929,11 +935,51 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
929935
}
930936

931937
public long countCpusForAccount(long accountId) {
932-
return _resourceCountDao.countCpuNumberAllocatedToAccount(accountId);
938+
long cputotal = 0;
939+
// user vms
940+
SearchBuilder<UserVmJoinVO> userVmSearch = _userVmJoinDao.createSearchBuilder();
941+
userVmSearch.and("accountId", userVmSearch.entity().getAccountId(), Op.EQ);
942+
userVmSearch.and("state", userVmSearch.entity().getState(), SearchCriteria.Op.NIN);
943+
userVmSearch.and("displayVm", userVmSearch.entity().isDisplayVm(), Op.EQ);
944+
userVmSearch.groupBy(userVmSearch.entity().getId()); // select distinct
945+
userVmSearch.done();
946+
947+
SearchCriteria<UserVmJoinVO> sc1 = userVmSearch.create();
948+
sc1.setParameters("accountId", accountId);
949+
if (VirtualMachineManager.ResoureCountRunningVMsonly.value())
950+
sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging, State.Stopped});
951+
else
952+
sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging});
953+
sc1.setParameters("displayVm", 1);
954+
List<UserVmJoinVO> userVms = _userVmJoinDao.search(sc1,null);
955+
for (UserVmJoinVO vm : userVms) {
956+
cputotal += Long.valueOf(vm.getCpu());
957+
}
958+
return cputotal;
933959
}
934960

935961
public long calculateMemoryForAccount(long accountId) {
936-
return _resourceCountDao.countMemoryAllocatedToAccount(accountId);
962+
long ramtotal = 0;
963+
// user vms
964+
SearchBuilder<UserVmJoinVO> userVmSearch = _userVmJoinDao.createSearchBuilder();
965+
userVmSearch.and("accountId", userVmSearch.entity().getAccountId(), Op.EQ);
966+
userVmSearch.and("state", userVmSearch.entity().getState(), SearchCriteria.Op.NIN);
967+
userVmSearch.and("displayVm", userVmSearch.entity().isDisplayVm(), Op.EQ);
968+
userVmSearch.groupBy(userVmSearch.entity().getId()); // select distinct
969+
userVmSearch.done();
970+
971+
SearchCriteria<UserVmJoinVO> sc1 = userVmSearch.create();
972+
sc1.setParameters("accountId", accountId);
973+
if (VirtualMachineManager.ResoureCountRunningVMsonly.value())
974+
sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging, State.Stopped});
975+
else
976+
sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging});
977+
sc1.setParameters("displayVm", 1);
978+
List<UserVmJoinVO> userVms = _userVmJoinDao.search(sc1,null);
979+
for (UserVmJoinVO vm : userVms) {
980+
ramtotal += Long.valueOf(vm.getRamSize());
981+
}
982+
return ramtotal;
937983
}
938984

939985
public long calculateSecondaryStorageForAccount(long accountId) {

server/src/main/java/com/cloud/vm/UserVmManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.cloud.exception.ConcurrentOperationException;
3131
import com.cloud.exception.InsufficientCapacityException;
3232
import com.cloud.exception.ManagementServerException;
33+
import com.cloud.exception.ResourceAllocationException;
3334
import com.cloud.exception.ResourceUnavailableException;
3435
import com.cloud.exception.VirtualMachineMigrationException;
3536
import com.cloud.offering.ServiceOffering;
@@ -99,10 +100,10 @@ public interface UserVmManager extends UserVmService {
99100
boolean expunge(UserVmVO vm, long callerUserId, Account caller);
100101

101102
Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long hostId, Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse)
102-
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
103+
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException;
103104

104105
Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId, Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse)
105-
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
106+
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException;
106107

107108
boolean upgradeVirtualMachine(Long id, Long serviceOfferingId, Map<String, String> customParameters) throws ResourceUnavailableException,
108109
ConcurrentOperationException, ManagementServerException,

0 commit comments

Comments
 (0)