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) {
checkArgument(checkNotNull(request, "request is null") instanceof GeneratedHttpRequest<?>,
"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;
if (checkNotNull(input, "input is null") instanceof Long[]){
Long[] names = (Long[]) input;
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, checkNotNull(id.toString(),
/* or throw */"id must have a non-null value"));
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 java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@ -144,7 +145,7 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
private final GoGridClient client;
private final RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort;
private final RetryablePredicate<Server> serverLatestJobCompletedShort;
private final GetNodeMetadataStrategy getNode;
@Inject
@ -211,9 +212,13 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
@Override
public NodeMetadata execute(String id) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersById(
new Long(checkNotNull(id, "id"))));
return server == null ? null : serverToNodeMetadata.apply(server);
try {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersById(
new Long(checkNotNull(id, "id"))));
return server == null ? null : serverToNodeMetadata.apply(server);
} catch (NoSuchElementException e) {
return null;
}
}
}
@ -230,9 +235,7 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
@Override
public NodeMetadata execute(String id) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersById(
new Long(id)));
client.getServerServices().deleteById(server.getId());
client.getServerServices().deleteById(new Long(id));
return getNode.execute(id);
}
@ -297,7 +300,8 @@ public class GoGridComputeServiceContextModule extends AbstractModule {
holder.logger.debug(">> providing locations");
Location parent = new LocationImpl(LocationScope.PROVIDER, providerName, providerName, null);
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());
return locations;
}

View File

