Skip to content

Commit

Permalink
Add limit configuration for number of projects (apache#9172)
Browse files Browse the repository at this point in the history
  • Loading branch information
my-code-AL authored Jul 15, 2024
1 parent b9c7275 commit afdf4d7
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 1 deletion.
4 changes: 4 additions & 0 deletions api/src/main/java/com/cloud/user/ResourceLimitService.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public interface ResourceLimitService {
"A comma-separated list of tags for host resource limits", true);
static final ConfigKey<String> ResourceLimitStorageTags = new ConfigKey<>("Advanced", String.class, "resource.limit.storage.tags", "",
"A comma-separated list of tags for storage resource limits", true);
static final ConfigKey<Long> DefaultMaxAccountProjects = new ConfigKey<>("Account Defaults",Long.class,"max.account.projects","10",
"The default maximum number of projects that can be created for an account",false);
static final ConfigKey<Long> DefaultMaxDomainProjects = new ConfigKey<>("Domain Defaults",Long.class,"max.domain.projects","50",
"The default maximum number of projects that can be created for a domain",false);

static final List<ResourceType> HostTagsSupportingTypes = List.of(ResourceType.user_vm, ResourceType.cpu, ResourceType.memory);
static final List<ResourceType> StorageTagsSupportingTypes = List.of(ResourceType.volume, ResourceType.primary_storage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class UpdateResourceLimitCmd extends BaseCmd {
+ "2 - Volume. Number of disk volumes a user can create. "
+ "3 - Snapshot. Number of snapshots a user can create. "
+ "4 - Template. Number of templates that a user can register/create. "
+ "5 - Project. Number of projects a user can create. "
+ "6 - Network. Number of guest network a user can create. "
+ "7 - VPC. Number of VPC a user can create. "
+ "8 - CPU. Total number of CPU cores a user can use. "
Expand Down
9 changes: 9 additions & 0 deletions server/src/main/java/com/cloud/configuration/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,14 @@ public enum Config {
"200",
"The default maximum primary storage space (in GiB) that can be used for an account",
null),
DefaultMaxAccountProjects(
"Account Defaults",
ManagementServer.class,
Long.class,
"max.account.projects",
"10",
"The default maximum number of projects that can be created for an account",
null),

//disabling lb as cluster sync does not work with distributed cluster
SubDomainNetworkAccess(
Expand Down Expand Up @@ -1414,6 +1422,7 @@ public enum Config {
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),
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),
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),
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),

DefaultMaxProjectUserVms(
"Project Defaults",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ public boolean configure(final String name, final Map<String, Object> params) th
accountResourceLimitMap.put(Resource.ResourceType.memory.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountMemory.key())));
accountResourceLimitMap.put(Resource.ResourceType.primary_storage.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPrimaryStorage.key())));
accountResourceLimitMap.put(Resource.ResourceType.secondary_storage.name(), MaxAccountSecondaryStorage.value());
accountResourceLimitMap.put(Resource.ResourceType.project.name(), DefaultMaxAccountProjects.value());

domainResourceLimitMap.put(Resource.ResourceType.public_ip.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainPublicIPs.key())));
domainResourceLimitMap.put(Resource.ResourceType.snapshot.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainSnapshots.key())));
Expand All @@ -313,6 +314,7 @@ public boolean configure(final String name, final Map<String, Object> params) th
domainResourceLimitMap.put(Resource.ResourceType.memory.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainMemory.key())));
domainResourceLimitMap.put(Resource.ResourceType.primary_storage.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainPrimaryStorage.key())));
domainResourceLimitMap.put(Resource.ResourceType.secondary_storage.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainSecondaryStorage.key())));
domainResourceLimitMap.put(Resource.ResourceType.project.name(), DefaultMaxDomainProjects.value());
} catch (NumberFormatException e) {
logger.error("NumberFormatException during configuration", e);
throw new ConfigurationException("Configuration failed due to NumberFormatException, see log for the stacktrace");
Expand Down Expand Up @@ -2137,7 +2139,9 @@ public ConfigKey<?>[] getConfigKeys() {
MaxAccountSecondaryStorage,
MaxProjectSecondaryStorage,
ResourceLimitHostTags,
ResourceLimitStorageTags
ResourceLimitStorageTags,
DefaultMaxAccountProjects,
DefaultMaxDomainProjects
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ protected void updateResourceLimit() {

// update resource Limit for a domain for resource_type = 11 (Secondary storage (in GiB))
resourceLimitServiceCall(null, (long)1, 10, (long)400);

// update resource Limit for an account for resource_type = 5 (Project)
resourceLimitServiceCall((long) 1, (long) 1, 5, (long) 50);

// update resource Limit for a domain for resource_type = 5 (Project)
resourceLimitServiceCall(null, (long) 1, 5, (long) 100);
}

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

@Test
public void testFindCorrectResourceLimitForAccountProjects() {
AccountVO account = Mockito.mock(AccountVO.class);
Mockito.when(account.getId()).thenReturn(1L);
Mockito.when(accountManager.isRootAdmin(1L)).thenReturn(true);

long result = resourceLimitManager.findCorrectResourceLimitForAccount(account,
Resource.ResourceType.project, hostTags.get(0));
Assert.assertEquals(Resource.RESOURCE_UNLIMITED, result);

Mockito.when(accountManager.isRootAdmin(1L)).thenReturn(false);
ResourceLimitVO limit = new ResourceLimitVO();
limit.setMax(10L);
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(1L, Resource.ResourceOwnerType.Account,
Resource.ResourceType.project, hostTags.get(0))).thenReturn(limit);
result = resourceLimitManager.findCorrectResourceLimitForAccount(account, Resource.ResourceType.project,
hostTags.get(0));
Assert.assertEquals(10L, result);

long defaultAccountProjectsMax = 15L;
Map<String, Long> accountResourceLimitMap = new HashMap<>();
accountResourceLimitMap.put(Resource.ResourceType.project.name(), defaultAccountProjectsMax);
resourceLimitManager.accountResourceLimitMap = accountResourceLimitMap;
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(1L, Resource.ResourceOwnerType.Account,
Resource.ResourceType.project, hostTags.get(0))).thenReturn(null);
result = resourceLimitManager.findCorrectResourceLimitForAccount(account, Resource.ResourceType.project,
hostTags.get(0));
Assert.assertEquals(defaultAccountProjectsMax, result);
}

@Test
public void testFindCorrectResourceLimitForAccountId1() {
// long accountId = 1L;
Expand Down Expand Up @@ -472,6 +508,68 @@ public void testFindCorrectResourceLimitForDomain() {
Assert.assertEquals(defaultDomainCpuMax, result);
}

@Test
public void testResourceUnlimitedForDomainProjects() {
DomainVO domain = Mockito.mock(DomainVO.class);
Mockito.when(domain.getId()).thenReturn(1L);

long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project,
hostTags.get(0));
Assert.assertEquals(Resource.RESOURCE_UNLIMITED, result);
}
@Test
public void testSpecificLimitForDomainProjects() {
DomainVO domain = Mockito.mock(DomainVO.class);
Mockito.when(domain.getId()).thenReturn(2L);

ResourceLimitVO limit = new ResourceLimitVO();
limit.setMax(100L);
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(2L, Resource.ResourceOwnerType.Domain, Resource.ResourceType.project, hostTags.get(0))).thenReturn(limit);

long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project, hostTags.get(0));
Assert.assertEquals(100L, result);
}

@Test
public void testParentDomainLimitForDomainProjects() {
DomainVO domain = Mockito.mock(DomainVO.class);
Mockito.when(domain.getId()).thenReturn(3L);

DomainVO parentDomain = Mockito.mock(DomainVO.class);
Mockito.when(domain.getParent()).thenReturn(5L);
Mockito.when(domainDao.findById(5L)).thenReturn(parentDomain);

ResourceLimitVO limit = new ResourceLimitVO();
limit.setMax(200L);
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(3L, Resource.ResourceOwnerType.Domain,
Resource.ResourceType.project, hostTags.get(0))).thenReturn(null);
Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(5L, Resource.ResourceOwnerType.Domain,
Resource.ResourceType.project, hostTags.get(0))).thenReturn(limit);

long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project,
hostTags.get(0));
Assert.assertEquals(200L, result);
}

@Test
public void testDefaultDomainProjectLimit() {
DomainVO domain = Mockito.mock(DomainVO.class);
Mockito.when(domain.getId()).thenReturn(4L);
Mockito.when(domain.getParent()).thenReturn(null);

long defaultDomainProjectsMax = 250L;
Map<String, Long> domainResourceLimitMap = new HashMap<>();
domainResourceLimitMap.put(Resource.ResourceType.project.name(), defaultDomainProjectsMax);
resourceLimitManager.domainResourceLimitMap = domainResourceLimitMap;

Mockito.when(resourceLimitDao.findByOwnerIdAndTypeAndTag(4L, Resource.ResourceOwnerType.Domain,
Resource.ResourceType.project, hostTags.get(0))).thenReturn(null);

long result = resourceLimitManager.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.project,
hostTags.get(0));
Assert.assertEquals(defaultDomainProjectsMax, result);
}

@Test
public void testCheckResourceLimitWithTag() {
AccountVO account = Mockito.mock(AccountVO.class);
Expand Down

0 comments on commit afdf4d7

Please sign in to comment.