mirror of https://github.com/apache/jclouds.git
Issue 851:add save/delete image support to go grid
This commit is contained in:
parent
d5a9162348
commit
d8b465ec2e
|
@ -27,6 +27,7 @@ public enum ServerImageState {
|
|||
|
||||
AVAILABLE("Available"),
|
||||
SAVING("Saving"),
|
||||
TRASH("Trash"),
|
||||
UNRECOGNIZED("Unknown");
|
||||
|
||||
String type;
|
||||
|
|
|
@ -60,6 +60,7 @@ public class GoGridErrorHandler implements HttpErrorHandler {
|
|||
exception = new ResourceNotFoundException(Iterables.get(errors, 0).getMessage(), exception);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 403:
|
||||
exception = new AuthorizationException(exception.getMessage(), exception);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds 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.jclouds.gogrid.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.jclouds.gogrid.reference.GoGridQueryParams.DESCRIPTION_KEY;
|
||||
|
||||
import org.jclouds.http.options.BaseHttpRequestOptions;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class SaveImageOptions extends BaseHttpRequestOptions {
|
||||
|
||||
public SaveImageOptions withDescription(String description) {
|
||||
checkArgument(description.length() <= 500, "Description cannot be longer than 500 characters");
|
||||
checkState(!queryParameters.containsKey(DESCRIPTION_KEY), "Can't have duplicate image description");
|
||||
queryParameters.put(DESCRIPTION_KEY, description);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see SaveImageOptions#withDescription(String)
|
||||
*/
|
||||
public static SaveImageOptions withDescription(String description) {
|
||||
SaveImageOptions options = new SaveImageOptions();
|
||||
return options.withDescription(description);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,10 +19,12 @@
|
|||
package org.jclouds.gogrid.services;
|
||||
|
||||
import static org.jclouds.gogrid.reference.GoGridHeaders.VERSION;
|
||||
import static org.jclouds.gogrid.reference.GoGridQueryParams.ID_KEY;
|
||||
import static org.jclouds.gogrid.reference.GoGridQueryParams.IMAGE_DESCRIPTION_KEY;
|
||||
import static org.jclouds.gogrid.reference.GoGridQueryParams.IMAGE_FRIENDLY_NAME_KEY;
|
||||
import static org.jclouds.gogrid.reference.GoGridQueryParams.IMAGE_KEY;
|
||||
import static org.jclouds.gogrid.reference.GoGridQueryParams.LOOKUP_LIST_KEY;
|
||||
import static org.jclouds.gogrid.reference.GoGridQueryParams.SERVER_ID_OR_NAME_KEY;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -40,10 +42,13 @@ import org.jclouds.gogrid.functions.ParseImageFromJsonResponse;
|
|||
import org.jclouds.gogrid.functions.ParseImageListFromJsonResponse;
|
||||
import org.jclouds.gogrid.functions.ParseOptionsFromJsonResponse;
|
||||
import org.jclouds.gogrid.options.GetImageListOptions;
|
||||
import org.jclouds.gogrid.options.SaveImageOptions;
|
||||
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;
|
||||
|
||||
|
@ -68,8 +73,7 @@ public interface GridImageAsyncClient {
|
|||
@GET
|
||||
@ResponseParser(ParseImageListFromJsonResponse.class)
|
||||
@Path("/grid/image/get")
|
||||
ListenableFuture<Set<ServerImage>> getImagesById(
|
||||
@BinderParam(BindIdsToQueryParams.class) Long... ids);
|
||||
ListenableFuture<Set<ServerImage>> getImagesById(@BinderParam(BindIdsToQueryParams.class) Long... ids);
|
||||
|
||||
/**
|
||||
* @see GridImageClient#getImagesByName
|
||||
|
@ -77,8 +81,7 @@ public interface GridImageAsyncClient {
|
|||
@GET
|
||||
@ResponseParser(ParseImageListFromJsonResponse.class)
|
||||
@Path("/grid/image/get")
|
||||
ListenableFuture<Set<ServerImage>> getImagesByName(
|
||||
@BinderParam(BindNamesToQueryParams.class) String... names);
|
||||
ListenableFuture<Set<ServerImage>> getImagesByName(@BinderParam(BindNamesToQueryParams.class) String... names);
|
||||
|
||||
/**
|
||||
* @see GridImageClient#editImageDescription
|
||||
|
@ -106,4 +109,22 @@ public interface GridImageAsyncClient {
|
|||
@Path("/common/lookup/list")
|
||||
@QueryParams(keys = LOOKUP_LIST_KEY, values = "datacenter")
|
||||
ListenableFuture<Set<Option>> getDatacenters();
|
||||
|
||||
/**
|
||||
* @see GridImageClient#deleteById(Long)
|
||||
*/
|
||||
@GET
|
||||
@ResponseParser(ParseImageFromJsonResponse.class)
|
||||
@Path("/grid/image/delete")
|
||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<ServerImage> deleteById(@QueryParam(ID_KEY) long id);
|
||||
|
||||
/**
|
||||
* @see GridImageClient#saveImageFromServer
|
||||
*/
|
||||
@GET
|
||||
@ResponseParser(ParseImageFromJsonResponse.class)
|
||||
@Path("/grid/image/save")
|
||||
ListenableFuture<ServerImage> saveImageFromServer(@QueryParam(IMAGE_FRIENDLY_NAME_KEY) String friendlyName,
|
||||
@QueryParam(SERVER_ID_OR_NAME_KEY) String idOrName, SaveImageOptions... options);
|
||||
}
|
||||
|
|
|
@ -25,15 +25,37 @@ import org.jclouds.concurrent.Timeout;
|
|||
import org.jclouds.gogrid.domain.Option;
|
||||
import org.jclouds.gogrid.domain.ServerImage;
|
||||
import org.jclouds.gogrid.options.GetImageListOptions;
|
||||
import org.jclouds.gogrid.options.SaveImageOptions;
|
||||
|
||||
/**
|
||||
* Manages the server images
|
||||
*
|
||||
* @see <a href="http://wiki.gogrid.com/wiki/index.php/API#Server_Image_Methods"/>
|
||||
* @see <a
|
||||
* href="http://wiki.gogrid.com/wiki/index.php/API#Server_Image_Methods"/>
|
||||
* @author Oleksiy Yarmula
|
||||
*/
|
||||
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
|
||||
public interface GridImageClient {
|
||||
/**
|
||||
* Deletes an existing image
|
||||
*
|
||||
* @param id
|
||||
* id of the existing image
|
||||
*/
|
||||
ServerImage deleteById(long id);
|
||||
|
||||
/**
|
||||
* This call will save a private (visible to only you) server image to your
|
||||
* library of available images. The image will be saved from an existing
|
||||
* server.
|
||||
*
|
||||
* @param idOrName
|
||||
* id or name of the existing server
|
||||
* @param friendlyName
|
||||
* friendly name of the image
|
||||
* @return saved server image
|
||||
*/
|
||||
ServerImage saveImageFromServer(String friendlyName, String idOrName, SaveImageOptions... options);
|
||||
|
||||
/**
|
||||
* Returns all server images.
|
||||
|
@ -85,9 +107,9 @@ public interface GridImageClient {
|
|||
ServerImage editImageFriendlyName(String idOrName, String newFriendlyName);
|
||||
|
||||
/**
|
||||
* Retrieves the list of supported Datacenters to save images in. The objects will have
|
||||
* datacenter ID, name and description. In most cases, id or name will be used for
|
||||
* {@link #getImageList}.
|
||||
* Retrieves the list of supported Datacenters to save images in. The objects
|
||||
* will have datacenter ID, name and description. In most cases, id or name
|
||||
* will be used for {@link #getImageList}.
|
||||
*
|
||||
* @return supported datacenters
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds 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.jclouds.gogrid.options;
|
||||
|
||||
import static org.jclouds.gogrid.options.SaveImageOptions.Builder.withDescription;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.jclouds.http.options.HttpRequestOptions;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests possible uses of SaveImageOptions and SaveImageOptions.Builder.*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
//NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
@Test(groups = "unit", testName = "SaveImageOptionsTest")
|
||||
public class SaveImageOptionsTest {
|
||||
|
||||
@Test
|
||||
public void testAssignability() {
|
||||
assert HttpRequestOptions.class.isAssignableFrom(SaveImageOptions.class);
|
||||
assert !String.class.isAssignableFrom(SaveImageOptions.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithDescription() {
|
||||
SaveImageOptions options = new SaveImageOptions();
|
||||
options.withDescription("test");
|
||||
assertEquals(options.buildQueryParameters().get("description"), Collections
|
||||
.singletonList("test"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testWith501LengthDescription() {
|
||||
SaveImageOptions options = new SaveImageOptions();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < 1 * 501; i++)
|
||||
builder.append('a');
|
||||
|
||||
String description = builder.toString();
|
||||
|
||||
options.withDescription(description);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWith500LengthDescription() {
|
||||
SaveImageOptions options = new SaveImageOptions();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < 1 * 500; i++)
|
||||
builder.append('a');
|
||||
|
||||
String description = builder.toString();
|
||||
|
||||
options.withDescription(description);
|
||||
assertEquals(options.buildQueryParameters().get("description"), Collections
|
||||
.singletonList(description));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullWithDescription() {
|
||||
SaveImageOptions options = new SaveImageOptions();
|
||||
assertEquals(options.buildQueryParameters().get("description"), Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithDescriptionStatic() {
|
||||
SaveImageOptions options = withDescription("test");
|
||||
assertEquals(options.buildQueryParameters().get("description"), Collections
|
||||
.singletonList("test"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testWithDescriptionNPE() {
|
||||
withDescription(null);
|
||||
}
|
||||
|
||||
}
|
|
@ -26,7 +26,9 @@ import org.jclouds.gogrid.domain.ServerImageType;
|
|||
import org.jclouds.gogrid.functions.ParseImageFromJsonResponse;
|
||||
import org.jclouds.gogrid.functions.ParseImageListFromJsonResponse;
|
||||
import org.jclouds.gogrid.options.GetImageListOptions;
|
||||
import org.jclouds.gogrid.options.SaveImageOptions;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -38,7 +40,8 @@ import com.google.inject.TypeLiteral;
|
|||
*
|
||||
* @author Oleksiy Yarmula
|
||||
*/
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during
|
||||
// surefire
|
||||
@Test(groups = "unit", testName = "GridImageAsyncClientTest")
|
||||
public class GridImageAsyncClientTest extends BaseGoGridAsyncClientTest<GridImageAsyncClient> {
|
||||
|
||||
|
@ -139,6 +142,56 @@ public class GridImageAsyncClientTest extends BaseGoGridAsyncClientTest<GridImag
|
|||
assertPayloadEquals(httpRequest, null, null, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteById() throws NoSuchMethodException, IOException {
|
||||
Method method = GridImageAsyncClient.class.getMethod("deleteById", long.class);
|
||||
HttpRequest httpRequest = processor.createRequest(method, 11l);
|
||||
|
||||
assertRequestLineEquals(httpRequest, "GET https://api.gogrid.com/api/grid/image/delete?v=1.5&id=11 HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(httpRequest, "");
|
||||
assertPayloadEquals(httpRequest, null, null, false);
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, ParseImageFromJsonResponse.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveImageFromServerNoOptions() throws NoSuchMethodException, IOException {
|
||||
Method method = GridImageAsyncClient.class.getMethod("saveImageFromServer", String.class, String.class,
|
||||
SaveImageOptions[].class);
|
||||
HttpRequest httpRequest = processor.createRequest(method, "friendly", "serverName");
|
||||
|
||||
assertRequestLineEquals(httpRequest,
|
||||
"GET https://api.gogrid.com/api/grid/image/save?v=1.5&friendlyName=friendly&server=serverName HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(httpRequest, "");
|
||||
assertPayloadEquals(httpRequest, null, null, false);
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, ParseImageFromJsonResponse.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveImageOptions() throws NoSuchMethodException, IOException {
|
||||
Method method = GridImageAsyncClient.class.getMethod("saveImageFromServer", String.class, String.class,
|
||||
SaveImageOptions[].class);
|
||||
HttpRequest httpRequest = processor.createRequest(method, "friendly", "serverName",
|
||||
new SaveImageOptions().withDescription("fooy"));
|
||||
|
||||
assertRequestLineEquals(
|
||||
httpRequest,
|
||||
"GET https://api.gogrid.com/api/grid/image/save?v=1.5&friendlyName=friendly&server=serverName&description=fooy HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(httpRequest, "");
|
||||
assertPayloadEquals(httpRequest, null, null, false);
|
||||
|
||||
assertResponseParserClassEquals(method, httpRequest, ParseImageFromJsonResponse.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeLiteral<RestAnnotationProcessor<GridImageAsyncClient>> createTypeLiteral() {
|
||||
return new TypeLiteral<RestAnnotationProcessor<GridImageAsyncClient>>() {
|
||||
|
|
|
@ -19,20 +19,34 @@
|
|||
package org.jclouds.gogrid.services;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jclouds.gogrid.domain.Ip;
|
||||
import org.jclouds.gogrid.domain.Server;
|
||||
import org.jclouds.gogrid.domain.ServerImage;
|
||||
import org.jclouds.gogrid.domain.ServerImageState;
|
||||
import org.jclouds.gogrid.options.SaveImageOptions;
|
||||
import org.jclouds.gogrid.predicates.ServerLatestJobCompleted;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during
|
||||
// surefire
|
||||
@Test(groups = "unit", testName = "GridImageClientLiveTest")
|
||||
public class GridImageClientLiveTest extends BaseGoGridClientLiveTest {
|
||||
|
||||
|
@ -43,8 +57,8 @@ public class GridImageClientLiveTest extends BaseGoGridClientLiveTest {
|
|||
assert image.getId() >= 0 : image;
|
||||
checkImage(image);
|
||||
|
||||
ServerImage query = Iterables.getOnlyElement(restContext.getApi().getImageServices().getImagesById(
|
||||
image.getId()));
|
||||
ServerImage query = Iterables.getOnlyElement(restContext.getApi().getImageServices()
|
||||
.getImagesById(image.getId()));
|
||||
assertEquals(query.getId(), image.getId());
|
||||
|
||||
checkImage(query);
|
||||
|
@ -69,4 +83,61 @@ public class GridImageClientLiveTest extends BaseGoGridClientLiveTest {
|
|||
if (image.getUpdatedTime() == null)
|
||||
Logger.getAnonymousLogger().warning("image " + image.getId() + " is missing the updatedon field");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveServerToImage() throws IOException {
|
||||
RetryablePredicate<Server> serverLatestJobCompleted = new RetryablePredicate<Server>(
|
||||
new ServerLatestJobCompleted(restContext.getApi().getJobServices()), 800, 20, TimeUnit.SECONDS);
|
||||
|
||||
final String nameOfServer = "Server" + String.valueOf(new Date().getTime()).substring(6);
|
||||
ServerImage image = null;
|
||||
try {
|
||||
Set<Ip> availableIps = restContext.getApi().getIpServices().getUnassignedIpList();
|
||||
Ip availableIp = Iterables.getLast(availableIps);
|
||||
|
||||
Server createdServer = restContext.getApi().getServerServices()
|
||||
.addServer(nameOfServer, "5489", "1", availableIp.getIp());
|
||||
assertNotNull(createdServer);
|
||||
assert serverLatestJobCompleted.apply(createdServer);
|
||||
image = restContext
|
||||
.getApi()
|
||||
.getImageServices()
|
||||
.saveImageFromServer("friendlyName", createdServer.getName(),
|
||||
SaveImageOptions.Builder.withDescription("description"));
|
||||
|
||||
assertEquals(image.getFriendlyName(), "friendlyName");
|
||||
assertEquals(image.getDescription(), "description");
|
||||
assertFalse(image.isPublic());
|
||||
|
||||
assertEventuallyImageStateEquals(image, ServerImageState.AVAILABLE);
|
||||
|
||||
restContext.getApi().getImageServices().deleteById(image.getId());
|
||||
|
||||
assertEventuallyImageStateEquals(image, ServerImageState.TRASH);
|
||||
|
||||
} finally {
|
||||
if (image != null)
|
||||
try {
|
||||
restContext.getApi().getImageServices().deleteById(image.getId());
|
||||
} catch (Exception e) {
|
||||
// not failing so that we can ensure server below deletes
|
||||
e.printStackTrace();
|
||||
}
|
||||
// delete the server
|
||||
restContext.getApi().getServerServices().deleteByName(nameOfServer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void assertEventuallyImageStateEquals(ServerImage image, final ServerImageState state) {
|
||||
assertTrue(new RetryablePredicate<ServerImage>(new Predicate<ServerImage>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(ServerImage input) {
|
||||
return Iterables.getOnlyElement(restContext
|
||||
.getApi()
|
||||
.getImageServices().getImagesById(input.getId())).getState() == state;
|
||||
}
|
||||
}, 300, 1, TimeUnit.SECONDS).apply(image));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue