Move Api rate limit configurations from xml file to global

configuration, and also modify listCapabilitiesCmd to also return api
limit interval and max for UI consumption.
This commit is contained in:
Min Chen 2013-02-07 23:48:15 -08:00
parent 6d952a15ab
commit 0b1e3a4af0
7 changed files with 58 additions and 16 deletions

View File

@ -52,6 +52,8 @@ public class ListCapabilitiesCmd extends BaseCmd {
response.setProjectInviteRequired((Boolean)capabilities.get("projectInviteRequired")); response.setProjectInviteRequired((Boolean)capabilities.get("projectInviteRequired"));
response.setAllowUsersCreateProjects((Boolean)capabilities.get("allowusercreateprojects")); response.setAllowUsersCreateProjects((Boolean)capabilities.get("allowusercreateprojects"));
response.setDiskOffMaxSize((Long)capabilities.get("customDiskOffMaxSize")); response.setDiskOffMaxSize((Long)capabilities.get("customDiskOffMaxSize"));
response.setApiLimitInterval((Integer)capabilities.get("apiLimitInterval"));
response.setApiLimitMax((Integer)capabilities.get("apiLimitMax"));
response.setObjectName("capability"); response.setObjectName("capability");
response.setResponseName(getCommandName()); response.setResponseName(getCommandName());
this.setResponseObject(response); this.setResponseObject(response);

View File

@ -46,6 +46,12 @@ public class CapabilitiesResponse extends BaseResponse {
"create disk from disk offering with custom size") "create disk from disk offering with custom size")
private Long diskOffMaxSize; private Long diskOffMaxSize;
@SerializedName("apilimitinterval") @Param(description="time interval (in seconds) to reset api count")
private Integer apiLimitInterval;
@SerializedName("apilimitmax") @Param(description="Max allowed number of api requests within the specified interval")
private Integer apiLimitMax;
public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) { public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
this.securityGroupsEnabled = securityGroupsEnabled; this.securityGroupsEnabled = securityGroupsEnabled;
@ -75,4 +81,13 @@ public class CapabilitiesResponse extends BaseResponse {
this.diskOffMaxSize = diskOffMaxSize; this.diskOffMaxSize = diskOffMaxSize;
} }
public void setApiLimitInterval(Integer apiLimitInterval) {
this.apiLimitInterval = apiLimitInterval;
}
public void setApiLimitMax(Integer apiLimitMax) {
this.apiLimitMax = apiLimitMax;
}
} }

View File

