mirror of https://github.com/apache/jclouds.git
openstack-glance: Adding create, reserve, update, upload and delete methods to ImageClient
This commit is contained in:
parent
76531d62e0
commit
03267c6e33
|
@ -48,6 +48,10 @@ public class BaseListOptions extends BaseHttpRequestOptions {
|
||||||
* Indicates where to begin listing. The list will only include objects that occur after the
|
* Indicates where to begin listing. The list will only include objects that occur after the
|
||||||
* offset. This is convenient for pagination: To get the next page of results use the last result
|
* offset. This is convenient for pagination: To get the next page of results use the last result
|
||||||
* number of the current page + current page offset as the offset.
|
* number of the current page + current page offset as the offset.
|
||||||
|
* <p/>
|
||||||
|
* This isn't supported by newer openstack API implementations
|
||||||
|
*
|
||||||
|
* @see #marker(String) for the new mechanism to set the page offset
|
||||||
*/
|
*/
|
||||||
public BaseListOptions startAt(long offset) {
|
public BaseListOptions startAt(long offset) {
|
||||||
checkState(offset >= 0, "offset must be >= 0");
|
checkState(offset >= 0, "offset must be >= 0");
|
||||||
|
@ -55,6 +59,19 @@ public class BaseListOptions extends BaseHttpRequestOptions {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The marker parameter is the ID of the last item in the previous list
|
||||||
|
* (i.e. return the page of items after the marker).
|
||||||
|
* <p/>
|
||||||
|
* This is only supported by newer openstack API implementations
|
||||||
|
*
|
||||||
|
* @see #startAt for the old mechanism to set the page offset
|
||||||
|
*/
|
||||||
|
public BaseListOptions marker(String marker) {
|
||||||
|
queryParameters.put("marker", checkNotNull(marker, "marker"));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To reduce load on the service, list operations will return a maximum of 1,000 items at a time.
|
* To reduce load on the service, list operations will return a maximum of 1,000 items at a time.
|
||||||
* To navigate the collection, the parameters limit and offset can be set in the URI
|
* To navigate the collection, the parameters limit and offset can be set in the URI
|
||||||
|
@ -81,7 +98,15 @@ public class BaseListOptions extends BaseHttpRequestOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see BaseListOptions#maxResults(long)
|
* @see BaseListOptions#marker
|
||||||
|
*/
|
||||||
|
public static BaseListOptions marker(String marker) {
|
||||||
|
BaseListOptions options = new BaseListOptions();
|
||||||
|
return options.marker(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see BaseListOptions#maxResults
|
||||||
*/
|
*/
|
||||||
public static BaseListOptions maxResults(int maxKeys) {
|
public static BaseListOptions maxResults(int maxKeys) {
|
||||||
BaseListOptions options = new BaseListOptions();
|
BaseListOptions options = new BaseListOptions();
|
||||||
|
|
|
@ -246,6 +246,10 @@ public class ImageDetails extends Image {
|
||||||
return this.location;
|
return this.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<String> getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
public Date getUpdatedAt() {
|
public Date getUpdatedAt() {
|
||||||
return this.updatedAt;
|
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.io.InputStream;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.HEAD;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
import org.jclouds.openstack.filters.AuthenticateRequest;
|
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||||
import org.jclouds.openstack.glance.v1_0.domain.Image;
|
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.ImageDetails;
|
||||||
import org.jclouds.openstack.glance.v1_0.functions.ParseImageDetailsFromHeaders;
|
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.ExceptionParser;
|
||||||
import org.jclouds.rest.annotations.RequestFilters;
|
import org.jclouds.rest.annotations.RequestFilters;
|
||||||
import org.jclouds.rest.annotations.ResponseParser;
|
import org.jclouds.rest.annotations.ResponseParser;
|
||||||
import org.jclouds.rest.annotations.SelectJson;
|
import org.jclouds.rest.annotations.SelectJson;
|
||||||
import org.jclouds.rest.annotations.SkipEncoding;
|
import org.jclouds.rest.annotations.SkipEncoding;
|
||||||
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
|
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
|
||||||
|
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
@ -47,6 +48,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||||
*
|
*
|
||||||
* @see ImageClient
|
* @see ImageClient
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
* @author Adam Lowe
|
||||||
* @see <a href="http://glance.openstack.org/glanceapi.html">api doc</a>
|
* @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>
|
* @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)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@Path("/images")
|
@Path("/images")
|
||||||
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||||
ListenableFuture<Set<Image>> list();
|
ListenableFuture<Set<Image>> list(ListImageOptions... options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ImageClient#listInDetail
|
* @see ImageClient#listInDetail
|
||||||
|
@ -72,7 +74,7 @@ public interface ImageAsyncClient {
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@Path("/images/detail")
|
@Path("/images/detail")
|
||||||
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||||
ListenableFuture<Set<ImageDetails>> listInDetail();
|
ListenableFuture<Set<ImageDetails>> listInDetail(ListImageOptions... options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ImageClient#show
|
* @see ImageClient#show
|
||||||
|
@ -91,9 +93,49 @@ public interface ImageAsyncClient {
|
||||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||||
ListenableFuture<InputStream> getAsStream(@PathParam("id") String id);
|
ListenableFuture<InputStream> getAsStream(@PathParam("id") String id);
|
||||||
|
|
||||||
// POST /images -- Store image data and return metadata about the
|
/**
|
||||||
// newly-stored image
|
* @see ImageClient#create
|
||||||
// PUT /images/<ID> -- Update image metadata and/or upload image
|
*/
|
||||||
// data for a previously-reserved image
|
@POST
|
||||||
// DELETE /images/<ID> -- Delete the image with id <ID>
|
@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 java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.jclouds.concurrent.Timeout;
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
import org.jclouds.javax.annotation.Nullable;
|
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.Image;
|
||||||
import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
|
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
|
* Image Services
|
||||||
*
|
*
|
||||||
* @see ImageAsyncClient
|
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
* @author Adam Lowe
|
||||||
|
* @see ImageAsyncClient
|
||||||
* @see <a href="http://glance.openstack.org/glanceapi.html">api doc</a>
|
* @see <a href="http://glance.openstack.org/glanceapi.html">api doc</a>
|
||||||
*/
|
*/
|
||||||
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||||
|
@ -39,12 +45,12 @@ public interface ImageClient {
|
||||||
/**
|
/**
|
||||||
* Returns a set of brief metadata about images
|
* Returns a set of brief metadata about images
|
||||||
*/
|
*/
|
||||||
Set<Image> list();
|
Set<Image> list(ListImageOptions... options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set of detailed metadata about images
|
* Returns a set of detailed metadata about images
|
||||||
*/
|
*/
|
||||||
Set<ImageDetails> listInDetail();
|
Set<ImageDetails> listInDetail(ListImageOptions... options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return metadata about an image with id
|
* Return metadata about an image with id
|
||||||
|
@ -58,9 +64,46 @@ public interface ImageClient {
|
||||||
@Nullable
|
@Nullable
|
||||||
InputStream getAsStream(String id);
|
InputStream getAsStream(String id);
|
||||||
|
|
||||||
// POST /images -- Store image data and return metadata about the
|
/**
|
||||||
// newly-stored image
|
* Create a new image
|
||||||
// PUT /images/<ID> -- Update image metadata and/or upload image
|
*
|
||||||
// data for a previously-reserved image
|
* @return detailed metadata about the newly stored image
|
||||||
// DELETE /images/<ID> -- Delete the image with id <ID>
|
*/
|
||||||
|
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;
|
package org.jclouds.openstack.glance.v1_0.functions;
|
||||||
|
|
||||||
|
import static org.jclouds.openstack.glance.v1_0.options.ImageField.*;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.jclouds.date.DateService;
|
import org.jclouds.date.DateService;
|
||||||
import org.jclouds.http.HttpResponse;
|
import org.jclouds.http.HttpResponse;
|
||||||
import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
|
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.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.ImageDetails;
|
||||||
|
import org.jclouds.openstack.glance.v1_0.domain.Image.Status;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This parses {@link ImageDetails} from HTTP headers.
|
* This parses {@link ImageDetails} from HTTP headers.
|
||||||
|
@ -44,23 +47,27 @@ public class ParseImageDetailsFromHeaders implements Function<HttpResponse, Imag
|
||||||
|
|
||||||
public ImageDetails apply(HttpResponse from) {
|
public ImageDetails apply(HttpResponse from) {
|
||||||
ImageDetails.Builder<?> builder = ImageDetails.builder()
|
ImageDetails.Builder<?> builder = ImageDetails.builder()
|
||||||
.id(from.getFirstHeaderOrNull("X-Image-Meta-Id"))
|
.id(from.getFirstHeaderOrNull(ID.asHeader()))
|
||||||
.name(from.getFirstHeaderOrNull("X-Image-Meta-Name"))
|
.name(from.getFirstHeaderOrNull(NAME.asHeader()))
|
||||||
.checksum(from.getFirstHeaderOrNull("X-Image-Meta-Checksum"))
|
.checksum(Optional.fromNullable(from.getFirstHeaderOrNull(CHECKSUM.asHeader())))
|
||||||
.containerFormat(ContainerFormat.fromValue(from.getFirstHeaderOrNull("X-Image-Meta-Container_format")))
|
.minDisk(Long.parseLong(from.getFirstHeaderOrNull(MIN_DISK.asHeader())))
|
||||||
.diskFormat(DiskFormat.fromValue(from.getFirstHeaderOrNull("X-Image-Meta-Disk_format")))
|
.minRam(Long.parseLong(from.getFirstHeaderOrNull(MIN_RAM.asHeader())))
|
||||||
.size(Long.parseLong(from.getFirstHeaderOrNull("X-Image-Meta-Size")))
|
.isPublic(Boolean.parseBoolean(from.getFirstHeaderOrNull(IS_PUBLIC.asHeader())))
|
||||||
.minDisk(Long.parseLong(from.getFirstHeaderOrNull("X-Image-Meta-Min_disk")))
|
.createdAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull(CREATED_AT.asHeader())))
|
||||||
.minRam(Long.parseLong(from.getFirstHeaderOrNull("X-Image-Meta-Min_ram")))
|
.updatedAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull(UPDATED_AT.asHeader())))
|
||||||
.isPublic(Boolean.parseBoolean(from.getFirstHeaderOrNull("X-Image-Meta-Is_public")))
|
.owner(Optional.fromNullable(from.getFirstHeaderOrNull(OWNER.asHeader())))
|
||||||
.createdAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull("X-Image-Meta-Created_at")))
|
.location(Optional.fromNullable(from.getFirstHeaderOrNull(LOCATION.asHeader())))
|
||||||
.updatedAt(dateService.iso8601SecondsDateParse(from.getFirstHeaderOrNull("X-Image-Meta-Updated_at")))
|
.status(Status.fromValue(from.getFirstHeaderOrNull(STATUS.asHeader())));
|
||||||
.owner(from.getFirstHeaderOrNull("X-Image-Meta-Owner"))
|
|
||||||
.status(Image.Status.fromValue(from.getFirstHeaderOrNull("X-Image-Meta-Status")));
|
|
||||||
|
|
||||||
String deletedAt = from.getFirstHeaderOrNull("X-Image-Meta-Deleted_at");
|
String containerFormat = from.getFirstHeaderOrNull(CONTAINER_FORMAT.asHeader());
|
||||||
if (deletedAt != null)
|
String diskFormat = from.getFirstHeaderOrNull(DISK_FORMAT.asHeader());
|
||||||
builder.deletedAt(dateService.iso8601SecondsDateParse(deletedAt));
|
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();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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,240 @@
|
||||||
|
/**
|
||||||
|
* 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 java.util.Date;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jclouds.openstack.options.BaseListOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Lowe
|
||||||
|
* @see <a href="http://glance.openstack.org/glanceapi.html"/>
|
||||||
|
*/
|
||||||
|
public class ListImageOptions extends BaseListOptions {
|
||||||
|
/**
|
||||||
|
* 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 BaseListOptions#maxResults
|
||||||
|
*/
|
||||||
|
public static ListImageOptions maxResults(int limit) {
|
||||||
|
return ListImageOptions.class.cast(new ListImageOptions().maxResults(limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see BaseListOptions#marker
|
||||||
|
*/
|
||||||
|
public static ListImageOptions marker(String marker) {
|
||||||
|
return ListImageOptions.class.cast(new ListImageOptions().marker(marker));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see BaseListOptions#changesSince
|
||||||
|
*/
|
||||||
|
public static ListImageOptions changesSince(Date ifModifiedSince) {
|
||||||
|
return ListImageOptions.class.cast(new BaseListOptions().changesSince(ifModifiedSince));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
package org.jclouds.openstack.glance.v1_0.features;
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
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.assertNull;
|
||||||
import static org.testng.Assert.assertTrue;
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.http.HttpResponse;
|
import org.jclouds.http.HttpResponse;
|
||||||
import org.jclouds.io.Payloads;
|
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.GlanceClient;
|
||||||
import org.jclouds.openstack.glance.v1_0.functions.ParseImageDetailsFromHeadersTest;
|
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.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.ParseImagesInDetailTest;
|
||||||
import org.jclouds.openstack.glance.v1_0.parse.ParseImagesTest;
|
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.jclouds.util.Strings2;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
@ -40,6 +49,7 @@ import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
* @author Adam Lowe
|
||||||
*/
|
*/
|
||||||
@Test(groups = "unit", testName = "ImageClientExpectTest")
|
@Test(groups = "unit", testName = "ImageClientExpectTest")
|
||||||
public class ImageClientExpectTest extends BaseGlanceClientExpectTest {
|
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"));
|
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,34 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.openstack.glance.v1_0.features;
|
package org.jclouds.openstack.glance.v1_0.features;
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
|
|
||||||
|
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 static org.testng.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
|
import org.jclouds.io.payloads.FilePayload;
|
||||||
|
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.Image;
|
||||||
import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
|
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.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 org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
* @author Adam Lowe
|
||||||
*/
|
*/
|
||||||
@Test(groups = "live", testName = "ImageClientLiveTest")
|
@Test(groups = "live", testName = "ImageClientLiveTest")
|
||||||
public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
||||||
|
@ -37,7 +54,7 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
||||||
public void testList() throws Exception {
|
public void testList() throws Exception {
|
||||||
for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
|
for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
|
||||||
ImageClient client = glanceContext.getApi().getImageClientForRegion(zoneId);
|
ImageClient client = glanceContext.getApi().getImageClientForRegion(zoneId);
|
||||||
Set<Image> response = client.list();
|
Set<Image> response = client.list(ListImageOptions.Builder.maxResults(100));
|
||||||
assert null != response;
|
assert null != response;
|
||||||
for (Image image : response) {
|
for (Image image : response) {
|
||||||
checkImage(image);
|
checkImage(image);
|
||||||
|
@ -49,8 +66,6 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
||||||
assert image.getId() != null : image;
|
assert image.getId() != null : image;
|
||||||
assert image.getSize().isPresent() : image;
|
assert image.getSize().isPresent() : image;
|
||||||
assert image.getChecksum().isPresent() : image;
|
assert image.getChecksum().isPresent() : image;
|
||||||
assert image.getContainerFormat().isPresent() : image;
|
|
||||||
assert image.getContainerFormat().isPresent() : image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -69,6 +84,7 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkImageDetails(ImageDetails image) {
|
private void checkImageDetails(ImageDetails image) {
|
||||||
|
checkImage(image);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,4 +94,54 @@ public class ImageClientLiveTest extends BaseGlanceClientLiveTest {
|
||||||
assertEquals(newDetails.getLinks(), image.getLinks());
|
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.maxResults(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.maxResults(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