Skip to content

Commit 86ada92

Browse files
committed
Fix some bugs and add java integration test for api rate limit plugin.
1 parent c1a540c commit 86ada92

8 files changed

Lines changed: 622 additions & 151 deletions

File tree

client/tomcatconf/components.xml.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ under the License.
185185
<pluggableservice name="ApiDiscoveryService" key="org.apache.cloudstack.discovery.ApiDiscoveryService" class="org.apache.cloudstack.discovery.ApiDiscoveryServiceImpl"/>
186186
<pluggableservice name="VirtualRouterElementService" key="com.cloud.network.element.VirtualRouterElementService" class="com.cloud.network.element.VirtualRouterElement"/>
187187
<pluggableservice name="NiciraNvpElementService" key="com.cloud.network.element.NiciraNvpElementService" class="com.cloud.network.element.NiciraNvpElement"/>
188-
<pluggableservice name="ApiRateLimitService" key="org.apache.cloudstack.api.ratelimit.ApiRateLimitService" class="org.apache.cloudstack.ratelimit.ApiRateLimitServiceImpl"/>
188+
<pluggableservice name="ApiRateLimitService" key="org.apache.cloudstack.ratelimit.ApiRateLimitService" class="org.apache.cloudstack.ratelimit.ApiRateLimitServiceImpl"/>
189189
<dao name="OvsTunnelInterfaceDao" class="com.cloud.network.ovs.dao.OvsTunnelInterfaceDaoImpl" singleton="false"/>
190190
<dao name="OvsTunnelAccountDao" class="com.cloud.network.ovs.dao.OvsTunnelNetworkDaoImpl" singleton="false"/>
191191
<dao name="NiciraNvpDao" class="com.cloud.network.dao.NiciraNvpDaoImpl" singleton="false"/>

