mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-1484: provide api.throttling.enabled gloabl configuration settings to enable/disable api throttling feature.
This commit is contained in:
parent
5750fd9631
commit
9c5c4753e9
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -33,4 +33,6 @@ public interface ApiRateLimitService extends PluggableService{
|
|||
public void setTimeToLive(int timeToLive);
|
||||
|
||||
public void setMaxAllowed(int max);
|
||||
|
||||
public void setEnabled(boolean enabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@ import org.springframework.stereotype.Component;
|
|||
public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker, ApiRateLimitService {
|
||||
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
|
||||
*/
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
Loading…
Reference in New Issue