CLOUDSTACK-1484: provide api.throttling.enabled gloabl configuration settings to enable/disable api throttling feature.
Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/9c5c4753 Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/9c5c4753 Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/9c5c4753 Branch: refs/heads/ui-multiple-nics Commit: 9c5c4753e9210d863c0aec0da0e1771d5ca991ba Parents: 5750fd9 Author: Min Chen <[email protected]> Authored: Mon Mar 4 16:31:58 2013 -0800 Committer: Min Chen <[email protected]> Committed: Tue Mar 5 09:44:09 2013 -0800 ---------------------------------------------------------------------- .../command/user/config/ListCapabilitiesCmd.java | 8 +++- .../command/admin/ratelimit/ResetApiLimitCmd.java | 9 +++++ .../api/command/user/ratelimit/GetApiLimitCmd.java | 11 ++++++ .../cloudstack/ratelimit/ApiRateLimitService.java | 2 + .../ratelimit/ApiRateLimitServiceImpl.java | 19 +++++++++++ .../cloudstack/ratelimit/ApiRateLimitTest.java | 25 +++++++++++++++ server/src/com/cloud/configuration/Config.java | 3 +- .../src/com/cloud/server/ManagementServerImpl.java | 7 +++- setup/db/db/schema-40to410.sql | 1 + 9 files changed, 80 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java index eb862e6..a30e26c 100644 --- a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java @@ -52,8 +52,12 @@ public class ListCapabilitiesCmd extends BaseCmd { response.setProjectInviteRequired((Boolean)capabilities.get("projectInviteRequired")); response.setAllowUsersCreateProjects((Boolean)capabilities.get("allowusercreateprojects")); response.setDiskOffMaxSize((Long)capabilities.get("customDiskOffMaxSize")); - response.setApiLimitInterval((Integer)capabilities.get("apiLimitInterval")); - response.setApiLimitMax((Integer)capabilities.get("apiLimitMax")); + if (capabilities.containsKey("apiLimitInterval")) { + response.setApiLimitInterval((Integer) capabilities.get("apiLimitInterval")); + } + if (capabilities.containsKey("apiLimitMax")) { + response.setApiLimitMax((Integer) capabilities.get("apiLimitMax")); + } response.setObjectName("capability"); response.setResponseName(getCommandName()); this.setResponseObject(response); http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java ---------------------------------------------------------------------- diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java b/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java index 5a7ac86..7ec5316 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java @@ -29,6 +29,8 @@ import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.ratelimit.ApiRateLimitService; import org.apache.log4j.Logger; +import com.cloud.configuration.Config; +import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -43,6 +45,9 @@ public class ResetApiLimitCmd extends BaseCmd { @Inject ApiRateLimitService _apiLimitService; + @Inject + ConfigurationDao _configDao; + ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -89,6 +94,10 @@ public class ResetApiLimitCmd extends BaseCmd { @Override public void execute(){ + boolean apiLimitEnabled = Boolean.parseBoolean(_configDao.getValue(Config.ApiLimitEnabled.key())); + if ( !apiLimitEnabled ){ + throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "This api is only available when api.throttling.enabled = true."); + } boolean result = _apiLimitService.resetApiLimit(this.accountId); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java ---------------------------------------------------------------------- diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java b/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java index 1afa932..ba92e8b 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java @@ -21,6 +21,7 @@ import java.util.List; import org.apache.cloudstack.api.ACL; import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; @@ -35,6 +36,9 @@ import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.ratelimit.ApiRateLimitService; + +import com.cloud.configuration.Config; +import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; @@ -55,6 +59,9 @@ public class GetApiLimitCmd extends BaseCmd { @Inject ApiRateLimitService _apiLimitService; + @Inject + ConfigurationDao _configDao; + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -76,6 +83,10 @@ public class GetApiLimitCmd extends BaseCmd { @Override public void execute(){ + boolean apiLimitEnabled = Boolean.parseBoolean(_configDao.getValue(Config.ApiLimitEnabled.key())); + if ( !apiLimitEnabled ){ + throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "This api is only available when api.throttling.enabled = true."); + } Account caller = UserContext.current().getCaller(); ApiLimitResponse response = _apiLimitService.searchApiLimit(caller); response.setResponseName(getCommandName()); http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java ---------------------------------------------------------------------- diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java index a135556..ad421b6 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java @@ -33,4 +33,6 @@ public interface ApiRateLimitService extends PluggableService{ public void setTimeToLive(int timeToLive); public void setMaxAllowed(int max); + + public void setEnabled(boolean enabled); } http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java ---------------------------------------------------------------------- diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java index d23a11d..7d1b43a 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java @@ -50,6 +50,11 @@ public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker, private static final Logger s_logger = Logger.getLogger(ApiRateLimitServiceImpl.class); /** + * True if api rate limiting is enabled + */ + private boolean enabled = false; + + /** * Fixed time duration where api rate limit is set, in seconds */ private int timeToLive = 1; @@ -73,6 +78,10 @@ public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker, if (_store == null) { // get global configured duration and max values + String isEnabled = _configDao.getValue(Config.ApiLimitEnabled.key()); + if ( isEnabled != null ){ + enabled = Boolean.parseBoolean(isEnabled); + } String duration = _configDao.getValue(Config.ApiLimitInterval.key()); if (duration != null) { timeToLive = Integer.parseInt(duration); @@ -140,6 +149,10 @@ public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker, @Override public boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException { + // check if api rate limiting is enabled or not + if (!enabled){ + return true; + } Long accountId = user.getAccountId(); Account account = _accountService.getAccount(accountId); if ( _accountService.isRootAdmin(account.getType())){ @@ -192,5 +205,11 @@ public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker, } + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + + } + } http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java ---------------------------------------------------------------------- diff --git a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java index 1a77a4e..3c6cadf 100644 --- a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java +++ b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java @@ -55,6 +55,7 @@ public class ApiRateLimitTest { when(_configDao.getValue(Config.ApiLimitInterval.key())).thenReturn(null); when(_configDao.getValue(Config.ApiLimitMax.key())).thenReturn(null); when(_configDao.getValue(Config.ApiLimitCacheSize.key())).thenReturn(null); + when(_configDao.getValue(Config.ApiLimitEnabled.key())).thenReturn("true"); // enable api rate limiting _limitService._configDao = _configDao; _limitService.configure("ApiRateLimitTest", Collections.<String, Object> emptyMap()); @@ -106,6 +107,8 @@ public class ApiRateLimitTest { + " accesses take less than a second to perform", isUnderLimit(key)); } + + @Test public void canDoReasonableNumberOfApiAccessPerSecond() throws Exception { int allowedRequests = 200; @@ -232,4 +235,26 @@ public class ApiRateLimitTest { } + @Test + public void disableApiLimit() throws Exception { + try { + int allowedRequests = 200; + _limitService.setMaxAllowed(allowedRequests); + _limitService.setTimeToLive(1); + _limitService.setEnabled(false); + + User key = createFakeUser(); + + for (int i = 0; i < allowedRequests + 1; i++) { + assertTrue("We should allow more than " + allowedRequests + " requests per second when api throttling is disabled.", + isUnderLimit(key)); + } + } finally { + _limitService.setEnabled(true); // enable api throttling to avoid + // impacting other testcases + } + + } + + } http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/server/src/com/cloud/configuration/Config.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 8a75a96..418f97d 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -372,7 +372,8 @@ public enum Config { 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), - ApiLimitInterval("Advanced", ManagementServer.class, Integer.class, "api.throttling.interval", "1", "Time interval (in seconds) to reset API count", null), + ApiLimitEnabled("Advanced", ManagementServer.class, Boolean.class, "api.throttling.enabled", "true", "Enable/disable Api rate limit", 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), http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/server/src/com/cloud/server/ManagementServerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 95b2973..3c615e1 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2535,6 +2535,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe String userPublicTemplateEnabled = _configs.get(Config.AllowPublicUserTemplates.key()); // add some parameters UI needs to handle API throttling + boolean apiLimitEnabled = Boolean.parseBoolean(_configDao.getValue(Config.ApiLimitEnabled.key())); Integer apiLimitInterval = Integer.valueOf(_configDao.getValue(Config.ApiLimitInterval.key())); Integer apiLimitMax = Integer.valueOf(_configDao.getValue(Config.ApiLimitMax.key())); @@ -2546,8 +2547,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe capabilities.put("projectInviteRequired", _projectMgr.projectInviteRequired()); capabilities.put("allowusercreateprojects", _projectMgr.allowUserToCreateProject()); capabilities.put("customDiskOffMaxSize", diskOffMaxSize); - capabilities.put("apiLimitInterval", apiLimitInterval); - capabilities.put("apiLimitMax", apiLimitMax); + if (apiLimitEnabled) { + capabilities.put("apiLimitInterval", apiLimitInterval); + capabilities.put("apiLimitMax", apiLimitMax); + } return capabilities; } http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9c5c4753/setup/db/db/schema-40to410.sql ---------------------------------------------------------------------- diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index 4fa83a0..706a197 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -241,6 +241,7 @@ UPDATE `cloud`.`volumes` 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', 'api.throttling.enabled', 'false', 'Enable/Disable Api rate limit'); 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');
