Issue 298: gogrid: fixed commands to be graceful when no servers exist

This commit is contained in:
Adrian Cole 2010-07-02 09:40:25 -07:00
parent 75a7c56420
commit 32e7ca0a1f
12 changed files with 169 additions and 130 deletions

View File

@ -52,17 +52,20 @@ public class BindIdsToQueryParams implements Binder {
public void bindToRequest(HttpRequest request, Object input) { public void bindToRequest(HttpRequest request, Object input) {
checkArgument(checkNotNull(request, "request is null") instanceof GeneratedHttpRequest<?>, checkArgument(checkNotNull(request, "request is null") instanceof GeneratedHttpRequest<?>,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
checkArgument(checkNotNull(input, "input is null") instanceof Long[],
"this binder is only valid for Long[] arguments");
Long[] names = (Long[]) input;
GeneratedHttpRequest<?> generatedRequest = (GeneratedHttpRequest<?>) request; GeneratedHttpRequest<?> generatedRequest = (GeneratedHttpRequest<?>) request;
for (Long id : names) { if (checkNotNull(input, "input is null") instanceof Long[]){
generatedRequest.addQueryParam(ID_KEY, checkNotNull(id.toString(), Long[] names = (Long[]) input;
/* or throw */"id must have a non-null value")); for (long id : names)
generatedRequest.addQueryParam(ID_KEY, id + "");
} else if (input instanceof long[]) {
long[] names = (long[]) input;
for (long id : names)
generatedRequest.addQueryParam(ID_KEY, id + "");
} else {
throw new IllegalArgumentException("this binder is only valid for Long[] arguments: "+input.getClass());
} }
} }
} }

View File

@ -24,6 +24,7 @@ import static org.jclouds.compute.predicates.ImagePredicates.architectureIn;
import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_DEFAULT_DC; import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_DEFAULT_DC;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -144,7 +145,7 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy { public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
private final GoGridClient client; private final GoGridClient client;
private final RetryablePredicate<Server> serverLatestJobCompleted; private final RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort; private final RetryablePredicate<Server> serverLatestJobCompletedShort;
private final GetNodeMetadataStrategy getNode; private final GetNodeMetadataStrategy getNode;
@Inject @Inject
@ -211,9 +212,13 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
@Override @Override
public NodeMetadata execute(String id) { public NodeMetadata execute(String id) {
try {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersById( Server server = Iterables.getOnlyElement(client.getServerServices().getServersById(
new Long(checkNotNull(id, "id")))); new Long(checkNotNull(id, "id"))));
return server == null ? null : serverToNodeMetadata.apply(server); return server == null ? null : serverToNodeMetadata.apply(server);
} catch (NoSuchElementException e) {
return null;
}
} }
} }
@ -230,9 +235,7 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
@Override @Override
public NodeMetadata execute(String id) { public NodeMetadata execute(String id) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersById( client.getServerServices().deleteById(new Long(id));
new Long(id)));
client.getServerServices().deleteById(server.getId());
return getNode.execute(id); return getNode.execute(id);
} }
@ -297,7 +300,8 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
holder.logger.debug(">> providing locations"); holder.logger.debug(">> providing locations");
Location parent = new LocationImpl(LocationScope.PROVIDER, providerName, providerName, null); Location parent = new LocationImpl(LocationScope.PROVIDER, providerName, providerName, null);
for (Option dc : sync.getServerServices().getDatacenters()) for (Option dc : sync.getServerServices().getDatacenters())
locations.add(new LocationImpl(LocationScope.ZONE, dc.getId() + "", dc.getDescription(), parent)); locations.add(new LocationImpl(LocationScope.ZONE, dc.getId() + "", dc.getDescription(),
parent));
holder.logger.debug("<< locations(%d)", locations.size()); holder.logger.debug("<< locations(%d)", locations.size());
return locations; return locations;
} }

View File

