Skip to content

Commit 3dccebc

Browse files
committed
make dynamicapichecker cache confgurable, fix test
Signed-off-by: Abhishek Kumar <[email protected]>
1 parent fd424d5 commit 3dccebc

File tree

4 files changed

+43
-11
lines changed

4 files changed

+43
-11
lines changed

api/src/main/java/org/apache/cloudstack/acl/RoleService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public interface RoleService {
3030
ConfigKey<Boolean> EnableDynamicApiChecker = new ConfigKey<>("Advanced", Boolean.class, "dynamic.apichecker.enabled", "false",
3131
"If set to true, this enables the dynamic role-based api access checker and disables the default static role-based api access checker.", true);
3232

33+
ConfigKey<Integer> DynamicApiCheckerCachePeriod = new ConfigKey<>("Advanced", Integer.class,
34+
"dynamic.apichecker.cache.period", "0",
35+
"Defines the expiration time in seconds for the Dynamic API Checker cache, determining how long cached data is retained before being refreshed. If set to zero then caching will be disabled",
36+
false);
37+
3338
boolean isEnabled();
3439

3540
/**

plugins/acl/dynamic-role-based/src/main/java/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
5151
private List<PluggableService> services;
5252
private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
5353

54-
final private LazyCache<Long, Account> accountCache;
55-
final private LazyCache<Long, Pair<Role, List<RolePermission>>> rolePermissionsCache;
54+
private LazyCache<Long, Account> accountCache;
55+
private LazyCache<Long, Pair<Role, List<RolePermission>>> rolePermissionsCache;
56+
private int cachePeriod;
5657

5758
private static final Logger LOGGER = Logger.getLogger(DynamicRoleBasedAPIAccessChecker.class.getName());
5859

@@ -61,10 +62,6 @@ protected DynamicRoleBasedAPIAccessChecker() {
6162
for (RoleType roleType : RoleType.values()) {
6263
annotationRoleBasedApisMap.put(roleType, new HashSet<String>());
6364
}
64-
accountCache = new LazyCache<>(32, 60,
65-
this::getAccountFromId);
66-
rolePermissionsCache = new LazyCache<>(32, 60,
67-
this::getRolePermissions);
6865
}
6966

7067
@Override
@@ -127,16 +124,30 @@ protected Pair<Role, List<RolePermission>> getRolePermissions(long roleId) {
127124
return new Pair<>(accountRole, roleService.findAllPermissionsBy(accountRole.getId()));
128125
}
129126

127+
protected Pair<Role, List<RolePermission>> getRolePermissionsUsingCache(long roleId) {
128+
if (cachePeriod > 0) {
129+
return rolePermissionsCache.get(roleId);
130+
}
131+
return getRolePermissions(roleId);
132+
}
133+
134+
protected Account getAccountFromIdUsingCache(long accountId) {
135+
if (cachePeriod > 0) {
136+
return accountCache.get(accountId);
137+
}
138+
return getAccountFromId(accountId);
139+
}
140+
130141
@Override
131142
public boolean checkAccess(User user, String commandName) throws PermissionDeniedException {
132143
if (!isEnabled()) {
133144
return true;
134145
}
135-
Account account = accountCache.get(user.getAccountId());
146+
Account account = getAccountFromIdUsingCache(user.getAccountId());
136147
if (account == null) {
137148
throw new PermissionDeniedException(String.format("Account for user id [%s] cannot be found", user.getUuid()));
138149
}
139-
Pair<Role, List<RolePermission>> roleAndPermissions = rolePermissionsCache.get(account.getRoleId());
150+
Pair<Role, List<RolePermission>> roleAndPermissions = getRolePermissionsUsingCache(account.getRoleId());
140151
final Role accountRole = roleAndPermissions.first();
141152
if (accountRole == null) {
142153
throw new PermissionDeniedException(String.format("Account role for user id [%s] cannot be found.", user.getUuid()));
@@ -153,7 +164,7 @@ public boolean checkAccess(User user, String commandName) throws PermissionDenie
153164
}
154165

155166
public boolean checkAccess(Account account, String commandName) {
156-
Pair<Role, List<RolePermission>> roleAndPermissions = rolePermissionsCache.get(account.getRoleId());
167+
Pair<Role, List<RolePermission>> roleAndPermissions = getRolePermissionsUsingCache(account.getRoleId());
157168
final Role accountRole = roleAndPermissions.first();
158169
if (accountRole == null) {
159170
throw new PermissionDeniedException(String.format("The account [%s] has role null or unknown.", account));
@@ -198,6 +209,9 @@ public void addApiToRoleBasedAnnotationsMap(final RoleType roleType, final Strin
198209
@Override
199210
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
200211
super.configure(name, params);
212+
cachePeriod = Math.max(0, RoleService.DynamicApiCheckerCachePeriod.value());
213+
accountCache = new LazyCache<>(32, cachePeriod, this::getAccountFromId);
214+
rolePermissionsCache = new LazyCache<>(32, cachePeriod, this::getRolePermissions);
201215
return true;
202216
}
203217

server/src/main/java/org/apache/cloudstack/acl/RoleManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ public String getConfigComponentName() {
486486

487487
@Override
488488
public ConfigKey<?>[] getConfigKeys() {
489-
return new ConfigKey<?>[] {RoleService.EnableDynamicApiChecker};
489+
return new ConfigKey<?>[] {RoleService.EnableDynamicApiChecker, RoleService.DynamicApiCheckerCachePeriod};
490490
}
491491

492492
@Override

test/integration/smoke/test_dynamicroles.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818
from marvin.cloudstackAPI import *
1919
from marvin.cloudstackTestCase import cloudstackTestCase
2020
from marvin.cloudstackException import CloudstackAPIException
21-
from marvin.lib.base import Account, Role, RolePermission
21+
from marvin.lib.base import Account, Role, RolePermission, Configurations
2222
from marvin.lib.utils import cleanup_resources
2323
from nose.plugins.attrib import attr
2424
from random import shuffle
2525

2626
import copy
2727
import random
2828
import re
29+
import time
2930

3031

3132
class TestData(object):
@@ -109,6 +110,14 @@ def setUp(self):
109110
self.testdata["account"],
110111
roleid=self.role.id
111112
)
113+
114+
cache_period_config = Configurations.list(
115+
self.apiclient,
116+
name='dynamic.apichecker.cache.period'
117+
)[0]
118+
119+
self.cache_period = int(cache_period_config.value)
120+
112121
self.cleanup = [
113122
self.account,
114123
self.rolepermission,
@@ -623,6 +632,8 @@ def test_role_account_acls(self):
623632
testdata
624633
)
625634

635+
time.sleep(self.cache_period + 5)
636+
626637
userApiClient = self.getUserApiClient(self.account.name, domain=self.account.domain, role_type=self.account.roletype)
627638

628639
# Perform listApis check
@@ -645,6 +656,8 @@ def test_role_account_acls_multiple_mgmt_servers(self):
645656
self.dbclient.execute("insert into role_permissions (uuid, role_id, rule, permission, sort_order) values (UUID(), %d, '%s', '%s', %d)" % (roleId, rule, perm.upper(), sortOrder))
646657
sortOrder += 1
647658

659+
time.sleep(self.cache_period + 5)
660+
648661
userApiClient = self.getUserApiClient(self.account.name, domain=self.account.domain, role_type=self.account.roletype)
649662

650663
# Perform listApis check

0 commit comments

Comments
 (0)