From f7ff65e57ffd7c5eb429968aa9ede6b86455473a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Aur=C3=A8le=20Brothier?= Date: Thu, 1 Nov 2018 14:20:16 +0100 Subject: [PATCH] Remove api rate limiting plugin --- client/pom.xml | 5 - plugins/api/rate-limit/pom.xml | 45 ---- .../admin/ratelimit/ResetApiLimitCmd.java | 106 -------- .../user/ratelimit/GetApiLimitCmd.java | 79 ------ .../api/response/ApiLimitResponse.java | 87 ------ .../ratelimit/ApiRateLimitService.java | 39 --- .../ratelimit/ApiRateLimitServiceImpl.java | 202 -------------- .../ratelimit/EhcacheLimitStore.java | 91 ------- .../cloudstack/ratelimit/LimitStore.java | 48 ---- .../cloudstack/ratelimit/StoreEntry.java | 32 --- .../cloudstack/ratelimit/StoreEntryImpl.java | 59 ---- .../cloudstack/rate-limit/module.properties | 18 -- .../rate-limit/spring-rate-limit-context.xml | 32 --- .../ratelimit/ApiRateLimitTest.java | 253 ------------------ .../ratelimit/integration/APITest.java | 204 -------------- .../ratelimit/integration/LoginResponse.java | 139 ---------- .../integration/RateLimitIntegrationTest.java | 208 -------------- plugins/pom.xml | 1 - 18 files changed, 1648 deletions(-) delete mode 100644 plugins/api/rate-limit/pom.xml delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/response/ApiLimitResponse.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitService.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/LimitStore.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntry.java delete mode 100644 plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntryImpl.java delete mode 100644 plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties delete mode 100644 plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/spring-rate-limit-context.xml delete mode 100644 plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java delete mode 100644 plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java delete mode 100644 plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/LoginResponse.java delete mode 100644 plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java diff --git a/client/pom.xml b/client/pom.xml index cf384a6fd06c..bbf3be806684 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -108,11 +108,6 @@ cloud-plugin-dedicated-resources ${project.version} - - org.apache.cloudstack - cloud-plugin-api-limit-account-based - ${project.version} - org.apache.cloudstack cloud-plugin-api-discovery diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml deleted file mode 100644 index 72c904c9d81c..000000000000 --- a/plugins/api/rate-limit/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - 4.0.0 - cloud-plugin-api-limit-account-based - Apache CloudStack Plugin - API Rate Limit - - org.apache.cloudstack - cloudstack-plugins - 4.12.0.0-SNAPSHOT - ../../pom.xml - - - - - org.apache.maven.plugins - maven-surefire-plugin - - always - -Xmx2048m -XX:MaxPermSize=1024m - - org/apache/cloudstack/ratelimit/integration/* - - - - - - diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java deleted file mode 100644 index fab68e3856cd..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/admin/ratelimit/ResetApiLimitCmd.java +++ /dev/null @@ -1,106 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.command.admin.ratelimit; - -import javax.inject.Inject; - -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.ACL; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.AccountResponse; -import org.apache.cloudstack.api.response.ApiLimitResponse; -import org.apache.cloudstack.api.response.SuccessResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.ratelimit.ApiRateLimitService; - -import com.cloud.configuration.Config; -import com.cloud.user.Account; - -@APICommand(name = "resetApiLimit", responseObject = ApiLimitResponse.class, description = "Reset api count", - requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class ResetApiLimitCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(ResetApiLimitCmd.class.getName()); - - private static final String s_name = "resetapilimitresponse"; - - @Inject - ApiRateLimitService _apiLimitService; - - @Inject - ConfigurationDao _configDao; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @ACL - @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.UUID, entityType = AccountResponse.class, description = "the ID of the acount whose limit to be reset") - private Long accountId; - - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public Long getAccountId() { - return accountId; - } - - public void setAccountId(Long accountId) { - this.accountId = accountId; - } - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked - } - - @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()); - this.setResponseObject(response); - } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to reset api limit counter"); - } - } -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java deleted file mode 100644 index 51b2064fa900..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java +++ /dev/null @@ -1,79 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.command.user.ratelimit; - -import javax.inject.Inject; - -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.ApiLimitResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.ratelimit.ApiRateLimitService; - -import com.cloud.configuration.Config; -import com.cloud.user.Account; - -@APICommand(name = "getApiLimit", responseObject = ApiLimitResponse.class, description = "Get API limit count for the caller", - requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class GetApiLimitCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetApiLimitCmd.class.getName()); - - private static final String s_name = "getapilimitresponse"; - - @Inject - ApiRateLimitService _apiLimitService; - - @Inject - ConfigurationDao _configDao; - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked - } - - @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 = CallContext.current().getCallingAccount(); - ApiLimitResponse response = _apiLimitService.searchApiLimit(caller); - response.setResponseName(getCommandName()); - response.setObjectName("apilimit"); - this.setResponseObject(response); - } -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/response/ApiLimitResponse.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/response/ApiLimitResponse.java deleted file mode 100644 index ddd5fa3ded7d..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/api/response/ApiLimitResponse.java +++ /dev/null @@ -1,87 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.api.response; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -public class ApiLimitResponse extends BaseResponse { - @SerializedName(ApiConstants.ACCOUNT_ID) - @Param(description = "the account uuid of the api remaining count") - private String accountId; - - @SerializedName(ApiConstants.ACCOUNT) - @Param(description = "the account name of the api remaining count") - private String accountName; - - @SerializedName("apiIssued") - @Param(description = "number of api already issued") - private int apiIssued; - - @SerializedName("apiAllowed") - @Param(description = "currently allowed number of apis") - private int apiAllowed; - - @SerializedName("expireAfter") - @Param(description = "seconds left to reset counters") - private long expireAfter; - - public void setAccountId(String accountId) { - this.accountId = accountId; - } - - public void setAccountName(String accountName) { - this.accountName = accountName; - } - - public void setApiIssued(int apiIssued) { - this.apiIssued = apiIssued; - } - - public void setApiAllowed(int apiAllowed) { - this.apiAllowed = apiAllowed; - } - - public void setExpireAfter(long duration) { - this.expireAfter = duration; - } - - public String getAccountId() { - return accountId; - } - - public String getAccountName() { - return accountName; - } - - public int getApiIssued() { - return apiIssued; - } - - public int getApiAllowed() { - return apiAllowed; - } - - public long getExpireAfter() { - return expireAfter; - } - -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitService.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitService.java deleted file mode 100644 index bb97f5a6ee09..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitService.java +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit; - -import org.apache.cloudstack.api.response.ApiLimitResponse; - -import com.cloud.user.Account; -import com.cloud.utils.component.PluggableService; - -/** - * Provide API rate limit service - * - */ -public interface ApiRateLimitService extends PluggableService { - - public ApiLimitResponse searchApiLimit(Account caller); - - public boolean resetApiLimit(Long accountId); - - public void setTimeToLive(int timeToLive); - - public void setMaxAllowed(int max); - - public void setEnabled(boolean enabled); -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java deleted file mode 100644 index e35a332c54d1..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java +++ /dev/null @@ -1,202 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import net.sf.ehcache.Cache; -import net.sf.ehcache.CacheManager; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import org.apache.cloudstack.acl.APIChecker; -import org.apache.cloudstack.api.command.admin.ratelimit.ResetApiLimitCmd; -import org.apache.cloudstack.api.command.user.ratelimit.GetApiLimitCmd; -import org.apache.cloudstack.api.response.ApiLimitResponse; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; - -import com.cloud.configuration.Config; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.RequestLimitException; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.utils.component.AdapterBase; - -@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 - */ - private int timeToLive = 1; - - /** - * Max number of api requests during timeToLive duration. - */ - private int maxAllowed = 30; - - private LimitStore _store = null; - - @Inject - AccountService _accountService; - - @Inject - ConfigurationDao _configDao; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); - - 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); - } - String maxReqs = _configDao.getValue(Config.ApiLimitMax.key()); - if (maxReqs != null) { - maxAllowed = Integer.parseInt(maxReqs); - } - // create limit store - EhcacheLimitStore cacheStore = new EhcacheLimitStore(); - int maxElements = 10000; - String cachesize = _configDao.getValue(Config.ApiLimitCacheSize.key()); - if (cachesize != null) { - maxElements = Integer.parseInt(cachesize); - } - CacheManager cm = CacheManager.create(); - Cache cache = new Cache("api-limit-cache", maxElements, false, false, timeToLive, timeToLive); - cm.addCache(cache); - s_logger.info("Limit Cache created with timeToLive=" + timeToLive + ", maxAllowed=" + maxAllowed + ", maxElements=" + maxElements); - cacheStore.setCache(cache); - _store = cacheStore; - - } - - return true; - } - - @Override - public ApiLimitResponse searchApiLimit(Account caller) { - ApiLimitResponse response = new ApiLimitResponse(); - response.setAccountId(caller.getUuid()); - response.setAccountName(caller.getAccountName()); - StoreEntry entry = _store.get(caller.getId()); - if (entry == null) { - - /* Populate the entry, thus unlocking any underlying mutex */ - entry = _store.create(caller.getId(), timeToLive); - response.setApiIssued(0); - response.setApiAllowed(maxAllowed); - response.setExpireAfter(timeToLive); - } else { - response.setApiIssued(entry.getCounter()); - response.setApiAllowed(maxAllowed - entry.getCounter()); - response.setExpireAfter(entry.getExpireDuration()); - } - - return response; - } - - @Override - public boolean resetApiLimit(Long accountId) { - if (accountId != null) { - _store.create(accountId, timeToLive); - } else { - _store.resetCounters(); - } - return true; - } - - @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.getId())) { - // no API throttling on root admin - return true; - } - StoreEntry entry = _store.get(accountId); - - if (entry == null) { - - /* Populate the entry, thus unlocking any underlying mutex */ - entry = _store.create(accountId, timeToLive); - } - - /* Increment the client count and see whether we have hit the maximum allowed clients yet. */ - int current = entry.incrementAndGet(); - - if (current <= maxAllowed) { - s_logger.trace("account (" + account.getAccountId() + "," + account.getAccountName() + ") has current count = " + current); - return true; - } else { - long expireAfter = entry.getExpireDuration(); - // for this exception, we can just show the same message to user and admin users. - String msg = "The given user has reached his/her account api limit, please retry after " + expireAfter + " ms."; - s_logger.warn(msg); - throw new RequestLimitException(msg); - } - } - - @Override - public List> getCommands() { - List> cmdList = new ArrayList>(); - cmdList.add(ResetApiLimitCmd.class); - cmdList.add(GetApiLimitCmd.class); - return cmdList; - } - - @Override - public void setTimeToLive(int timeToLive) { - this.timeToLive = timeToLive; - } - - @Override - public void setMaxAllowed(int max) { - maxAllowed = max; - - } - - @Override - public void setEnabled(boolean enabled) { - this.enabled = enabled; - - } - -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java deleted file mode 100644 index 3840c49ba190..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit; - -import net.sf.ehcache.Ehcache; -import net.sf.ehcache.Element; -import net.sf.ehcache.constructs.blocking.BlockingCache; -import net.sf.ehcache.constructs.blocking.LockTimeoutException; - -/** - * A Limit store implementation using Ehcache. - * - */ -public class EhcacheLimitStore implements LimitStore { - - private BlockingCache cache; - - public void setCache(Ehcache cache) { - BlockingCache ref; - - if (!(cache instanceof BlockingCache)) { - ref = new BlockingCache(cache); - cache.getCacheManager().replaceCacheWithDecoratedCache(cache, new BlockingCache(cache)); - } else { - ref = (BlockingCache)cache; - } - - this.cache = ref; - } - - @Override - public StoreEntry create(Long key, int timeToLive) { - StoreEntryImpl result = new StoreEntryImpl(timeToLive); - Element element = new Element(key, result); - element.setTimeToLive(timeToLive); - cache.put(element); - return result; - } - - @Override - public StoreEntry get(Long key) { - - Element entry = null; - - try { - - /* This may block. */ - entry = cache.get(key); - } catch (LockTimeoutException e) { - throw new RuntimeException(); - } catch (RuntimeException e) { - - /* Release the lock that may have been acquired. */ - cache.put(new Element(key, null)); - } - - StoreEntry result = null; - - if (entry != null) { - - /* - * We don't need to check isExpired() on the result, since ehcache takes care of expiring entries for us. - * c.f. the get(Key) implementation in this class. - */ - result = (StoreEntry)entry.getObjectValue(); - } - - return result; - } - - @Override - public void resetCounters() { - cache.removeAll(); - - } - -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/LimitStore.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/LimitStore.java deleted file mode 100644 index f564b389df74..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/LimitStore.java +++ /dev/null @@ -1,48 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit; - -/** - * Interface to define how an api limit store should work. - * - */ -public interface LimitStore { - - /** - * Returns a store entry for the given account. A value of null means that there is no - * such entry and the calling client must call create to avoid - * other clients potentially being blocked without any hope of progressing. A non-null - * entry means that it has not expired and can be used to determine whether the current client should be allowed to - * proceed with the rate-limited action or not. - * - */ - StoreEntry get(Long account); - - /** - * Creates a new store entry - * - * @param account - * the user account, key to the store - * @param timeToLiveInSecs - * the positive time-to-live in seconds - * @return a non-null entry - */ - StoreEntry create(Long account, int timeToLiveInSecs); - - void resetCounters(); - -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntry.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntry.java deleted file mode 100644 index ce493ac17907..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntry.java +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit; - -/** - * Interface for each entry in LimitStore. - * - */ -public interface StoreEntry { - - int getCounter(); - - int incrementAndGet(); - - boolean isExpired(); - - long getExpireDuration(); /* seconds to reset counter */ -} diff --git a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntryImpl.java b/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntryImpl.java deleted file mode 100644 index f870489fb45a..000000000000 --- a/plugins/api/rate-limit/src/main/java/org/apache/cloudstack/ratelimit/StoreEntryImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Implementation of limit store entry. - * - */ -public class StoreEntryImpl implements StoreEntry { - - private final long expiry; - - private final AtomicInteger counter; - - StoreEntryImpl(int timeToLive) { - this.expiry = System.currentTimeMillis() + timeToLive * 1000; - this.counter = new AtomicInteger(0); - } - - @Override - public boolean isExpired() { - return System.currentTimeMillis() > expiry; - } - - @Override - public long getExpireDuration() { - if (isExpired()) - return 0; // already expired - else { - return expiry - System.currentTimeMillis(); - } - } - - @Override - public int incrementAndGet() { - return this.counter.incrementAndGet(); - } - - @Override - public int getCounter() { - return this.counter.get(); - } -} diff --git a/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties b/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties deleted file mode 100644 index c998a87d9370..000000000000 --- a/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -name=rate-limit -parent=api \ No newline at end of file diff --git a/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/spring-rate-limit-context.xml b/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/spring-rate-limit-context.xml deleted file mode 100644 index d25c57cb0c5b..000000000000 --- a/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/spring-rate-limit-context.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - diff --git a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java b/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java deleted file mode 100644 index a16179eed51e..000000000000 --- a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/ApiRateLimitTest.java +++ /dev/null @@ -1,253 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import javax.naming.ConfigurationException; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import org.apache.cloudstack.api.response.ApiLimitResponse; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; - -import com.cloud.configuration.Config; -import com.cloud.exception.RequestLimitException; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.AccountVO; -import com.cloud.user.User; -import com.cloud.user.UserVO; - -public class ApiRateLimitTest { - - static ApiRateLimitServiceImpl s_limitService = new ApiRateLimitServiceImpl(); - static AccountService s_accountService = mock(AccountService.class); - static ConfigurationDao s_configDao = mock(ConfigurationDao.class); - private static long s_acctIdSeq = 5L; - private static Account s_testAccount; - - @BeforeClass -public static void setUp() throws ConfigurationException { - - when(s_configDao.getValue(Config.ApiLimitInterval.key())).thenReturn(null); - when(s_configDao.getValue(Config.ApiLimitMax.key())).thenReturn(null); - when(s_configDao.getValue(Config.ApiLimitCacheSize.key())).thenReturn(null); - when(s_configDao.getValue(Config.ApiLimitEnabled.key())).thenReturn("true"); // enable api rate limiting - s_limitService._configDao = s_configDao; - - s_limitService.configure("ApiRateLimitTest", Collections. emptyMap()); - - s_limitService._accountService = s_accountService; - - // Standard responses - AccountVO acct = new AccountVO(s_acctIdSeq); - acct.setType(Account.ACCOUNT_TYPE_NORMAL); - acct.setAccountName("demo"); - s_testAccount = acct; - - when(s_accountService.getAccount(5L)).thenReturn(s_testAccount); - when(s_accountService.isRootAdmin(5L)).thenReturn(false); - } - - @Before - public void testSetUp() { - // reset counter for each test - s_limitService.resetApiLimit(null); - } - - private User createFakeUser() { - UserVO user = new UserVO(); - user.setAccountId(s_acctIdSeq); - return user; - } - - private boolean isUnderLimit(User key) { - try { - s_limitService.checkAccess(key, null); - return true; - } catch (RequestLimitException ex) { - return false; - } - } - - @Test - public void sequentialApiAccess() { - int allowedRequests = 1; - s_limitService.setMaxAllowed(allowedRequests); - s_limitService.setTimeToLive(1); - - User key = createFakeUser(); - assertTrue("Allow for the first request", isUnderLimit(key)); - - assertFalse("Second request should be blocked, since we assume that the two api " + " accesses take less than a second to perform", isUnderLimit(key)); - } - - @Test - public void canDoReasonableNumberOfApiAccessPerSecond() throws Exception { - int allowedRequests = 200; - s_limitService.setMaxAllowed(allowedRequests); - s_limitService.setTimeToLive(1); - - User key = createFakeUser(); - - for (int i = 0; i < allowedRequests; i++) { - assertTrue("We should allow " + allowedRequests + " requests per second, but failed at request " + i, isUnderLimit(key)); - } - - assertFalse("We should block >" + allowedRequests + " requests per second", isUnderLimit(key)); - } - - @Test - public void multipleClientsCanAccessWithoutBlocking() throws Exception { - int allowedRequests = 200; - s_limitService.setMaxAllowed(allowedRequests); - s_limitService.setTimeToLive(1); - - final User key = createFakeUser(); - - int clientCount = allowedRequests; - Runnable[] clients = new Runnable[clientCount]; - final boolean[] isUsable = new boolean[clientCount]; - - final CountDownLatch startGate = new CountDownLatch(1); - - final CountDownLatch endGate = new CountDownLatch(clientCount); - - for (int i = 0; i < isUsable.length; ++i) { - final int j = i; - clients[j] = new Runnable() { - - /** - * {@inheritDoc} - */ - @Override - public void run() { - try { - startGate.await(); - - isUsable[j] = isUnderLimit(key); - - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - endGate.countDown(); - } - } - }; - } - - ExecutorService executor = Executors.newFixedThreadPool(clientCount); - - for (Runnable runnable : clients) { - executor.execute(runnable); - } - - startGate.countDown(); - - endGate.await(); - - for (boolean b : isUsable) { - assertTrue("Concurrent client request should be allowed within limit", b); - } - } - - @Test - public void expiryOfCounterIsSupported() throws Exception { - int allowedRequests = 1; - s_limitService.setMaxAllowed(allowedRequests); - s_limitService.setTimeToLive(1); - - User key = createFakeUser(); - - assertTrue("The first request should be allowed", isUnderLimit(key)); - - // Allow the token to expire - Thread.sleep(1020); - - assertTrue("Another request after interval should be allowed as well", isUnderLimit(key)); - } - - @Test - public void verifyResetCounters() throws Exception { - int allowedRequests = 1; - s_limitService.setMaxAllowed(allowedRequests); - s_limitService.setTimeToLive(1); - - User key = createFakeUser(); - - assertTrue("The first request should be allowed", isUnderLimit(key)); - - assertFalse("Another request should be blocked", isUnderLimit(key)); - - s_limitService.resetApiLimit(key.getAccountId()); - - assertTrue("Another request should be allowed after reset counter", isUnderLimit(key)); - } - - @Test - public void verifySearchCounter() throws Exception { - int allowedRequests = 10; - s_limitService.setMaxAllowed(allowedRequests); - s_limitService.setTimeToLive(1); - - User key = createFakeUser(); - - for (int i = 0; i < 5; i++) { - assertTrue("Issued 5 requests", isUnderLimit(key)); - } - - ApiLimitResponse response = s_limitService.searchApiLimit(s_testAccount); - assertEquals("apiIssued is incorrect", 5, response.getApiIssued()); - assertEquals("apiAllowed is incorrect", 5, response.getApiAllowed()); - // using <= to account for inaccurate System.currentTimeMillis() clock in Windows environment - assertTrue("expiredAfter is incorrect", response.getExpireAfter() <= 1000); - - } - - @Test - public void disableApiLimit() throws Exception { - try { - int allowedRequests = 200; - s_limitService.setMaxAllowed(allowedRequests); - s_limitService.setTimeToLive(1); - s_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 { - s_limitService.setEnabled(true); // enable api throttling to avoid - // impacting other testcases - } - - } - -} diff --git a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java b/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java deleted file mode 100644 index bfe3468de667..000000000000 --- a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/APITest.java +++ /dev/null @@ -1,204 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit.integration; - -import java.io.BufferedReader; -import java.io.EOFException; -import java.io.InputStreamReader; -import java.math.BigInteger; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Iterator; - -import com.google.gson.Gson; - -import org.apache.cloudstack.api.response.SuccessResponse; - -import com.cloud.api.ApiGsonHelper; -import com.cloud.utils.exception.CloudRuntimeException; - -/** - * Base class for API Test - * - */ -public abstract class APITest { - - protected String rootUrl = "http://localhost:8080/client/api"; - protected String sessionKey = null; - protected String cookieToSent = null; - - /** - * Sending an api request through Http GET - * @param command command name - * @param params command query parameters in a HashMap - * @return http request response string - */ - protected String sendRequest(String command, HashMap params) { - try { - // Construct query string - StringBuilder sBuilder = new StringBuilder(); - sBuilder.append("command="); - sBuilder.append(command); - if (params != null && params.size() > 0) { - Iterator keys = params.keySet().iterator(); - while (keys.hasNext()) { - String key = keys.next(); - sBuilder.append("&"); - sBuilder.append(key); - sBuilder.append("="); - sBuilder.append(URLEncoder.encode(params.get(key), "UTF-8")); - } - } - - // Construct request url - String reqUrl = rootUrl + "?" + sBuilder.toString(); - - // Send Http GET request - URL url = new URL(reqUrl); - HttpURLConnection conn = (HttpURLConnection)url.openConnection(); - conn.setRequestMethod("GET"); - - if (!command.equals("login") && cookieToSent != null) { - // add the cookie to a request - conn.setRequestProperty("Cookie", cookieToSent); - } - conn.connect(); - - if (command.equals("login")) { - // if it is login call, store cookie - String headerName = null; - for (int i = 1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) { - if (headerName.equals("Set-Cookie")) { - String cookie = conn.getHeaderField(i); - cookie = cookie.substring(0, cookie.indexOf(";")); - String cookieName = cookie.substring(0, cookie.indexOf("=")); - String cookieValue = cookie.substring(cookie.indexOf("=") + 1, cookie.length()); - cookieToSent = cookieName + "=" + cookieValue; - } - } - } - - // Get the response - StringBuilder response = new StringBuilder(); - BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line; - try { - while ((line = rd.readLine()) != null) { - response.append(line); - } - } catch (EOFException ex) { - // ignore this exception - System.out.println("EOF exception due to java bug"); - } - rd.close(); - - return response.toString(); - - } catch (Exception e) { - throw new CloudRuntimeException("Problem with sending api request", e); - } - } - - protected String createMD5String(String password) { - MessageDigest md5; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new CloudRuntimeException("Error", e); - } - - md5.reset(); - BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes())); - - // make sure our MD5 hash value is 32 digits long... - StringBuffer sb = new StringBuffer(); - String pwStr = pwInt.toString(16); - int padding = 32 - pwStr.length(); - for (int i = 0; i < padding; i++) { - sb.append('0'); - } - sb.append(pwStr); - return sb.toString(); - } - - protected Object fromSerializedString(String result, Class repCls) { - try { - if (result != null && !result.isEmpty()) { - // get real content - int start; - int end; - if (repCls == LoginResponse.class || repCls == SuccessResponse.class) { - - start = result.indexOf('{', result.indexOf('{') + 1); // find - // the - // second - // { - - end = result.lastIndexOf('}', result.lastIndexOf('}') - 1); // find - // the - // second - // } - // backwards - - } else { - // get real content - start = result.indexOf('{', result.indexOf('{', result.indexOf('{') + 1) + 1); // find - // the - // third - // { - end = result.lastIndexOf('}', result.lastIndexOf('}', result.lastIndexOf('}') - 1) - 1); // find - // the - // third - // } - // backwards - } - if (start < 0 || end < 0) { - throw new CloudRuntimeException("Response format is wrong: " + result); - } - String content = result.substring(start, end + 1); - Gson gson = ApiGsonHelper.getBuilder().create(); - return gson.fromJson(content, repCls); - } - return null; - } catch (RuntimeException e) { - throw new CloudRuntimeException("Caught runtime exception when doing GSON deserialization on: " + result, e); - } - } - - /** - * Login call - * @param username user name - * @param password password (plain password, we will do MD5 hash here for you) - * @return login response string - */ - protected void login(String username, String password) { - //String md5Psw = createMD5String(password); - // send login request - HashMap params = new HashMap(); - params.put("response", "json"); - params.put("username", username); - params.put("password", password); - String result = this.sendRequest("login", params); - LoginResponse loginResp = (LoginResponse)fromSerializedString(result, LoginResponse.class); - sessionKey = loginResp.getSessionkey(); - - } -} diff --git a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/LoginResponse.java b/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/LoginResponse.java deleted file mode 100644 index 97cdccef8d66..000000000000 --- a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/LoginResponse.java +++ /dev/null @@ -1,139 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit.integration; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -/** - * Login Response object - * - */ -public class LoginResponse extends BaseResponse { - - @SerializedName("timeout") - @Param(description = "session timeout period") - private String timeout; - - @SerializedName("sessionkey") - @Param(description = "login session key") - private String sessionkey; - - @SerializedName("username") - @Param(description = "login username") - private String username; - - @SerializedName("userid") - @Param(description = "login user internal uuid") - private String userid; - - @SerializedName("firstname") - @Param(description = "login user firstname") - private String firstname; - - @SerializedName("lastname") - @Param(description = "login user lastname") - private String lastname; - - @SerializedName("account") - @Param(description = "login user account type") - private String account; - - @SerializedName("domainid") - @Param(description = "login user domain id") - private String domainid; - - @SerializedName("type") - @Param(description = "login user type") - private int type; - - public String getTimeout() { - return timeout; - } - - public void setTimeout(String timeout) { - this.timeout = timeout; - } - - public String getSessionkey() { - return sessionkey; - } - - public void setSessionkey(String sessionkey) { - this.sessionkey = sessionkey; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getUserid() { - return userid; - } - - public void setUserid(String userid) { - this.userid = userid; - } - - public String getFirstname() { - return firstname; - } - - public void setFirstname(String firstname) { - this.firstname = firstname; - } - - public String getLastname() { - return lastname; - } - - public void setLastname(String lastname) { - this.lastname = lastname; - } - - public String getAccount() { - return account; - } - - public void setAccount(String account) { - this.account = account; - } - - public String getDomainid() { - return domainid; - } - - public void setDomainid(String domainid) { - this.domainid = domainid; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - -} diff --git a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java b/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java deleted file mode 100644 index aa8167273473..000000000000 --- a/plugins/api/rate-limit/src/test/java/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java +++ /dev/null @@ -1,208 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.ratelimit.integration; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import org.junit.Before; -import org.junit.Test; - -import org.apache.cloudstack.api.response.ApiLimitResponse; -import org.apache.cloudstack.api.response.SuccessResponse; - -import com.cloud.utils.exception.CloudRuntimeException; - -/** - * Test fixture to do integration rate limit test. - * Currently we commented out this test suite since it requires a real MS and Db running. - */ -public class RateLimitIntegrationTest extends APITest { - - private static int apiMax = 25; // assuming ApiRateLimitService set api.throttling.max = 25 - - @Before - public void setup() { - // always reset count for each testcase - login("admin", "password"); - - // issue reset api limit calls - final HashMap params = new HashMap(); - params.put("response", "json"); - params.put("sessionkey", sessionKey); - String resetResult = sendRequest("resetApiLimit", params); - assertNotNull("Reset count failed!", fromSerializedString(resetResult, SuccessResponse.class)); - - } - - @Test - public void testNoApiLimitOnRootAdmin() throws Exception { - // issue list Accounts calls - final HashMap params = new HashMap(); - params.put("response", "json"); - params.put("listAll", "true"); - params.put("sessionkey", sessionKey); - // assuming ApiRateLimitService set api.throttling.max = 25 - int clientCount = 26; - Runnable[] clients = new Runnable[clientCount]; - final boolean[] isUsable = new boolean[clientCount]; - - final CountDownLatch startGate = new CountDownLatch(1); - - final CountDownLatch endGate = new CountDownLatch(clientCount); - - for (int i = 0; i < isUsable.length; ++i) { - final int j = i; - clients[j] = new Runnable() { - - /** - * {@inheritDoc} - */ - @Override - public void run() { - try { - startGate.await(); - - sendRequest("listAccounts", params); - - isUsable[j] = true; - - } catch (CloudRuntimeException e) { - isUsable[j] = false; - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - endGate.countDown(); - } - } - }; - } - - ExecutorService executor = Executors.newFixedThreadPool(clientCount); - - for (Runnable runnable : clients) { - executor.execute(runnable); - } - - startGate.countDown(); - - endGate.await(); - - int rejectCount = 0; - for (int i = 0; i < isUsable.length; ++i) { - if (!isUsable[i]) - rejectCount++; - } - - assertEquals("No request should be rejected!", 0, rejectCount); - - } - - @Test - public void testApiLimitOnUser() throws Exception { - // log in using normal user - login("demo", "password"); - // issue list Accounts calls - final HashMap params = new HashMap(); - params.put("response", "json"); - params.put("listAll", "true"); - params.put("sessionkey", sessionKey); - - int clientCount = apiMax + 1; - Runnable[] clients = new Runnable[clientCount]; - final boolean[] isUsable = new boolean[clientCount]; - - final CountDownLatch startGate = new CountDownLatch(1); - - final CountDownLatch endGate = new CountDownLatch(clientCount); - - for (int i = 0; i < isUsable.length; ++i) { - final int j = i; - clients[j] = new Runnable() { - - /** - * {@inheritDoc} - */ - @Override - public void run() { - try { - startGate.await(); - - sendRequest("listAccounts", params); - - isUsable[j] = true; - - } catch (CloudRuntimeException e) { - isUsable[j] = false; - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - endGate.countDown(); - } - } - }; - } - - ExecutorService executor = Executors.newFixedThreadPool(clientCount); - - for (Runnable runnable : clients) { - executor.execute(runnable); - } - - startGate.countDown(); - - endGate.await(); - - int rejectCount = 0; - for (int i = 0; i < isUsable.length; ++i) { - if (!isUsable[i]) - rejectCount++; - } - - assertEquals("Only one request should be rejected!", 1, rejectCount); - - } - - @Test - public void testGetApiLimitOnUser() throws Exception { - // log in using normal user - login("demo", "password"); - - // issue an api call - HashMap params = new HashMap(); - params.put("response", "json"); - params.put("listAll", "true"); - params.put("sessionkey", sessionKey); - sendRequest("listAccounts", params); - - // issue get api limit calls - final HashMap params2 = new HashMap(); - params2.put("response", "json"); - params2.put("sessionkey", sessionKey); - String getResult = sendRequest("getApiLimit", params2); - ApiLimitResponse getLimitResp = (ApiLimitResponse)fromSerializedString(getResult, ApiLimitResponse.class); - assertEquals("Issued api count is incorrect!", 2, getLimitResp.getApiIssued()); // should be 2 apis issues plus this getlimit api - assertEquals("Allowed api count is incorrect!", apiMax - 2, getLimitResp.getApiAllowed()); - } -} diff --git a/plugins/pom.xml b/plugins/pom.xml index 7e693af5bbef..8662e345e9d4 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -55,7 +55,6 @@ alert-handlers/syslog-alerts api/discovery - api/rate-limit api/solidfire-intg-test ca/root-ca