Skip to content

Commit afdf4d7

Browse files
authored
Add limit configuration for number of projects (#9172)
1 parent b9c7275 commit afdf4d7

File tree

5 files changed

+117
-1
lines changed

5 files changed

+117
-1
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ public interface ResourceLimitService {
4646
"A comma-separated list of tags for host resource limits", true);
4747
static final ConfigKey<String> ResourceLimitStorageTags = new ConfigKey<>("Advanced", String.class, "resource.limit.storage.tags", "",
4848
"A comma-separated list of tags for storage resource limits", true);
49+
static final ConfigKey<Long> DefaultMaxAccountProjects = new ConfigKey<>("Account Defaults",Long.class,"max.account.projects","10",
50+
"The default maximum number of projects that can be created for an account",false);
51+
static final ConfigKey<Long> DefaultMaxDomainProjects = new ConfigKey<>("Domain Defaults",Long.class,"max.domain.projects","50",
52+
"The default maximum number of projects that can be created for a domain",false);
4953

5054
static final List<ResourceType> HostTagsSupportingTypes = List.of(ResourceType.user_vm, ResourceType.cpu, ResourceType.memory);
5155
static final List<ResourceType> StorageTagsSupportingTypes = List.of(ResourceType.volume, ResourceType.primary_storage);

api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public class UpdateResourceLimitCmd extends BaseCmd {
6262
+ "2 - Volume. Number of disk volumes a user can create. "
6363
+ "3 - Snapshot. Number of snapshots a user can create. "
6464
+ "4 - Template. Number of templates that a user can register/create. "
65+
+ "5 - Project. Number of projects a user can create. "
6566
+ "6 - Network. Number of guest network a user can create. "
6667
+ "7 - VPC. Number of VPC a user can create. "
6768
+ "8 - CPU. Total number of CPU cores a user can use. "

server/src/main/java/com/cloud/configuration/Config.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,14 @@ public enum Config {
13651365
"200",
13661366
"The default maximum primary storage space (in GiB) that can be used for an account",
13671367
null),
1368+
DefaultMaxAccountProjects(
1369+
"Account Defaults",
1370+
ManagementServer.class,
1371+
Long.class,
1372+
"max.account.projects",
1373+
"10",
1374+
"The default maximum number of projects that can be created for an account",
1375+
null),
13681376

13691377
//disabling lb as cluster sync does not work with distributed cluster
13701378
SubDomainNetworkAccess(
@@ -1414,6 +1422,7 @@ public enum Config {
14141422
DefaultMaxDomainMemory("Domain Defaults", ManagementServer.class, Long.class, "max.domain.memory", "81920", "The default maximum memory (in MB) that can be used for a domain", null),
14151423
DefaultMaxDomainPrimaryStorage("Domain Defaults", ManagementServer.class, Long.class, "max.domain.primary.storage", "400", "The default maximum primary storage space (in GiB) that can be used for a domain", null),
14161424
DefaultMaxDomainSecondaryStorage("Domain Defaults", ManagementServer.class, Long.class, "max.domain.secondary.storage", "800", "The default maximum secondary storage space (in GiB) that can be used for a domain", null),
1425+
DefaultMaxDomainProjects("Domain Defaults",ManagementServer.class,Long.class,"max.domain.projects","50","The default maximum number of projects that can be created for a domain",null),
14171426

14181427
DefaultMaxProjectUserVms(
14191428
"Project Defaults",

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ public boolean configure(final String name, final Map<String, Object> params) th
301301
accountResourceLimitMap.put(Resource.ResourceType.memory.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountMemory.key())));
302302
accountResourceLimitMap.put(Resource.ResourceType.primary_storage.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPrimaryStorage.key())));
303303
accountResourceLimitMap.put(Resource.ResourceType.secondary_storage.name(), MaxAccountSecondaryStorage.value());
304+
accountResourceLimitMap.put(Resource.ResourceType.project.name(), DefaultMaxAccountProjects.value());
304305

305306
domainResourceLimitMap.put(Resource.ResourceType.public_ip.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainPublicIPs.key())));
306307
domainResourceLimitMap.put(Resource.ResourceType.snapshot.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainSnapshots.key())));
@@ -313,6 +314,7 @@ public boolean configure(final String name, final Map<String, Object> params) th
313314
domainResourceLimitMap.put(Resource.ResourceType.memory.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainMemory.key())));
314315
domainResourceLimitMap.put(Resource.ResourceType.primary_storage.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainPrimaryStorage.key())));
315316
domainResourceLimitMap.put(Resource.ResourceType.secondary_storage.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainSecondaryStorage.key())));
317+
domainResourceLimitMap.put(Resource.ResourceType.project.name(), DefaultMaxDomainProjects.value());
316318
} catch (NumberFormatException e) {
317319
logger.error("NumberFormatException during configuration", e);
318320
throw new ConfigurationException("Configuration failed due to NumberFormatException, see log for the stacktrace");
@@ -2137,7 +2139,9 @@ public ConfigKey<?>[] getConfigKeys() {
21372139
MaxAccountSecondaryStorage,
21382140
MaxProjectSecondaryStorage,
21392141
ResourceLimitHostTags,
2140-
ResourceLimitStorageTags
2142+
ResourceLimitStorageTags,
2143+
DefaultMaxAccountProjects,
2144+
DefaultMaxDomainProjects
21412145
};
21422146
}
21432147

server/src/test/java/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ protected void updateResourceLimit() {
190190

191191
// update resource Limit for a domain for resource_type = 11 (Secondary storage (in GiB))
192192
resourceLimitServiceCall(null, (long)1, 10, (long)400);
193+
194+
// update resource Limit for an account for resource_type = 5 (Project)
195+
resourceLimitServiceCall((long) 1, (long) 1, 5, (long) 50);
196+
197+
// update resource Limit for a domain for resource_type = 5 (Project)
198+
resourceLimitServiceCall(null, (long) 1, 5, (long) 100);
193199
}
194200

