Fix resource count discrepancies (#8302)

* Fix resource count discrepancies

* Fixup while removing vm

* Fix discrepancies when starting VMs

* Fixup tests

* Fix failing tests

* Don't take lock when amount is negative

---------

Co-authored-by: dahn <daan@onecht.net>
This commit is contained in:
Vishesh 2024-03-13 18:22:44 +05:30 committed by GitHub
parent 6dc3d06037
commit e87c6cfcb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 398 additions and 154 deletions

View File

@ -34,6 +34,8 @@ ResourceReservation extends InternalIdentity {
Resource.ResourceType getResourceType();
Long getResourceId();
String getTag();
Long getReservedAmount();

View File

@ -1,4 +1,4 @@
// Licensed to the Apacohe Software Foundation (ASF) under one
// 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
@ -49,6 +49,7 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import javax.persistence.EntityExistsException;
import com.cloud.configuration.Resource;
import com.cloud.domain.Domain;
import com.cloud.domain.dao.DomainDao;
import com.cloud.network.vpc.VpcVO;
@ -87,6 +88,7 @@ import org.apache.cloudstack.framework.messagebus.MessageDispatcher;
import org.apache.cloudstack.framework.messagebus.MessageHandler;
import org.apache.cloudstack.jobs.JobInfo;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
@ -296,6 +298,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Inject
private VMInstanceDao _vmDao;
@Inject
private ReservationDao _reservationDao;
@Inject
private ServiceOfferingDao _offeringDao;
@Inject
private DiskOfferingDao _diskOfferingDao;
@ -914,7 +918,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@DB
protected Ternary<VMInstanceVO, ReservationContext, ItWorkVO> changeToStartState(final VirtualMachineGuru vmGuru, final VMInstanceVO vm, final User caller,
final Account account) throws ConcurrentOperationException {
final Account account, Account owner, ServiceOfferingVO offering, VirtualMachineTemplate template) throws ConcurrentOperationException {
final long vmId = vm.getId();
ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Starting, vm.getType(), vm.getId());
@ -934,6 +938,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
if (logger.isDebugEnabled()) {
logger.debug("Successfully transitioned to start state for " + vm + " reservation id = " + work.getId());
}
if (VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
_resourceLimitMgr.incrementVmResourceCount(owner.getAccountId(), vm.isDisplay(), offering, template);
}
return new Ternary<>(vm, context, work);
}
@ -1126,7 +1133,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
final VirtualMachineGuru vmGuru = getVmGuru(vm);
final Ternary<VMInstanceVO, ReservationContext, ItWorkVO> start = changeToStartState(vmGuru, vm, caller, account);
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
final ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
final VirtualMachineTemplate template = _entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vm.getTemplateId());
final Ternary<VMInstanceVO, ReservationContext, ItWorkVO> start = changeToStartState(vmGuru, vm, caller, account, owner, offering, template);
if (start == null) {
return;
}
@ -1136,8 +1146,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
ItWorkVO work = start.third();
VMInstanceVO startedVm = null;
final ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
final VirtualMachineTemplate template = _entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vm.getTemplateId());
DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null, ctx);
if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
@ -1150,12 +1158,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
// check resource count if ResourceCountRunningVMsonly.value() = true
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
if (VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
_resourceLimitMgr.incrementVmResourceCount(owner.getAccountId(), vm.isDisplay(), offering, template);
}
boolean canRetry = true;
ExcludeList avoids = null;
try {
@ -2277,16 +2279,21 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
_workDao.update(work.getId(), work);
}
boolean result = stateTransitTo(vm, Event.OperationSucceeded, null);
if (result) {
vm.setPowerState(PowerState.PowerOff);
_vmDao.update(vm.getId(), vm);
if (VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
_resourceLimitMgr.decrementVmResourceCount(vm.getAccountId(), vm.isDisplay(), offering, template);
boolean result = Transaction.execute(new TransactionCallbackWithException<Boolean, NoTransitionException>() {
@Override
public Boolean doInTransaction(TransactionStatus status) throws NoTransitionException {
boolean result = stateTransitTo(vm, Event.OperationSucceeded, null);
if (result && VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
_resourceLimitMgr.decrementVmResourceCount(vm.getAccountId(), vm.isDisplay(), offering, template);
}
return result;
}
} else {
});
if (!result) {
throw new CloudRuntimeException("unable to stop " + vm);
}
} catch (final NoTransitionException e) {
@ -2319,6 +2326,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
vm.setLastHostId(vm.getHostId());
}
}
if (e.equals(VirtualMachine.Event.DestroyRequested) || e.equals(VirtualMachine.Event.ExpungeOperation)) {
_reservationDao.setResourceId(Resource.ResourceType.user_vm, null);
_reservationDao.setResourceId(Resource.ResourceType.cpu, null);
_reservationDao.setResourceId(Resource.ResourceType.memory, null);
}
return _stateMachine.transitTo(vm, e, new Pair<>(vm.getHostId(), hostId), _vmDao);
}

View File

