mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Fix resource count discrepancies (#8302)
* Fix resource count discrepancies * Fixup while removing vm * Fix discrepancies when starting VMs * Fixup tests * Fix failing tests * Don't take lock when amount is negative --------- Co-authored-by: dahn <daan@onecht.net>
This commit is contained in:
parent
6dc3d06037
commit
e87c6cfcb1
@ -34,6 +34,8 @@ ResourceReservation extends InternalIdentity {
|
|||||||
|
|
||||||
Resource.ResourceType getResourceType();
|
Resource.ResourceType getResourceType();
|
||||||
|
|
||||||
|
Long getResourceId();
|
||||||
|
|
||||||
String getTag();
|
String getTag();
|
||||||
|
|
||||||
Long getReservedAmount();
|
Long getReservedAmount();
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Licensed to the Apacohe Software Foundation (ASF) under one
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// or more contributor license agreements. See the NOTICE file
|
||||||
// distributed with this work for additional information
|
// distributed with this work for additional information
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
@ -49,6 +49,7 @@ import javax.inject.Inject;
|
|||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
import javax.persistence.EntityExistsException;
|
import javax.persistence.EntityExistsException;
|
||||||
|
|
||||||
|
import com.cloud.configuration.Resource;
|
||||||
import com.cloud.domain.Domain;
|
import com.cloud.domain.Domain;
|
||||||
import com.cloud.domain.dao.DomainDao;
|
import com.cloud.domain.dao.DomainDao;
|
||||||
import com.cloud.network.vpc.VpcVO;
|
import com.cloud.network.vpc.VpcVO;
|
||||||
@ -87,6 +88,7 @@ import org.apache.cloudstack.framework.messagebus.MessageDispatcher;
|
|||||||
import org.apache.cloudstack.framework.messagebus.MessageHandler;
|
import org.apache.cloudstack.framework.messagebus.MessageHandler;
|
||||||
import org.apache.cloudstack.jobs.JobInfo;
|
import org.apache.cloudstack.jobs.JobInfo;
|
||||||
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
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.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
@ -296,6 +298,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
@Inject
|
@Inject
|
||||||
private VMInstanceDao _vmDao;
|
private VMInstanceDao _vmDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
private ReservationDao _reservationDao;
|
||||||
|
@Inject
|
||||||
private ServiceOfferingDao _offeringDao;
|
private ServiceOfferingDao _offeringDao;
|
||||||
@Inject
|
@Inject
|
||||||
private DiskOfferingDao _diskOfferingDao;
|
private DiskOfferingDao _diskOfferingDao;
|
||||||
@ -914,7 +918,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
|
|
||||||
@DB
|
@DB
|
||||||
protected Ternary<VMInstanceVO, ReservationContext, ItWorkVO> changeToStartState(final VirtualMachineGuru vmGuru, final VMInstanceVO vm, final User caller,
|
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();
|
final long vmId = vm.getId();
|
||||||
|
|
||||||
ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Starting, vm.getType(), vm.getId());
|
ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Starting, vm.getType(), vm.getId());
|
||||||
@ -934,6 +938,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Successfully transitioned to start state for " + vm + " reservation id = " + work.getId());
|
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);
|
return new Ternary<>(vm, context, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1126,7 +1133,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
|
|
||||||
final VirtualMachineGuru vmGuru = getVmGuru(vm);
|
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) {
|
if (start == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1136,8 +1146,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
ItWorkVO work = start.third();
|
ItWorkVO work = start.third();
|
||||||
|
|
||||||
VMInstanceVO startedVm = null;
|
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);
|
DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null, ctx);
|
||||||
if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
|
if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
|
||||||
@ -1150,12 +1158,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
|
|
||||||
final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
|
final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
|
||||||
|
|
||||||
// check resource count if ResourceCountRunningVMsonly.value() = true
|
|
||||||
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
|
|
||||||
if (VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
|
|
||||||
_resourceLimitMgr.incrementVmResourceCount(owner.getAccountId(), vm.isDisplay(), offering, template);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean canRetry = true;
|
boolean canRetry = true;
|
||||||
ExcludeList avoids = null;
|
ExcludeList avoids = null;
|
||||||
try {
|
try {
|
||||||
@ -2277,16 +2279,21 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
_workDao.update(work.getId(), work);
|
_workDao.update(work.getId(), work);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean result = stateTransitTo(vm, Event.OperationSucceeded, null);
|
boolean result = Transaction.execute(new TransactionCallbackWithException<Boolean, NoTransitionException>() {
|
||||||
if (result) {
|
@Override
|
||||||
vm.setPowerState(PowerState.PowerOff);
|
public Boolean doInTransaction(TransactionStatus status) throws NoTransitionException {
|
||||||
_vmDao.update(vm.getId(), vm);
|
boolean result = stateTransitTo(vm, Event.OperationSucceeded, null);
|
||||||
if (VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
|
|
||||||
ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
|
if (result && VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
|
||||||
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
|
ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
|
||||||
_resourceLimitMgr.decrementVmResourceCount(vm.getAccountId(), vm.isDisplay(), offering, template);
|
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);
|
throw new CloudRuntimeException("unable to stop " + vm);
|
||||||
}
|
}
|
||||||
} catch (final NoTransitionException e) {
|
} catch (final NoTransitionException e) {
|
||||||
@ -2319,6 +2326,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
vm.setLastHostId(vm.getHostId());
|
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);
|
return _stateMachine.transitTo(vm, e, new Pair<>(vm.getHostId(), hostId), _vmDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1006,6 +1006,7 @@ public class VirtualMachineManagerImplTest {
|
|||||||
public void testOrchestrateStartNonNullPodId() throws Exception {
|
public void testOrchestrateStartNonNullPodId() throws Exception {
|
||||||
VMInstanceVO vmInstance = new VMInstanceVO();
|
VMInstanceVO vmInstance = new VMInstanceVO();
|
||||||
ReflectionTestUtils.setField(vmInstance, "id", 1L);
|
ReflectionTestUtils.setField(vmInstance, "id", 1L);
|
||||||
|
ReflectionTestUtils.setField(vmInstance, "accountId", 1L);
|
||||||
ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid");
|
ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid");
|
||||||
ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L);
|
ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L);
|
||||||
ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm");
|
ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm");
|
||||||
@ -1019,6 +1020,7 @@ public class VirtualMachineManagerImplTest {
|
|||||||
User user = mock(User.class);
|
User user = mock(User.class);
|
||||||
|
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
|
Account owner = mock(Account.class);
|
||||||
|
|
||||||
ReservationContext ctx = mock(ReservationContext.class);
|
ReservationContext ctx = mock(ReservationContext.class);
|
||||||
|
|
||||||
@ -1042,12 +1044,13 @@ public class VirtualMachineManagerImplTest {
|
|||||||
doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance);
|
doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance);
|
||||||
|
|
||||||
Ternary<VMInstanceVO, ReservationContext, ItWorkVO> start = new Ternary<>(vmInstance, ctx, work);
|
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(ctx.getJournal()).thenReturn(Mockito.mock(Journal.class));
|
||||||
|
|
||||||
when(serviceOfferingDaoMock.findById(vmInstance.getId(), vmInstance.getServiceOfferingId())).thenReturn(serviceOffering);
|
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);
|
when(_entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vmInstance.getTemplateId())).thenReturn(template);
|
||||||
|
|
||||||
Host destHost = mock(Host.class);
|
Host destHost = mock(Host.class);
|
||||||
@ -1099,6 +1102,7 @@ public class VirtualMachineManagerImplTest {
|
|||||||
public void testOrchestrateStartNullPodId() throws Exception {
|
public void testOrchestrateStartNullPodId() throws Exception {
|
||||||
VMInstanceVO vmInstance = new VMInstanceVO();
|
VMInstanceVO vmInstance = new VMInstanceVO();
|
||||||
ReflectionTestUtils.setField(vmInstance, "id", 1L);
|
ReflectionTestUtils.setField(vmInstance, "id", 1L);
|
||||||
|
ReflectionTestUtils.setField(vmInstance, "accountId", 1L);
|
||||||
ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid");
|
ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid");
|
||||||
ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L);
|
ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L);
|
||||||
ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm");
|
ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm");
|
||||||
@ -1112,6 +1116,7 @@ public class VirtualMachineManagerImplTest {
|
|||||||
User user = mock(User.class);
|
User user = mock(User.class);
|
||||||
|
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
|
Account owner = mock(Account.class);
|
||||||
|
|
||||||
ReservationContext ctx = mock(ReservationContext.class);
|
ReservationContext ctx = mock(ReservationContext.class);
|
||||||
|
|
||||||
@ -1135,12 +1140,13 @@ public class VirtualMachineManagerImplTest {
|
|||||||
doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance);
|
doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance);
|
||||||
|
|
||||||
Ternary<VMInstanceVO, ReservationContext, ItWorkVO> start = new Ternary<>(vmInstance, ctx, work);
|
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(ctx.getJournal()).thenReturn(Mockito.mock(Journal.class));
|
||||||
|
|
||||||
when(serviceOfferingDaoMock.findById(vmInstance.getId(), vmInstance.getServiceOfferingId())).thenReturn(serviceOffering);
|
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);
|
when(_entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vmInstance.getTemplateId())).thenReturn(template);
|
||||||
|
|
||||||
Host destHost = mock(Host.class);
|
Host destHost = mock(Host.class);
|
||||||
|
|||||||
@ -182,6 +182,7 @@ public class VolumeVO implements Volume {
|
|||||||
@Column(name = "encrypt_format")
|
@Column(name = "encrypt_format")
|
||||||
private String encryptFormat;
|
private String encryptFormat;
|
||||||
|
|
||||||
|
|
||||||
// Real Constructor
|
// Real Constructor
|
||||||
public VolumeVO(Type type, String name, long dcId, long domainId,
|
public VolumeVO(Type type, String name, long dcId, long domainId,
|
||||||
long accountId, long diskOfferingId, Storage.ProvisioningType provisioningType, long size,
|
long accountId, long diskOfferingId, Storage.ProvisioningType provisioningType, long size,
|
||||||
|
|||||||
@ -23,9 +23,15 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
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.commons.collections.CollectionUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -71,6 +77,8 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
|
protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
|
||||||
private final SearchBuilder<VolumeVO> poolAndPathSearch;
|
private final SearchBuilder<VolumeVO> poolAndPathSearch;
|
||||||
@Inject
|
@Inject
|
||||||
|
ReservationDao reservationDao;
|
||||||
|
@Inject
|
||||||
ResourceTagDao _tagsDao;
|
ResourceTagDao _tagsDao;
|
||||||
|
|
||||||
protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?";
|
protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?";
|
||||||
@ -443,6 +451,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
CountByAccount.and("account", CountByAccount.entity().getAccountId(), SearchCriteria.Op.EQ);
|
CountByAccount.and("account", CountByAccount.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||||
CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN);
|
CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN);
|
||||||
CountByAccount.and("displayVolume", CountByAccount.entity().isDisplayVolume(), Op.EQ);
|
CountByAccount.and("displayVolume", CountByAccount.entity().isDisplayVolume(), Op.EQ);
|
||||||
|
CountByAccount.and("idNIN", CountByAccount.entity().getId(), Op.NIN);
|
||||||
CountByAccount.done();
|
CountByAccount.done();
|
||||||
|
|
||||||
primaryStorageSearch = createSearchBuilder(SumCount.class);
|
primaryStorageSearch = createSearchBuilder(SumCount.class);
|
||||||
@ -454,6 +463,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
primaryStorageSearch.and("displayVolume", primaryStorageSearch.entity().isDisplayVolume(), Op.EQ);
|
primaryStorageSearch.and("displayVolume", primaryStorageSearch.entity().isDisplayVolume(), Op.EQ);
|
||||||
primaryStorageSearch.and("isRemoved", primaryStorageSearch.entity().getRemoved(), Op.NULL);
|
primaryStorageSearch.and("isRemoved", primaryStorageSearch.entity().getRemoved(), Op.NULL);
|
||||||
primaryStorageSearch.and("NotCountStates", primaryStorageSearch.entity().getState(), Op.NIN);
|
primaryStorageSearch.and("NotCountStates", primaryStorageSearch.entity().getState(), Op.NIN);
|
||||||
|
primaryStorageSearch.and("idNIN", primaryStorageSearch.entity().getId(), Op.NIN);
|
||||||
primaryStorageSearch.done();
|
primaryStorageSearch.done();
|
||||||
|
|
||||||
primaryStorageSearch2 = createSearchBuilder(SumCount.class);
|
primaryStorageSearch2 = createSearchBuilder(SumCount.class);
|
||||||
@ -468,6 +478,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
primaryStorageSearch2.and("displayVolume", primaryStorageSearch2.entity().isDisplayVolume(), Op.EQ);
|
primaryStorageSearch2.and("displayVolume", primaryStorageSearch2.entity().isDisplayVolume(), Op.EQ);
|
||||||
primaryStorageSearch2.and("isRemoved", primaryStorageSearch2.entity().getRemoved(), Op.NULL);
|
primaryStorageSearch2.and("isRemoved", primaryStorageSearch2.entity().getRemoved(), Op.NULL);
|
||||||
primaryStorageSearch2.and("NotCountStates", primaryStorageSearch2.entity().getState(), Op.NIN);
|
primaryStorageSearch2.and("NotCountStates", primaryStorageSearch2.entity().getState(), Op.NIN);
|
||||||
|
primaryStorageSearch2.and("idNIN", primaryStorageSearch2.entity().getId(), Op.NIN);
|
||||||
primaryStorageSearch2.done();
|
primaryStorageSearch2.done();
|
||||||
|
|
||||||
secondaryStorageSearch = createSearchBuilder(SumCount.class);
|
secondaryStorageSearch = createSearchBuilder(SumCount.class);
|
||||||
@ -506,15 +517,24 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long countAllocatedVolumesForAccount(long accountId) {
|
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();
|
SearchCriteria<Long> sc = CountByAccount.create();
|
||||||
sc.setParameters("account", accountId);
|
sc.setParameters("account", accountId);
|
||||||
sc.setParameters("state", Volume.State.Destroy, Volume.State.Expunged);
|
sc.setParameters("state", State.Destroy, State.Expunged);
|
||||||
sc.setParameters("displayVolume", 1);
|
sc.setParameters("displayVolume", 1);
|
||||||
|
if (CollectionUtils.isNotEmpty(reservedResourceIds)) {
|
||||||
|
sc.setParameters("idNIN", reservedResourceIds.toArray());
|
||||||
|
}
|
||||||
return customSearch(sc, null).get(0);
|
return customSearch(sc, null).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long primaryStorageUsedForAccount(long accountId, List<Long> virtualRouters) {
|
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;
|
SearchCriteria<SumCount> sc;
|
||||||
if (!virtualRouters.isEmpty()) {
|
if (!virtualRouters.isEmpty()) {
|
||||||
sc = primaryStorageSearch2.create();
|
sc = primaryStorageSearch2.create();
|
||||||
@ -526,6 +546,9 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
sc.setParameters("states", State.Allocated);
|
sc.setParameters("states", State.Allocated);
|
||||||
sc.setParameters("NotCountStates", State.Destroy, State.Expunged);
|
sc.setParameters("NotCountStates", State.Destroy, State.Expunged);
|
||||||
sc.setParameters("displayVolume", 1);
|
sc.setParameters("displayVolume", 1);
|
||||||
|
if (CollectionUtils.isNotEmpty(reservedResourceIds)) {
|
||||||
|
sc.setParameters("idNIN", reservedResourceIds.toArray());
|
||||||
|
}
|
||||||
List<SumCount> storageSpace = customSearch(sc, null);
|
List<SumCount> storageSpace = customSearch(sc, null);
|
||||||
if (storageSpace != null) {
|
if (storageSpace != null) {
|
||||||
return storageSpace.get(0).sum;
|
return storageSpace.get(0).sum;
|
||||||
@ -863,4 +886,14 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
}
|
}
|
||||||
return listBy(sc);
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,10 +26,16 @@ import java.util.Hashtable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
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.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
@ -91,6 +97,8 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||||||
NetworkDao networkDao;
|
NetworkDao networkDao;
|
||||||
@Inject
|
@Inject
|
||||||
NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
|
NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
|
||||||
|
@Inject
|
||||||
|
ReservationDao reservationDao;
|
||||||
|
|
||||||
private static final String LIST_PODS_HAVING_VMS_FOR_ACCOUNT =
|
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') "
|
"SELECT pod_id FROM cloud.vm_instance WHERE data_center_id = ? AND account_id = ? AND pod_id IS NOT NULL AND (state = 'Running' OR state = 'Stopped') "
|
||||||
@ -198,6 +206,7 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||||||
CountByAccount.and("type", CountByAccount.entity().getType(), SearchCriteria.Op.EQ);
|
CountByAccount.and("type", CountByAccount.entity().getType(), SearchCriteria.Op.EQ);
|
||||||
CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN);
|
CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN);
|
||||||
CountByAccount.and("displayVm", CountByAccount.entity().isDisplayVm(), SearchCriteria.Op.EQ);
|
CountByAccount.and("displayVm", CountByAccount.entity().isDisplayVm(), SearchCriteria.Op.EQ);
|
||||||
|
CountByAccount.and("idNIN", CountByAccount.entity().getId(), SearchCriteria.Op.NIN);
|
||||||
CountByAccount.done();
|
CountByAccount.done();
|
||||||
|
|
||||||
CountActiveAccount = createSearchBuilder(Long.class);
|
CountActiveAccount = createSearchBuilder(Long.class);
|
||||||
@ -697,6 +706,9 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long countAllocatedVMsForAccount(long accountId, boolean runningVMsonly) {
|
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();
|
SearchCriteria<Long> sc = CountByAccount.create();
|
||||||
sc.setParameters("account", accountId);
|
sc.setParameters("account", accountId);
|
||||||
sc.setParameters("type", VirtualMachine.Type.User);
|
sc.setParameters("type", VirtualMachine.Type.User);
|
||||||
@ -705,6 +717,11 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||||||
else
|
else
|
||||||
sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging});
|
sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging});
|
||||||
sc.setParameters("displayVm", 1);
|
sc.setParameters("displayVm", 1);
|
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(reservedResourceIds)) {
|
||||||
|
sc.setParameters("idNIN", reservedResourceIds.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
return customSearch(sc, null).get(0);
|
return customSearch(sc, null).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,4 +809,15 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||||||
sc.setParameters("ids", ids.toArray());
|
sc.setParameters("ids", ids.toArray());
|
||||||
return listBy(sc);
|
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")
|
@Column(name = "tag")
|
||||||
String tag;
|
String tag;
|
||||||
|
|
||||||
|
@Column(name = "resource_id")
|
||||||
|
Long resourceId;
|
||||||
|
|
||||||
@Column(name = "amount")
|
@Column(name = "amount")
|
||||||
long 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) {
|
public ReservationVO(Long accountId, Long domainId, Resource.ResourceType resourceType, String tag, Long delta) {
|
||||||
if (delta == null || delta <= 0) {
|
if (delta == null) {
|
||||||
throw new CloudRuntimeException("resource reservations can not be made for no resources");
|
throw new CloudRuntimeException("resource reservations can not be made for null resources");
|
||||||
}
|
}
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
this.domainId = domainId;
|
this.domainId = domainId;
|
||||||
@ -101,4 +104,14 @@ public class ReservationVO implements ResourceReservation {
|
|||||||
public Long getReservedAmount() {
|
public Long getReservedAmount() {
|
||||||
return amount;
|
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.configuration.Resource;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface ReservationDao extends GenericDao<ReservationVO, Long> {
|
public interface ReservationDao extends GenericDao<ReservationVO, Long> {
|
||||||
long getAccountReservation(Long account, Resource.ResourceType resourceType, String tag);
|
long getAccountReservation(Long account, Resource.ResourceType resourceType, String tag);
|
||||||
long getDomainReservation(Long domain, 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,51 @@
|
|||||||
package org.apache.cloudstack.reservation.dao;
|
package org.apache.cloudstack.reservation.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.reservation.ReservationVO;
|
import org.apache.cloudstack.reservation.ReservationVO;
|
||||||
|
|
||||||
import com.cloud.configuration.Resource;
|
import com.cloud.configuration.Resource;
|
||||||
import com.cloud.utils.db.GenericDaoBase;
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import org.apache.cloudstack.user.ResourceReservation;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> implements ReservationDao {
|
public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> implements ReservationDao {
|
||||||
|
|
||||||
|
protected transient Logger logger = LogManager.getLogger(getClass());
|
||||||
private static final String RESOURCE_TYPE = "resourceType";
|
private static final String RESOURCE_TYPE = "resourceType";
|
||||||
private static final String RESOURCE_TAG = "resourceTag";
|
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 ACCOUNT_ID = "accountId";
|
||||||
private static final String DOMAIN_ID = "domainId";
|
private static final String DOMAIN_ID = "domainId";
|
||||||
|
private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeSearch;
|
||||||
private final SearchBuilder<ReservationVO> listAccountAndTypeSearch;
|
private final SearchBuilder<ReservationVO> listAccountAndTypeSearch;
|
||||||
private final SearchBuilder<ReservationVO> listAccountAndTypeAndNoTagSearch;
|
private final SearchBuilder<ReservationVO> listAccountAndTypeAndNoTagSearch;
|
||||||
|
|
||||||
private final SearchBuilder<ReservationVO> listDomainAndTypeSearch;
|
private final SearchBuilder<ReservationVO> listDomainAndTypeSearch;
|
||||||
private final SearchBuilder<ReservationVO> listDomainAndTypeAndNoTagSearch;
|
private final SearchBuilder<ReservationVO> listDomainAndTypeAndNoTagSearch;
|
||||||
|
private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeAndNoTagSearch;
|
||||||
|
|
||||||
public ReservationDaoImpl() {
|
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 = createSearchBuilder();
|
||||||
listAccountAndTypeSearch.and(ACCOUNT_ID, listAccountAndTypeSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
listAccountAndTypeSearch.and(ACCOUNT_ID, listAccountAndTypeSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||||
listAccountAndTypeSearch.and(RESOURCE_TYPE, listAccountAndTypeSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
|
listAccountAndTypeSearch.and(RESOURCE_TYPE, listAccountAndTypeSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
|
||||||
@ -98,4 +122,43 @@ public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> impl
|
|||||||
}
|
}
|
||||||
return total;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,14 @@ DROP INDEX `i_resource_count__type_domaintId`,
|
|||||||
ADD UNIQUE INDEX `i_resource_count__type_tag_accountId` (`type`,`tag`,`account_id`),
|
ADD UNIQUE INDEX `i_resource_count__type_tag_accountId` (`type`,`tag`,`account_id`),
|
||||||
ADD UNIQUE INDEX `i_resource_count__type_tag_domaintId` (`type`,`tag`,`domain_id`);
|
ADD UNIQUE INDEX `i_resource_count__type_tag_domaintId` (`type`,`tag`,`domain_id`);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`resource_reservation`
|
||||||
|
ADD COLUMN `resource_id` bigint unsigned NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`resource_reservation`
|
||||||
|
MODIFY COLUMN `amount` bigint NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
-- Update Default System offering for Router to 512MiB
|
-- Update Default System offering for Router to 512MiB
|
||||||
UPDATE `cloud`.`service_offering` SET ram_size = 512 WHERE unique_name IN ("Cloud.Com-SoftwareRouter", "Cloud.Com-SoftwareRouter-Local",
|
UPDATE `cloud`.`service_offering` SET ram_size = 512 WHERE unique_name IN ("Cloud.Com-SoftwareRouter", "Cloud.Com-SoftwareRouter-Local",
|
||||||
"Cloud.Com-InternalLBVm", "Cloud.Com-InternalLBVm-Local",
|
"Cloud.Com-InternalLBVm", "Cloud.Com-InternalLBVm-Local",
|
||||||
@ -61,4 +69,3 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings','for_nsx', 'int(1
|
|||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"');
|
||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','for_nsx', 'int(1) unsigned DEFAULT "0" COMMENT "is nsx enabled for the resource"');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','for_nsx', 'int(1) unsigned DEFAULT "0" COMMENT "is nsx enabled for the resource"');
|
||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','nsx_mode', 'varchar(32) COMMENT "mode in which the network would route traffic"');
|
||||||
|
|
||||||
|
|||||||
@ -955,5 +955,4 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
|||||||
public String getUserDataDetails() {
|
public String getUserDataDetails() {
|
||||||
return userDataDetails;
|
return userDataDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,13 +62,32 @@ public class CheckedReservation implements AutoCloseable {
|
|||||||
return String.format("%s-%s", ResourceReservation.class.getSimpleName(), type.getName());
|
return String.format("%s-%s", ResourceReservation.class.getSimpleName(), type.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkLimitAndPersistReservation(Account account, ResourceType resourceType, String tag, Long amount) throws ResourceAllocationException {
|
protected void checkLimitAndPersistReservations(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount) throws ResourceAllocationException {
|
||||||
resourceLimitService.checkResourceLimitWithTag(account, resourceType, tag, amount);
|
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);
|
ReservationVO reservationVO = new ReservationVO(account.getAccountId(), account.getDomainId(), resourceType, tag, amount);
|
||||||
|
if (resourceId != null) {
|
||||||
|
reservationVO.setResourceId(resourceId);
|
||||||
|
}
|
||||||
ResourceReservation reservation = reservationDao.persist(reservationVO);
|
ResourceReservation reservation = reservationDao.persist(reservationVO);
|
||||||
this.reservations.add(reservation);
|
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
|
* - check if adding a reservation is allowed
|
||||||
* - create DB entry for reservation
|
* - create DB entry for reservation
|
||||||
@ -77,8 +96,8 @@ public class CheckedReservation implements AutoCloseable {
|
|||||||
* @param amount positive number of the resource type to reserve
|
* @param amount positive number of the resource type to reserve
|
||||||
* @throws ResourceAllocationException
|
* @throws ResourceAllocationException
|
||||||
*/
|
*/
|
||||||
public CheckedReservation(Account account, ResourceType resourceType, List<String> resourceLimitTags, Long amount,
|
public CheckedReservation(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount,
|
||||||
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
|
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
|
||||||
this.reservationDao = reservationDao;
|
this.reservationDao = reservationDao;
|
||||||
this.resourceLimitService = resourceLimitService;
|
this.resourceLimitService = resourceLimitService;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
@ -86,36 +105,28 @@ public class CheckedReservation implements AutoCloseable {
|
|||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.reservations = new ArrayList<>();
|
this.reservations = new ArrayList<>();
|
||||||
this.resourceLimitTags = resourceLimitTags;
|
this.resourceLimitTags = resourceLimitTags;
|
||||||
setGlobalLock();
|
|
||||||
if (this.amount != null && this.amount <= 0) {
|
|
||||||
if(logger.isDebugEnabled()){
|
|
||||||
logger.debug(String.format("not reserving no amount of resources for %s in domain %d, type: %s, %s ", account.getAccountName(), account.getDomainId(), resourceType, amount));
|
|
||||||
}
|
|
||||||
this.amount = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.amount != null) {
|
if (this.amount != null && this.amount != 0) {
|
||||||
if(quotaLimitLock.lock(TRY_TO_GET_LOCK_TIME)) {
|
if (amount > 0) {
|
||||||
try {
|
setGlobalLock();
|
||||||
checkLimitAndPersistReservation(account, resourceType, null, amount);
|
if (quotaLimitLock.lock(TRY_TO_GET_LOCK_TIME)) {
|
||||||
if (CollectionUtils.isNotEmpty(resourceLimitTags)) {
|
try {
|
||||||
for (String tag: resourceLimitTags) {
|
checkLimitAndPersistReservations(account, resourceType, resourceId, resourceLimitTags, amount);
|
||||||
checkLimitAndPersistReservation(account, resourceType, tag, 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());
|
} else {
|
||||||
} catch (NullPointerException npe) {
|
throw new ResourceAllocationException(String.format("unable to acquire resource reservation \"%s\"", quotaLimitLock.getName()), resourceType);
|
||||||
throw new CloudRuntimeException("not enough means to check limits", npe);
|
|
||||||
} finally {
|
|
||||||
quotaLimitLock.unlock();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new ResourceAllocationException(String.format("unable to acquire resource reservation \"%s\"", quotaLimitLock.getName()), resourceType);
|
checkLimitAndPersistReservations(account, resourceType, resourceId, resourceLimitTags, amount);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(logger.isDebugEnabled()) {
|
logger.debug("not reserving any amount of resources for {} in domain {}, type: {}, tag: {}",
|
||||||
logger.debug(String.format("not reserving no amount of resources for %s in domain %d, type: %s, tag: %s", account.getAccountName(), account.getDomainId(), resourceType, getResourceLimitTagsAsString()));
|
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.Configurable;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
||||||
|
import org.apache.cloudstack.reservation.ReservationVO;
|
||||||
import org.apache.cloudstack.reservation.dao.ReservationDao;
|
import org.apache.cloudstack.reservation.dao.ReservationDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
||||||
@ -1273,9 +1274,11 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
if (CollectionUtils.isEmpty(offerings) && CollectionUtils.isEmpty(templates)) {
|
if (CollectionUtils.isEmpty(offerings) && CollectionUtils.isEmpty(templates)) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
return _userVmJoinDao.listByAccountServiceOfferingTemplateAndNotInState(accountId, states,
|
|
||||||
|
return _userVmJoinDao.listByAccountServiceOfferingTemplateAndNotInState(accountId, states,
|
||||||
offerings.stream().map(ServiceOfferingVO::getId).collect(Collectors.toList()),
|
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) {
|
protected List<UserVmJoinVO> getVmsWithAccount(long accountId) {
|
||||||
@ -1293,12 +1296,26 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
vrIds);
|
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) {
|
protected long calculateVmCountForAccount(long accountId, String tag) {
|
||||||
if (StringUtils.isEmpty(tag)) {
|
if (StringUtils.isEmpty(tag)) {
|
||||||
return _userVmDao.countAllocatedVMsForAccount(accountId, VirtualMachineManager.ResourceCountRunningVMsonly.value());
|
return _userVmDao.countAllocatedVMsForAccount(accountId, VirtualMachineManager.ResourceCountRunningVMsonly.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
|
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) {
|
protected long calculateVolumeCountForAccount(long accountId, String tag) {
|
||||||
@ -1316,10 +1333,12 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
}
|
}
|
||||||
long cputotal = 0;
|
long cputotal = 0;
|
||||||
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
|
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
|
||||||
|
|
||||||
for (UserVmJoinVO vm : vms) {
|
for (UserVmJoinVO vm : vms) {
|
||||||
cputotal += vm.getCpu();
|
cputotal += vm.getCpu();
|
||||||
}
|
}
|
||||||
return cputotal;
|
long reservedCpus = calculateReservedResources(vms, accountId, ResourceType.cpu, tag);
|
||||||
|
return cputotal - reservedCpus;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long calculateVmMemoryCountForAccount(long accountId, String tag) {
|
protected long calculateVmMemoryCountForAccount(long accountId, String tag) {
|
||||||
@ -1328,10 +1347,12 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
}
|
}
|
||||||
long memory = 0;
|
long memory = 0;
|
||||||
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
|
List<UserVmJoinVO> vms = getVmsWithAccountAndTag(accountId, tag);
|
||||||
|
|
||||||
for (UserVmJoinVO vm : vms) {
|
for (UserVmJoinVO vm : vms) {
|
||||||
memory += vm.getRamSize();
|
memory += vm.getRamSize();
|
||||||
}
|
}
|
||||||
return memory;
|
long reservedMemory = calculateReservedResources(vms, accountId, ResourceType.memory, tag);
|
||||||
|
return memory - reservedMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long countCpusForAccount(long accountId) {
|
public long countCpusForAccount(long accountId) {
|
||||||
@ -1340,7 +1361,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
for (UserVmJoinVO vm : userVms) {
|
for (UserVmJoinVO vm : userVms) {
|
||||||
cputotal += vm.getCpu();
|
cputotal += vm.getCpu();
|
||||||
}
|
}
|
||||||
return cputotal;
|
long reservedCpuTotal = calculateReservedResources(userVms, accountId, ResourceType.cpu, null);
|
||||||
|
return cputotal - reservedCpuTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long calculateMemoryForAccount(long accountId) {
|
public long calculateMemoryForAccount(long accountId) {
|
||||||
@ -1349,7 +1371,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
for (UserVmJoinVO vm : userVms) {
|
for (UserVmJoinVO vm : userVms) {
|
||||||
ramtotal += vm.getRamSize();
|
ramtotal += vm.getRamSize();
|
||||||
}
|
}
|
||||||
return ramtotal;
|
long reservedRamTotal = calculateReservedResources(userVms, accountId, ResourceType.memory, null);
|
||||||
|
return ramtotal - reservedRamTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long calculateSecondaryStorageForAccount(long accountId) {
|
public long calculateSecondaryStorageForAccount(long accountId) {
|
||||||
@ -1625,32 +1648,44 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DB
|
||||||
@Override
|
@Override
|
||||||
public void incrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering) {
|
public void incrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering) {
|
||||||
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
|
Transaction.execute(new TransactionCallbackNoReturn() {
|
||||||
if (CollectionUtils.isEmpty(tags)) {
|
@Override
|
||||||
return;
|
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
}
|
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
|
||||||
for (String tag : tags) {
|
if (CollectionUtils.isEmpty(tags)) {
|
||||||
incrementResourceCountWithTag(accountId, ResourceType.volume, tag);
|
return;
|
||||||
if (size != null) {
|
}
|
||||||
incrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
|
for (String tag : tags) {
|
||||||
|
incrementResourceCountWithTag(accountId, ResourceType.volume, tag);
|
||||||
|
if (size != null) {
|
||||||
|
incrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DB
|
||||||
@Override
|
@Override
|
||||||
public void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering) {
|
public void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering) {
|
||||||
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
|
Transaction.execute(new TransactionCallbackNoReturn() {
|
||||||
if (CollectionUtils.isEmpty(tags)) {
|
@Override
|
||||||
return;
|
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
}
|
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
|
||||||
for (String tag : tags) {
|
if (CollectionUtils.isEmpty(tags)) {
|
||||||
decrementResourceCountWithTag(accountId, ResourceType.volume, tag);
|
return;
|
||||||
if (size != null) {
|
}
|
||||||
decrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
|
for (String tag : tags) {
|
||||||
|
decrementResourceCountWithTag(accountId, ResourceType.volume, tag);
|
||||||
|
if (size != null) {
|
||||||
|
decrementResourceCountWithTag(accountId, ResourceType.primary_storage, tag, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1711,32 +1746,43 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) {
|
public void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) {
|
||||||
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
|
Transaction.execute(new TransactionCallbackNoReturn() {
|
||||||
if (CollectionUtils.isEmpty(tags)) {
|
@Override
|
||||||
return;
|
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
}
|
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
|
||||||
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
|
if (CollectionUtils.isEmpty(tags)) {
|
||||||
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
|
return;
|
||||||
for (String tag : tags) {
|
}
|
||||||
incrementResourceCountWithTag(accountId, ResourceType.user_vm, tag);
|
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
|
||||||
incrementResourceCountWithTag(accountId, ResourceType.cpu, tag, cpu);
|
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
|
||||||
incrementResourceCountWithTag(accountId, ResourceType.memory, tag, ram);
|
for (String tag : tags) {
|
||||||
}
|
incrementResourceCountWithTag(accountId, ResourceType.user_vm, tag);
|
||||||
|
incrementResourceCountWithTag(accountId, ResourceType.cpu, tag, cpu);
|
||||||
|
incrementResourceCountWithTag(accountId, ResourceType.memory, tag, ram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) {
|
public void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering,
|
||||||
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
|
VirtualMachineTemplate template) {
|
||||||
if (CollectionUtils.isEmpty(tags)) {
|
Transaction.execute(new TransactionCallbackNoReturn() {
|
||||||
return;
|
@Override
|
||||||
}
|
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
|
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
|
||||||
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
|
if (CollectionUtils.isEmpty(tags)) {
|
||||||
for (String tag : tags) {
|
return;
|
||||||
decrementResourceCountWithTag(accountId, ResourceType.user_vm, tag);
|
}
|
||||||
decrementResourceCountWithTag(accountId, ResourceType.cpu, tag, cpu);
|
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
|
||||||
decrementResourceCountWithTag(accountId, ResourceType.memory, tag, ram);
|
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
|
@Override
|
||||||
|
|||||||
@ -5700,37 +5700,47 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
boolean status;
|
boolean status;
|
||||||
State vmState = vm.getState();
|
State vmState = vm.getState();
|
||||||
|
|
||||||
try {
|
Account owner = _accountMgr.getAccount(vm.getAccountId());
|
||||||
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) {
|
ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId());
|
||||||
// Mark the account's volumes as destroyed
|
|
||||||
List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
|
try (CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, vmId, null, -1L, reservationDao, resourceLimitService);
|
||||||
for (VolumeVO volume : volumes) {
|
CheckedReservation cpuReservation = new CheckedReservation(owner, ResourceType.cpu, vmId, null, -1 * Long.valueOf(offering.getCpu()), reservationDao, resourceLimitService);
|
||||||
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, vmId, null, -1 * Long.valueOf(offering.getRamSize()), reservationDao, resourceLimitService);
|
||||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
|
) {
|
||||||
Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume());
|
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) {
|
if (vmState != State.Error) {
|
||||||
// Get serviceOffering and template for Virtual Machine
|
// Get serviceOffering and template for Virtual Machine
|
||||||
ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId());
|
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
|
||||||
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
|
//Update Resource Count for the given account
|
||||||
//Update Resource Count for the given account
|
resourceCountDecrement(vm.getAccountId(), vm.isDisplayVm(), offering, template);
|
||||||
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);
|
} catch (Exception e) {
|
||||||
} else {
|
throw new CloudRuntimeException("Failed to destroy vm with specified vmId", e);
|
||||||
CloudRuntimeException ex = new CloudRuntimeException("Failed to destroy vm with specified vmId");
|
|
||||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@
|
|||||||
package com.cloud.resourcelimit;
|
package com.cloud.resourcelimit;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@ -108,9 +107,10 @@ public class CheckedReservationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getNoAmount() {
|
public void getNoAmount() {
|
||||||
|
Mockito.when(reservationDao.persist(Mockito.any())).thenReturn(reservation);
|
||||||
try (CheckedReservation cr = new CheckedReservation(account, Resource.ResourceType.cpu,-11l, reservationDao, resourceLimitService) ) {
|
try (CheckedReservation cr = new CheckedReservation(account, Resource.ResourceType.cpu,-11l, reservationDao, resourceLimitService) ) {
|
||||||
Long amount = cr.getReservedAmount();
|
Long amount = cr.getReservedAmount();
|
||||||
assertNull(amount);
|
assertEquals(Long.valueOf(-11L), amount);
|
||||||
} catch (NullPointerException npe) {
|
} catch (NullPointerException npe) {
|
||||||
fail("NPE caught");
|
fail("NPE caught");
|
||||||
} catch (ResourceAllocationException rae) {
|
} 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.DomainResponse;
|
||||||
import org.apache.cloudstack.api.response.TaggedResourceLimitAndCountResponse;
|
import org.apache.cloudstack.api.response.TaggedResourceLimitAndCountResponse;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import org.apache.cloudstack.reservation.dao.ReservationDao;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -106,6 +107,8 @@ public class ResourceLimitManagerImplTest extends TestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
ResourceCountDao resourceCountDao;
|
ResourceCountDao resourceCountDao;
|
||||||
@Mock
|
@Mock
|
||||||
|
private ReservationDao reservationDao;
|
||||||
|
@Mock
|
||||||
UserVmJoinDao userVmJoinDao;
|
UserVmJoinDao userVmJoinDao;
|
||||||
@Mock
|
@Mock
|
||||||
ServiceOfferingDao serviceOfferingDao;
|
ServiceOfferingDao serviceOfferingDao;
|
||||||
@ -675,7 +678,9 @@ public class ResourceLimitManagerImplTest extends TestCase {
|
|||||||
Assert.assertEquals(2L, resourceLimitManager.calculateVmCountForAccount(accountId, tag));
|
Assert.assertEquals(2L, resourceLimitManager.calculateVmCountForAccount(accountId, tag));
|
||||||
|
|
||||||
tag = "tag";
|
tag = "tag";
|
||||||
Mockito.doReturn(List.of(UserVmJoinVO.class)).when(resourceLimitManager).getVmsWithAccountAndTag(accountId, tag);
|
UserVmJoinVO vm = Mockito.mock(UserVmJoinVO.class);
|
||||||
|
Mockito.when(vm.getId()).thenReturn(1L);
|
||||||
|
Mockito.doReturn(List.of(vm)).when(resourceLimitManager).getVmsWithAccountAndTag(accountId, tag);
|
||||||
Assert.assertEquals(1L, resourceLimitManager.calculateVmCountForAccount(accountId, tag));
|
Assert.assertEquals(1L, resourceLimitManager.calculateVmCountForAccount(accountId, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
@ -123,10 +124,10 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
|
|||||||
DomainVO domain = new DomainVO();
|
DomainVO domain = new DomainVO();
|
||||||
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
|
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
|
||||||
|
|
||||||
when(_orchSrvc.getVirtualMachine(nullable(String.class))).thenReturn(vmEntity);
|
lenient().when(_orchSrvc.getVirtualMachine(nullable(String.class))).thenReturn(vmEntity);
|
||||||
when(vmEntity.destroy(nullable(Boolean.class))).thenReturn(true);
|
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);
|
VolumeVO vol = new VolumeVO(VOLUME_UUID, 1l, 1l, 1l, 1l, 1l, "folder", "path", null, 50, Type.ROOT);
|
||||||
vol.setDisplayVolume(true);
|
vol.setDisplayVolume(true);
|
||||||
@ -136,20 +137,20 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
|
|||||||
lenient().when(securityChecker.checkAccess(Mockito.eq(account), nullable(ControlledEntity.class), nullable(AccessType.class), nullable(String.class))).thenReturn(true);
|
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.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm));
|
||||||
lenient().when(_userVmDao.findByUuid(nullable(String.class))).thenReturn(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);
|
ServiceOfferingVO offering = mock(ServiceOfferingVO.class);
|
||||||
lenient().when(offering.getCpu()).thenReturn(500);
|
lenient().when(offering.getCpu()).thenReturn(500);
|
||||||
lenient().when(offering.getId()).thenReturn(1l);
|
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);
|
lenient().when(_domainMgr.getDomain(nullable(Long.class))).thenReturn(domain);
|
||||||
|
|
||||||
Mockito.lenient().doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class));
|
Mockito.doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,22 +191,22 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
|
|||||||
// If the VM is already destroyed, no events should get emitted
|
// If the VM is already destroyed, no events should get emitted
|
||||||
public void destroyedVMRootVolumeUsageEvent()
|
public void destroyedVMRootVolumeUsageEvent()
|
||||||
throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
|
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);
|
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(true);
|
||||||
Assert.assertEquals(0, emittedEvents.size());
|
Assert.assertEquals(0, emittedEvents.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore()
|
||||||
@Test
|
@Test
|
||||||
// If the VM is running, we should see one emitted event for the root
|
// If the VM is running, we should see one emitted event for the root
|
||||||
// volume.
|
// volume.
|
||||||
public void runningVMRootVolumeUsageEvent()
|
public void runningVMRootVolumeUsageEvent()
|
||||||
throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
|
throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
|
||||||
Mockito.doNothing().when(vmStatsDaoMock).removeAllByVmId(Mockito.anyLong());
|
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);
|
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false);
|
||||||
UsageEventVO event = emittedEvents.get(0);
|
UsageEventVO event = emittedEvents.get(0);
|
||||||
Assert.assertEquals(EventTypes.EVENT_VOLUME_DELETE, event.getType());
|
Assert.assertEquals(EventTypes.EVENT_VOLUME_DELETE, event.getType());
|
||||||
Assert.assertEquals(VOLUME_UUID, event.getResourceName());
|
Assert.assertEquals(VOLUME_UUID, event.getResourceName());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,4 +75,5 @@
|
|||||||
<bean id="nsxControllerDaoImpl" class="com.cloud.network.dao.NsxProviderDaoImpl" />
|
<bean id="nsxControllerDaoImpl" class="com.cloud.network.dao.NsxProviderDaoImpl" />
|
||||||
<bean id="vlanDetailsDao" class="com.cloud.dc.dao.VlanDetailsDaoImpl" />
|
<bean id="vlanDetailsDao" class="com.cloud.dc.dao.VlanDetailsDaoImpl" />
|
||||||
<bean id="publicIpQuarantineDaoImpl" class="com.cloud.network.dao.PublicIpQuarantineDaoImpl" />
|
<bean id="publicIpQuarantineDaoImpl" class="com.cloud.network.dao.PublicIpQuarantineDaoImpl" />
|
||||||
|
<bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />
|
||||||
</beans>
|
</beans>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user