@ -34,7 +34,9 @@ import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.collect.Iterables;
import com.google.common.io.Closeables; import com.google.common.io.Closeables;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -52,10 +54,17 @@ public class GoGridErrorHandler implements HttpErrorHandler {
@Override @Override
public void handleError(HttpCommand command, HttpResponse response) { public void handleError(HttpCommand command, HttpResponse response) {
Exception exception; Exception exception = new HttpResponseException(command, response);
Set<ErrorResponse> errors = parseErrorsFromContentOrNull(response.getContent()); Set<ErrorResponse> errors = parseErrorsFromContentOrNull(response.getContent());
switch (response.getStatusCode()) { switch (response.getStatusCode()) {
case 400:
if (Iterables.get(errors, 0).getMessage().indexOf("No object found") != -1) {
exception = new ResourceNotFoundException(Iterables.get(errors, 0).getMessage(),
exception);
break;
}
case 403: case 403:
exception = new AuthorizationException(command.getRequest(), errors != null ? errors exception = new AuthorizationException(command.getRequest(), errors != null ? errors
.toString() : response.getStatusLine()); .toString() : response.getStatusLine());
break; break;

View File

@ -64,11 +64,11 @@ public interface GridJobAsyncClient {
@BinderParam(BindObjectNameToGetJobsRequestQueryParams.class) String objectName); @BinderParam(BindObjectNameToGetJobsRequestQueryParams.class) String objectName);
/** /**
* @see GridJobClient#getJobsById(Long...) * @see GridJobClient#getJobsById
*/ */
@GET @GET
@ResponseParser(ParseJobListFromJsonResponse.class) @ResponseParser(ParseJobListFromJsonResponse.class)
@Path("/grid/job/get") @Path("/grid/job/get")
ListenableFuture<Set<Job>> getJobsById(@BinderParam(BindIdsToQueryParams.class) Long... ids); ListenableFuture<Set<Job>> getJobsById(@BinderParam(BindIdsToQueryParams.class) long... ids);
} }

View File

@ -18,13 +18,13 @@
*/ */
package org.jclouds.gogrid.services; package org.jclouds.gogrid.services;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.gogrid.domain.Job; import org.jclouds.gogrid.domain.Job;
import org.jclouds.gogrid.options.GetJobListOptions; import org.jclouds.gogrid.options.GetJobListOptions;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/** /**
* Manages the customer's jobs. * Manages the customer's jobs.
* *
@ -36,28 +36,25 @@ import java.util.concurrent.TimeUnit;
public interface GridJobClient { public interface GridJobClient {
/** /**
* Returns all jobs found. * Returns all jobs found. The resulting set may be narrowed down by providing
* The resulting set may be narrowed * {@link GetJobListOptions}.
* down by providing {@link GetJobListOptions}.
* *
* By default, the result is <=100 items from * By default, the result is <=100 items from the date range of 4 weeks ago to now.
* the date range of 4 weeks ago to now.
* *
* NOTE: this method results in a big * NOTE: this method results in a big volume of data in response
* volume of data in response
* *
* @return * @return jobs found by request
* jobs found by request
*/ */
Set<Job> getJobList(GetJobListOptions... options); Set<Job> getJobList(GetJobListOptions... options);
/** /**
* Returns jobs found for an object with a provided name. * Returns jobs found for an object with a provided name.
* *
* Usually, in GoGrid a name will uniquely identify the object, * Usually, in GoGrid a name will uniquely identify the object, or, as the docs state, some API
* or, as the docs state, some API methods will cause errors. * methods will cause errors.
* *
* @param serverName name of the object * @param serverName
* name of the object
* @return found jobs for the object * @return found jobs for the object
*/ */
Set<Job> getJobsForObjectName(String serverName); Set<Job> getJobsForObjectName(String serverName);
@ -65,12 +62,12 @@ public interface GridJobClient {
/** /**
* Returns jobs for the corresponding id(s). * Returns jobs for the corresponding id(s).
* *
* NOTE: there is a 1:1 relation between a * NOTE: there is a 1:1 relation between a job and its ID.
* job and its ID.
* *
* @param ids ids for the jobs * @param ids
* ids for the jobs
* @return jobs found by the ids * @return jobs found by the ids
*/ */
Set<Job> getJobsById(Long... ids); Set<Job> getJobsById(long... ids);
} }

View File

@ -52,12 +52,15 @@ 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;
import org.jclouds.gogrid.functions.ReturnEmptySetOnNotFound;
import org.jclouds.gogrid.options.AddServerOptions; import org.jclouds.gogrid.options.AddServerOptions;
import org.jclouds.gogrid.options.GetServerListOptions; import org.jclouds.gogrid.options.GetServerListOptions;
import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -87,6 +90,7 @@ public interface GridServerAsyncClient {
*/ */
@GET @GET
@ResponseParser(ParseServerListFromJsonResponse.class) @ResponseParser(ParseServerListFromJsonResponse.class)
@ExceptionParser(ReturnEmptySetOnNotFound.class)
@Path("/grid/server/get") @Path("/grid/server/get")
ListenableFuture<Set<Server>> getServersByName( ListenableFuture<Set<Server>> getServersByName(
@BinderParam(BindNamesToQueryParams.class) String... names); @BinderParam(BindNamesToQueryParams.class) String... names);
@ -96,9 +100,10 @@ public interface GridServerAsyncClient {
*/ */
@GET @GET
@ResponseParser(ParseServerListFromJsonResponse.class) @ResponseParser(ParseServerListFromJsonResponse.class)
@ExceptionParser(ReturnEmptySetOnNotFound.class)
@Path("/grid/server/get") @Path("/grid/server/get")
ListenableFuture<Set<Server>> getServersById( ListenableFuture<Set<Server>> getServersById(
@BinderParam(BindIdsToQueryParams.class) Long... ids); @BinderParam(BindIdsToQueryParams.class) long... ids);
/** /**
* @see GridServerClient#getServerCredentialsList * @see GridServerClient#getServerCredentialsList
@ -134,7 +139,8 @@ public interface GridServerAsyncClient {
@GET @GET
@ResponseParser(ParseServerFromJsonResponse.class) @ResponseParser(ParseServerFromJsonResponse.class)
@Path("/grid/server/delete") @Path("/grid/server/delete")
ListenableFuture<Server> deleteById(@QueryParam(ID_KEY) Long id); @ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Server> deleteById(@QueryParam(ID_KEY) long id);
/** /**
* @see GridServerClient#deleteByName(String) * @see GridServerClient#deleteByName(String)
@ -142,6 +148,7 @@ public interface GridServerAsyncClient {
@GET @GET
@ResponseParser(ParseServerFromJsonResponse.class) @ResponseParser(ParseServerFromJsonResponse.class)
@Path("/grid/server/delete") @Path("/grid/server/delete")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Server> deleteByName(@QueryParam(NAME_KEY) String name); ListenableFuture<Server> deleteByName(@QueryParam(NAME_KEY) String name);
/** /**
@ -162,5 +169,3 @@ public interface GridServerAsyncClient {
@QueryParams(keys = LOOKUP_LIST_KEY, values = "server.datacenter") @QueryParams(keys = LOOKUP_LIST_KEY, values = "server.datacenter")
ListenableFuture<Set<Option>> getDatacenters(); ListenableFuture<Set<Option>> getDatacenters();
} }

View File

@ -79,7 +79,7 @@ public interface GridServerClient {
* to get the servers * to get the servers
* @return server(s) matching the ids * @return server(s) matching the ids
*/ */
Set<Server> getServersById(Long... ids); Set<Server> getServersById(long... ids);
/** /**
* Returns a map of running servers' names to the log in credentials. * Returns a map of running servers' names to the log in credentials.
@ -124,7 +124,7 @@ public interface GridServerClient {
* id of the server to delete * id of the server to delete
* @return server before the command is executed * @return server before the command is executed
*/ */
Server deleteById(Long id); Server deleteById(long id);
/** /**
* Deletes the server by name; * Deletes the server by name;

View File

@ -94,8 +94,10 @@ public class GoGridLiveTest {
@BeforeGroups(groups = { "live" }) @BeforeGroups(groups = { "live" })
public void setupClient() { public void setupClient() {
String identity = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity"); String identity = checkNotNull(System.getProperty("jclouds.test.identity"),
String credential = checkNotNull(System.getProperty("jclouds.test.credential"), "jclouds.test.credential"); "jclouds.test.identity");
String credential = checkNotNull(System.getProperty("jclouds.test.credential"),
"jclouds.test.credential");
context = new RestContextFactory().createContext("gogrid", identity, credential, ImmutableSet context = new RestContextFactory().createContext("gogrid", identity, credential, ImmutableSet
.<Module> of(new Log4JLoggingModule())); .<Module> of(new Log4JLoggingModule()));
@ -217,13 +219,13 @@ public class GoGridLiveTest {
assert latestJob.equals(latestJobFetched) : "Job and its reprentation found by ID don't match"; assert latestJob.equals(latestJobFetched) : "Job and its reprentation found by ID don't match";
List<Long> idsOfAllJobs = new ArrayList<Long>(); long[] idsOfAllJobs = new long[jobs.size()];
int i = 0;
for (Job job : jobs) { for (Job job : jobs) {
idsOfAllJobs.add(job.getId()); idsOfAllJobs[i++] = job.getId();
} }
Set<Job> jobsFetched = client.getJobServices().getJobsById( Set<Job> jobsFetched = client.getJobServices().getJobsById(idsOfAllJobs);
idsOfAllJobs.toArray(new Long[jobs.size()]));
assert jobsFetched.size() == jobs.size() : format( assert jobsFetched.size() == jobs.size() : format(
"Number of jobs fetched by ids doesn't match the number of jobs " "Number of jobs fetched by ids doesn't match the number of jobs "
+ "requested. Requested/expected: %d. Found: %d.", jobs.size(), jobsFetched + "requested. Requested/expected: %d. Found: %d.", jobs.size(), jobsFetched

View File

@ -18,12 +18,12 @@
*/ */
package org.jclouds.gogrid.binders; package org.jclouds.gogrid.binders;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.replay;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test;
/** /**
* Tests that id bindings are proper for request * Tests that id bindings are proper for request
* *
@ -45,4 +45,19 @@ public class BindIdsToQueryParamsTest {
binder.bindToRequest(request, input); binder.bindToRequest(request, input);
} }
@Test
public void testBinding2() {
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
long[] input = { 123L, 456L };
BindIdsToQueryParams binder = new BindIdsToQueryParams();
request.addQueryParam("id", "123");
request.addQueryParam("id", "456");
replay(request);
binder.bindToRequest(request, input);
}
} }

View File

@ -23,6 +23,8 @@
*/ */
package org.jclouds.gogrid.mock; package org.jclouds.gogrid.mock;
import java.net.URI;
import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
@ -70,7 +72,7 @@ public class HttpCommandMock implements HttpCommand {
@Override @Override
public HttpRequest getRequest() { public HttpRequest getRequest() {
return null; return new HttpRequest("GET", URI.create("http://localhost"));
} }
@Override @Override

View File

@ -106,7 +106,7 @@ public class GridJobAsyncClientTest extends BaseGoGridAsyncClientTest<GridJobAsy
@Test @Test
public void testGetJobsById() throws NoSuchMethodException, IOException { public void testGetJobsById() throws NoSuchMethodException, IOException {
Method method = GridJobAsyncClient.class.getMethod("getJobsById", Long[].class); Method method = GridJobAsyncClient.class.getMethod("getJobsById", long[].class);
GeneratedHttpRequest<GridJobAsyncClient> httpRequest = processor.createRequest(method, 123L, GeneratedHttpRequest<GridJobAsyncClient> httpRequest = processor.createRequest(method, 123L,
456L); 456L);

View File

@ -48,8 +48,10 @@ import org.jclouds.gogrid.domain.PowerCommand;
import org.jclouds.gogrid.functions.ParseOptionsFromJsonResponse; 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.ReturnEmptySetOnNotFound;
import org.jclouds.gogrid.options.AddServerOptions; import org.jclouds.gogrid.options.AddServerOptions;
import org.jclouds.gogrid.options.GetServerListOptions; import org.jclouds.gogrid.options.GetServerListOptions;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -129,7 +131,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
assertResponseParserClassEquals(method, httpRequest, ParseServerListFromJsonResponse.class); assertResponseParserClassEquals(method, httpRequest, ParseServerListFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFound.class);
checkFilters(httpRequest); checkFilters(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
@ -143,7 +145,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
@Test @Test
public void testGetServersById() throws NoSuchMethodException, IOException { public void testGetServersById() throws NoSuchMethodException, IOException {
Method method = GridServerAsyncClient.class.getMethod("getServersById", Long[].class); Method method = GridServerAsyncClient.class.getMethod("getServersById", long[].class);
GeneratedHttpRequest<GridServerAsyncClient> httpRequest = processor.createRequest(method, GeneratedHttpRequest<GridServerAsyncClient> httpRequest = processor.createRequest(method,
123L); 123L);
@ -154,7 +156,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
assertResponseParserClassEquals(method, httpRequest, ParseServerListFromJsonResponse.class); assertResponseParserClassEquals(method, httpRequest, ParseServerListFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFound.class);
checkFilters(httpRequest); checkFilters(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
@ -261,7 +263,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
assertResponseParserClassEquals(method, httpRequest, ParseServerFromJsonResponse.class); assertResponseParserClassEquals(method, httpRequest, ParseServerFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest); checkFilters(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);