@ -1006,6 +1006,7 @@ public class VirtualMachineManagerImplTest {
public void testOrchestrateStartNonNullPodId() throws Exception {
VMInstanceVO vmInstance = new VMInstanceVO();
ReflectionTestUtils.setField(vmInstance, "id", 1L);
ReflectionTestUtils.setField(vmInstance, "accountId", 1L);
ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid");
ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L);
ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm");
@ -1019,6 +1020,7 @@ public class VirtualMachineManagerImplTest {
User user = mock(User.class);
Account account = mock(Account.class);
Account owner = mock(Account.class);
ReservationContext ctx = mock(ReservationContext.class);
@ -1042,12 +1044,13 @@ public class VirtualMachineManagerImplTest {
doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance);
Ternary<VMInstanceVO, ReservationContext, ItWorkVO> start = new Ternary<>(vmInstance, ctx, work);
Mockito.doReturn(start).when(virtualMachineManagerImpl).changeToStartState(vmGuru, vmInstance, user, account);
Mockito.doReturn(start).when(virtualMachineManagerImpl).changeToStartState(vmGuru, vmInstance, user, account, owner, serviceOffering, template);
when(ctx.getJournal()).thenReturn(Mockito.mock(Journal.class));
when(serviceOfferingDaoMock.findById(vmInstance.getId(), vmInstance.getServiceOfferingId())).thenReturn(serviceOffering);
when(_entityMgr.findById(Account.class, vmInstance.getAccountId())).thenReturn(owner);
when(_entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vmInstance.getTemplateId())).thenReturn(template);
Host destHost = mock(Host.class);
@ -1099,6 +1102,7 @@ public class VirtualMachineManagerImplTest {
public void testOrchestrateStartNullPodId() throws Exception {
VMInstanceVO vmInstance = new VMInstanceVO();
ReflectionTestUtils.setField(vmInstance, "id", 1L);
ReflectionTestUtils.setField(vmInstance, "accountId", 1L);
ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid");
ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L);
ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm");
@ -1112,6 +1116,7 @@ public class VirtualMachineManagerImplTest {
User user = mock(User.class);
Account account = mock(Account.class);
Account owner = mock(Account.class);
ReservationContext ctx = mock(ReservationContext.class);
@ -1135,12 +1140,13 @@ public class VirtualMachineManagerImplTest {
doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance);
Ternary<VMInstanceVO, ReservationContext, ItWorkVO> start = new Ternary<>(vmInstance, ctx, work);
Mockito.doReturn(start).when(virtualMachineManagerImpl).changeToStartState(vmGuru, vmInstance, user, account);
Mockito.doReturn(start).when(virtualMachineManagerImpl).changeToStartState(vmGuru, vmInstance, user, account, owner, serviceOffering, template);
when(ctx.getJournal()).thenReturn(Mockito.mock(Journal.class));
when(serviceOfferingDaoMock.findById(vmInstance.getId(), vmInstance.getServiceOfferingId())).thenReturn(serviceOffering);
when(_entityMgr.findById(Account.class, vmInstance.getAccountId())).thenReturn(owner);
when(_entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vmInstance.getTemplateId())).thenReturn(template);
Host destHost = mock(Host.class);

View File

@ -182,6 +182,7 @@ public class VolumeVO implements Volume {
@Column(name = "encrypt_format")
private String encryptFormat;
// Real Constructor
public VolumeVO(Type type, String name, long dcId, long domainId,
long accountId, long diskOfferingId, Storage.ProvisioningType provisioningType, long size,

View File

@ -23,9 +23,15 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import com.cloud.configuration.Resource;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import org.apache.cloudstack.reservation.ReservationVO;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
@ -71,6 +77,8 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
private final SearchBuilder<VolumeVO> poolAndPathSearch;
@Inject
ReservationDao reservationDao;
@Inject
ResourceTagDao _tagsDao;
protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?";
@ -443,6 +451,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
CountByAccount.and("account", CountByAccount.entity().getAccountId(), SearchCriteria.Op.EQ);
CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN);
CountByAccount.and("displayVolume", CountByAccount.entity().isDisplayVolume(), Op.EQ);
CountByAccount.and("idNIN", CountByAccount.entity().getId(), Op.NIN);
CountByAccount.done();
primaryStorageSearch = createSearchBuilder(SumCount.class);
@ -454,6 +463,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
primaryStorageSearch.and("displayVolume", primaryStorageSearch.entity().isDisplayVolume(), Op.EQ);
primaryStorageSearch.and("isRemoved", primaryStorageSearch.entity().getRemoved(), Op.NULL);
primaryStorageSearch.and("NotCountStates", primaryStorageSearch.entity().getState(), Op.NIN);
primaryStorageSearch.and("idNIN", primaryStorageSearch.entity().getId(), Op.NIN);
primaryStorageSearch.done();
primaryStorageSearch2 = createSearchBuilder(SumCount.class);
@ -468,6 +478,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
primaryStorageSearch2.and("displayVolume", primaryStorageSearch2.entity().isDisplayVolume(), Op.EQ);
primaryStorageSearch2.and("isRemoved", primaryStorageSearch2.entity().getRemoved(), Op.NULL);
primaryStorageSearch2.and("NotCountStates", primaryStorageSearch2.entity().getState(), Op.NIN);
primaryStorageSearch2.and("idNIN", primaryStorageSearch2.entity().getId(), Op.NIN);
primaryStorageSearch2.done();
secondaryStorageSearch = createSearchBuilder(SumCount.class);
@ -506,15 +517,24 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
@Override
public Long countAllocatedVolumesForAccount(long accountId) {
List<ReservationVO> reservations = reservationDao.getReservationsForAccount(accountId, Resource.ResourceType.volume, null);
List<Long> reservedResourceIds = reservations.stream().filter(reservation -> reservation.getReservedAmount() > 0).map(ReservationVO::getResourceId).collect(Collectors.toList());
SearchCriteria<Long> sc = CountByAccount.create();
sc.setParameters("account", accountId);
sc.setParameters("state", Volume.State.Destroy, Volume.State.Expunged);
sc.setParameters("state", State.Destroy, State.Expunged);
sc.setParameters("displayVolume", 1);
if (CollectionUtils.isNotEmpty(reservedResourceIds)) {
sc.setParameters("idNIN", reservedResourceIds.toArray());
}
return customSearch(sc, null).get(0);
}
@Override
public long primaryStorageUsedForAccount(long accountId, List<Long> virtualRouters) {
List<ReservationVO> reservations = reservationDao.getReservationsForAccount(accountId, Resource.ResourceType.volume, null);
List<Long> reservedResourceIds = reservations.stream().filter(reservation -> reservation.getReservedAmount() > 0).map(ReservationVO::getResourceId).collect(Collectors.toList());
SearchCriteria<SumCount> sc;
if (!virtualRouters.isEmpty()) {
sc = primaryStorageSearch2.create();
@ -526,6 +546,9 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
sc.setParameters("states", State.Allocated);
sc.setParameters("NotCountStates", State.Destroy, State.Expunged);
sc.setParameters("displayVolume", 1);
if (CollectionUtils.isNotEmpty(reservedResourceIds)) {
sc.setParameters("idNIN", reservedResourceIds.toArray());
}
List<SumCount> storageSpace = customSearch(sc, null);
if (storageSpace != null) {
return storageSpace.get(0).sum;
@ -863,4 +886,14 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
}
return listBy(sc);
}
@Override
public VolumeVO persist(VolumeVO entity) {
return Transaction.execute((TransactionCallback<VolumeVO>) status -> {
VolumeVO volume = super.persist(entity);
reservationDao.setResourceId(Resource.ResourceType.volume, volume.getId());
reservationDao.setResourceId(Resource.ResourceType.primary_storage, volume.getId());
return volume;
});
}
}

View File

@ -26,10 +26,16 @@ import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import com.cloud.configuration.Resource;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import org.apache.cloudstack.reservation.ReservationVO;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.commons.collections.CollectionUtils;
import com.cloud.network.Network;
@ -91,6 +97,8 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
NetworkDao networkDao;
@Inject
NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
@Inject
ReservationDao reservationDao;
private static final String LIST_PODS_HAVING_VMS_FOR_ACCOUNT =
"SELECT pod_id FROM cloud.vm_instance WHERE data_center_id = ? AND account_id = ? AND pod_id IS NOT NULL AND (state = 'Running' OR state = 'Stopped') "
@ -198,6 +206,7 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
CountByAccount.and("type", CountByAccount.entity().getType(), SearchCriteria.Op.EQ);
CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN);
CountByAccount.and("displayVm", CountByAccount.entity().isDisplayVm(), SearchCriteria.Op.EQ);
CountByAccount.and("idNIN", CountByAccount.entity().getId(), SearchCriteria.Op.NIN);
CountByAccount.done();
CountActiveAccount = createSearchBuilder(Long.class);
@ -697,6 +706,9 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
@Override
public Long countAllocatedVMsForAccount(long accountId, boolean runningVMsonly) {
List<ReservationVO> reservations = reservationDao.getReservationsForAccount(accountId, Resource.ResourceType.user_vm, null);
List<Long> reservedResourceIds = reservations.stream().filter(reservation -> reservation.getReservedAmount() > 0).map(ReservationVO::getResourceId).collect(Collectors.toList());
SearchCriteria<Long> sc = CountByAccount.create();
sc.setParameters("account", accountId);
sc.setParameters("type", VirtualMachine.Type.User);
@ -705,6 +717,11 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
else
sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging});
sc.setParameters("displayVm", 1);
if (CollectionUtils.isNotEmpty(reservedResourceIds)) {
sc.setParameters("idNIN", reservedResourceIds.toArray());
}
return customSearch(sc, null).get(0);
}
@ -792,4 +809,15 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
sc.setParameters("ids", ids.toArray());
return listBy(sc);
}
@Override
public UserVmVO persist(UserVmVO entity) {
return Transaction.execute((TransactionCallback<UserVmVO>) status -> {
UserVmVO userVM = super.persist(entity);
reservationDao.setResourceId(Resource.ResourceType.user_vm, userVM.getId());
reservationDao.setResourceId(Resource.ResourceType.cpu, userVM.getId());
reservationDao.setResourceId(Resource.ResourceType.memory, userVM.getId());
return userVM;
});
}
}

