Fix resource count discrepancies (#376)

* Fix resource count discrepancies

* Fixup while removing vm

* Fix discrepancies when starting VMs

* Fixup tests

* Fixups

* Don't take lock when amount is negative
This commit is contained in:
Vishesh 2024-03-13 18:22:34 +05:30 committed by GitHub
parent 1510b44f03
commit ba3284bdc5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 388 additions and 141 deletions

View File

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

View File

@ -48,6 +48,8 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import javax.persistence.EntityExistsException;
import com.cloud.configuration.Resource;
import com.cloud.event.ActionEventUtils;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
@ -79,6 +81,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;
@ -165,7 +168,6 @@ import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.deploy.DeploymentPlanningManager;
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.event.UsageEventVO;
@ -289,6 +291,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Inject
private VMInstanceDao _vmDao;
@Inject
private ReservationDao _reservationDao;
@Inject
private ServiceOfferingDao _offeringDao;
@Inject
private DiskOfferingDao _diskOfferingDao;
@ -898,7 +902,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());
@ -918,6 +922,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
if (s_logger.isDebugEnabled()) {
s_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);
}
@ -1108,7 +1115,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;
}
@ -1118,8 +1128,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) {
@ -1134,12 +1142,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);
}
String adminError = null;
boolean canRetry = true;
ExcludeList avoids = null;
@ -2222,16 +2224,25 @@ 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) {
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);
}
}
return result;
}
} else {
});
if (!result) {
throw new CloudRuntimeException("unable to stop " + vm);
}
} catch (final NoTransitionException e) {
@ -2264,6 +2275,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

@ -946,6 +946,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");
@ -959,6 +960,7 @@ public class VirtualMachineManagerImplTest {
User user = mock(User.class);
Account account = mock(Account.class);
Account owner = mock(Account.class);
ReservationContext ctx = mock(ReservationContext.class);
@ -982,12 +984,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);
@ -1038,6 +1041,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");
@ -1051,6 +1055,7 @@ public class VirtualMachineManagerImplTest {
User user = mock(User.class);
Account account = mock(Account.class);
Account owner = mock(Account.class);
ReservationContext ctx = mock(ReservationContext.class);
@ -1074,12 +1079,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

@ -22,9 +22,15 @@ import java.sql.SQLException;
import java.util.ArrayList;
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.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -69,6 +75,8 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch2;
protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
@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 = ?";
@ -441,6 +449,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);
@ -452,6 +461,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);
@ -466,6 +476,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);
@ -489,15 +500,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();
@ -509,6 +529,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;
@ -816,4 +839,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

@ -25,10 +25,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 org.apache.log4j.Logger;
@ -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') "
@ -194,6 +202,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);
@ -693,6 +702,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);
@ -701,6 +713,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);
}
@ -778,4 +795,15 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
sc.setParameters("userDataId", userdataId);
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,50 @@
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.log4j.Logger;
public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> implements ReservationDao {
public static final Logger logger = Logger.getLogger(ReservationDaoImpl.class);
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 +121,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

@ -329,3 +329,9 @@ from
`cloud`.`async_job` ON async_job.instance_id = account.id
and async_job.instance_type = 'Account'
and async_job.job_status = 0;
ALTER TABLE `cloud`.`resource_reservation`
ADD COLUMN `resource_id` bigint unsigned NULL;
ALTER TABLE `cloud`.`resource_reservation`
MODIFY COLUMN `amount` bigint NOT NULL;

View File

@ -58,7 +58,8 @@ public class ScaleIOGatewayClientImplTest {
@Rule
public WireMockRule wireMockRule = new WireMockRule(wireMockConfig()
.httpsPort(port)
.dynamicHttpsPort()
.dynamicPort()
.needClientAuth(false)
.basicAdminAuthenticator(username, password)
.bindAddress("localhost"));
@ -70,7 +71,7 @@ public class ScaleIOGatewayClientImplTest {
.withHeader("content-type", "application/json;charset=UTF-8")
.withBody(sessionKey)));
client = new ScaleIOGatewayClientImpl(String.format("https://localhost:%d/api", port), username, password, false, timeout, maxConnections);
client = new ScaleIOGatewayClientImpl(String.format("https://localhost:%d/api", wireMockRule.httpsPort()), username, password, false, timeout, maxConnections);
wireMockRule.stubFor(post("/api/types/Volume/instances")
.willReturn(aResponse()

View File

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

View File

@ -61,13 +61,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
@ -76,8 +95,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;
@ -85,35 +104,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(LOG.isDebugEnabled()){
LOG.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(LOG.isDebugEnabled()){
LOG.debug(String.format("not reserving no amount of resources for %s in domain %d, type: %s, tag: %s", account.getAccountName(), account.getDomainId(), resourceType, getResourceLimitTagsAsString()));
LOG.debug(String.format("not reserving any amount of resources for %s in domain %d, type: %s, tag: %s", 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;
@ -1283,9 +1284,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) {
@ -1303,12 +1306,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) {
@ -1326,10 +1343,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) {
@ -1338,10 +1357,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) {
@ -1350,7 +1371,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) {
@ -1359,7 +1381,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) {
@ -1635,32 +1658,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
@ -1721,32 +1756,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

@ -5581,37 +5581,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.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@ -40,6 +39,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.test.util.ReflectionTestUtils;
@ -53,6 +53,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
@RunWith(PowerMockRunner.class)
@PrepareForTest({GlobalLock.class, CheckedReservation.class})
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
public class CheckedReservationTest {
@Mock
@ -107,7 +108,7 @@ public class CheckedReservationTest {
boolean fail = false;
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.log4j.Logger;
@ -103,6 +104,8 @@ public class ResourceLimitManagerImplTest {
@Mock
ResourceCountDao resourceCountDao;
@Mock
private ReservationDao reservationDao;
@Mock
UserVmJoinDao userVmJoinDao;
@Mock
ServiceOfferingDao serviceOfferingDao;

View File

@ -38,6 +38,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;
@ -124,10 +125,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);
@ -137,20 +138,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));
}
@ -191,22 +192,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

@ -72,4 +72,5 @@
<bean id="PassphraseDaoImpl" class="org.apache.cloudstack.secret.dao.PassphraseDaoImpl" />
<bean id="configurationGroupDaoImpl" class="org.apache.cloudstack.framework.config.dao.ConfigurationGroupDaoImpl" />
<bean id="configurationSubGroupDaoImpl" class="org.apache.cloudstack.framework.config.dao.ConfigurationSubGroupDaoImpl" />
<bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />
</beans>