plugins/api/rate-limit/pom.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,26 @@
2626
<version>4.1.0-SNAPSHOT</version>
2727
<relativePath>../../pom.xml</relativePath>
2828
</parent>
29+
<build>
30+
<defaultGoal>install</defaultGoal>
31+
<sourceDirectory>src</sourceDirectory>
32+
<testSourceDirectory>test</testSourceDirectory>
33+
<testResources>
34+
<testResource>
35+
<directory>test/resources</directory>
36+
</testResource>
37+
</testResources>
38+
<plugins>
39+
<plugin>
40+
<groupId>org.apache.maven.plugins</groupId>
41+
<artifactId>maven-surefire-plugin</artifactId>
42+
<configuration>
43+
<argLine>-Xmx1024m</argLine>
44+
<excludes>
45+
<exclude>org/apache/cloudstack/ratelimit/integration/*</exclude>
46+
</excludes>
47+
</configuration>
48+
</plugin>
49+
</plugins>
50+
</build>
2951
</project>

plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
import com.cloud.utils.exception.CloudRuntimeException;
4747

4848
@APICommand(name = "getApiLimit", responseObject=ApiLimitResponse.class, description="Get API limit count for the caller")
49-
public class GetApiLimitCmd extends BaseListCmd {
49+
public class GetApiLimitCmd extends BaseCmd {
5050
private static final Logger s_logger = Logger.getLogger(GetApiLimitCmd.class.getName());
5151

5252
private static final String s_name = "getapilimitresponse";
@@ -81,6 +81,7 @@ public void execute(){
8181
Account caller = UserContext.current().getCaller();
8282
ApiLimitResponse response = _apiLimitService.searchApiLimit(caller);
8383
response.setResponseName(getCommandName());
84+
response.setObjectName("apilimit");
8485
this.setResponseObject(response);
8586
}
8687
}
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.ratelimit.integration;
18+
19+
import java.io.BufferedReader;
20+
import java.io.EOFException;
21+
import java.io.InputStreamReader;
22+
import java.math.BigInteger;
23+
import java.net.HttpURLConnection;
24+
import java.net.URL;
25+
import java.net.URLEncoder;
26+
import java.security.MessageDigest;
27+
import java.security.NoSuchAlgorithmException;
28+
import java.util.HashMap;
29+
import java.util.Iterator;
30+
31+
import org.apache.cloudstack.api.response.SuccessResponse;
32+
33+
import com.cloud.api.ApiGsonHelper;
34+
import com.cloud.utils.exception.CloudRuntimeException;
35+
import com.google.gson.Gson;
36+
37+
/**
38+
* Base class for API Test
39+
*
40+
* @author Min Chen
41+
*
42+
*/
43+
public abstract class APITest {
44+
45+
protected String rootUrl = "http://localhost:8080/client/api";
46+
protected String sessionKey = null;
47+
protected String cookieToSent = null;
48+
49+
50+
/**
51+
* Sending an api request through Http GET
52+
* @param command command name
53+
* @param params command query parameters in a HashMap
54+
* @return http request response string
55+
*/
56+
protected String sendRequest(String command, HashMap<String, String> params){
57+
try {
58+
// Construct query string
59+
StringBuilder sBuilder = new StringBuilder();
60+
sBuilder.append("command=");
61+
sBuilder.append(command);
62+
if ( params != null && params.size() > 0){
63+
Iterator<String> keys = params.keySet().iterator();
64+
while (keys.hasNext()){
65+
String key = keys.next();
66+
sBuilder.append("&");
67+
sBuilder.append(key);
68+
sBuilder.append("=");
69+
sBuilder.append(URLEncoder.encode(params.get(key), "UTF-8"));
70+
}
71+
}
72+
73+
// Construct request url
74+
String reqUrl = rootUrl + "?" + sBuilder.toString();
75+
76+
// Send Http GET request
77+
URL url = new URL(reqUrl);
78+
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
79+
conn.setRequestMethod("GET");
80+
81+
if ( !command.equals("login") && cookieToSent != null){
82+
// add the cookie to a request
83+
conn.setRequestProperty("Cookie", cookieToSent);
84+
}
85+
conn.connect();
86+
87+
88+
if ( command.equals("login")){
89+
// if it is login call, store cookie
90+
String headerName=null;
91+
for (int i=1; (headerName = conn.getHeaderFieldKey(i))!=null; i++) {
92+
if (headerName.equals("Set-Cookie")) {
93+
String cookie = conn.getHeaderField(i);
94+
cookie = cookie.substring(0, cookie.indexOf(";"));
95+
String cookieName = cookie.substring(0, cookie.indexOf("="));
96+
String cookieValue = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
97+
cookieToSent = cookieName + "=" + cookieValue;
98+
}
99+
}
100+
}
101+
102+
// Get the response
103+
StringBuilder response = new StringBuilder();
104+
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
105+
String line;
106+
try {
107+
while ((line = rd.readLine()) != null) {
108+
response.append(line);
109+
}
110+
} catch (EOFException ex) {
111+
// ignore this exception
112+
System.out.println("EOF exception due to java bug");
113+
}
114+
rd.close();
115+
116+
117+
118+
return response.toString();
119+
120+
} catch (Exception e) {
121+
throw new CloudRuntimeException("Problem with sending api request", e);
122+
}
123+
}
124+
125+
protected String createMD5String(String password) {
126+
MessageDigest md5;
127+
try {
128+
md5 = MessageDigest.getInstance("MD5");
129+
} catch (NoSuchAlgorithmException e) {
130+
throw new CloudRuntimeException("Error", e);
131+
}
132+
133+
md5.reset();
134+
BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
135+
136+
// make sure our MD5 hash value is 32 digits long...
137+
StringBuffer sb = new StringBuffer();
138+
String pwStr = pwInt.toString(16);
139+
int padding = 32 - pwStr.length();
140+
for (int i = 0; i < padding; i++) {
141+
sb.append('0');
142+
}
143+
sb.append(pwStr);
144+
return sb.toString();
145+
}
146+
147+
148+
protected Object fromSerializedString(String result, Class<?> repCls) {
149+
try {
150+
if (result != null && !result.isEmpty()) {
151+
// get real content
152+
int start;
153+
int end;
154+
if (repCls == LoginResponse.class || repCls == SuccessResponse.class) {
155+
156+
start = result.indexOf('{', result.indexOf('{') + 1); // find
157+
// the
158+
// second
159+
// {
160+
161+
end = result.lastIndexOf('}', result.lastIndexOf('}') - 1); // find
162+
// the
163+
// second
164+
// }
165+
// backwards
166+
167+
} else {
168+
// get real content
169+
start = result.indexOf('{', result.indexOf('{', result.indexOf('{') + 1) + 1); // find
170+
// the
171+
// third
172+
// {
173+
end = result.lastIndexOf('}', result.lastIndexOf('}', result.lastIndexOf('}') - 1) - 1); // find
174+
// the
175+
// third
176+
// }
177+
// backwards
178+
}
179+
if (start < 0 || end < 0) {
180+
throw new CloudRuntimeException("Response format is wrong: " + result);
181+
}
182+
String content = result.substring(start, end + 1);
183+
Gson gson = ApiGsonHelper.getBuilder().create();
184+
return gson.fromJson(content, repCls);
185+
}
186+
return null;
187+
} catch (RuntimeException e) {
188+
throw new CloudRuntimeException("Caught runtime exception when doing GSON deserialization on: " + result, e);
189+
}
190+
}
191+
192+
/**
193+
* Login call
194+
* @param username user name
195+
* @param password password (plain password, we will do MD5 hash here for you)
196+
* @return login response string
197+
*/
198+
protected void login(String username, String password)
199+
{
200+
//String md5Psw = createMD5String(password);
201+
// send login request
202+
HashMap<String, String> params = new HashMap<String, String>();
203+
params.put("response", "json");
204+
params.put("username", username);
205+
params.put("password", password);
206+
String result = this.sendRequest("login", params);
207+
LoginResponse loginResp = (LoginResponse)fromSerializedString(result, LoginResponse.class);
208+
sessionKey = loginResp.getSessionkey();
209+
210+
}
211+
}

0 commit comments

Comments
 (0)