Skip to content

Commit 89df318

Browse files
DaanHooglandDaan Hoogland
authored andcommitted
[20.3] resource allocation
1 parent 56dc119 commit 89df318

10 files changed

Lines changed: 101 additions & 57 deletions

File tree

api/src/main/java/com/cloud/user/ResourceLimitService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ public interface ResourceLimitService {
185185
*/
186186
public void checkResourceLimit(Account account, ResourceCount.ResourceType type, long... count) throws ResourceAllocationException;
187187
public void checkResourceLimitWithTag(Account account, ResourceCount.ResourceType type, String tag, long... count) throws ResourceAllocationException;
188+
public void checkResourceLimitWithTag(Account account, Long domainId, boolean considerSystemAccount, ResourceCount.ResourceType type, String tag, long... count) throws ResourceAllocationException;
188189

189190
/**
190191
* Gets the count of resources for a resource type and account
@@ -284,4 +285,5 @@ void checkVmResourceLimitsForTemplateChange(Account owner, Boolean display, Serv
284285
void incrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
285286
void decrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
286287

288+
long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag);
287289
}

engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ void implementNetworkElementsAndResources(DeployDestination dest, ReservationCon
302302

303303
void removeDhcpServiceInSubnet(Nic nic);
304304

305-
boolean resourceCountNeedsUpdate(NetworkOffering ntwkOff, ACLType aclType);
305+
boolean isResourceCountUpdateNeeded(NetworkOffering networkOffering);
306306

307307
void prepareAllNicsForMigration(VirtualMachineProfile vm, DeployDestination dest);
308308

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@
3939
import javax.inject.Inject;
4040
import javax.naming.ConfigurationException;
4141

42+
import com.cloud.configuration.Resource;
4243
import com.cloud.dc.ASNumberVO;
4344
import com.cloud.bgp.BGPService;
4445
import com.cloud.dc.VlanDetailsVO;
4546
import com.cloud.dc.dao.ASNumberDao;
4647
import com.cloud.dc.dao.VlanDetailsDao;
4748
import com.cloud.network.dao.NsxProviderDao;
49+
import com.cloud.resourcelimit.CheckedReservation;
4850
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
4951
import org.apache.cloudstack.annotation.AnnotationService;
5052
import org.apache.cloudstack.annotation.dao.AnnotationDao;
@@ -62,6 +64,7 @@
6264
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
6365
import org.apache.cloudstack.network.RoutedIpv4Manager;
6466
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
67+
import org.apache.cloudstack.reservation.dao.ReservationDao;
6568
import org.apache.commons.collections.CollectionUtils;
6669
import org.apache.commons.lang3.BooleanUtils;
6770
import org.apache.commons.lang3.ObjectUtils;
@@ -441,6 +444,8 @@ public void setDhcpProviders(final List<DhcpServiceProvider> dhcpProviders) {
441444
ClusterDao clusterDao;
442445
@Inject
443446
RoutedIpv4Manager routedIpv4Manager;
447+
@Inject
448+
private ReservationDao reservationDao;
444449

445450
protected StateMachine2<Network.State, Network.Event, Network> _stateMachine;
446451
ScheduledExecutorService _executor;
@@ -2721,12 +2726,6 @@ private Network createGuestNetwork(final long networkOfferingId, final String na
27212726
return null;
27222727
}
27232728

2724-
final boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, aclType);
2725-
//check resource limits
2726-
if (updateResourceCount) {
2727-
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.network, isDisplayNetworkEnabled);
2728-
}
2729-
27302729
// Validate network offering
27312730
if (ntwkOff.getState() != NetworkOffering.State.Enabled) {
27322731
// see NetworkOfferingVO
@@ -2745,6 +2744,8 @@ private Network createGuestNetwork(final long networkOfferingId, final String na
27452744

27462745
boolean ipv6 = false;
27472746

2747+
try (CheckedReservation networkReservation = new CheckedReservation(owner, domainId, Resource.ResourceType.network, null, null, 1L, reservationDao, _resourceLimitMgr)) {
2748+
27482749
if (StringUtils.isNoneBlank(ip6Gateway, ip6Cidr)) {
27492750
ipv6 = true;
27502751
}
@@ -3084,8 +3085,8 @@ public Network doInTransaction(final TransactionStatus status) {
30843085
}
30853086
}
30863087

3087-
if (updateResourceCount) {
3088-
_resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.network, isDisplayNetworkEnabled);
3088+
if (isResourceCountUpdateNeeded(ntwkOff)) {
3089+
changeAccountResourceCountOrRecalculateDomainResourceCount(owner.getAccountId(), domainId, isDisplayNetworkEnabled, true);
30893090
}
30903091
UsageEventUtils.publishNetworkCreation(network);
30913092

@@ -3096,6 +3097,10 @@ public Network doInTransaction(final TransactionStatus status) {
30963097
CallContext.current().setEventDetails("Network Id: " + network.getId());
30973098
CallContext.current().putContextParameter(Network.class, network.getUuid());
30983099
return network;
3100+
} catch (Exception e) {
3101+
logger.error(e);
3102+
throw new RuntimeException(e);
3103+
}
30993104
}
31003105

31013106
@Override
@@ -3460,9 +3465,8 @@ public List<VlanVO> doInTransaction(TransactionStatus status) {
34603465
}
34613466

34623467
final NetworkOffering ntwkOff = _entityMgr.findById(NetworkOffering.class, networkFinal.getNetworkOfferingId());
3463-
final boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, networkFinal.getAclType());
3464-
if (updateResourceCount) {
3465-
_resourceLimitMgr.decrementResourceCount(networkFinal.getAccountId(), ResourceType.network, networkFinal.getDisplayNetwork());
3468+
if (isResourceCountUpdateNeeded(ntwkOff)) {
3469+
changeAccountResourceCountOrRecalculateDomainResourceCount(networkFinal.getAccountId(), networkFinal.getDomainId(), networkFinal.getDisplayNetwork(), false);
34663470
}
34673471
}
34683472
return deletedVlans.second();
@@ -3485,6 +3489,23 @@ public List<VlanVO> doInTransaction(TransactionStatus status) {
34853489
return success;
34863490
}
34873491

3492+
/**
3493+
* If it is a shared network with {@link ACLType#Domain}, it will belong to account {@link Account#ACCOUNT_ID_SYSTEM} and the resources will be not incremented for the
3494+
* domain. Therefore, we force the recalculation of the domain's resource count in this case. Otherwise, it will change the count for the account owner.
3495+
* @param incrementAccountResourceCount If true, the account resource count will be incremented by 1; otherwise, it will decremented by 1.
3496+
*/
3497+
private void changeAccountResourceCountOrRecalculateDomainResourceCount(Long accountId, Long domainId, boolean displayNetwork, boolean incrementAccountResourceCount) {
3498+
if (Account.ACCOUNT_ID_SYSTEM == accountId && ObjectUtils.isNotEmpty(domainId)) {
3499+
_resourceLimitMgr.recalculateDomainResourceCount(domainId, ResourceType.network, null);
3500+
} else {
3501+
if (incrementAccountResourceCount) {
3502+
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.network, displayNetwork);
3503+
} else {
3504+
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.network, displayNetwork);
3505+
}
3506+
}
3507+
}
3508+
34883509
private void publishDeletedVlanRanges(List<VlanVO> deletedVlanRangeToPublish) {
34893510
if (CollectionUtils.isNotEmpty(deletedVlanRangeToPublish)) {
34903511
for (VlanVO vlan : deletedVlanRangeToPublish) {
@@ -3494,10 +3515,8 @@ private void publishDeletedVlanRanges(List<VlanVO> deletedVlanRangeToPublish) {
34943515
}
34953516

34963517
@Override
3497-
public boolean resourceCountNeedsUpdate(final NetworkOffering ntwkOff, final ACLType aclType) {
3498-
//Update resource count only for Isolated account specific non-system networks
3499-
final boolean updateResourceCount = ntwkOff.getGuestType() == GuestType.Isolated && !ntwkOff.isSystemOnly() && aclType == ACLType.Account;
3500-
return updateResourceCount;
3518+
public boolean isResourceCountUpdateNeeded(NetworkOffering networkOffering) {
3519+
return !networkOffering.isSystemOnly();
35013520
}
35023521

35033522
protected Pair<Boolean, List<VlanVO>> deleteVlansInNetwork(final NetworkVO network, final long userId, final Account callerAccount) {

server/src/main/java/com/cloud/network/NetworkServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3168,7 +3168,7 @@ public Network updateGuestNetwork(final UpdateNetworkCmd cmd) {
31683168
if (displayNetwork != null && displayNetwork != network.getDisplayNetwork()) {
31693169
// Update resource count if it needs to be updated
31703170
NetworkOffering networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId());
3171-
if (_networkMgr.resourceCountNeedsUpdate(networkOffering, network.getAclType())) {
3171+
if (_networkMgr.isResourceCountUpdateNeeded(networkOffering)) {
31723172
_resourceLimitMgr.changeResourceCount(network.getAccountId(), Resource.ResourceType.network, displayNetwork);
31733173
}
31743174

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

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class CheckedReservation implements AutoCloseable {
4949

5050
ResourceLimitService resourceLimitService;
5151
private final Account account;
52+
private Long domainId;
5253
private final ResourceType resourceType;
5354
private Long amount;
5455
private List<ResourceReservation> reservations;
@@ -73,12 +74,12 @@ private void removeAllReservations() {
7374
this.reservations = null;
7475
}
7576

76-
protected void checkLimitAndPersistReservations(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount) throws ResourceAllocationException {
77+
protected void checkLimitAndPersistReservations(Account account, Long domainId, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount) throws ResourceAllocationException {
7778
try {
78-
checkLimitAndPersistReservation(account, resourceType, resourceId, null, amount);
79+
checkLimitAndPersistReservation(account, domainId, resourceType, resourceId, null, amount);
7980
if (CollectionUtils.isNotEmpty(resourceLimitTags)) {
8081
for (String tag : resourceLimitTags) {
81-
checkLimitAndPersistReservation(account, resourceType, resourceId, tag, amount);
82+
checkLimitAndPersistReservation(account, domainId, resourceType, resourceId, tag, amount);
8283
}
8384
}
8485
} catch (ResourceAllocationException rae) {
@@ -87,11 +88,11 @@ protected void checkLimitAndPersistReservations(Account account, ResourceType re
8788
}
8889
}
8990

90-
protected void checkLimitAndPersistReservation(Account account, ResourceType resourceType, Long resourceId, String tag, Long amount) throws ResourceAllocationException {
91+
protected void checkLimitAndPersistReservation(Account account, Long domainId, ResourceType resourceType, Long resourceId, String tag, Long amount) throws ResourceAllocationException {
9192
if (amount > 0) {
92-
resourceLimitService.checkResourceLimitWithTag(account, resourceType, tag, amount);
93+
resourceLimitService.checkResourceLimitWithTag(account, domainId, true, resourceType, tag, amount);
9394
}
94-
ReservationVO reservationVO = new ReservationVO(account.getAccountId(), account.getDomainId(), resourceType, tag, amount);
95+
ReservationVO reservationVO = new ReservationVO(account.getAccountId(), domainId, resourceType, tag, amount);
9596
if (resourceId != null) {
9697
reservationVO.setResourceId(resourceId);
9798
}
@@ -114,9 +115,20 @@ public CheckedReservation(Account account, ResourceType resourceType, List<Strin
114115
*/
115116
public CheckedReservation(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount,
116117
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
118+
this(account, account.getDomainId(), resourceType, resourceId, resourceLimitTags, amount, reservationDao, resourceLimitService);
119+
}
120+
121+
public CheckedReservation(Account account, Long domainId, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount,
122+
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
117123
this.reservationDao = reservationDao;
118124
this.resourceLimitService = resourceLimitService;
119125
this.account = account;
126+
127+
this.domainId = domainId;
128+
if (domainId == null) {
129+
this.domainId = account.getDomainId();
130+
}
131+
120132
this.resourceType = resourceType;
121133
this.amount = amount;
122134
this.reservations = new ArrayList<>();
@@ -127,7 +139,7 @@ public CheckedReservation(Account account, ResourceType resourceType, Long resou
127139
setGlobalLock();
128140
if (quotaLimitLock.lock(TRY_TO_GET_LOCK_TIME)) {
129141
try {
130-
checkLimitAndPersistReservations(account, resourceType, resourceId, resourceLimitTags, amount);
142+
checkLimitAndPersistReservations(account, this.domainId, resourceType, resourceId, resourceLimitTags, amount);
131143
CallContext.current().putContextParameter(getContextParameterKey(), getIds());
132144
} catch (NullPointerException npe) {
133145
throw new CloudRuntimeException("not enough means to check limits", npe);
@@ -138,11 +150,11 @@ public CheckedReservation(Account account, ResourceType resourceType, Long resou
138150
throw new ResourceAllocationException(String.format("unable to acquire resource reservation \"%s\"", quotaLimitLock.getName()), resourceType);
139151
}
140152
} else {
141-
checkLimitAndPersistReservations(account, resourceType, resourceId, resourceLimitTags, amount);
153+
checkLimitAndPersistReservations(account, this.domainId, resourceType, resourceId, resourceLimitTags, amount);
142154
}
143155
} else {
144156
logger.debug("not reserving any amount of resources for {} in domain {}, type: {}, tag: {}",
145-
account.getAccountName(), account.getDomainId(), resourceType, getResourceLimitTagsAsString());
157+
account.getAccountName(), this.domainId, resourceType, getResourceLimitTagsAsString());
146158
}
147159
}
148160

@@ -153,7 +165,7 @@ public CheckedReservation(Account account, ResourceType resourceType, Long amoun
153165

154166
@NotNull
155167
private void setGlobalLock() {
156-
String lockName = String.format("CheckedReservation-%s/%d", account.getDomainId(), resourceType.getOrdinal());
168+
String lockName = String.format("CheckedReservation-%s/%d", this.domainId, resourceType.getOrdinal());
157169
setQuotaLimitLock(GlobalLock.getInternLock(lockName));
158170
}
159171

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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import javax.inject.Inject;
3737
import javax.naming.ConfigurationException;
3838

39+
import com.cloud.network.dao.NetworkDomainDao;
3940
import com.cloud.utils.Ternary;
4041
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
4142
import org.apache.cloudstack.api.response.AccountResponse;
@@ -192,6 +193,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
192193
ServiceOfferingDao serviceOfferingDao;
193194
@Inject
194195
DiskOfferingDao diskOfferingDao;
196+
@Inject
197+
private NetworkDomainDao networkDomainDao;
195198

196199
protected GenericSearchBuilder<TemplateDataStoreVO, SumCount> templateSizeSearch;
197200
protected GenericSearchBuilder<SnapshotDataStoreVO, SumCount> snapshotSizeSearch;
@@ -488,15 +491,7 @@ public long findCorrectResourceLimitForDomain(Domain domain, ResourceType type,
488491
return max;
489492
}
490493

491-
protected void checkDomainResourceLimit(final Account account, final Project project, final ResourceType type, String tag, long numResources) throws ResourceAllocationException {
492-
// check all domains in the account's domain hierarchy
493-
Long domainId;
494-
if (project != null) {
495-
domainId = project.getDomainId();
496-
} else {
497-
domainId = account.getDomainId();
498-
}
499-
494+
protected void checkDomainResourceLimit(Long domainId, final ResourceType type, String tag, long numResources) throws ResourceAllocationException {
500495
while (domainId != null) {
501496
DomainVO domain = _domainDao.findById(domainId);
502497
// no limit check if it is ROOT domain
@@ -618,18 +613,31 @@ public void checkResourceLimit(final Account account, final ResourceType type, l
618613

619614
@Override
620615
public void checkResourceLimitWithTag(final Account account, final ResourceType type, String tag, long... count) throws ResourceAllocationException {
616+
checkResourceLimitWithTag(account, null, false, type, tag, count);
617+
}
618+
619+
@Override
620+
public void checkResourceLimitWithTag(final Account account, Long domainId, boolean considerSystemAccount, final ResourceType type, String tag, long... count) throws ResourceAllocationException {
621621
final long numResources = ((count.length == 0) ? 1 : count[0]);
622622
Project project = null;
623623

624624
// Don't place any limits on system or root admin accounts
625-
if (_accountMgr.isRootAdmin(account.getId())) {
625+
if (_accountMgr.isRootAdmin(account.getId()) && !(considerSystemAccount && Account.ACCOUNT_ID_SYSTEM == account.getId())) {
626626
return;
627627
}
628628

629629
if (account.getType() == Account.Type.PROJECT) {
630630
project = _projectDao.findByProjectAccountId(account.getId());
631631
}
632632

633+
if (domainId == null) {
634+
if (project != null) {
635+
domainId = project.getDomainId();
636+
} else {
637+
domainId = account.getDomainId();
638+
}
639+
}
640+
Long domainIdFinal = domainId;
633641
final Project projectFinal = project;
634642
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
635643
@Override
@@ -639,7 +647,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Resour
639647
// Check account limits
640648
checkAccountResourceLimit(account, projectFinal, type, tag, numResources);
641649
// check all domains in the account's domain hierarchy
642-
checkDomainResourceLimit(account, projectFinal, type, tag, numResources);
650+
checkDomainResourceLimit(domainIdFinal, type, tag, numResources);
643651
}
644652
});
645653
}
@@ -1155,7 +1163,7 @@ protected boolean updateResourceCountForAccount(final long accountId, final Reso
11551163
* @param type the resource type to do the recalculation for
11561164
* @return the resulting new resource count
11571165
*/
1158-
protected long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag) {
1166+
public long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag) {
11591167
List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId);
11601168
List<DomainVO> childDomains = _domainDao.findImmediateChildrenForParent(domainId);
11611169

@@ -1196,6 +1204,10 @@ protected long recalculateDomainResourceCount(final long domainId, final Resourc
11961204
newResourceCount += _projectDao.countProjectsForDomain(domainId);
11971205
}
11981206

1207+
if (type == ResourceType.network) {
1208+
newResourceCount += networkDomainDao.listDomainNetworkMapByDomain(domainId).size();
1209+
}
1210+
11991211
// TODO make sure that the resource counts are not null
12001212
for (ResourceCountVO resourceCount : resourceCounts) {
12011213
if (resourceCount.getResourceOwnerType() == ResourceOwnerType.Domain && resourceCount.getDomainId() == domainId) {

0 commit comments

Comments
 (0)