View File

@ -51,6 +51,9 @@ public class ReservationVO implements ResourceReservation {
@Column(name = "tag")
String tag;
@Column(name = "resource_id")
Long resourceId;
@Column(name = "amount")
long amount;
@ -58,8 +61,8 @@ public class ReservationVO implements ResourceReservation {
}
public ReservationVO(Long accountId, Long domainId, Resource.ResourceType resourceType, String tag, Long delta) {
if (delta == null || delta <= 0) {
throw new CloudRuntimeException("resource reservations can not be made for no resources");
if (delta == null) {
throw new CloudRuntimeException("resource reservations can not be made for null resources");
}
this.accountId = accountId;
this.domainId = domainId;
@ -101,4 +104,14 @@ public class ReservationVO implements ResourceReservation {
public Long getReservedAmount() {
return amount;
}
@Override
public Long getResourceId() {
return resourceId;
}
public void setResourceId(long resourceId) {
this.resourceId = resourceId;
}
}

View File

@ -23,7 +23,12 @@ import org.apache.cloudstack.reservation.ReservationVO;
import com.cloud.configuration.Resource;
import com.cloud.utils.db.GenericDao;
import java.util.List;
public interface ReservationDao extends GenericDao<ReservationVO, Long> {
long getAccountReservation(Long account, Resource.ResourceType resourceType, String tag);
long getDomainReservation(Long domain, Resource.ResourceType resourceType, String tag);
void setResourceId(Resource.ResourceType type, Long resourceId);
List<Long> getResourceIds(long accountId, Resource.ResourceType type);
List<ReservationVO> getReservationsForAccount(long accountId, Resource.ResourceType type, String tag);
}

View File

@ -19,27 +19,51 @@
package org.apache.cloudstack.reservation.dao;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.reservation.ReservationVO;
import com.cloud.configuration.Resource;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import org.apache.cloudstack.user.ResourceReservation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> implements ReservationDao {
protected transient Logger logger = LogManager.getLogger(getClass());
private static final String RESOURCE_TYPE = "resourceType";
private static final String RESOURCE_TAG = "resourceTag";
private static final String RESOURCE_ID = "resourceId";
private static final String ACCOUNT_ID = "accountId";
private static final String DOMAIN_ID = "domainId";
private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeSearch;
private final SearchBuilder<ReservationVO> listAccountAndTypeSearch;
private final SearchBuilder<ReservationVO> listAccountAndTypeAndNoTagSearch;
private final SearchBuilder<ReservationVO> listDomainAndTypeSearch;
private final SearchBuilder<ReservationVO> listDomainAndTypeAndNoTagSearch;
private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeAndNoTagSearch;
public ReservationDaoImpl() {
listResourceByAccountAndTypeSearch = createSearchBuilder();
listResourceByAccountAndTypeSearch.and(ACCOUNT_ID, listResourceByAccountAndTypeSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
listResourceByAccountAndTypeSearch.and(RESOURCE_TYPE, listResourceByAccountAndTypeSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
listResourceByAccountAndTypeSearch.and(RESOURCE_ID, listResourceByAccountAndTypeSearch.entity().getResourceId(), SearchCriteria.Op.NNULL);
listResourceByAccountAndTypeSearch.and(RESOURCE_TAG, listResourceByAccountAndTypeSearch.entity().getTag(), SearchCriteria.Op.EQ);
listResourceByAccountAndTypeSearch.done();
listResourceByAccountAndTypeAndNoTagSearch = createSearchBuilder();
listResourceByAccountAndTypeAndNoTagSearch.and(ACCOUNT_ID, listResourceByAccountAndTypeAndNoTagSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
listResourceByAccountAndTypeAndNoTagSearch.and(RESOURCE_TYPE, listResourceByAccountAndTypeAndNoTagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
listResourceByAccountAndTypeAndNoTagSearch.and(RESOURCE_ID, listResourceByAccountAndTypeAndNoTagSearch.entity().getResourceId(), SearchCriteria.Op.NNULL);
listResourceByAccountAndTypeAndNoTagSearch.and(RESOURCE_TAG, listResourceByAccountAndTypeAndNoTagSearch.entity().getTag(), SearchCriteria.Op.NULL);
listResourceByAccountAndTypeAndNoTagSearch.done();
listAccountAndTypeSearch = createSearchBuilder();
listAccountAndTypeSearch.and(ACCOUNT_ID, listAccountAndTypeSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
listAccountAndTypeSearch.and(RESOURCE_TYPE, listAccountAndTypeSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
@ -98,4 +122,43 @@ public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> impl
}
return total;
}
@Override
public void setResourceId(Resource.ResourceType type, Long resourceId) {
Object obj = CallContext.current().getContextParameter(String.format("%s-%s", ResourceReservation.class.getSimpleName(), type.getName()));
if (obj instanceof List) {
try {
List<Long> reservationIds = (List<Long>)obj;
for (Long reservationId : reservationIds) {
ReservationVO reservation = findById(reservationId);
if (reservation != null) {
reservation.setResourceId(resourceId);
persist(reservation);
}
}
} catch (Exception e) {
logger.warn("Failed to persist reservation for resource type " + type.getName() + " for resource id " + resourceId, e);
}
}
}
@Override
public List<Long> getResourceIds(long accountId, Resource.ResourceType type) {
SearchCriteria<ReservationVO> sc = listResourceByAccountAndTypeSearch.create();
sc.setParameters(ACCOUNT_ID, accountId);
sc.setParameters(RESOURCE_TYPE, type);
return listBy(sc).stream().map(ReservationVO::getResourceId).collect(Collectors.toList());
}
@Override
public List<ReservationVO> getReservationsForAccount(long accountId, Resource.ResourceType type, String tag) {
SearchCriteria<ReservationVO> sc = tag == null ?
listResourceByAccountAndTypeAndNoTagSearch.create() : listResourceByAccountAndTypeSearch.create();
sc.setParameters(ACCOUNT_ID, accountId);
sc.setParameters(RESOURCE_TYPE, type);
if (tag != null) {
sc.setParameters(RESOURCE_TAG, tag);
}
return listBy(sc);
}
}

View File

@ -29,6 +29,14 @@ DROP INDEX `i_resource_count__type_domaintId`,
ADD UNIQUE INDEX `i_resource_count__type_tag_accountId` (`type`,`tag`,`account_id`),
ADD UNIQUE INDEX `i_resource_count__type_tag_domaintId` (`type`,`tag`,`domain_id`);
ALTER TABLE `cloud`.`resource_reservation`
ADD COLUMN `resource_id` bigint unsigned NULL;
ALTER TABLE `cloud`.`resource_reservation`
MODIFY COLUMN `amount` bigint NOT NULL;
-- Update Default System offering for Router to 512MiB
UPDATE `cloud`.`service_offering` SET ram_size = 512 WHERE unique_name IN ("Cloud.Com-SoftwareRouter", "Cloud.Com-SoftwareRouter-Local",
"Cloud.Com-InternalLBVm", "Cloud.Com-InternalLBVm-Local",
@ -61,4 +69,3 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings','for_nsx', 'int(1
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','for_nsx', 'int(1) unsigned DEFAULT "0" COMMENT "is nsx enabled for the resource"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"');

View File

@ -955,5 +955,4 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
public String getUserDataDetails() {
return userDataDetails;
}
}

View File

@ -62,13 +62,32 @@ public class CheckedReservation implements AutoCloseable {
return String.format("%s-%s", ResourceReservation.class.getSimpleName(), type.getName());
}
protected void checkLimitAndPersistReservation(Account account, ResourceType resourceType, String tag, Long amount) throws ResourceAllocationException {
resourceLimitService.checkResourceLimitWithTag(account, resourceType, tag, amount);
protected void checkLimitAndPersistReservations(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount) throws ResourceAllocationException {
checkLimitAndPersistReservation(account, resourceType, resourceId, null, amount);
if (CollectionUtils.isNotEmpty(resourceLimitTags)) {
for (String tag : resourceLimitTags) {
checkLimitAndPersistReservation(account, resourceType, resourceId, tag, amount);
}
}
}
protected void checkLimitAndPersistReservation(Account account, ResourceType resourceType, Long resourceId, String tag, Long amount) throws ResourceAllocationException {
if (amount > 0) {
resourceLimitService.checkResourceLimitWithTag(account, resourceType, tag, amount);
}
ReservationVO reservationVO = new ReservationVO(account.getAccountId(), account.getDomainId(), resourceType, tag, amount);
if (resourceId != null) {
reservationVO.setResourceId(resourceId);
}
ResourceReservation reservation = reservationDao.persist(reservationVO);
this.reservations.add(reservation);
}
public CheckedReservation(Account account, ResourceType resourceType, List<String> resourceLimitTags, Long amount,
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, resourceType, null, resourceLimitTags, amount, reservationDao, resourceLimitService);
}
/**
* - check if adding a reservation is allowed
* - create DB entry for reservation
@ -77,8 +96,8 @@ public class CheckedReservation implements AutoCloseable {
* @param amount positive number of the resource type to reserve
* @throws ResourceAllocationException
*/
public CheckedReservation(Account account, ResourceType resourceType, List<String> resourceLimitTags, Long amount,
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
public CheckedReservation(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount,
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this.reservationDao = reservationDao;
this.resourceLimitService = resourceLimitService;
this.account = account;
@ -86,36 +105,28 @@ public class CheckedReservation implements AutoCloseable {
this.amount = amount;
this.reservations = new ArrayList<>();
this.resourceLimitTags = resourceLimitTags;
setGlobalLock();
if (this.amount != null && this.amount <= 0) {
if(logger.isDebugEnabled()){
logger.debug(String.format("not reserving no amount of resources for %s in domain %d, type: %s, %s ", account.getAccountName(), account.getDomainId(), resourceType, amount));
}
this.amount = null;
}
if (this.amount != null) {
if(quotaLimitLock.lock(TRY_TO_GET_LOCK_TIME)) {
try {
checkLimitAndPersistReservation(account, resourceType, null, amount);
if (CollectionUtils.isNotEmpty(resourceLimitTags)) {
for (String tag: resourceLimitTags) {
checkLimitAndPersistReservation(account, resourceType, tag, amount);
}
if (this.amount != null && this.amount != 0) {
if (amount > 0) {
setGlobalLock();
if (quotaLimitLock.lock(TRY_TO_GET_LOCK_TIME)) {
try {
checkLimitAndPersistReservations(account, resourceType, resourceId, resourceLimitTags, amount);
CallContext.current().putContextParameter(getContextParameterKey(), getIds());
} catch (NullPointerException npe) {
throw new CloudRuntimeException("not enough means to check limits", npe);
} finally {
quotaLimitLock.unlock();
}
CallContext.current().putContextParameter(getContextParameterKey(), getIds());
} catch (NullPointerException npe) {
throw new CloudRuntimeException("not enough means to check limits", npe);
} finally {
quotaLimitLock.unlock();
} else {
throw new ResourceAllocationException(String.format("unable to acquire resource reservation \"%s\"", quotaLimitLock.getName()), resourceType);
}
} else {
throw new ResourceAllocationException(String.format("unable to acquire resource reservation \"%s\"", quotaLimitLock.getName()), resourceType);
checkLimitAndPersistReservations(account, resourceType, resourceId, resourceLimitTags, amount);
}
} else {
if(logger.isDebugEnabled()) {
logger.debug(String.format("not reserving no amount of resources for %s in domain %d, type: %s, tag: %s", account.getAccountName(), account.getDomainId(), resourceType, getResourceLimitTagsAsString()));
}
logger.debug("not reserving any amount of resources for {} in domain {}, type: {}, tag: {}",
account.getAccountName(), account.getDomainId(), resourceType, getResourceLimitTagsAsString());
}
}

View File

@ -45,6 +45,7 @@ import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.ReservationVO;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
@ -1273,9 +1274,11 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
if (CollectionUtils.isEmpty(offerings) && CollectionUtils.isEmpty(templates)) {
return new ArrayList<>();
}
return _userVmJoinDao.listByAccountServiceOfferingTemplateAndNotInState(accountId, states,
return _userVmJoinDao.listByAccountServiceOfferingTemplateAndNotInState(accountId, states,
offerings.stream().map(ServiceOfferingVO::getId).collect(Collectors.toList()),
templates.stream().map(VMTemplateVO::getId).collect(Collectors.toList()));
templates.stream().map(VMTemplateVO::getId).collect(Collectors.toList())
);
}
protected List<UserVmJoinVO> getVmsWithAccount(long accountId) {
@ -1293,12 +1296,26 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
vrIds);
}
private long calculateReservedResources(List<UserVmJoinVO> vms, long accountId, ResourceType type, String tag) {
Set<Long> vmIds = vms.stream().map(UserVmJoinVO::getId).collect(Collectors.toSet());
List<ReservationVO> reservations = reservationDao.getReservationsForAccount(accountId, type, tag);
long reserved = 0;
for (ReservationVO reservation : reservations) {
if (vmIds.contains(reservation.getResourceId()) ? reservation.getReservedAmount() > 0 : reservation.getReservedAmount() < 0) {
reserved += reservation.getReservedAmount();
}
}
return reserved;
}
protected long calculateVmCountForAccount(long accountId, String tag) {
if (StringUtils.isEmpty(tag)) {
return _userVmDao.countAllocatedVMsForAccount(accountId, VirtualMachineManager.ResourceCountRunningVMsonly.value());
}
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
return vms.size();
long reservedVMs = calculateReservedResources(vms, accountId, ResourceType.user_vm, tag);
return vms.size() - reservedVMs;
}
protected long calculateVolumeCountForAccount(long accountId, String tag) {
@ -1316,10 +1333,12 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
}
long cputotal = 0;
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
for (UserVmJoinVO vm : vms) {
cputotal += vm.getCpu();
}
return cputotal;
long reservedCpus = calculateReservedResources(vms, accountId, ResourceType.cpu, tag);
return cputotal - reservedCpus;
}
protected long calculateVmMemoryCountForAccount(long accountId, String tag) {
@ -1328,10 +1347,12 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
}
long memory = 0;
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
for (UserVmJoinVO vm : vms) {
memory += vm.getRamSize();
}
return memory;
long reservedMemory = calculateReservedResources(vms, accountId, ResourceType.memory, tag);
return memory - reservedMemory;
}
public long countCpusForAccount(long accountId) {
@ -1340,7 +1361,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
for (UserVmJoinVO vm : userVms) {
cputotal += vm.getCpu();
}
return cputotal;
long reservedCpuTotal = calculateReservedResources(userVms, accountId, ResourceType.cpu, null);
return cputotal - reservedCpuTotal;
}
public long calculateMemoryForAccount(long accountId) {
@ -1349,7 +1371,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
for (UserVmJoinVO vm : userVms) {
ramtotal += vm.getRamSize();
}
return ramtotal;
long reservedRamTotal = calculateReservedResources(userVms, accountId, ResourceType.memory, null);
return ramtotal - reservedRamTotal;
}
public long calculateSecondaryStorageForAccount(long accountId) {
@ -1625,32 +1648,44 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
}
}
@DB
@Override
public void incrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering) {
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
if (CollectionUtils.isEmpty(tags)) {
return;
}
for (String tag : tags) {
incrementResourceCountWithTag(accountId, ResourceType.volume, tag);
if (size != null) {
incrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
if (CollectionUtils.isEmpty(tags)) {
return;
}
for (String tag : tags) {
incrementResourceCountWithTag(accountId, ResourceType.volume, tag);
if (size != null) {
incrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
}
}
}
}
});
}
@DB
@Override
public void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering) {
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
if (CollectionUtils.isEmpty(tags)) {
return;
}
for (String tag : tags) {
decrementResourceCountWithTag(accountId, ResourceType.volume, tag);
if (size != null) {
decrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
if (CollectionUtils.isEmpty(tags)) {
return;
}
for (String tag : tags) {
decrementResourceCountWithTag(accountId, ResourceType.volume, tag);
if (size != null) {
decrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
}
}
}
}
});
}
@Override
@ -1711,32 +1746,43 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
@Override
public void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
for (String tag : tags) {
incrementResourceCountWithTag(accountId, ResourceType.user_vm, tag);
incrementResourceCountWithTag(accountId, ResourceType.cpu, tag, cpu);
incrementResourceCountWithTag(accountId, ResourceType.memory, tag, ram);
}
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
for (String tag : tags) {
incrementResourceCountWithTag(accountId, ResourceType.user_vm, tag);
incrementResourceCountWithTag(accountId, ResourceType.cpu, tag, cpu);
incrementResourceCountWithTag(accountId, ResourceType.memory, tag, ram);
}
}
});
}
@Override
public void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
for (String tag : tags) {
decrementResourceCountWithTag(accountId, ResourceType.user_vm, tag);
decrementResourceCountWithTag(accountId, ResourceType.cpu, tag, cpu);
decrementResourceCountWithTag(accountId, ResourceType.memory, tag, ram);
}
public void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering,
VirtualMachineTemplate template) {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
for (String tag : tags) {
decrementResourceCountWithTag(accountId, ResourceType.user_vm, tag);
decrementResourceCountWithTag(accountId, ResourceType.cpu, tag, cpu);
decrementResourceCountWithTag(accountId, ResourceType.memory, tag, ram);
}
}
});
}
@Override