@ -34,7 +34,9 @@ import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
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.inject.Inject;
@ -52,10 +54,17 @@ public class GoGridErrorHandler implements HttpErrorHandler {
@Override
public void handleError(HttpCommand command, HttpResponse response) {
Exception exception;
Exception exception = new HttpResponseException(command, response);
Set<ErrorResponse> errors = parseErrorsFromContentOrNull(response.getContent());
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:
exception = new AuthorizationException(command.getRequest(), errors != null ? errors
.toString() : response.getStatusLine());
break;

View File

@ -64,11 +64,11 @@ public interface GridJobAsyncClient {
@BinderParam(BindObjectNameToGetJobsRequestQueryParams.class) String objectName);
/**
* @see GridJobClient#getJobsById(Long...)
* @see GridJobClient#getJobsById
*/
@GET
@ResponseParser(ParseJobListFromJsonResponse.class)
@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,59 +18,56 @@
*/
package org.jclouds.gogrid.services;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.gogrid.domain.Job;
import org.jclouds.gogrid.options.GetJobListOptions;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Manages the customer's jobs.
*
*
* @see <a href="http://wiki.gogrid.com/wiki/index.php/API#Job_Methods" />
*
*
* @author Oleksiy Yarmula
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface GridJobClient {
/**
* Returns all jobs found.
* The resulting set may be narrowed
* down by providing {@link GetJobListOptions}.
*
* By default, the result is <=100 items from
* the date range of 4 weeks ago to now.
*
* NOTE: this method results in a big
* volume of data in response
*
* @return
* jobs found by request
*/
Set<Job> getJobList(GetJobListOptions... options);
/**
* Returns all jobs found. The resulting set may be narrowed down by providing
* {@link GetJobListOptions}.
*
* By default, the result is <=100 items from the date range of 4 weeks ago to now.
*
* NOTE: this method results in a big volume of data in response
*
* @return jobs found by request
*/
Set<Job> getJobList(GetJobListOptions... options);
/**
* Returns jobs found for an object with a provided name.
*
* Usually, in GoGrid a name will uniquely identify the object,
* or, as the docs state, some API methods will cause errors.
*
* @param serverName name of the object
* @return found jobs for the object
*/
Set<Job> getJobsForObjectName(String serverName);
/**
* Returns jobs found for an object with a provided name.
*
* Usually, in GoGrid a name will uniquely identify the object, or, as the docs state, some API
* methods will cause errors.
*
* @param serverName
* name of the object
* @return found jobs for the object
*/
Set<Job> getJobsForObjectName(String serverName);
/**
* Returns jobs for the corresponding id(s).
*
* NOTE: there is a 1:1 relation between a
* job and its ID.
*
* @param ids ids for the jobs
* @return jobs found by the ids
*/
Set<Job> getJobsById(Long... ids);
/**
* Returns jobs for the corresponding id(s).
*
* NOTE: there is a 1:1 relation between a job and its ID.
*
* @param ids
* ids for the jobs
* @return jobs found by the 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.ParseServerListFromJsonResponse;
import org.jclouds.gogrid.functions.ParseServerNameToCredentialsMapFromJsonResponse;
import org.jclouds.gogrid.functions.ReturnEmptySetOnNotFound;
import org.jclouds.gogrid.options.AddServerOptions;
import org.jclouds.gogrid.options.GetServerListOptions;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
@ -87,6 +90,7 @@ public interface GridServerAsyncClient {
*/
@GET
@ResponseParser(ParseServerListFromJsonResponse.class)
@ExceptionParser(ReturnEmptySetOnNotFound.class)
@Path("/grid/server/get")
ListenableFuture<Set<Server>> getServersByName(
@BinderParam(BindNamesToQueryParams.class) String... names);
@ -96,9 +100,10 @@ public interface GridServerAsyncClient {
*/
@GET
@ResponseParser(ParseServerListFromJsonResponse.class)
@ExceptionParser(ReturnEmptySetOnNotFound.class)
@Path("/grid/server/get")
ListenableFuture<Set<Server>> getServersById(
@BinderParam(BindIdsToQueryParams.class) Long... ids);
@BinderParam(BindIdsToQueryParams.class) long... ids);
/**
* @see GridServerClient#getServerCredentialsList
@ -134,7 +139,8 @@ public interface GridServerAsyncClient {
@GET
@ResponseParser(ParseServerFromJsonResponse.class)
@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)
@ -142,6 +148,7 @@ public interface GridServerAsyncClient {
@GET
@ResponseParser(ParseServerFromJsonResponse.class)
@Path("/grid/server/delete")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Server> deleteByName(@QueryParam(NAME_KEY) String name);
/**
@ -162,5 +169,3 @@ public interface GridServerAsyncClient {
@QueryParams(keys = LOOKUP_LIST_KEY, values = "server.datacenter")
ListenableFuture<Set<Option>> getDatacenters();
}

View File

@ -79,7 +79,7 @@ public interface GridServerClient {
* to get the servers
* @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.
@ -124,7 +124,7 @@ public interface GridServerClient {
* id of the server to delete
* @return server before the command is executed
*/
Server deleteById(Long id);
Server deleteById(long id);
/**
* Deletes the server by name;

View File

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

View File

@ -18,12 +18,12 @@
*/
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.replay;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test;
/**
* Tests that id bindings are proper for request
*
@ -31,18 +31,33 @@ import static org.easymock.classextension.EasyMock.replay;
*/
public class BindIdsToQueryParamsTest {
@Test
public void testBinding() {
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
Long[] input = {123L, 456L};
@Test
public void testBinding() {
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
Long[] input = { 123L, 456L };
BindIdsToQueryParams binder = new BindIdsToQueryParams();
BindIdsToQueryParams binder = new BindIdsToQueryParams();
request.addQueryParam("id", "123");
request.addQueryParam("id", "456");
replay(request);
request.addQueryParam("id", "123");
request.addQueryParam("id", "456");
replay(request);
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;
import java.net.URI;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpRequest;
@ -31,54 +33,54 @@ import org.jclouds.http.HttpRequest;
*/
public class HttpCommandMock implements HttpCommand {
@Override
public int incrementRedirectCount() {
return 0;
}
@Override
public int incrementRedirectCount() {
return 0;
}
@Override
public int getRedirectCount() {
return 0;
}
@Override
public int getRedirectCount() {
return 0;
}
@Override
public boolean isReplayable() {
return false;
}
@Override
public boolean isReplayable() {
return false;
}
@Override
public void changeSchemeHostAndPortTo(String scheme, String host, int port) {
}
@Override
public void changeSchemeHostAndPortTo(String scheme, String host, int port) {
}
@Override
public void changeToGETRequest() {
}
@Override
public void changeToGETRequest() {
}
@Override
public void changePathTo(String newPath) {
}
@Override
public void changePathTo(String newPath) {
}
@Override
public int incrementFailureCount() {
return 0;
}
@Override
public int incrementFailureCount() {
return 0;
}
@Override
public int getFailureCount() {
return 0;
}
@Override
public int getFailureCount() {
return 0;
}
@Override
public HttpRequest getRequest() {
return null;
}
@Override
public HttpRequest getRequest() {
return new HttpRequest("GET", URI.create("http://localhost"));
}
@Override
public void setException(Exception exception) {
}
@Override
public void setException(Exception exception) {
}
@Override
public Exception getException() {
return null;
}
@Override
public Exception getException() {
return null;
}
}

View File

@ -106,7 +106,7 @@ public class GridJobAsyncClientTest extends BaseGoGridAsyncClientTest<GridJobAsy
@Test
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,
456L);

View File

@ -48,8 +48,10 @@ import org.jclouds.gogrid.domain.PowerCommand;
import org.jclouds.gogrid.functions.ParseOptionsFromJsonResponse;
import org.jclouds.gogrid.functions.ParseServerFromJsonResponse;
import org.jclouds.gogrid.functions.ParseServerListFromJsonResponse;
import org.jclouds.gogrid.functions.ReturnEmptySetOnNotFound;
import org.jclouds.gogrid.options.AddServerOptions;
import org.jclouds.gogrid.options.GetServerListOptions;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
@ -129,7 +131,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
assertResponseParserClassEquals(method, httpRequest, ParseServerListFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFound.class);
checkFilters(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
@ -143,7 +145,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
@Test
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,
123L);
@ -154,7 +156,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
assertResponseParserClassEquals(method, httpRequest, ParseServerListFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFound.class);
checkFilters(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
@ -261,7 +263,7 @@ public class GridServerAsyncClientTest extends BaseGoGridAsyncClientTest<GridSer
assertResponseParserClassEquals(method, httpRequest, ParseServerFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);