mirror of https://github.com/apache/jclouds.git
Merge pull request #656 from aplowe/openstack-nova2
Openstack glance: adding create, reserve, update, upload and delete methods to ImageClient
This commit is contained in:
commit
adf2b5996a
|
@ -81,7 +81,7 @@ public class BaseListOptions extends BaseHttpRequestOptions {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see BaseListOptions#maxResults(long)
|
||||
* @see BaseListOptions#maxResults
|
||||
*/
|
||||
public static BaseListOptions maxResults(int maxKeys) {
|
||||
BaseListOptions options = new BaseListOptions();
|
||||
|
|
|
@ -472,8 +472,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
Payload payload = null;
|
||||
HttpRequestOptions options = findOptionsIn(method, args);
|
||||
if (options != null) {
|
||||
for(HttpRequestOptions options : findOptionsIn(method, args)) {
|
||||
injector.injectMembers(options);// TODO test case
|
||||
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
|
||||
headers.put(header.getKey(), Strings2.replaceTokens(header.getValue(), tokenValues.entries()));
|
||||
|
@ -1051,30 +1050,26 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
//TODO: change to LoadingCache<ClassMethodArgs, HttpRequestOptions and move this logic to the CacheLoader.
|
||||
private HttpRequestOptions findOptionsIn(Method method, Object... args) throws ExecutionException {
|
||||
for (int index : methodToIndexesOfOptions.get(method)) {
|
||||
private Set<HttpRequestOptions> findOptionsIn(Method method, Object... args) throws ExecutionException {
|
||||
ImmutableSet.Builder<HttpRequestOptions> result = ImmutableSet.builder();
|
||||
for (int index : methodToIndexesOfOptions.get(method)) {
|
||||
if (args.length >= index + 1) {// accomodate varargs
|
||||
if (args[index] instanceof Object[]) {
|
||||
Object[] options = (Object[]) args[index];
|
||||
if (options.length == 0) {
|
||||
} else if (options.length == 1) {
|
||||
if (options[0] instanceof HttpRequestOptions) {
|
||||
HttpRequestOptions binder = (HttpRequestOptions) options[0];
|
||||
injector.injectMembers(binder);
|
||||
return binder;
|
||||
}
|
||||
} else {
|
||||
if (options[0] instanceof HttpRequestOptions) {
|
||||
throw new IllegalArgumentException("we currently do not support multiple varargs options in: "
|
||||
+ method.getName());
|
||||
for (Object option : (Object[]) args[index]) {
|
||||
if (option instanceof HttpRequestOptions) {
|
||||
result.add((HttpRequestOptions) option);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return (HttpRequestOptions) args[index];
|
||||
for (; index < args.length; index++) {
|
||||
if (args[index] instanceof HttpRequestOptions) {
|
||||
result.add((HttpRequestOptions) args[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return result.build();
|
||||
}
|
||||
|
||||
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues, Method method,
|
||||
|
|
|
@ -511,6 +511,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
@POST
|
||||
public void varargs(HttpRequestOptions... options);
|
||||
|
||||
@POST
|
||||
public void varargsWithReq(String required, HttpRequestOptions... options);
|
||||
|
||||
@POST
|
||||
public void post(HttpRequestOptions options);
|
||||
|
||||
|
@ -531,6 +534,12 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
assertPayloadEquals(request, "", "application/octet-stream", false);
|
||||
}
|
||||
|
||||
private class TestHttpRequestOptions extends BaseHttpRequestOptions {
|
||||
TestHttpRequestOptions payload(String payload) { this.payload = payload; return this; }
|
||||
TestHttpRequestOptions headerParams(Multimap<String, String> headers) { this.headers.putAll(headers); return this; }
|
||||
TestHttpRequestOptions queryParams(Multimap<String, String> params) { this.queryParameters.putAll(params); return this; }
|
||||
}
|
||||
|
||||
public void testHttpRequestOptionsPayloadParam() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPayloadParamVarargs.class.getMethod("post", Payload.class);
|
||||
HttpRequest request = factory(TestQuery.class).createRequest(method, Payloads.newStringPayload("foo"));
|
||||
|
@ -541,48 +550,51 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
|
||||
public void testHttpRequestWithOnlyContentType() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPayloadParamVarargs.class.getMethod("post", HttpRequestOptions.class);
|
||||
verifyTestPostOptions(method);
|
||||
}
|
||||
|
||||
public void testPayloadParamVarargs() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPayloadParamVarargs.class.getMethod("varargs", Array.newInstance(HttpRequestOptions.class, 0)
|
||||
.getClass());
|
||||
verifyTestPostOptions(method);
|
||||
}
|
||||
|
||||
private void verifyTestPostOptions(Method method) throws IOException {
|
||||
HttpRequest request = factory(TestPayloadParamVarargs.class).createRequest(method, new HttpRequestOptions() {
|
||||
|
||||
public Multimap<String, String> buildMatrixParameters() {
|
||||
return LinkedHashMultimap.create();
|
||||
}
|
||||
|
||||
public String buildPathSuffix() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Multimap<String, String> buildQueryParameters() {
|
||||
return LinkedHashMultimap.create();
|
||||
}
|
||||
|
||||
public Multimap<String, String> buildFormParameters() {
|
||||
return LinkedHashMultimap.create();
|
||||
}
|
||||
|
||||
public Multimap<String, String> buildRequestHeaders() {
|
||||
return LinkedHashMultimap.create();
|
||||
}
|
||||
|
||||
public String buildStringPayload() {
|
||||
return "fooya";
|
||||
}
|
||||
|
||||
});
|
||||
HttpRequest request = factory(TestPayloadParamVarargs.class).createRequest(method, new TestHttpRequestOptions().payload("fooya"));
|
||||
assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "");
|
||||
assertPayloadEquals(request, "fooya", "application/unknown", false);
|
||||
}
|
||||
|
||||
public void testHeaderAndQueryVarargs() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPayloadParamVarargs.class.getMethod("varargs", Array.newInstance(HttpRequestOptions.class, 0)
|
||||
.getClass());
|
||||
HttpRequest request = factory(TestPayloadParamVarargs.class).createRequest(method,
|
||||
new TestHttpRequestOptions().payload("fooya"),
|
||||
new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")),
|
||||
new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")));
|
||||
assertRequestLineEquals(request, "POST http://localhost:9999?key=value HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "X-header-1: fooya\n");
|
||||
assertPayloadEquals(request, "fooya", "application/unknown", false);
|
||||
}
|
||||
|
||||
public void testHeaderAndQueryVarargsPlusReq() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPayloadParamVarargs.class.getMethod("varargsWithReq", String.class, Array.newInstance(HttpRequestOptions.class, 0)
|
||||
.getClass());
|
||||
HttpRequest request = factory(TestPayloadParamVarargs.class).createRequest(method, "required param",
|
||||
new Object[]{ new TestHttpRequestOptions().payload("fooya"),
|
||||
new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")),
|
||||
new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value"))});
|
||||
assertRequestLineEquals(request, "POST http://localhost:9999?key=value HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "X-header-1: fooya\n");
|
||||
assertPayloadEquals(request, "fooya", "application/unknown", false);
|
||||
}
|
||||
|
||||
public void testDuplicateHeaderAndQueryVarargs() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPayloadParamVarargs.class.getMethod("varargs", Array.newInstance(HttpRequestOptions.class, 0)
|
||||
.getClass());
|
||||
HttpRequest request = factory(TestPayloadParamVarargs.class).createRequest(method,
|
||||
new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")),
|
||||
new TestHttpRequestOptions().payload("fooya"),
|
||||
new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")),
|
||||
new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "anothervalue")),
|
||||
new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya again!")),
|
||||
new TestHttpRequestOptions().payload("last_payload_wins!"));
|
||||
assertRequestLineEquals(request, "POST http://localhost:9999?key=value&key=anothervalue HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "X-header-1: fooya\nX-header-1: fooya again!\n");
|
||||
assertPayloadEquals(request, "last_payload_wins!", "application/unknown", false);
|
||||
}
|
||||
|
||||
public class TestCustomMethod {
|
||||
@FOO
|
||||
public void foo() {
|
||||
|
|
|
@ -246,6 +246,10 @@ public class ImageDetails extends Image {
|
|||
return this.location;
|
||||
}
|
||||
|
||||
public Optional<String> getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return this.updatedAt;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* 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.openstack.glance.v1_0.domain;
|
||||
|
||||
/**
|
||||
* Backing store types for glance images
|
||||
*
|
||||
* @author Adam Lowe
|
||||
* @see <a href= "http://glance.openstack.org/architecture.html#what-is-a-store" />
|
||||
*/
|
||||
public enum StoreType {
|
||||
/**
|
||||
* Filesystem store
|
||||
*/
|
||||
FILE,
|
||||
/**
|
||||
* S3 store
|
||||
*/
|
||||
S3,
|
||||
/**
|
||||
* Openstack swift store
|
||||
*/
|
||||
SWIFT,
|
||||
/**
|
||||
* RADOS (Reliable Autonomic Distributed Object Store) Block Device store
|
||||
*/
|
||||
RBD,
|
||||
/**
|
||||
* HTTP (read-only) store
|
||||
*/
|
||||
HTTP;
|
||||
|
||||
public String value() {
|
||||
return name().toLowerCase().replace("_", "+");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value();
|
||||
}
|
||||
}
|
|
@ -21,23 +21,24 @@ package org.jclouds.openstack.glance.v1_0.features;
|
|||
import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HEAD;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.io.Payload;
|
||||
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.Image;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
|
||||
import org.jclouds.openstack.glance.v1_0.functions.ParseImageDetailsFromHeaders;
|
||||
import org.jclouds.openstack.glance.v1_0.options.CreateImageOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.options.ListImageOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.options.UpdateImageOptions;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
@ -47,6 +48,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||
*
|
||||
* @see ImageClient
|
||||
* @author Adrian Cole
|
||||
* @author Adam Lowe
|
||||
* @see <a href="http://glance.openstack.org/glanceapi.html">api doc</a>
|
||||
* @see <a href="https://github.com/openstack/glance/blob/master/glance/api/v1/images.py">api src</a>
|
||||
*/
|
||||
|
@ -62,7 +64,7 @@ public interface ImageAsyncClient {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/images")
|
||||
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||
ListenableFuture<Set<Image>> list();
|
||||
ListenableFuture<Set<Image>> list(ListImageOptions... options);
|
||||
|
||||
/**
|
||||
* @see ImageClient#listInDetail
|
||||
|
@ -72,7 +74,7 @@ public interface ImageAsyncClient {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/images/detail")
|
||||
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||
ListenableFuture<Set<ImageDetails>> listInDetail();
|
||||
ListenableFuture<Set<ImageDetails>> listInDetail(ListImageOptions... options);
|
||||
|
||||
/**
|
||||
* @see ImageClient#show
|
||||
|
@ -91,9 +93,49 @@ public interface ImageAsyncClient {
|
|||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||
ListenableFuture<InputStream> getAsStream(@PathParam("id") String id);
|
||||
|
||||
// POST /images -- Store image data and return metadata about the
|
||||
// newly-stored image
|
||||
// PUT /images/<ID> -- Update image metadata and/or upload image
|
||||
// data for a previously-reserved image
|
||||
// DELETE /images/<ID> -- Delete the image with id <ID>
|
||||
/**
|
||||
* @see ImageClient#create
|
||||
*/
|
||||
@POST
|
||||
@Path("/images")
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@SelectJson("image")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
ListenableFuture<ImageDetails> create(@HeaderParam("x-image-meta-name") String name, Payload payload, CreateImageOptions... options);
|
||||
|
||||
/**
|
||||
* @see ImageClient#reserve
|
||||
*/
|
||||
@POST
|
||||
@Path("/images")
|
||||
@SelectJson("image")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
ListenableFuture<ImageDetails> reserve(@HeaderParam("x-image-meta-name") String name, CreateImageOptions... options);
|
||||
|
||||
/**
|
||||
* @see ImageClient#upload
|
||||
*/
|
||||
@PUT
|
||||
@Path("/images/{id}")
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@SelectJson("image")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
ListenableFuture<ImageDetails> upload(@PathParam("id") String id, Payload imageData, UpdateImageOptions... options);
|
||||
|
||||
/**
|
||||
* @see ImageClient#update
|
||||
*/
|
||||
@PUT
|
||||
@Path("/images/{id}")
|
||||
@SelectJson("image")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
ListenableFuture<ImageDetails> update(@PathParam("id") String id, UpdateImageOptions... options);
|
||||
|
||||
/**
|
||||
* @see ImageClient#delete
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/images/{id}")
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> delete(@PathParam("id") String id);
|
||||
}
|
||||
|
|
|
@ -23,15 +23,21 @@ import java.util.Set;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.io.Payload;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.Image;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
|
||||
import org.jclouds.openstack.glance.v1_0.options.CreateImageOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.options.UpdateImageOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.options.ListImageOptions;
|
||||
|
||||
/**
|
||||
* Image Services
|
||||
*
|
||||
* @see ImageAsyncClient
|
||||
* @author Adrian Cole
|
||||
* @author Adam Lowe
|
||||
* @see ImageAsyncClient
|
||||
* @see <a href="http://glance.openstack.org/glanceapi.html">api doc</a>
|
||||
*/
|
||||
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||
|
@ -39,12 +45,12 @@ public interface ImageClient {
|
|||
/**
|
||||
* Returns a set of brief metadata about images
|
||||
*/
|
||||
Set<Image> list();
|
||||
Set<Image> list(ListImageOptions... options);
|
||||
|
||||
/**
|
||||
* Returns a set of detailed metadata about images
|
||||
*/
|
||||
Set<ImageDetails> listInDetail();
|
||||
Set<ImageDetails> listInDetail(ListImageOptions... options);
|
||||
|
||||
/**
|
||||
* Return metadata about an image with id
|
||||
|
@ -58,9 +64,46 @@ public interface ImageClient {
|
|||
@Nullable
|
||||
InputStream getAsStream(String id);
|
||||
|
||||
// POST /images -- Store image data and return metadata about the
|
||||
// newly-stored image
|
||||
// PUT /images/<ID> -- Update image metadata and/or upload image
|
||||
// data for a previously-reserved image
|
||||
// DELETE /images/<ID> -- Delete the image with id <ID>
|
||||
/**
|
||||
* Create a new image
|
||||
*
|
||||
* @return detailed metadata about the newly stored image
|
||||
*/
|
||||
ImageDetails create(String name, Payload imageData, CreateImageOptions... options);
|
||||
|
||||
/**
|
||||
* Reserve a new image to be uploaded later
|
||||
*
|
||||
* @return detailed metadata about the newly stored image
|
||||
* @see #upload
|
||||
*/
|
||||
ImageDetails reserve(String name, CreateImageOptions... options);
|
||||
|
||||
/**
|
||||
* Adjust the metadata stored for an existing image
|
||||
*
|
||||
* @return detailed metadata about the updated image
|
||||
*/
|
||||
ImageDetails update(String id, UpdateImageOptions... options);
|
||||
|
||||
/**
|
||||
* Upload image data for a previously-reserved image
|
||||
* <p/>
|
||||
* If an image was previously reserved, and thus is in the queued state, then image data can be added using this method.
|
||||
* If the image already as data associated with it (e.g. not in the queued state), then you will receive a 409
|
||||
* Conflict exception.
|
||||
*
|
||||
* @param imageData the new image to upload
|
||||
* @param options can be used to adjust the metadata stored for the image in the same call
|
||||
* @return detailed metadata about the updated image
|
||||
* @see #reserve
|
||||
*/
|
||||
ImageDetails upload(String id, Payload imageData, UpdateImageOptions... options);
|
||||
|
||||
/**
|
||||
* Delete the image with the specified id
|
||||
*
|
||||
* @return true if successful
|
||||
*/
|
||||
Boolean delete(String id);
|
||||
}
|
||||
|
|
|
@ -18,16 +18,19 @@
|
|||
*/
|
||||
package org.jclouds.openstack.glance.v1_0.functions;
|
||||
|
||||
import static org.jclouds.openstack.glance.v1_0.options.ImageField.*;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.Image;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.Image.Status;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
/**
|
||||
* This parses {@link ImageDetails} from HTTP headers.
|
||||
|
@ -44,23 +47,27 @@ public class ParseImageDetailsFromHeaders implements Function<HttpResponse, Imag
|
|||
|
||||
public ImageDetails apply(HttpResponse from) {
|
||||
ImageDetails.Builder<?> builder = ImageDetails.builder()
|
||||
.id(from.getFirstHeaderOrNull("X-Image-Meta-Id"))
|
||||
.name(from.getFirstHeaderOrNull("X-Image-Meta-Name"))
|
||||
.checksum(from.getFirstHeaderOrNull("X-Image-Meta-Checksum"))
|
||||
.containerFormat(ContainerFormat.fromValue(from.getFirstHeaderOrNull("X-Image-Meta-Container_format")))
|
||||
.diskFormat(DiskFormat.fromValue(from.getFirstHeaderOrNull("X-Image-Meta-Disk_format")))
|
||||
.size(Long.parseLong(from.getFirstHeaderOrNull("X-Image-Meta-Size")))
|
||||
.minDisk(Long.parseLong(from.getFirstHeaderOrNull("X-Image-Meta-Min_disk")))
|
||||
.minRam(Long.parseLong(from.getFirstHeaderOrNull("X-Image-Meta-Min_ram")))
|
||||
.isPublic(Boolean.parseBoolean(from.getFirstHeaderOrNull("X-Image-Meta-Is_public")))
|
||||
.createdAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull("X-Image-Meta-Created_at")))
|
||||
.updatedAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull("X-Image-Meta-Updated_at")))
|
||||
.owner(from.getFirstHeaderOrNull("X-Image-Meta-Owner"))
|
||||
.status(Image.Status.fromValue(from.getFirstHeaderOrNull("X-Image-Meta-Status")));
|
||||
.id(from.getFirstHeaderOrNull(ID.asHeader()))
|
||||
.name(from.getFirstHeaderOrNull(NAME.asHeader()))
|
||||
.checksum(Optional.fromNullable(from.getFirstHeaderOrNull(CHECKSUM.asHeader())))
|
||||
.minDisk(Long.parseLong(from.getFirstHeaderOrNull(MIN_DISK.asHeader())))
|
||||
.minRam(Long.parseLong(from.getFirstHeaderOrNull(MIN_RAM.asHeader())))
|
||||
.isPublic(Boolean.parseBoolean(from.getFirstHeaderOrNull(IS_PUBLIC.asHeader())))
|
||||
.createdAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull(CREATED_AT.asHeader())))
|
||||
.updatedAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull(UPDATED_AT.asHeader())))
|
||||
.owner(Optional.fromNullable(from.getFirstHeaderOrNull(OWNER.asHeader())))
|
||||
.location(Optional.fromNullable(from.getFirstHeaderOrNull(LOCATION.asHeader())))
|
||||
.status(Status.fromValue(from.getFirstHeaderOrNull(STATUS.asHeader())));
|
||||
|
||||
String deletedAt = from.getFirstHeaderOrNull("X-Image-Meta-Deleted_at");
|
||||
if (deletedAt != null)
|
||||
builder.deletedAt(dateService.iso8601SecondsDateParse(deletedAt));
|
||||
String containerFormat = from.getFirstHeaderOrNull(CONTAINER_FORMAT.asHeader());
|
||||
String diskFormat = from.getFirstHeaderOrNull(DISK_FORMAT.asHeader());
|
||||
String deletedAt = from.getFirstHeaderOrNull(DELETED_AT.asHeader());
|
||||
String size = from.getFirstHeaderOrNull(SIZE.asHeader());
|
||||
|
||||
if (containerFormat != null) builder.containerFormat(ContainerFormat.fromValue(containerFormat));
|
||||
if (diskFormat != null) builder.diskFormat(DiskFormat.fromValue(diskFormat));
|
||||
if (deletedAt != null) builder.deletedAt(dateService.iso8601SecondsDateParse(deletedAt));
|
||||
if (size != null) builder.size(Long.parseLong(size));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* 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.openstack.glance.v1_0.options;
|
||||
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.StoreType;
|
||||
|
||||
/**
|
||||
*
|
||||
* <h2></h2>Usage</h2> The recommended way to instantiate a CreateImageOptions object is to statically import
|
||||
* CreateImageOptions.Builder.* and invoke a static creation method for each option as needed:
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.openstack.glance.v1_0.options.CreateImageOptions.Builder.*
|
||||
*
|
||||
*
|
||||
* // this will create an image with the name "imageName", minimum required disk of 10GB, etc.
|
||||
* details = client.create("imageName", minDisk(10), isPublic(true), property("mykey", "somevalue"));
|
||||
* <code>
|
||||
|
||||
* @author Adam Lowe
|
||||
* @see <a href="http://glance.openstack.org/glanceapi.html"/>
|
||||
*/
|
||||
public class CreateImageOptions extends UpdateImageOptions {
|
||||
|
||||
/**
|
||||
* When present, Glance will use the supplied identifier for the image instead of generating one. If the identifier
|
||||
* already exists in that Glance node, then a 409 Conflict will be returned by Glance. The value of the header must
|
||||
* be a uuid in hexadecimal string notation (i.e. 71c675ab-d94f-49cd-a114-e12490b328d9).
|
||||
*/
|
||||
public CreateImageOptions id(String id) {
|
||||
headers.put(ImageField.ID.asHeader(), id);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#id
|
||||
*/
|
||||
public static CreateImageOptions id(String id) {
|
||||
return new CreateImageOptions().id(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#storeType
|
||||
*/
|
||||
public static CreateImageOptions storeType(StoreType storeType) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().storeType(storeType));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#diskFormat
|
||||
*/
|
||||
public static CreateImageOptions diskFormat(DiskFormat diskFormat) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().diskFormat(diskFormat));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#containerFormat
|
||||
*/
|
||||
public static CreateImageOptions containerFormat(ContainerFormat containerFormat) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().containerFormat(containerFormat));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#size
|
||||
*/
|
||||
public static CreateImageOptions size(long size) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().size(size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#checksum
|
||||
*/
|
||||
public static CreateImageOptions checksum(String checksum) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().checksum(checksum));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#isPublic
|
||||
*/
|
||||
public static CreateImageOptions isPublic(boolean isPublic) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().isPublic(isPublic));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#isProtected
|
||||
*/
|
||||
public static CreateImageOptions isProtected(boolean isProtected) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().isProtected(isProtected));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#minRam
|
||||
*/
|
||||
public static CreateImageOptions minRam(long ram) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().minRam(ram));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#minDisk
|
||||
*/
|
||||
public static CreateImageOptions minDisk(long disk) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().minDisk(disk));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#owner
|
||||
*/
|
||||
public static CreateImageOptions owner(String owner) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().owner(owner));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.glance.v1_0.options.CreateImageOptions#property
|
||||
*/
|
||||
public static CreateImageOptions property(String key, String value) {
|
||||
return CreateImageOptions.class.cast(new CreateImageOptions().property(key, value));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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.openstack.glance.v1_0.options;
|
||||
|
||||
import static com.google.common.base.CaseFormat.LOWER_UNDERSCORE;
|
||||
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
|
||||
|
||||
import org.jclouds.util.Strings2;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
/**
|
||||
* Fields used in Glance options
|
||||
*/
|
||||
public enum ImageField {
|
||||
ID, NAME, CHECKSUM, MIN_DISK, MIN_RAM, IS_PUBLIC, PROTECTED, CREATED_AT, UPDATED_AT, DELETED_AT,
|
||||
OWNER, LOCATION, STATUS, DISK_FORMAT, CONTAINER_FORMAT, SIZE, SIZE_MIN, SIZE_MAX, STORE, PROPERTY;
|
||||
|
||||
public static final String HEADER_PREFIX = "X-Image-Meta-";
|
||||
|
||||
public String asParam() {
|
||||
return name().toLowerCase();
|
||||
}
|
||||
|
||||
public String asHeader() {
|
||||
return HEADER_PREFIX + name().charAt(0) + name().substring(1).toLowerCase();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
/**
|
||||
* 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.openstack.glance.v1_0.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.jclouds.openstack.glance.v1_0.options.ImageField.*;
|
||||
|
||||
import org.jclouds.http.options.BaseHttpRequestOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.Image.Status;
|
||||
|
||||
/**
|
||||
* <h2></h2>Usage</h2> The recommended way to instantiate a ListImageOptions object is to statically import
|
||||
* ListImageOptions.Builder.* and invoke a static creation method for each option as needed:
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.openstack.glance.v1_0.options.ListImageOptions.Builder.*
|
||||
*
|
||||
*
|
||||
* // this will list the first 10 images with the name "name", minimum required disk of 5GB.
|
||||
* list = client.list(name("newName"), limit(10), minDisk(5));
|
||||
* <code>
|
||||
*
|
||||
* @author Adam Lowe
|
||||
* @see <a href="http://glance.openstack.org/glanceapi.html"/>
|
||||
*/
|
||||
public class ListImageOptions extends BaseHttpRequestOptions {
|
||||
public static final ListImageOptions NONE = new ListImageOptions();
|
||||
|
||||
/**
|
||||
* Given a string value x, return object names greater in value than the specified marker.
|
||||
*/
|
||||
public ListImageOptions marker(String marker) {
|
||||
queryParameters.put("marker", checkNotNull(marker, "marker"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For an integer value n, limits the number of results to n values.
|
||||
*/
|
||||
public ListImageOptions limit(int limit) {
|
||||
checkState(limit >= 0, "limit must be >= 0");
|
||||
checkState(limit <= 10000, "limit must be <= 10000");
|
||||
queryParameters.put("limit", Integer.toString(limit));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only those images having a matching name attribute
|
||||
*/
|
||||
public ListImageOptions name(String name) {
|
||||
queryParameters.put(NAME.asParam(), name);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only those images that have the requested status
|
||||
*/
|
||||
public ListImageOptions status(Status status) {
|
||||
queryParameters.put(STATUS.asParam(), status.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only those images having a matching container format
|
||||
*/
|
||||
public ListImageOptions containerFormat(ContainerFormat containerFormat) {
|
||||
queryParameters.put(CONTAINER_FORMAT.asParam(), containerFormat.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only those images having a matching disk format
|
||||
*/
|
||||
public ListImageOptions diskFormat(DiskFormat diskFormat) {
|
||||
queryParameters.put(DISK_FORMAT.asParam(), diskFormat.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only those images having a matching min ram size
|
||||
*/
|
||||
public ListImageOptions minRam(long ram) {
|
||||
queryParameters.put(MIN_RAM.asParam(), Long.toString(ram));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only those images having a matching min disk size
|
||||
*/
|
||||
public ListImageOptions minDisk(long disk) {
|
||||
queryParameters.put(MIN_DISK.asParam(), Long.toString(disk));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return those images that have a size attribute greater than or equal to size
|
||||
*/
|
||||
public ListImageOptions minSize(long size) {
|
||||
queryParameters.put(SIZE_MIN.asParam(), Long.toString(size));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return those images that have a size attribute less than or equal to size
|
||||
*/
|
||||
public ListImageOptions maxSize(long size) {
|
||||
queryParameters.put(SIZE_MAX.asParam(), Long.toString(size));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only public images or only private images
|
||||
*/
|
||||
public ListImageOptions isPublic(boolean isPublic) {
|
||||
queryParameters.put(IS_PUBLIC.asParam(), Boolean.toString(isPublic));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to only protected or unprotected images
|
||||
*/
|
||||
public ListImageOptions isProtected(boolean isProtected) {
|
||||
queryParameters.put(PROTECTED.asParam(), Boolean.toString(isProtected));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Results will be ordered by the specified image attribute.
|
||||
*/
|
||||
public ListImageOptions sortBy(ImageField key) {
|
||||
queryParameters.put("sort_key", key.asParam());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascending sort order (smallest first).
|
||||
* <p/>
|
||||
* NOTE: default behavior is to sort descending (largest first)
|
||||
*/
|
||||
public ListImageOptions sortAscending() {
|
||||
queryParameters.put("sort_dir", "asc");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see ListImageOptions#name
|
||||
*/
|
||||
public static ListImageOptions name(String name) {
|
||||
return new ListImageOptions().name(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#diskFormat
|
||||
*/
|
||||
public static ListImageOptions diskFormat(DiskFormat diskFormat) {
|
||||
return new ListImageOptions().diskFormat(diskFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#containerFormat
|
||||
*/
|
||||
public static ListImageOptions containerFormat(ContainerFormat containerFormat) {
|
||||
return new ListImageOptions().containerFormat(containerFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#minRam
|
||||
*/
|
||||
public static ListImageOptions minRam(long size) {
|
||||
return new ListImageOptions().minRam(size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#minDisk
|
||||
*/
|
||||
public static ListImageOptions minDisk(long size) {
|
||||
return new ListImageOptions().minDisk(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#minSize
|
||||
*/
|
||||
public static ListImageOptions minSize(long size) {
|
||||
return new ListImageOptions().minSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#maxSize
|
||||
*/
|
||||
public static ListImageOptions maxSize(long size) {
|
||||
return new ListImageOptions().maxSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#sortBy
|
||||
*/
|
||||
public static ListImageOptions status(Status status) {
|
||||
return new ListImageOptions().status(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#sortBy
|
||||
*/
|
||||
public static ListImageOptions sortBy(ImageField sortKey) {
|
||||
return new ListImageOptions().sortBy(sortKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#sortAscending
|
||||
*/
|
||||
public static ListImageOptions sortAscending() {
|
||||
return new ListImageOptions().sortAscending();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#isPublic
|
||||
*/
|
||||
public static ListImageOptions isPublic(boolean isPublic) {
|
||||
return ListImageOptions.class.cast(new ListImageOptions().isPublic(isPublic));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#isProtected
|
||||
*/
|
||||
public static ListImageOptions isProtected(boolean isProtected) {
|
||||
return ListImageOptions.class.cast(new ListImageOptions().isProtected(isProtected));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#limit
|
||||
*/
|
||||
public static ListImageOptions limit(int limit) {
|
||||
return new ListImageOptions().limit(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListImageOptions#marker
|
||||
*/
|
||||
public static ListImageOptions marker(String marker) {
|
||||
ListImageOptions options = new ListImageOptions();
|
||||
return options.marker(marker);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
/**
|
||||
* 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.openstack.glance.v1_0.options;
|
||||
|
||||
import static org.jclouds.openstack.glance.v1_0.options.ImageField.*;
|
||||
|
||||
import org.jclouds.http.options.BaseHttpRequestOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.StoreType;
|
||||
|
||||
/**
|
||||
* <h2></h2>Usage</h2> The recommended way to instantiate a UpdateImageOptions object is to statically import
|
||||
* UpdateImageOptions.Builder.* and invoke a static creation method for each option as needed:
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.openstack.glance.v1_0.options.UpdateImageOptions.Builder.*
|
||||
*
|
||||
*
|
||||
* // this will adjust the image with id 'id' the name "newName", minimum required disk of 5GB, etc.
|
||||
* details = client.update(id, name("newName"), minDisk(5), isPublic(true), property("mykey", "somevalue"));
|
||||
* <code>
|
||||
* @author Adam Lowe
|
||||
* @see <a href="http://glance.openstack.org/glanceapi.html"/>
|
||||
*/
|
||||
public class UpdateImageOptions extends BaseHttpRequestOptions {
|
||||
|
||||
/**
|
||||
* Adjust the name of the image
|
||||
*/
|
||||
public UpdateImageOptions name(String name) {
|
||||
headers.put(NAME.asHeader(), name);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When present, Glance will attempt to store the disk image data in the backing store indicated by the value of the
|
||||
* header. If the Glance node does not support the backing store, Glance will return a 400 Bad Request.
|
||||
*/
|
||||
public UpdateImageOptions storeType(StoreType storeType) {
|
||||
headers.put(STORE.asHeader(), storeType.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateImageOptions diskFormat(DiskFormat diskFormat) {
|
||||
headers.put(DISK_FORMAT.asHeader(), diskFormat.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateImageOptions containerFormat(ContainerFormat containerFormat) {
|
||||
headers.put(CONTAINER_FORMAT.asHeader(), containerFormat.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When present, Glance assumes that the expected size of the request body will be the value of this header. If the
|
||||
* length in bytes of the request body does not match the value of this header, Glance will return a 400 Bad Request.
|
||||
*/
|
||||
public UpdateImageOptions size(long size) {
|
||||
headers.put(SIZE.asHeader(), Long.toString(size));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 checksum of the image
|
||||
* <p/>
|
||||
* When present, Glance will verify the checksum generated from the backend store when storing your image against
|
||||
* this value and return a 400 Bad Request if the values do not match.
|
||||
*/
|
||||
public UpdateImageOptions checksum(String checksum) {
|
||||
headers.put(CHECKSUM.asHeader(), checksum);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateImageOptions location(String location) {
|
||||
headers.put(LOCATION.asHeader(), location);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the image as public, meaning that any user may view its metadata and may read the disk image
|
||||
* from Glance.
|
||||
*/
|
||||
public UpdateImageOptions isPublic(boolean isPublic) {
|
||||
headers.put(IS_PUBLIC.asHeader(), Boolean.toString(isPublic));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the image as protected - if set to true the image cannot be deleted till it is unset.
|
||||
*/
|
||||
public UpdateImageOptions isProtected(boolean isProtected) {
|
||||
headers.put(PROTECTED.asHeader(), Boolean.toString(isProtected));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The expected minimum ram required in megabytes to run this image on a server (default 0).
|
||||
*/
|
||||
public UpdateImageOptions minRam(long ram) {
|
||||
headers.put(MIN_RAM.asHeader(), Long.toString(ram));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The expected minimum disk required in gigabytes to run this image on a server (default 0).
|
||||
*/
|
||||
public UpdateImageOptions minDisk(long disk) {
|
||||
headers.put(MIN_DISK.asHeader(), Long.toString(disk));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Glance normally sets the owner of an image to be the tenant or user (depending on the “owner_is_tenant”
|
||||
* configuration option) of the authenticated user issuing the request. However, if the authenticated user has the
|
||||
* Admin role, this default may be overridden by setting this header to null or to a string identifying the owner of
|
||||
* the image.
|
||||
*/
|
||||
public UpdateImageOptions owner(String owner) {
|
||||
headers.put(OWNER.asHeader(), owner);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom, free-form image properties stored with the image.
|
||||
*/
|
||||
public UpdateImageOptions property(String key, String value) {
|
||||
if (!key.toLowerCase().startsWith(PROPERTY.asHeader() + "-")) {
|
||||
key = PROPERTY.asHeader() + "-" + key;
|
||||
}
|
||||
headers.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
/**
|
||||
* @see UpdateImageOptions#name
|
||||
*/
|
||||
public static UpdateImageOptions name(String name) {
|
||||
return new UpdateImageOptions().name(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#storeType
|
||||
*/
|
||||
public static UpdateImageOptions storeType(StoreType storeType) {
|
||||
return new UpdateImageOptions().storeType(storeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#diskFormat
|
||||
*/
|
||||
public static UpdateImageOptions diskFormat(DiskFormat diskFormat) {
|
||||
return new UpdateImageOptions().diskFormat(diskFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#containerFormat
|
||||
*/
|
||||
public static UpdateImageOptions containerFormat(ContainerFormat containerFormat) {
|
||||
return new UpdateImageOptions().containerFormat(containerFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#size
|
||||
*/
|
||||
public static UpdateImageOptions size(long size) {
|
||||
return new UpdateImageOptions().size(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#checksum
|
||||
*/
|
||||
public static UpdateImageOptions checksum(String checksum) {
|
||||
return new UpdateImageOptions().checksum(checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#location
|
||||
*/
|
||||
public static UpdateImageOptions location(String location) {
|
||||
return new UpdateImageOptions().location(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#isPublic
|
||||
*/
|
||||
public static UpdateImageOptions isPublic(boolean isPublic) {
|
||||
return new UpdateImageOptions().isPublic(isPublic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#isProtected
|
||||
*/
|
||||
public static UpdateImageOptions isProtected(boolean isProtected) {
|
||||
return new UpdateImageOptions().isProtected(isProtected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#minRam
|
||||
*/
|
||||
public static UpdateImageOptions minRam(long ram) {
|
||||
return new UpdateImageOptions().minRam(ram);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#minDisk
|
||||
*/
|
||||
public static UpdateImageOptions minDisk(long disk) {
|
||||
return new UpdateImageOptions().minDisk(disk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#owner
|
||||
*/
|
||||
public static UpdateImageOptions owner(String owner) {
|
||||
return new UpdateImageOptions().owner(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UpdateImageOptions#property
|
||||
*/
|
||||
public static UpdateImageOptions property(String key, String value) {
|
||||
return new UpdateImageOptions().property(key, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,19 +19,28 @@
|
|||
package org.jclouds.openstack.glance.v1_0.features;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.io.Payloads;
|
||||
import org.jclouds.io.payloads.StringPayload;
|
||||
import org.jclouds.openstack.glance.v1_0.GlanceClient;
|
||||
import org.jclouds.openstack.glance.v1_0.functions.ParseImageDetailsFromHeadersTest;
|
||||
import org.jclouds.openstack.glance.v1_0.internal.BaseGlanceClientExpectTest;
|
||||
import org.jclouds.openstack.glance.v1_0.options.UpdateImageOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.parse.ParseImageDetailsTest;
|
||||
import org.jclouds.openstack.glance.v1_0.parse.ParseImagesInDetailTest;
|
||||
import org.jclouds.openstack.glance.v1_0.parse.ParseImagesTest;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.jclouds.util.Strings2;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -40,6 +49,7 @@ import com.google.common.collect.ImmutableSet;
|
|||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ImageClientExpectTest")
|
||||
public class ImageClientExpectTest extends BaseGlanceClientExpectTest {
|
||||
|
@ -199,4 +209,272 @@ public class ImageClientExpectTest extends BaseGlanceClientExpectTest {
|
|||
assertNull(clientWhenNoExist.getImageClientForRegion("az-1.region-a.geo-1").getAsStream("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
|
||||
}
|
||||
|
||||
public void testCreateWhenResponseIs2xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("POST")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("x-image-meta-name", "test").put("Accept", MediaType.APPLICATION_JSON).put("X-Auth-Token", authToken).build())
|
||||
.payload(payloadFromStringWithContentType("somedata", MediaType.APPLICATION_OCTET_STREAM))
|
||||
.build();
|
||||
|
||||
HttpResponse createResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResource("/image.json")).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, createResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
assertEquals(clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").create("test", new StringPayload("somedata")),
|
||||
new ParseImageDetailsTest().expected());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testCreateWhenResponseIs4xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("POST")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("x-image-meta-name", "test").put("Accept", MediaType.APPLICATION_JSON).put("X-Auth-Token", authToken).build())
|
||||
.payload(payloadFromStringWithContentType("somedata", MediaType.APPLICATION_OCTET_STREAM))
|
||||
.build();
|
||||
|
||||
HttpResponse createResponse = HttpResponse.builder().statusCode(401)
|
||||
.payload(payloadFromResource("/image.json")).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, createResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").create("test", new StringPayload("somedata"));
|
||||
}
|
||||
|
||||
public void testReserveWhenResponseIs2xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("POST")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("x-image-meta-name", "test").put("Accept", MediaType.APPLICATION_JSON).put("X-Auth-Token", authToken).build())
|
||||
.build();
|
||||
|
||||
HttpResponse createResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResource("/image.json")).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, createResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
assertEquals(clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").reserve("test"), new ParseImageDetailsTest().expected());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testReserveWhenResponseIs4xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("POST")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("x-image-meta-name", "test").put("Accept", MediaType.APPLICATION_JSON).put("X-Auth-Token", authToken).build())
|
||||
.build();
|
||||
|
||||
HttpResponse createResponse = HttpResponse.builder().statusCode(401)
|
||||
.payload(payloadFromResource("/image.json")).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, createResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").reserve("test");
|
||||
}
|
||||
|
||||
public void testUpdateMetadataWhenResponseIs2xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("PUT")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("Accept", MediaType.APPLICATION_JSON)
|
||||
.put("X-Image-Meta-Name", "newname")
|
||||
.put("X-Image-Meta-Is_public", "true")
|
||||
.put("X-Image-Meta-Protected", "true")
|
||||
.put("X-Image-Meta-Checksum", "XXXX")
|
||||
.put("X-Image-Meta-Location", "somewhere")
|
||||
.put("X-Image-Meta-Min_disk", "10")
|
||||
.put("X-Image-Meta-Min_ram", "2048")
|
||||
.put("X-Auth-Token", authToken).build())
|
||||
.build();
|
||||
|
||||
HttpResponse updateResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResource("/image.json")).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, updateResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
assertEquals(clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1")
|
||||
.update("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
|
||||
UpdateImageOptions.Builder.name("newname"),
|
||||
UpdateImageOptions.Builder.isPublic(true),
|
||||
UpdateImageOptions.Builder.isProtected(true),
|
||||
UpdateImageOptions.Builder.checksum("XXXX"),
|
||||
UpdateImageOptions.Builder.location("somewhere"),
|
||||
UpdateImageOptions.Builder.minDisk(10),
|
||||
UpdateImageOptions.Builder.minRam(2048)),
|
||||
new ParseImageDetailsTest().expected());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
public void testUpdateMetadataWhenResponseIs4xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("PUT")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("Accept", MediaType.APPLICATION_JSON)
|
||||
.put("X-Image-Meta-Name", "newname")
|
||||
.put("X-Image-Meta-Is_public", "true")
|
||||
.put("X-Auth-Token", authToken).build())
|
||||
.build();
|
||||
|
||||
HttpResponse updateResponse = HttpResponse.builder().statusCode(404).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, updateResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1")
|
||||
.update("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
|
||||
UpdateImageOptions.Builder.name("newname"),
|
||||
UpdateImageOptions.Builder.isPublic(true));
|
||||
}
|
||||
|
||||
public void testUpdateImageWhenResponseIs2xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("PUT")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("Accept", MediaType.APPLICATION_JSON).put("X-Auth-Token", authToken).build())
|
||||
.payload(payloadFromStringWithContentType("somenewdata", MediaType.APPLICATION_OCTET_STREAM))
|
||||
.build();
|
||||
|
||||
HttpResponse updateResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResource("/image.json")).build();
|
||||
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, updateResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
assertEquals(clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
|
||||
new StringPayload("somenewdata")), new ParseImageDetailsTest().expected());
|
||||
}
|
||||
|
||||
public void testUpdateNameAndImageWhenResponseIs2xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("PUT")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("Accept", MediaType.APPLICATION_JSON)
|
||||
.put("X-Image-Meta-Name", "anothernewname")
|
||||
.put("X-Auth-Token", authToken).build())
|
||||
.payload(payloadFromStringWithContentType("somenewdata", MediaType.APPLICATION_OCTET_STREAM))
|
||||
.build();
|
||||
|
||||
HttpResponse updateResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResource("/image.json")).build();
|
||||
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, updateResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
assertEquals(clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
|
||||
new StringPayload("somenewdata"), UpdateImageOptions.Builder.name("anothernewname")), new ParseImageDetailsTest().expected());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void testUpdateNameAndImageWhenResponseIs4xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("PUT")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("Accept", MediaType.APPLICATION_JSON)
|
||||
.put("X-Image-Meta-Name", "anothernewname")
|
||||
.put("X-Auth-Token", authToken).build())
|
||||
.payload(payloadFromStringWithContentType("somenewdata", MediaType.APPLICATION_OCTET_STREAM))
|
||||
.build();
|
||||
|
||||
HttpResponse updateResponse = HttpResponse.builder().statusCode(403).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, updateResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
|
||||
new StringPayload("somenewdata"), UpdateImageOptions.Builder.name("anothernewname"));
|
||||
}
|
||||
|
||||
public void testDeleteWhenResponseIs2xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("DELETE")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("X-Auth-Token", authToken).build())
|
||||
.build();
|
||||
|
||||
HttpResponse getResponse = HttpResponse.builder().statusCode(200).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, getResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
assertTrue(clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").delete("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
|
||||
}
|
||||
|
||||
public void testDeleteWhenResponseIs4xx() throws Exception {
|
||||
HttpRequest get = HttpRequest
|
||||
.builder()
|
||||
.method("DELETE")
|
||||
.endpoint(URI.create("https://glance.jclouds.org:9292/v1.0/images/fcc451d0-f6e4-4824-ad8f-70ec12326d07"))
|
||||
.headers(
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put("X-Auth-Token", authToken).build())
|
||||
.build();
|
||||
|
||||
HttpResponse getResponse = HttpResponse.builder().statusCode(404).build();
|
||||
|
||||
GlanceClient clientWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
|
||||
responseWithKeystoneAccess, get, getResponse);
|
||||
|
||||
assertEquals(clientWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
|
||||
|
||||
assertFalse(clientWhenExist.getImageClientForRegion("az-1.region-a.geo-1").delete("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,29 @@
|
|||
*/
|
||||
package org.jclouds.openstack.glance.v1_0.features;
|
||||
|
||||
|
||||
import static org.jclouds.openstack.glance.v1_0.options.CreateImageOptions.Builder.containerFormat;
|
||||
import static org.jclouds.openstack.glance.v1_0.options.CreateImageOptions.Builder.diskFormat;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.io.payloads.StringPayload;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.Image;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
|
||||
import org.jclouds.openstack.glance.v1_0.internal.BaseGlanceClientLiveTest;
|
||||
import org.jclouds.openstack.glance.v1_0.options.ListImageOptions;
|
||||
import org.jclouds.openstack.glance.v1_0.options.UpdateImageOptions;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = "live", testName = "ImageClientLiveTest")
|
||||
public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
||||
|
@ -37,7 +49,7 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
|||
public void testList() throws Exception {
|
||||
for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
|
||||
ImageClient client = glanceContext.getApi().getImageClientForRegion(zoneId);
|
||||
Set<Image> response = client.list();
|
||||
Set<Image> response = client.list(ListImageOptions.Builder.limit(100));
|
||||
assert null != response;
|
||||
for (Image image : response) {
|
||||
checkImage(image);
|
||||
|
@ -47,10 +59,8 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
|||
|
||||
private void checkImage(Image image) {
|
||||
assert image.getId() != null : image;
|
||||
assert image.getSize().isPresent() : image;
|
||||
assert image.getChecksum().isPresent() : image;
|
||||
assert image.getContainerFormat().isPresent() : image;
|
||||
assert image.getContainerFormat().isPresent() : image;
|
||||
assert image.getName() != null : image;
|
||||
assert image.getLinks() != null : image;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -69,7 +79,9 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
|||
}
|
||||
|
||||
private void checkImageDetails(ImageDetails image) {
|
||||
//TODO
|
||||
checkImage(image);
|
||||
assertTrue(image.getMinDisk() >= 0);
|
||||
assertTrue(image.getMinRam() >= 0);
|
||||
}
|
||||
|
||||
private void checkImageDetailsEqual(ImageDetails image, ImageDetails newDetails) {
|
||||
|
@ -78,4 +90,54 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
|||
assertEquals(newDetails.getLinks(), image.getLinks());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUpdateAndDeleteImage() {
|
||||
StringPayload imageData = new StringPayload("This isn't really an image!");
|
||||
for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
|
||||
ImageClient client = glanceContext.getApi().getImageClientForRegion(zoneId);
|
||||
ImageDetails details = client.create("jclouds-live-test", imageData, diskFormat(DiskFormat.RAW), containerFormat(ContainerFormat.BARE));
|
||||
assertEquals(details.getName(), "jclouds-live-test");
|
||||
assertEquals(details.getSize().get().longValue(), imageData.getRawContent().length());
|
||||
|
||||
details = client.update(details.getId(), UpdateImageOptions.Builder.name("jclouds-live-test2"), UpdateImageOptions.Builder.minDisk(10));
|
||||
assertEquals(details.getName(), "jclouds-live-test2");
|
||||
assertEquals(details.getMinDisk(), 10);
|
||||
|
||||
Image fromListing = Iterables.getOnlyElement(client.list(ListImageOptions.Builder.name("jclouds-live-test2"), ListImageOptions.Builder.limit(2), ListImageOptions.Builder.containerFormat(ContainerFormat.BARE)));
|
||||
assertEquals(fromListing.getId(), details.getId());
|
||||
assertEquals(fromListing.getSize(), details.getSize());
|
||||
|
||||
assertEquals(Iterables.getOnlyElement(client.listInDetail(ListImageOptions.Builder.name("jclouds-live-test2"))), details);
|
||||
|
||||
assertTrue(client.delete(details.getId()));
|
||||
|
||||
assertTrue(client.list(ListImageOptions.Builder.name("jclouds-live-test2")).isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReserveUploadAndDeleteImage() {
|
||||
StringPayload imageData = new StringPayload("This isn't an image!");
|
||||
for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
|
||||
ImageClient client = glanceContext.getApi().getImageClientForRegion(zoneId);
|
||||
ImageDetails details = client.reserve("jclouds-live-res-test", diskFormat(DiskFormat.RAW), containerFormat(ContainerFormat.BARE));
|
||||
assertEquals(details.getName(), "jclouds-live-res-test");
|
||||
|
||||
details = client.upload(details.getId(), imageData, UpdateImageOptions.Builder.name("jclouds-live-res-test2"), UpdateImageOptions.Builder.minDisk(10));
|
||||
assertEquals(details.getName(), "jclouds-live-res-test2");
|
||||
assertEquals(details.getSize().get().longValue(), imageData.getRawContent().length());
|
||||
assertEquals(details.getMinDisk(), 10);
|
||||
|
||||
Image fromListing = Iterables.getOnlyElement(client.list(ListImageOptions.Builder.name("jclouds-live-res-test2"), ListImageOptions.Builder.limit(2), ListImageOptions.Builder.containerFormat(ContainerFormat.BARE)));
|
||||
assertEquals(fromListing.getId(), details.getId());
|
||||
assertEquals(fromListing.getSize(), details.getSize());
|
||||
|
||||
assertEquals(Iterables.getOnlyElement(client.listInDetail(ListImageOptions.Builder.name("jclouds-live-res-test2"))), details);
|
||||
|
||||
assertTrue(client.delete(details.getId()));
|
||||
|
||||
assertTrue(client.list(ListImageOptions.Builder.name("jclouds-live-res-test2")).isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* 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.openstack.glance.v1_0.parse;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||
import org.jclouds.json.BaseItemParserTest;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.Image;
|
||||
import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ParseImageDetailTest")
|
||||
public class ParseImageDetailsTest extends BaseItemParserTest<ImageDetails> {
|
||||
|
||||
@Override
|
||||
public String resource() {
|
||||
return "/image.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
@SelectJson("image")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public ImageDetails expected() {
|
||||
return ImageDetails
|
||||
.builder()
|
||||
.id("02fa0378-f305-43cf-8058-8572fe1da795")
|
||||
.name("jclouds-live-test")
|
||||
.containerFormat(ContainerFormat.BARE)
|
||||
.diskFormat(DiskFormat.RAW)
|
||||
.checksum("6ae4e0fdc3c108a1bfe10ef5e436f4f4")
|
||||
.size(27)
|
||||
.status(Image.Status.ACTIVE)
|
||||
.owner("68a7c7abb7bf45ada1536dfa28ec2115")
|
||||
.isPublic(false)
|
||||
.createdAt(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-05-31T10:13:47"))
|
||||
.updatedAt(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-05-31T10:13:47"))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"image": {"status": "active", "name": "jclouds-live-test", "deleted": false, "container_format": "bare", "created_at": "2012-05-31T10:13:47", "disk_format": "raw", "updated_at": "2012-05-31T10:13:47", "properties": {}, "min_disk": 0, "protected": false, "id": "02fa0378-f305-43cf-8058-8572fe1da795", "checksum": "6ae4e0fdc3c108a1bfe10ef5e436f4f4", "owner": "68a7c7abb7bf45ada1536dfa28ec2115", "is_public": false, "deleted_at": null, "min_ram": 0, "size": 27}}
|
Loading…
Reference in New Issue