View File

@ -5700,37 +5700,47 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
boolean status;
State vmState = vm.getState();
try {
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
status = vmEntity.destroy(expunge);
} catch (CloudException e) {
CloudRuntimeException ex = new CloudRuntimeException("Unable to destroy with specified vmId", e);
ex.addProxyObject(vm.getUuid(), "vmId");
throw ex;
}
Account owner = _accountMgr.getAccount(vm.getAccountId());
if (status) {
// Mark the account's volumes as destroyed
List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
for (VolumeVO volume : volumes) {
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume());
ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId());
try (CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, vmId, null, -1L, reservationDao, resourceLimitService);
CheckedReservation cpuReservation = new CheckedReservation(owner, ResourceType.cpu, vmId, null, -1 * Long.valueOf(offering.getCpu()), reservationDao, resourceLimitService);
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, vmId, null, -1 * Long.valueOf(offering.getRamSize()), reservationDao, resourceLimitService);
) {
try {
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
status = vmEntity.destroy(expunge);
} catch (CloudException e) {
CloudRuntimeException ex = new CloudRuntimeException("Unable to destroy with specified vmId", e);
ex.addProxyObject(vm.getUuid(), "vmId");
throw ex;
}
if (status) {
// Mark the account's volumes as destroyed
List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
for (VolumeVO volume : volumes) {
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume());
}
}
}
if (vmState != State.Error) {
// Get serviceOffering and template for Virtual Machine
ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId());
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
//Update Resource Count for the given account
resourceCountDecrement(vm.getAccountId(), vm.isDisplayVm(),offering, template);
if (vmState != State.Error) {
// Get serviceOffering and template for Virtual Machine
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
//Update Resource Count for the given account
resourceCountDecrement(vm.getAccountId(), vm.isDisplayVm(), offering, template);
}
return _vmDao.findById(vmId);
} else {
CloudRuntimeException ex = new CloudRuntimeException("Failed to destroy vm with specified vmId");
ex.addProxyObject(vm.getUuid(), "vmId");
throw ex;
}
return _vmDao.findById(vmId);
} else {
CloudRuntimeException ex = new CloudRuntimeException("Failed to destroy vm with specified vmId");
ex.addProxyObject(vm.getUuid(), "vmId");
throw ex;
} catch (Exception e) {
throw new CloudRuntimeException("Failed to destroy vm with specified vmId", e);
}
}