@ -29,10 +29,13 @@ import net.sf.ehcache.CacheManager;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.api.ApiConstants.LDAPParams;
import org.apache.cloudstack.api.command.admin.ratelimit.ResetApiLimitCmd; import org.apache.cloudstack.api.command.admin.ratelimit.ResetApiLimitCmd;
import org.apache.cloudstack.api.command.user.ratelimit.GetApiLimitCmd; import org.apache.cloudstack.api.command.user.ratelimit.GetApiLimitCmd;
import org.apache.cloudstack.api.response.ApiLimitResponse; import org.apache.cloudstack.api.response.ApiLimitResponse;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.RequestLimitException; import com.cloud.exception.RequestLimitException;
import com.cloud.user.Account; import com.cloud.user.Account;
@ -61,29 +64,29 @@ public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker,
@Inject @Inject
AccountService _accountService; AccountService _accountService;
@Inject
ConfigurationDao _configDao;
@Override @Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params); super.configure(name, params);
if (_store == null) { if (_store == null) {
// not configured yet, note that since this class is both adapter
// and pluggableService, so this method
// may be invoked twice in ComponentLocator.
// get global configured duration and max values // get global configured duration and max values
Object duration = params.get("api.throttling.interval"); String duration = _configDao.getValue(Config.ApiLimitInterval.key());
if (duration != null) { if (duration != null) {
timeToLive = Integer.parseInt((String) duration); timeToLive = Integer.parseInt(duration);
} }
Object maxReqs = params.get("api.throttling.max"); String maxReqs = _configDao.getValue(Config.ApiLimitMax.key());
if (maxReqs != null) { if (maxReqs != null) {
maxAllowed = Integer.parseInt((String) maxReqs); maxAllowed = Integer.parseInt(maxReqs);
} }
// create limit store // create limit store
EhcacheLimitStore cacheStore = new EhcacheLimitStore(); EhcacheLimitStore cacheStore = new EhcacheLimitStore();
int maxElements = 10000; int maxElements = 10000;
Object cachesize = params.get("api.throttling.cachesize"); String cachesize = _configDao.getValue(Config.ApiLimitCacheSize.key());
if ( cachesize != null ){ if ( cachesize != null ){
maxElements = Integer.parseInt((String)cachesize); maxElements = Integer.parseInt(cachesize);
} }
CacheManager cm = CacheManager.create(); CacheManager cm = CacheManager.create();
Cache cache = new Cache("api-limit-cache", maxElements, false, false, timeToLive, timeToLive); Cache cache = new Cache("api-limit-cache", maxElements, false, false, timeToLive, timeToLive);

View File

@ -29,6 +29,8 @@ import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.exception.RequestLimitException; import com.cloud.exception.RequestLimitException;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountService; import com.cloud.user.AccountService;
@ -43,12 +45,18 @@ public class ApiRateLimitTest {
static ApiRateLimitServiceImpl _limitService = new ApiRateLimitServiceImpl(); static ApiRateLimitServiceImpl _limitService = new ApiRateLimitServiceImpl();
static AccountService _accountService = mock(AccountService.class); static AccountService _accountService = mock(AccountService.class);
static ConfigurationDao _configDao = mock(ConfigurationDao.class);
private static long acctIdSeq = 5L; private static long acctIdSeq = 5L;
private static Account testAccount; private static Account testAccount;
@BeforeClass @BeforeClass
public static void setUp() throws ConfigurationException { public static void setUp() throws ConfigurationException {
when(_configDao.getValue(Config.ApiLimitInterval.key())).thenReturn(null);
when(_configDao.getValue(Config.ApiLimitMax.key())).thenReturn(null);
when(_configDao.getValue(Config.ApiLimitCacheSize.key())).thenReturn(null);
_limitService._configDao = _configDao;
_limitService.configure("ApiRateLimitTest", Collections.<String, Object> emptyMap()); _limitService.configure("ApiRateLimitTest", Collections.<String, Object> emptyMap());
_limitService._accountService = _accountService; _limitService._accountService = _accountService;

View File

@ -358,12 +358,16 @@ public enum Config {
ConcurrentSnapshotsThresholdPerHost("Advanced", ManagementServer.class, Long.class, "concurrent.snapshots.threshold.perhost", ConcurrentSnapshotsThresholdPerHost("Advanced", ManagementServer.class, Long.class, "concurrent.snapshots.threshold.perhost",
null, "Limits number of snapshots that can be handled by the host concurrently; default is NULL - unlimited", null), null, "Limits number of snapshots that can be handled by the host concurrently; default is NULL - unlimited", null),
NetworkIPv6SearchRetryMax("Network", ManagementServer.class, Integer.class, "network.ipv6.search.retry.max", "10000", "The maximum number of retrying times to search for an available IPv6 address in the table", null), NetworkIPv6SearchRetryMax("Network", ManagementServer.class, Integer.class, "network.ipv6.search.retry.max", "10000", "The maximum number of retrying times to search for an available IPv6 address in the table", null),
ExternalBaremetalSystemUrl("Advanced", ManagementServer.class, String.class, "external.baremetal.system.url", null, "url of external baremetal system that CloudStack will talk to", null), ExternalBaremetalSystemUrl("Advanced", ManagementServer.class, String.class, "external.baremetal.system.url", null, "url of external baremetal system that CloudStack will talk to", null),
ExternalBaremetalResourceClassName("Advanced", ManagementServer.class, String.class, "external,baremetal.resource.classname", null, "class name for handling external baremetal resource", null), ExternalBaremetalResourceClassName("Advanced", ManagementServer.class, String.class, "external,baremetal.resource.classname", null, "class name for handling external baremetal resource", null),
EnableBaremetalSecurityGroupAgentEcho("Advanced", ManagementServer.class, Boolean.class, "enable.baremetal.securitygroup.agent.echo", "false", "After starting provision process, periodcially echo security agent installed in the template. Treat provisioning as success only if echo successfully", null), EnableBaremetalSecurityGroupAgentEcho("Advanced", ManagementServer.class, Boolean.class, "enable.baremetal.securitygroup.agent.echo", "false", "After starting provision process, periodcially echo security agent installed in the template. Treat provisioning as success only if echo successfully", null),
IntervalToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "interval.baremetal.securitygroup.agent.echo", "10", "Interval to echo baremetal security group agent, in seconds", null), IntervalToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "interval.baremetal.securitygroup.agent.echo", "10", "Interval to echo baremetal security group agent, in seconds", null),
TimeoutToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "timeout.baremetal.securitygroup.agent.echo", "3600", "Timeout to echo baremetal security group agent, in seconds, the provisioning process will be treated as a failure", null); TimeoutToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "timeout.baremetal.securitygroup.agent.echo", "3600", "Timeout to echo baremetal security group agent, in seconds, the provisioning process will be treated as a failure", null),
ApiLimitInterval("Advanced", ManagementServer.class, Integer.class, "api.throttling.interval", "1", "Time interval (in seconds) to reset API count", null),
ApiLimitMax("Advanced", ManagementServer.class, Integer.class, "api.throttling.max", "25", "Max allowed number of APIs within fixed interval", null),
ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null);
private final String _category; private final String _category;
private final Class<?> _componentClass; private final Class<?> _componentClass;

View File

@ -5,7 +5,7 @@
// to you under the Apache License, Version 2.0 (the // to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance // "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at // with the License. You may obtain a copy of the License at
// //
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, // Unless required by applicable law or agreed to in writing,
@ -375,7 +375,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Inject @Inject
S3Manager _s3Mgr; S3Manager _s3Mgr;
/* /*
@Inject @Inject
ComponentContext _forceContextRef; // create a dependency to ComponentContext so that it can be loaded beforehead ComponentContext _forceContextRef; // create a dependency to ComponentContext so that it can be loaded beforehead
@ -417,14 +417,14 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
for (String id : availableIds) { for (String id : availableIds) {
_availableIdsMap.put(id, true); _availableIdsMap.put(id, true);
} }
return true; return true;
} }
@Override @Override
public boolean start() { public boolean start() {
s_logger.info("Startup CloudStack management server..."); s_logger.info("Startup CloudStack management server...");
enableAdminUser("password"); enableAdminUser("password");
return true; return true;
} }
@ -2187,6 +2187,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
String userPublicTemplateEnabled = _configs.get(Config.AllowPublicUserTemplates.key()); String userPublicTemplateEnabled = _configs.get(Config.AllowPublicUserTemplates.key());
// add some parameters UI needs to handle API throttling
Integer apiLimitInterval = Integer.valueOf(_configDao.getValue(Config.ApiLimitInterval.key()));
Integer apiLimitMax = Integer.valueOf(_configDao.getValue(Config.ApiLimitMax.key()));
capabilities.put("securityGroupsEnabled", securityGroupsEnabled); capabilities.put("securityGroupsEnabled", securityGroupsEnabled);
capabilities capabilities
.put("userPublicTemplateEnabled", (userPublicTemplateEnabled == null || userPublicTemplateEnabled.equals("false") ? false : true)); .put("userPublicTemplateEnabled", (userPublicTemplateEnabled == null || userPublicTemplateEnabled.equals("false") ? false : true));
@ -2195,6 +2199,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
capabilities.put("projectInviteRequired", _projectMgr.projectInviteRequired()); capabilities.put("projectInviteRequired", _projectMgr.projectInviteRequired());
capabilities.put("allowusercreateprojects", _projectMgr.allowUserToCreateProject()); capabilities.put("allowusercreateprojects", _projectMgr.allowUserToCreateProject());
capabilities.put("customDiskOffMaxSize", diskOffMaxSize); capabilities.put("customDiskOffMaxSize", diskOffMaxSize);
capabilities.put("apiLimitInterval", apiLimitInterval);
capabilities.put("apiLimitMax", apiLimitMax);
return capabilities; return capabilities;
} }

View File

@ -146,6 +146,10 @@ UPDATE `cloud`.`counter` set uuid=id WHERE uuid is NULL;
UPDATE `cloud`.`conditions` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`conditions` set uuid=id WHERE uuid is NULL;
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', '"detail.batch.query.size"', '2000', 'Default entity detail batch query size for listing'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', '"detail.batch.query.size"', '2000', 'Default entity detail batch query size for listing');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', '"api.throttling.interval"', '1', 'Time interval (in seconds) to reset API count');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', '"api.throttling.max"', '25', 'Max allowed number of APIs within fixed interval');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', '"api.throttling.cachesize"', '50000', 'Account based API count cache size');
-- DB views for list api -- DB views for list api