195201
private void resourceLimitServiceCall(Long accountId, Long domainId, Integer resourceType, Long max) {
@@ -413,6 +419,36 @@ public void testFindCorrectResourceLimitForAccount() {
413419
Assert.assertEquals(defaultAccountCpuMax, result);
414420
}
415421

422+
@Test
423+
public void testFindCorrectResourceLimitForAccountProjects() {
424+
AccountVO account = Mockito.mock(AccountVO.class);
425+
Mockito.when(account.getId()).thenReturn(1L);
426+
Mockito.when(accountManager.isRootAdmin(1L)).thenReturn(true);
427+
428+
long result = resourceLimitManager.findCorrectResourceLimitForAccount(account,
429+
Resource.ResourceType.project, hostTags.get(0));
430+
Assert.assertEquals(Resource.RESOURCE_UNLIMITED, result);
431+
432+
Mockito.when(accountManager.isRootAdmin(1L)).thenReturn(false);
433+
ResourceLimitVO limit = new ResourceLimitVO();
434+
limit.setMax(10L);
435+
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(1L, Resource.ResourceOwnerType.Account,
436+
Resource.ResourceType.project, hostTags.get(0))).thenReturn(limit);
437+
result = resourceLimitManager.findCorrectResourceLimitForAccount(account, Resource.ResourceType.project,
438+
hostTags.get(0));
439+
Assert.assertEquals(10L, result);
440+
441+
long defaultAccountProjectsMax = 15L;
442+
Map<String, Long> accountResourceLimitMap = new HashMap<>();
443+
accountResourceLimitMap.put(Resource.ResourceType.project.name(), defaultAccountProjectsMax);
444+
resourceLimitManager.accountResourceLimitMap = accountResourceLimitMap;
445+
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(1L, Resource.ResourceOwnerType.Account,
446+
Resource.ResourceType.project, hostTags.get(0))).thenReturn(null);
447+
result = resourceLimitManager.findCorrectResourceLimitForAccount(account, Resource.ResourceType.project,
448+
hostTags.get(0));
449+
Assert.assertEquals(defaultAccountProjectsMax, result);
450+
}
451+
416452
@Test
417453
public void testFindCorrectResourceLimitForAccountId1() {
418454
// long accountId = 1L;
@@ -472,6 +508,68 @@ public void testFindCorrectResourceLimitForDomain() {
472508
Assert.assertEquals(defaultDomainCpuMax, result);
473509
}
474510

511+
@Test
512+
public void testResourceUnlimitedForDomainProjects() {
513+
DomainVO domain = Mockito.mock(DomainVO.class);
514+
Mockito.when(domain.getId()).thenReturn(1L);
515+
516+
long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project,
517+
hostTags.get(0));
518+
Assert.assertEquals(Resource.RESOURCE_UNLIMITED, result);
519+
}
520+
@Test
521+
public void testSpecificLimitForDomainProjects() {
522+
DomainVO domain = Mockito.mock(DomainVO.class);
523+
Mockito.when(domain.getId()).thenReturn(2L);
524+
525+
ResourceLimitVO limit = new ResourceLimitVO();
526+
limit.setMax(100L);
527+
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(2L, Resource.ResourceOwnerType.Domain, Resource.ResourceType.project, hostTags.get(0))).thenReturn(limit);
528+
529+
long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project, hostTags.get(0));
530+
Assert.assertEquals(100L, result);
531+
}
532+
533+
@Test
534+
public void testParentDomainLimitForDomainProjects() {
535+
DomainVO domain = Mockito.mock(DomainVO.class);
536+
Mockito.when(domain.getId()).thenReturn(3L);
537+
538+
DomainVO parentDomain = Mockito.mock(DomainVO.class);
539+
Mockito.when(domain.getParent()).thenReturn(5L);
540+
Mockito.when(domainDao.findById(5L)).thenReturn(parentDomain);
541+
542+
ResourceLimitVO limit = new ResourceLimitVO();
543+
limit.setMax(200L);
544+
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(3L, Resource.ResourceOwnerType.Domain,
545+
Resource.ResourceType.project, hostTags.get(0))).thenReturn(null);
546+
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(5L, Resource.ResourceOwnerType.Domain,
547+
Resource.ResourceType.project, hostTags.get(0))).thenReturn(limit);
548+
549+
long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project,
550+
hostTags.get(0));
551+
Assert.assertEquals(200L, result);
552+
}
553+
554+
@Test
555+
public void testDefaultDomainProjectLimit() {
556+
DomainVO domain = Mockito.mock(DomainVO.class);
557+
Mockito.when(domain.getId()).thenReturn(4L);
558+
Mockito.when(domain.getParent()).thenReturn(null);
559+
560+
long defaultDomainProjectsMax = 250L;
561+
Map<String, Long> domainResourceLimitMap = new HashMap<>();
562+
domainResourceLimitMap.put(Resource.ResourceType.project.name(), defaultDomainProjectsMax);
563+
resourceLimitManager.domainResourceLimitMap = domainResourceLimitMap;
564+
565+
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(4L, Resource.ResourceOwnerType.Domain,
566+
Resource.ResourceType.project, hostTags.get(0))).thenReturn(null);
567+
568+
long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project,
569+
hostTags.get(0));
570+
Assert.assertEquals(defaultDomainProjectsMax, result);
571+
}
572+
475573
@Test
476574
public void testCheckResourceLimitWithTag() {
477575
AccountVO account = Mockito.mock(AccountVO.class);

0 commit comments

Comments
 (0)