View File

@ -19,7 +19,6 @@
package com.cloud.resourcelimit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
@ -108,9 +107,10 @@ public class CheckedReservationTest {
@Test
public void getNoAmount() {
Mockito.when(reservationDao.persist(Mockito.any())).thenReturn(reservation);
try (CheckedReservation cr = new CheckedReservation(account, Resource.ResourceType.cpu,-11l, reservationDao, resourceLimitService) ) {
Long amount = cr.getReservedAmount();
assertNull(amount);
assertEquals(Long.valueOf(-11L), amount);
} catch (NullPointerException npe) {
fail("NPE caught");
} catch (ResourceAllocationException rae) {

View File

@ -27,6 +27,7 @@ import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.TaggedResourceLimitAndCountResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
@ -106,6 +107,8 @@ public class ResourceLimitManagerImplTest extends TestCase {
@Mock
ResourceCountDao resourceCountDao;
@Mock
private ReservationDao reservationDao;
@Mock
UserVmJoinDao userVmJoinDao;
@Mock
ServiceOfferingDao serviceOfferingDao;
@ -675,7 +678,9 @@ public class ResourceLimitManagerImplTest extends TestCase {
Assert.assertEquals(2L, resourceLimitManager.calculateVmCountForAccount(accountId, tag));
tag = "tag";
Mockito.doReturn(List.of(UserVmJoinVO.class)).when(resourceLimitManager).getVmsWithAccountAndTag(accountId, tag);
UserVmJoinVO vm = Mockito.mock(UserVmJoinVO.class);
Mockito.when(vm.getId()).thenReturn(1L);
Mockito.doReturn(List.of(vm)).when(resourceLimitManager).getVmsWithAccountAndTag(accountId, tag);
Assert.assertEquals(1L, resourceLimitManager.calculateVmCountForAccount(accountId, tag));
}

View File

@ -37,6 +37,7 @@ import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@ -123,10 +124,10 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
DomainVO domain = new DomainVO();
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
when(_orchSrvc.getVirtualMachine(nullable(String.class))).thenReturn(vmEntity);
when(vmEntity.destroy(nullable(Boolean.class))).thenReturn(true);
lenient().when(_orchSrvc.getVirtualMachine(nullable(String.class))).thenReturn(vmEntity);
lenient().when(vmEntity.destroy(nullable(Boolean.class))).thenReturn(true);
Mockito.lenient().doReturn(vm).when(_vmDao).findById(nullable(Long.class));
lenient().doReturn(vm).when(_vmDao).findById(nullable(Long.class));
VolumeVO vol = new VolumeVO(VOLUME_UUID, 1l, 1l, 1l, 1l, 1l, "folder", "path", null, 50, Type.ROOT);
vol.setDisplayVolume(true);
@ -136,20 +137,20 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
lenient().when(securityChecker.checkAccess(Mockito.eq(account), nullable(ControlledEntity.class), nullable(AccessType.class), nullable(String.class))).thenReturn(true);
when(_userVmDao.findById(nullable(Long.class))).thenReturn(vm);
lenient().when(_userVmDao.findById(nullable(Long.class))).thenReturn(vm);
lenient().when(_userVmDao.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm));
lenient().when(_userVmDao.findByUuid(nullable(String.class))).thenReturn(vm);
when(_volumeDao.findByInstance(nullable(Long.class))).thenReturn(volumes);
lenient().when(_volumeDao.findByInstance(nullable(Long.class))).thenReturn(volumes);
ServiceOfferingVO offering = mock(ServiceOfferingVO.class);
lenient().when(offering.getCpu()).thenReturn(500);
lenient().when(offering.getId()).thenReturn(1l);
when(serviceOfferingDao.findByIdIncludingRemoved(nullable(Long.class), nullable(Long.class))).thenReturn(offering);
lenient().when(serviceOfferingDao.findByIdIncludingRemoved(nullable(Long.class), nullable(Long.class))).thenReturn(offering);
lenient().when(_domainMgr.getDomain(nullable(Long.class))).thenReturn(domain);
Mockito.lenient().doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class));
Mockito.doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class));
}
@ -190,22 +191,22 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
// If the VM is already destroyed, no events should get emitted
public void destroyedVMRootVolumeUsageEvent()
throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
Mockito.lenient().doReturn(vm).when(_vmMgr).destroyVm(nullable(Long.class), nullable(Boolean.class));
lenient().doReturn(vm).when(_vmMgr).destroyVm(nullable(Long.class), nullable(Boolean.class));
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(true);
Assert.assertEquals(0, emittedEvents.size());
}
@Ignore()
@Test
// If the VM is running, we should see one emitted event for the root
// volume.
public void runningVMRootVolumeUsageEvent()
throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
Mockito.doNothing().when(vmStatsDaoMock).removeAllByVmId(Mockito.anyLong());
Mockito.lenient().when(_vmMgr.destroyVm(nullable(Long.class), nullable(Boolean.class))).thenReturn(vm);
Mockito.when(_vmMgr.destroyVm(nullable(Long.class), nullable(Boolean.class))).thenReturn(vm);
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false);
UsageEventVO event = emittedEvents.get(0);
Assert.assertEquals(EventTypes.EVENT_VOLUME_DELETE, event.getType());
Assert.assertEquals(VOLUME_UUID, event.getResourceName());
}
}

View File

@ -1,19 +1,19 @@
<!-- 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
<!-- 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. -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
@ -23,7 +23,7 @@
<context:annotation-config />
<!-- @DB support -->
<bean id="componentContext" class="com.cloud.utils.component.ComponentContext" />
<bean id="transactionContextBuilder" class="com.cloud.utils.db.TransactionContextBuilder" />
@ -75,4 +75,5 @@
<bean id="nsxControllerDaoImpl" class="com.cloud.network.dao.NsxProviderDaoImpl" />
<bean id="vlanDetailsDao" class="com.cloud.dc.dao.VlanDetailsDaoImpl" />
<bean id="publicIpQuarantineDaoImpl" class="com.cloud.network.dao.PublicIpQuarantineDaoImpl" />
<bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />
</beans>