added #getRamSizes() for GridServerClient. added convenience method to ip services. fixed idempotency issues with implementation of http request filter

This commit is contained in:
Alex Yarmula 2010-03-21 11:11:28 -07:00
parent b70da07b27
commit d6d7aba2be
13 changed files with 191 additions and 15 deletions

View File

@ -21,6 +21,13 @@ package org.jclouds.http;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
* NOTE: {@link #filter} must be idempotent in a sense that
* multiple calls to it with the same request yield in the
* same output.
* Example: this is required for request retrial
* ({@link org.jclouds.http.internal.BaseHttpCommandExecutorService},
* so that signatures can be updated.
*
* @author Adrian Cole * @author Adrian Cole
*/ */
public interface HttpRequestFilter { public interface HttpRequestFilter {

View File

@ -287,7 +287,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule {
* one can get with different instance types. The # of cores and disk sizes are purely empyrical * one can get with different instance types. The # of cores and disk sizes are purely empyrical
* and aren't guaranteed. However, these are the matches found: Ram: 512MB, CPU: 1 core, HDD: 28 * and aren't guaranteed. However, these are the matches found: Ram: 512MB, CPU: 1 core, HDD: 28
* GB Ram: 1GB, CPU: 1 core, HDD: 57 GB Ram: 2GB, CPU: 1 core, HDD: 113 GB Ram: 4GB, CPU: 3 * GB Ram: 1GB, CPU: 1 core, HDD: 57 GB Ram: 2GB, CPU: 1 core, HDD: 113 GB Ram: 4GB, CPU: 3
* cores, HDD: 233 GB Ram: 8GB, CPU: 6 cores, HDD: 462 GB * cores, HDD: 233 GB Ram: 8GB, CPU: 6 cores, HDD: 462 GB (as of March 2010)
* *
* @return matched size * @return matched size
*/ */

View File

@ -23,10 +23,12 @@
*/ */
package org.jclouds.gogrid.domain; package org.jclouds.gogrid.domain;
import com.google.common.primitives.Longs;
/** /**
* @author Oleksiy Yarmula * @author Oleksiy Yarmula
*/ */
public class Option { public class Option implements Comparable<Option> {
private Long id; private Long id;
private String name; private String name;
@ -86,4 +88,9 @@ public class Option {
result = 31 * result + (description != null ? description.hashCode() : 0); result = 31 * result + (description != null ? description.hashCode() : 0);
return result; return result;
} }
@Override
public int compareTo(Option o) {
return Longs.compare(id, o.id);
}
} }

View File

@ -23,7 +23,8 @@
*/ */
package org.jclouds.gogrid.filters; package org.jclouds.gogrid.filters;
import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
@ -33,11 +34,14 @@ import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import java.net.URI;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format; import static java.lang.String.format;
@ -74,8 +78,17 @@ public class SharedKeyLiteAuthentication implements HttpRequestFilter {
String toSign = createStringToSign(); String toSign = createStringToSign();
String signatureMd5 = getMd5For(toSign); String signatureMd5 = getMd5For(toSign);
generatedRequest.addQueryParam("sig", signatureMd5); String query = request.getEndpoint().getQuery();
generatedRequest.addQueryParam("api_key", apiKey); Multimap<String, String> decodedParams =
RestAnnotationProcessor.parseQueryToMap(query);
decodedParams.replaceValues("sig", ImmutableSet.of(signatureMd5));
decodedParams.replaceValues("api_key", ImmutableSet.of(apiKey));
String updatedQuery = RestAnnotationProcessor.makeQueryLine(decodedParams, null);
String requestBasePart = request.getEndpoint().toASCIIString();
String updatedEndpoint = requestBasePart.substring(0, requestBasePart.indexOf("?") + 1) + updatedQuery;
request.setEndpoint(URI.create(updatedEndpoint ));
HttpUtils.logRequest(signatureLog, request, "<<"); HttpUtils.logRequest(signatureLog, request, "<<");
} }

View File

@ -0,0 +1,61 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.gogrid.functions;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jclouds.gogrid.domain.LoadBalancer;
import org.jclouds.gogrid.domain.Option;
import org.jclouds.gogrid.domain.internal.GenericResponseContainer;
import org.jclouds.http.functions.ParseJson;
import javax.inject.Inject;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.SortedSet;
/**
* Parses the list of generic options.
*
* GoGrid uses options as containers for
* id/name/description objects.
*
* @author Oleksiy Yarmula
*/
public class ParseOptionsFromJsonResponse extends ParseJson<SortedSet<Option>> {
@Inject
public ParseOptionsFromJsonResponse(Gson gson) {
super(gson);
}
public SortedSet<Option> apply(InputStream stream) {
Type setType = new TypeToken<GenericResponseContainer<Option>>() {
}.getType();
GenericResponseContainer<Option> response;
try {
response = gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
return response.getList();
}
}

View File

@ -66,4 +66,6 @@ public interface GoGridQueryParams {
public static final String IMAGE_STATE_KEY = "image.state"; public static final String IMAGE_STATE_KEY = "image.state";
public static final String IMAGE_FRIENDLY_NAME_KEY = "friendlyName"; public static final String IMAGE_FRIENDLY_NAME_KEY = "friendlyName";
public static final String IMAGE_DESCRIPTION_KEY = "description"; public static final String IMAGE_DESCRIPTION_KEY = "description";
public static final String LOOKUP_LIST_KEY = "lookup";
} }

View File

@ -37,6 +37,7 @@ import java.util.Set;
import static org.jclouds.gogrid.reference.GoGridHeaders.VERSION; import static org.jclouds.gogrid.reference.GoGridHeaders.VERSION;
import static org.jclouds.gogrid.reference.GoGridQueryParams.IP_STATE_KEY; import static org.jclouds.gogrid.reference.GoGridQueryParams.IP_STATE_KEY;
import static org.jclouds.gogrid.reference.GoGridQueryParams.IP_TYPE_KEY;
/** /**
* @see org.jclouds.gogrid.services.GridImageClient * @see org.jclouds.gogrid.services.GridImageClient
@ -65,6 +66,16 @@ public interface GridIpAsyncClient {
@QueryParams(keys = IP_STATE_KEY, values = "Unassigned") @QueryParams(keys = IP_STATE_KEY, values = "Unassigned")
ListenableFuture<Set<Ip>> getUnassignedIpList(); ListenableFuture<Set<Ip>> getUnassignedIpList();
/**
* @see org.jclouds.gogrid.services.GridIpClient#getUnassignedPublicIpList()
*/
@GET
@ResponseParser(ParseIpListFromJsonResponse.class)
@Path("/grid/ip/list")
@QueryParams(keys = {IP_STATE_KEY, IP_TYPE_KEY}, values = {"Unassigned", "Public"})
ListenableFuture<Set<Ip>> getUnassignedPublicIpList();
/** /**
* @see org.jclouds.gogrid.services.GridIpClient#getAssignedIpList() * @see org.jclouds.gogrid.services.GridIpClient#getAssignedIpList()
*/ */

View File

@ -40,13 +40,25 @@ public interface GridIpClient {
Set<Ip> getIpList(GetIpListOptions... options); Set<Ip> getIpList(GetIpListOptions... options);
/** /**
* Returns the list of unassigned IPs * Returns the list of unassigned IPs.
*
* NOTE: this returns both public and private IPs!
*
* @return unassigned IPs * @return unassigned IPs
*/ */
Set<Ip> getUnassignedIpList(); Set<Ip> getUnassignedIpList();
/**
* Returns the list of unassigned public IPs.
* @return unassigned public IPs
*/
Set<Ip> getUnassignedPublicIpList();
/** /**
* Returns the list of assigned IPs * Returns the list of assigned IPs
*
* NOTE: this returns both public and private IPs!
*
* @return assigned IPs * @return assigned IPs
*/ */
Set<Ip> getAssignedIpList(); Set<Ip> getAssignedIpList();

View File

@ -33,9 +33,11 @@ import org.jclouds.domain.Credentials;
import org.jclouds.gogrid.GoGrid; import org.jclouds.gogrid.GoGrid;
import org.jclouds.gogrid.binders.BindIdsToQueryParams; import org.jclouds.gogrid.binders.BindIdsToQueryParams;
import org.jclouds.gogrid.binders.BindNamesToQueryParams; import org.jclouds.gogrid.binders.BindNamesToQueryParams;
import org.jclouds.gogrid.domain.Option;
import org.jclouds.gogrid.domain.PowerCommand; import org.jclouds.gogrid.domain.PowerCommand;
import org.jclouds.gogrid.domain.Server; import org.jclouds.gogrid.domain.Server;
import org.jclouds.gogrid.filters.SharedKeyLiteAuthentication; import org.jclouds.gogrid.filters.SharedKeyLiteAuthentication;
import org.jclouds.gogrid.functions.ParseOptionsFromJsonResponse;
import org.jclouds.gogrid.functions.ParseServerFromJsonResponse; import org.jclouds.gogrid.functions.ParseServerFromJsonResponse;
import org.jclouds.gogrid.functions.ParseServerListFromJsonResponse; import org.jclouds.gogrid.functions.ParseServerListFromJsonResponse;
import org.jclouds.gogrid.functions.ParseServerNameToCredentialsMapFromJsonResponse; import org.jclouds.gogrid.functions.ParseServerNameToCredentialsMapFromJsonResponse;
@ -132,6 +134,12 @@ public interface GridServerAsyncClient {
@Path("/grid/server/delete") @Path("/grid/server/delete")
ListenableFuture<Server> deleteByName(@QueryParam(NAME_KEY) String name); ListenableFuture<Server> deleteByName(@QueryParam(NAME_KEY) String name);
/**
* @see GridServerClient#getRamSizes
*/
@GET
@ResponseParser(ParseOptionsFromJsonResponse.class)
@Path("/common/lookup/list")
@QueryParams(keys = LOOKUP_LIST_KEY, values = "server.ram")
ListenableFuture<Set<Option>> getRamSizes();
} }

View File

@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.gogrid.domain.Option;
import org.jclouds.gogrid.domain.PowerCommand; import org.jclouds.gogrid.domain.PowerCommand;
import org.jclouds.gogrid.domain.Server; import org.jclouds.gogrid.domain.Server;
import org.jclouds.gogrid.options.AddServerOptions; import org.jclouds.gogrid.options.AddServerOptions;
@ -137,4 +138,16 @@ public interface GridServerClient {
* @return server before the command is executed * @return server before the command is executed
*/ */
Server deleteByName(String name); Server deleteByName(String name);
/**
* Retrieves the list of supported RAM configurations.
* The objects will have RAM ID, name and description. In
* most cases, id or name will be used for {@link #addServer}.
*
* To see how RAM maps to CPU and disk space (as of March 2010),
* see {@link org.jclouds.gogrid.config.GoGridComputeServiceContextModule#provideSizeToRam}.
*
* @return supported ram sizes
*/
Set<Option> getRamSizes();
} }

View File

@ -96,12 +96,14 @@ public class GoGridLiveTest {
final String nameOfServer = "Server" + String.valueOf(new Date().getTime()).substring(6); final String nameOfServer = "Server" + String.valueOf(new Date().getTime()).substring(6);
serversToDeleteAfterTheTests.add(nameOfServer); serversToDeleteAfterTheTests.add(nameOfServer);
Set<Ip> availableIps = client.getIpServices().getUnassignedIpList(); Set<Ip> availableIps = client.getIpServices().getUnassignedPublicIpList();
Ip availableIp = Iterables.getLast(availableIps); Ip availableIp = Iterables.getLast(availableIps);
String ram = Iterables.get(client.getServerServices().getRamSizes(), 0).getName();
Server createdServer = client.getServerServices().addServer(nameOfServer, Server createdServer = client.getServerServices().addServer(nameOfServer,
"GSI-f8979644-e646-4711-ad58-d98a5fa3612c", "GSI-f8979644-e646-4711-ad58-d98a5fa3612c",
"1", ram,
availableIp.getIp()); availableIp.getIp());
assertNotNull(createdServer); assertNotNull(createdServer);
assert serverLatestJobCompleted.apply(createdServer); assert serverLatestJobCompleted.apply(createdServer);
@ -147,11 +149,13 @@ public class GoGridLiveTest {
final String nameOfServer = "Server" + String.valueOf(new Date().getTime()).substring(6); final String nameOfServer = "Server" + String.valueOf(new Date().getTime()).substring(6);
serversToDeleteAfterTheTests.add(nameOfServer); serversToDeleteAfterTheTests.add(nameOfServer);
Set<Ip> availableIps = client.getIpServices().getUnassignedIpList(); Set<Ip> availableIps = client.getIpServices().getUnassignedPublicIpList();
String ram = Iterables.get(client.getServerServices().getRamSizes(), 0).getName();
Server createdServer = client.getServerServices().addServer(nameOfServer, Server createdServer = client.getServerServices().addServer(nameOfServer,
"GSI-f8979644-e646-4711-ad58-d98a5fa3612c", "GSI-f8979644-e646-4711-ad58-d98a5fa3612c",
"1", ram,
Iterables.getLast(availableIps).getIp()); Iterables.getLast(availableIps).getIp());
assert serverLatestJobCompleted.apply(createdServer); assert serverLatestJobCompleted.apply(createdServer);
@ -194,8 +198,7 @@ public class GoGridLiveTest {
final String nameOfLoadBalancer = "LoadBalancer" + String.valueOf(new Date().getTime()).substring(6); final String nameOfLoadBalancer = "LoadBalancer" + String.valueOf(new Date().getTime()).substring(6);
loadBalancersToDeleteAfterTest.add(nameOfLoadBalancer); loadBalancersToDeleteAfterTest.add(nameOfLoadBalancer);
GetIpListOptions ipOptions = new GetIpListOptions.Builder().unassignedPublicIps(); Set<Ip> availableIps = client.getIpServices().getUnassignedPublicIpList();
Set<Ip> availableIps = client.getIpServices().getIpList(ipOptions);
if(availableIps.size() < 4) throw new SkipException("Not enough available IPs (4 needed) to run the test"); if(availableIps.size() < 4) throw new SkipException("Not enough available IPs (4 needed) to run the test");
Iterator<Ip> ipIterator = availableIps.iterator(); Iterator<Ip> ipIterator = availableIps.iterator();

View File

@ -84,6 +84,16 @@ public class GridJobAsyncClientTest extends RestClientTest<GridJobAsyncClient> {
assertPayloadEquals(httpRequest, null); assertPayloadEquals(httpRequest, null);
} }
@Test
public void testGetJobListNoOptions() throws NoSuchMethodException, IOException {
Method method = GridJobAsyncClient.class.getMethod("getJobList", GetJobListOptions[].class);
GeneratedHttpRequest<GridJobAsyncClient> httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest,
"GET https://api.gogrid.com/api/grid/job/list?v=1.3 HTTP/1.1");
assertHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest, null);
}
@Test @Test
public void testGetJobsForServerName() throws NoSuchMethodException, IOException { public void testGetJobsForServerName() throws NoSuchMethodException, IOException {

View File

@ -54,6 +54,7 @@ import com.google.common.collect.Iterables;
import org.jclouds.gogrid.GoGrid; import org.jclouds.gogrid.GoGrid;
import org.jclouds.gogrid.domain.PowerCommand; import org.jclouds.gogrid.domain.PowerCommand;
import org.jclouds.gogrid.filters.SharedKeyLiteAuthentication; import org.jclouds.gogrid.filters.SharedKeyLiteAuthentication;
import org.jclouds.gogrid.functions.ParseOptionsFromJsonResponse;
import org.jclouds.gogrid.functions.ParseServerFromJsonResponse; import org.jclouds.gogrid.functions.ParseServerFromJsonResponse;
import org.jclouds.gogrid.options.AddServerOptions; import org.jclouds.gogrid.options.AddServerOptions;
import org.jclouds.gogrid.options.GetServerListOptions; import org.jclouds.gogrid.options.GetServerListOptions;
@ -280,6 +281,34 @@ public class GridServerAsyncClientTest extends RestClientTest<GridServerAsyncCli
} }
@Test
public void testGetRamSizes() throws NoSuchMethodException, IOException {
Method method = GridServerAsyncClient.class.getMethod("getRamSizes");
GeneratedHttpRequest<GridServerAsyncClient> httpRequest =
processor.createRequest(method);
assertRequestLineEquals(httpRequest,
"GET https://api.gogrid.com/api/common/lookup/list?v=1.3&lookup=server.ram " +
"HTTP/1.1");
assertHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, ParseOptionsFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
assertRequestLineEquals(httpRequest,
"GET https://api.gogrid.com/api/common/lookup/list?v=1.3&lookup=server.ram&" +
"sig=3f446f171455fbb5574aecff4997b273&api_key=foo " +
"HTTP/1.1");
assertHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest, null);
}
@Override @Override
protected void checkFilters(GeneratedHttpRequest<GridServerAsyncClient> httpMethod) { protected void checkFilters(GeneratedHttpRequest<GridServerAsyncClient> httpMethod) {
assertEquals(httpMethod.getFilters().size(), 1); assertEquals(httpMethod.getFilters().size(), 1);