mirror of https://github.com/apache/cloudstack.git
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:
parent
1510b44f03
commit
ba3284bdc5
|
|
@ -34,6 +34,8 @@ ResourceReservation extends InternalIdentity {
|
|||
|
||||
Resource.ResourceType getResourceType();
|
||||
|
||||
Long getResourceId();
|
||||
|
||||
String getTag();
|
||||
|
||||
Long getReservedAmount();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -947,5 +947,4 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
|||
public String getUserDataDetails() {
|
||||
return userDataDetails;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue