mirror of https://github.com/apache/jclouds.git
Merge pull request #965 from rackspace/openstack-nova-volume-attachment-api
OpenStack Nova Volume Attachment API
This commit is contained in:
commit
d557b581e3
|
@ -25,19 +25,20 @@ import org.jclouds.concurrent.Timeout;
|
||||||
import org.jclouds.javax.annotation.Nullable;
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
import org.jclouds.location.Zone;
|
import org.jclouds.location.Zone;
|
||||||
import org.jclouds.location.functions.ZoneToEndpoint;
|
import org.jclouds.location.functions.ZoneToEndpoint;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminApi;
|
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.HostAggregateApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.HostAggregateApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassApi;
|
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.QuotaApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.QuotaApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAttachmentApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
|
import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.features.ImageApi;
|
import org.jclouds.openstack.nova.v2_0.features.ImageApi;
|
||||||
|
@ -131,13 +132,6 @@ public interface NovaApi {
|
||||||
Optional<? extends SimpleTenantUsageApi> getSimpleTenantUsageExtensionForZone(
|
Optional<? extends SimpleTenantUsageApi> getSimpleTenantUsageExtensionForZone(
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides synchronous access to Volume features.
|
|
||||||
*/
|
|
||||||
@Delegate
|
|
||||||
Optional<? extends VolumeApi> getVolumeExtensionForZone(
|
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides synchronous access to Virtual Interface features.
|
* Provides synchronous access to Virtual Interface features.
|
||||||
*/
|
*/
|
||||||
|
@ -187,6 +181,20 @@ public interface NovaApi {
|
||||||
Optional<? extends QuotaClassApi> getQuotaClassExtensionForZone(
|
Optional<? extends QuotaClassApi> getQuotaClassExtensionForZone(
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Volume features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
Optional<? extends VolumeApi> getVolumeExtensionForZone(
|
||||||
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Volume Attachment features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
Optional<? extends VolumeAttachmentApi> getVolumeAttachmentExtensionForZone(
|
||||||
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides synchronous access to Volume Type features.
|
* Provides synchronous access to Volume Type features.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,7 +23,6 @@ import java.util.Set;
|
||||||
import org.jclouds.javax.annotation.Nullable;
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
import org.jclouds.location.Zone;
|
import org.jclouds.location.Zone;
|
||||||
import org.jclouds.location.functions.ZoneToEndpoint;
|
import org.jclouds.location.functions.ZoneToEndpoint;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminAsyncApi;
|
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationAsyncApi;
|
||||||
|
@ -32,10 +31,12 @@ import org.jclouds.openstack.nova.v2_0.extensions.KeyPairAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.QuotaAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.QuotaAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupAsyncApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAttachmentAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.features.FlavorAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.features.FlavorAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.features.ImageAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.features.ImageAsyncApi;
|
||||||
|
@ -129,13 +130,6 @@ public interface NovaAsyncApi {
|
||||||
Optional<? extends SimpleTenantUsageAsyncApi> getSimpleTenantUsageExtensionForZone(
|
Optional<? extends SimpleTenantUsageAsyncApi> getSimpleTenantUsageExtensionForZone(
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides asynchronous access to Volume features.
|
|
||||||
*/
|
|
||||||
@Delegate
|
|
||||||
Optional<? extends VolumeAsyncApi> getVolumeExtensionForZone(
|
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides asynchronous access to Virtual Interface features.
|
* Provides asynchronous access to Virtual Interface features.
|
||||||
*/
|
*/
|
||||||
|
@ -186,6 +180,20 @@ public interface NovaAsyncApi {
|
||||||
Optional<? extends QuotaClassAsyncApi> getQuotaClassExtensionForZone(
|
Optional<? extends QuotaClassAsyncApi> getQuotaClassExtensionForZone(
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous access to Volume features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
Optional<? extends VolumeAsyncApi> getVolumeExtensionForZone(
|
||||||
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous access to Volume features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
Optional<? extends VolumeAttachmentAsyncApi> getVolumeAttachmentExtensionForZone(
|
||||||
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides asynchronous access to Volume Type features.
|
* Provides asynchronous access to Volume Type features.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -32,8 +32,6 @@ import org.jclouds.http.annotation.Redirection;
|
||||||
import org.jclouds.http.annotation.ServerError;
|
import org.jclouds.http.annotation.ServerError;
|
||||||
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
import org.jclouds.openstack.nova.v2_0.NovaApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.NovaAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.NovaAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminApi;
|
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminAsyncApi;
|
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
|
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
|
||||||
|
@ -51,6 +49,8 @@ import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupAsyncApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageApi;
|
||||||
|
@ -59,6 +59,8 @@ import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAttachmentApi;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAttachmentAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi;
|
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi;
|
||||||
import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
|
import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
|
||||||
|
@ -103,7 +105,6 @@ public class NovaRestClientModule<S extends NovaApi, A extends NovaAsyncApi> ext
|
||||||
.put(KeyPairApi.class, KeyPairAsyncApi.class)
|
.put(KeyPairApi.class, KeyPairAsyncApi.class)
|
||||||
.put(HostAdministrationApi.class, HostAdministrationAsyncApi.class)
|
.put(HostAdministrationApi.class, HostAdministrationAsyncApi.class)
|
||||||
.put(SimpleTenantUsageApi.class, SimpleTenantUsageAsyncApi.class)
|
.put(SimpleTenantUsageApi.class, SimpleTenantUsageAsyncApi.class)
|
||||||
.put(VolumeApi.class, VolumeAsyncApi.class)
|
|
||||||
.put(VirtualInterfaceApi.class, VirtualInterfaceAsyncApi.class)
|
.put(VirtualInterfaceApi.class, VirtualInterfaceAsyncApi.class)
|
||||||
.put(ServerWithSecurityGroupsApi.class, ServerWithSecurityGroupsAsyncApi.class)
|
.put(ServerWithSecurityGroupsApi.class, ServerWithSecurityGroupsAsyncApi.class)
|
||||||
.put(ServerAdminApi.class, ServerAdminAsyncApi.class)
|
.put(ServerAdminApi.class, ServerAdminAsyncApi.class)
|
||||||
|
@ -111,6 +112,8 @@ public class NovaRestClientModule<S extends NovaApi, A extends NovaAsyncApi> ext
|
||||||
.put(FlavorExtraSpecsApi.class, FlavorExtraSpecsAsyncApi.class)
|
.put(FlavorExtraSpecsApi.class, FlavorExtraSpecsAsyncApi.class)
|
||||||
.put(QuotaApi.class, QuotaAsyncApi.class)
|
.put(QuotaApi.class, QuotaAsyncApi.class)
|
||||||
.put(QuotaClassApi.class, QuotaClassAsyncApi.class)
|
.put(QuotaClassApi.class, QuotaClassAsyncApi.class)
|
||||||
|
.put(VolumeApi.class, VolumeAsyncApi.class)
|
||||||
|
.put(VolumeAttachmentApi.class, VolumeAttachmentAsyncApi.class)
|
||||||
.put(VolumeTypeApi.class, VolumeTypeAsyncApi.class)
|
.put(VolumeTypeApi.class, VolumeTypeAsyncApi.class)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -83,29 +83,37 @@ public interface VolumeApi {
|
||||||
* List volume attachments for a given instance.
|
* List volume attachments for a given instance.
|
||||||
*
|
*
|
||||||
* @return all Floating IPs
|
* @return all Floating IPs
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#listAttachmentsOnServer(String)
|
||||||
*/
|
*/
|
||||||
FluentIterable<? extends VolumeAttachment> listAttachmentsOnServer(String serverId);
|
@Deprecated FluentIterable<? extends VolumeAttachment> listAttachmentsOnServer(String serverId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a specific attached volume.
|
* Get a specific attached volume.
|
||||||
*
|
*
|
||||||
* @return data about the given volume attachment.
|
* @return data about the given volume attachment.
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#getAttachmentForVolumeOnServer(String, String)
|
||||||
*/
|
*/
|
||||||
VolumeAttachment getAttachmentForVolumeOnServer(String volumeId, String serverId);
|
@Deprecated VolumeAttachment getAttachmentForVolumeOnServer(String volumeId, String serverId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach a volume to an instance
|
* Attach a volume to an instance
|
||||||
*
|
*
|
||||||
* @return data about the new volume attachment
|
* @return data about the new volume attachment
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#attachVolumeToServerAsDevice(String, String, String)
|
||||||
*/
|
*/
|
||||||
VolumeAttachment attachVolumeToServerAsDevice(String volumeId, String serverId, String device);
|
@Deprecated VolumeAttachment attachVolumeToServerAsDevice(String volumeId, String serverId, String device);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detach a Volume from an instance.
|
* Detach a Volume from an instance.
|
||||||
*
|
*
|
||||||
* @return true if successful
|
* @return true if successful
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#detachVolumeFromServer(String, String)
|
||||||
*/
|
*/
|
||||||
Boolean detachVolumeFromServer(String server_id, String volumeId);
|
@Deprecated Boolean detachVolumeFromServer(String server_id, String volumeId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a summary list of snapshots.
|
* Returns a summary list of snapshots.
|
||||||
|
|
|
@ -126,31 +126,37 @@ public interface VolumeAsyncApi {
|
||||||
* List volume attachments for a given instance.
|
* List volume attachments for a given instance.
|
||||||
*
|
*
|
||||||
* @return all Floating IPs
|
* @return all Floating IPs
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#listAttachmentsOnServer(String)
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/servers/{server_id}/os-volume_attachments")
|
@Path("/servers/{server_id}/os-volume_attachments")
|
||||||
@SelectJson("volumeAttachments")
|
@SelectJson("volumeAttachments")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
||||||
ListenableFuture<? extends FluentIterable<? extends VolumeAttachment>> listAttachmentsOnServer(@PathParam("server_id") String serverId);
|
@Deprecated ListenableFuture<? extends FluentIterable<? extends VolumeAttachment>> listAttachmentsOnServer(@PathParam("server_id") String serverId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a specific attached volume.
|
* Get a specific attached volume.
|
||||||
*
|
*
|
||||||
* @return data about the given volume attachment.
|
* @return data about the given volume attachment.
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#getAttachmentForVolumeOnServer(String, String)
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
||||||
@SelectJson("volumeAttachment")
|
@SelectJson("volumeAttachment")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||||
ListenableFuture<? extends VolumeAttachment> getAttachmentForVolumeOnServer(@PathParam("id") String volumeId,
|
@Deprecated ListenableFuture<? extends VolumeAttachment> getAttachmentForVolumeOnServer(@PathParam("id") String volumeId,
|
||||||
@PathParam("server_id") String serverId);
|
@PathParam("server_id") String serverId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach a volume to an instance
|
* Attach a volume to an instance
|
||||||
*
|
*
|
||||||
* @return the new Attachment
|
* @return the new Attachment
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#attachVolumeToServerAsDevice(String, String, String)
|
||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
@Path("/servers/{server_id}/os-volume_attachments")
|
@Path("/servers/{server_id}/os-volume_attachments")
|
||||||
|
@ -158,19 +164,21 @@ public interface VolumeAsyncApi {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@WrapWith("volumeAttachment")
|
@WrapWith("volumeAttachment")
|
||||||
ListenableFuture<? extends VolumeAttachment> attachVolumeToServerAsDevice(@PayloadParam("volumeId") String volumeId,
|
@Deprecated ListenableFuture<? extends VolumeAttachment> attachVolumeToServerAsDevice(@PayloadParam("volumeId") String volumeId,
|
||||||
@PathParam("server_id") String serverId, @PayloadParam("device") String device);
|
@PathParam("server_id") String serverId, @PayloadParam("device") String device);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detach a Volume from an instance.
|
* Detach a Volume from an instance.
|
||||||
*
|
*
|
||||||
* @return true if successful
|
* @return true if successful
|
||||||
|
* @deprecated To be removed in jclouds 1.7
|
||||||
|
* @see VolumeAttachmentApi#detachVolumeFromServer(String, String)
|
||||||
*/
|
*/
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||||
ListenableFuture<Boolean> detachVolumeFromServer(@PathParam("id") String volumeId, @PathParam("server_id") String serverId);
|
@Deprecated ListenableFuture<Boolean> detachVolumeFromServer(@PathParam("id") String volumeId, @PathParam("server_id") String serverId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a summary list of snapshots.
|
* Returns a summary list of snapshots.
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* 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.nova.v2_0.extensions;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.v2_0.ServiceType;
|
||||||
|
import org.jclouds.openstack.v2_0.services.Extension;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import com.google.common.collect.FluentIterable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Volume Attachments.
|
||||||
|
*
|
||||||
|
* This API strictly handles attaching Volumes to Servers. To create and manage Volumes you need to use one of the
|
||||||
|
* following APIs:
|
||||||
|
*
|
||||||
|
* 1. The Cinder API
|
||||||
|
* If your OpenStack deployment is Folsom or later and it supports the Cinder block storage service, use this API.
|
||||||
|
* @see org.jclouds.openstack.cinder.v1.features.VolumeApi
|
||||||
|
*
|
||||||
|
* 2. The nova-volume API
|
||||||
|
* If your OpenStack deployment is Essex or earlier and it supports the nova-volume extension, use this API.
|
||||||
|
* @see org.jclouds.openstack.nova.v2_0.extensions.VolumeApi
|
||||||
|
*
|
||||||
|
* @see VolumeAttachmentAsyncApi
|
||||||
|
* @author Everett Toews
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUMES)
|
||||||
|
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||||
|
public interface VolumeAttachmentApi {
|
||||||
|
/**
|
||||||
|
* List Volume Attachments for a given Server.
|
||||||
|
*
|
||||||
|
* @param serverId The ID of the Server
|
||||||
|
* @return All VolumeAttachments for the Server
|
||||||
|
*/
|
||||||
|
FluentIterable<? extends VolumeAttachment> listAttachmentsOnServer(String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific Volume Attachment for a Volume and Server.
|
||||||
|
*
|
||||||
|
* @param volumeId The ID of the Volume
|
||||||
|
* @param serverId The ID of the Server
|
||||||
|
* @return The Volume Attachment.
|
||||||
|
*/
|
||||||
|
VolumeAttachment getAttachmentForVolumeOnServer(String volumeId, String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a Volume to a Server.
|
||||||
|
*
|
||||||
|
* Note: If you are using KVM as your hypervisor then the actual device name in the Server will be different than
|
||||||
|
* the one specified. When the Server sees a new device, it picks the next available name (which in most cases is
|
||||||
|
* /dev/vdc) and the disk shows up there on the Server.
|
||||||
|
*
|
||||||
|
* @param serverId The ID of the Server
|
||||||
|
* @param volumeId The ID of the Volume
|
||||||
|
* @param device The name of the device this Volume will be identified as in the Server (e.g. /dev/vdc)
|
||||||
|
* @return The Volume Attachment.
|
||||||
|
*/
|
||||||
|
VolumeAttachment attachVolumeToServerAsDevice(String volumeId, String serverId, String device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach a Volume from a server.
|
||||||
|
*
|
||||||
|
* @param serverId The ID of the Server
|
||||||
|
* @param volumeId The ID of the Volume
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
boolean detachVolumeFromServer(String serverId, String volumeId);
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* 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.nova.v2_0.extensions;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.v2_0.ServiceType;
|
||||||
|
import org.jclouds.openstack.v2_0.services.Extension;
|
||||||
|
import org.jclouds.rest.annotations.ExceptionParser;
|
||||||
|
import org.jclouds.rest.annotations.PayloadParam;
|
||||||
|
import org.jclouds.rest.annotations.RequestFilters;
|
||||||
|
import org.jclouds.rest.annotations.SelectJson;
|
||||||
|
import org.jclouds.rest.annotations.SkipEncoding;
|
||||||
|
import org.jclouds.rest.annotations.WrapWith;
|
||||||
|
import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
|
||||||
|
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||||
|
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import com.google.common.collect.FluentIterable;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous access to Volume Attachments .
|
||||||
|
*
|
||||||
|
* @see VolumeAttachmentApi
|
||||||
|
* @author Everett Toews
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUMES)
|
||||||
|
@SkipEncoding({'/', '='})
|
||||||
|
@RequestFilters(AuthenticateRequest.class)
|
||||||
|
public interface VolumeAttachmentAsyncApi {
|
||||||
|
/**
|
||||||
|
* @see VolumeAttachmentApi#listAttachmentsOnServer(String)
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments")
|
||||||
|
@SelectJson("volumeAttachments")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<? extends FluentIterable<? extends VolumeAttachment>> listAttachmentsOnServer(
|
||||||
|
@PathParam("server_id") String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see VolumeAttachmentApi#getAttachmentForVolumeOnServer(String, String)
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
||||||
|
@SelectJson("volumeAttachment")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<? extends VolumeAttachment> getAttachmentForVolumeOnServer(
|
||||||
|
@PathParam("id") String volumeId,
|
||||||
|
@PathParam("server_id") String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see VolumeAttachmentApi#attachVolumeToServerAsDevice(String, String, String)
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments")
|
||||||
|
@SelectJson("volumeAttachment")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@WrapWith("volumeAttachment")
|
||||||
|
ListenableFuture<? extends VolumeAttachment> attachVolumeToServerAsDevice(
|
||||||
|
@PayloadParam("volumeId") String volumeId,
|
||||||
|
@PathParam("server_id") String serverId,
|
||||||
|
@PayloadParam("device") String device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see VolumeAttachmentApi#detachVolumeFromServer(String, String)
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Boolean> detachVolumeFromServer(
|
||||||
|
@PathParam("id") String volumeId,
|
||||||
|
@PathParam("server_id") String serverId);
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
/**
|
||||||
|
* 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.nova.v2_0.extensions;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertFalse;
|
||||||
|
import static org.testng.Assert.assertNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.date.DateService;
|
||||||
|
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.domain.Volume;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
|
||||||
|
import org.jclouds.rest.AuthorizationException;
|
||||||
|
import org.jclouds.rest.ResourceNotFoundException;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests VolumeAttachmentApi Guice wiring and parsing
|
||||||
|
*
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "VolumeAttachmentApiExpectTest")
|
||||||
|
public class VolumeAttachmentApiExpectTest extends BaseNovaApiExpectTest {
|
||||||
|
private DateService dateService = new SimpleDateFormatDateService();
|
||||||
|
|
||||||
|
public void testListAttachments() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-1/os-volume_attachments");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).build(),
|
||||||
|
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/attachment_list.json")).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<? extends VolumeAttachment> attachments = api.listAttachmentsOnServer("instance-1").toImmutableSet();
|
||||||
|
assertEquals(attachments, ImmutableSet.of(testAttachment()));
|
||||||
|
// double-check individual fields
|
||||||
|
VolumeAttachment attachment = Iterables.getOnlyElement(attachments);
|
||||||
|
assertEquals(attachment.getDevice(), "/dev/vdc");
|
||||||
|
assertEquals(attachment.getServerId(), "b4785058-cb80-491b-baa3-e4ee6546450e");
|
||||||
|
assertEquals(attachment.getId(), "1");
|
||||||
|
assertEquals(attachment.getVolumeId(), "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = AuthorizationException.class)
|
||||||
|
public void testListAttachmentsFail() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-2/os-volume_attachments");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).build(),
|
||||||
|
HttpResponse.builder().statusCode(401).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
api.listAttachmentsOnServer("instance-2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAttachment() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).build(),
|
||||||
|
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/attachment_details.json")).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
VolumeAttachment attachment = api.getAttachmentForVolumeOnServer("1", "instance-1");
|
||||||
|
assertEquals(attachment, testAttachment());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAttachmentFail() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).build(),
|
||||||
|
HttpResponse.builder().statusCode(404).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertNull(api.getAttachmentForVolumeOnServer("1", "instance-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAttachVolume() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-1/os-volume_attachments");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"volumeAttachment\":{\"volumeId\":\"1\",\"device\":\"/dev/vdc\"}}", MediaType.APPLICATION_JSON)).endpoint(endpoint).build(),
|
||||||
|
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/attachment_details.json")).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
VolumeAttachment result = api.attachVolumeToServerAsDevice("1", "instance-1", "/dev/vdc");
|
||||||
|
assertEquals(result, testAttachment());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||||
|
public void testAttachVolumeFail() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-1/os-volume_attachments");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"volumeAttachment\":{\"volumeId\":\"1\",\"device\":\"/dev/vdc\"}}", MediaType.APPLICATION_JSON)).endpoint(endpoint).build(),
|
||||||
|
HttpResponse.builder().statusCode(404).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
api.attachVolumeToServerAsDevice("1", "instance-1","/dev/vdc");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetachVolume() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||||
|
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/attachment_details.json")).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertTrue(api.detachVolumeFromServer("1", "instance-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetachVolumeFail() {
|
||||||
|
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeAttachmentApi api = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
authenticatedGET().endpoint(endpoint).method("DELETE").build(),
|
||||||
|
HttpResponse.builder().statusCode(404).build()
|
||||||
|
).getVolumeAttachmentExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertFalse(api.detachVolumeFromServer("1", "instance-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Volume testVolume() {
|
||||||
|
return Volume.builder().status(Volume.Status.IN_USE).description("This is a test volume").zone("nova").name("test")
|
||||||
|
.attachments(ImmutableSet.of(testAttachment())).size(1).id("1").created(dateService.iso8601SecondsDateParse("2012-04-23 12:16:45")).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected VolumeAttachment testAttachment() {
|
||||||
|
return VolumeAttachment.builder().device("/dev/vdc").serverId("b4785058-cb80-491b-baa3-e4ee6546450e").id("1").volumeId("1").build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
/**
|
||||||
|
* 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.nova.v2_0.extensions;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.openstack.nova.v2_0.domain.Volume;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.options.CreateVolumeOptions;
|
||||||
|
import org.jclouds.predicates.RetryablePredicate;
|
||||||
|
import org.testng.annotations.AfterClass;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of Volume Attachment API
|
||||||
|
*
|
||||||
|
* @author Everett Toews
|
||||||
|
*/
|
||||||
|
@Test(groups = "live", testName = "VolumeAttachmentApiLiveTest", singleThreaded = true)
|
||||||
|
public class VolumeAttachmentApiLiveTest extends BaseNovaApiLiveTest {
|
||||||
|
|
||||||
|
private Optional<? extends VolumeApi> volumeApi;
|
||||||
|
private Optional<? extends VolumeAttachmentApi> volumeAttachmentApi;
|
||||||
|
|
||||||
|
private String zone;
|
||||||
|
private Volume testVolume;
|
||||||
|
|
||||||
|
@BeforeClass(groups = {"integration", "live"})
|
||||||
|
@Override
|
||||||
|
public void setupContext() {
|
||||||
|
super.setupContext();
|
||||||
|
zone = Iterables.getLast(novaContext.getApi().getConfiguredZones(), "nova");
|
||||||
|
volumeApi = novaContext.getApi().getVolumeExtensionForZone(zone);
|
||||||
|
volumeAttachmentApi = novaContext.getApi().getVolumeAttachmentExtensionForZone(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass(groups = { "integration", "live" })
|
||||||
|
@Override
|
||||||
|
protected void tearDownContext() {
|
||||||
|
if (volumeApi.isPresent()) {
|
||||||
|
if (testVolume != null) {
|
||||||
|
final String volumeId = testVolume.getId();
|
||||||
|
assertTrue(volumeApi.get().delete(volumeId));
|
||||||
|
assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeApi volumeApi) {
|
||||||
|
return volumeApi.get(volumeId) == null;
|
||||||
|
}
|
||||||
|
}, 180 * 1000L).apply(volumeApi.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.tearDownContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateVolume() {
|
||||||
|
if (volumeApi.isPresent()) {
|
||||||
|
CreateVolumeOptions options = CreateVolumeOptions.Builder
|
||||||
|
.name("jclouds-test-volume")
|
||||||
|
.description("description of test volume")
|
||||||
|
.availabilityZone(zone);
|
||||||
|
|
||||||
|
testVolume = volumeApi.get().create(1, options);
|
||||||
|
assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeApi volumeApi) {
|
||||||
|
return volumeApi.get(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE;
|
||||||
|
}
|
||||||
|
}, 180 * 1000L).apply(volumeApi.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testCreateVolume")
|
||||||
|
public void testAttachments() {
|
||||||
|
if (volumeApi.isPresent()) {
|
||||||
|
String server_id = null;
|
||||||
|
try {
|
||||||
|
final String serverId = server_id = createServerInZone(zone).getId();
|
||||||
|
|
||||||
|
Set<? extends VolumeAttachment> attachments =
|
||||||
|
volumeAttachmentApi.get().listAttachmentsOnServer(serverId).toImmutableSet();
|
||||||
|
assertNotNull(attachments);
|
||||||
|
final int before = attachments.size();
|
||||||
|
|
||||||
|
VolumeAttachment testAttachment = volumeAttachmentApi.get().attachVolumeToServerAsDevice(
|
||||||
|
testVolume.getId(), serverId, "/dev/vdf");
|
||||||
|
assertNotNull(testAttachment.getId());
|
||||||
|
assertEquals(testAttachment.getVolumeId(), testVolume.getId());
|
||||||
|
|
||||||
|
assertTrue(new RetryablePredicate<VolumeAttachmentApi>(new Predicate<VolumeAttachmentApi>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeAttachmentApi volumeAttachmentApi) {
|
||||||
|
return volumeAttachmentApi.listAttachmentsOnServer(serverId).size() > before;
|
||||||
|
}
|
||||||
|
}, 60 * 1000L).apply(volumeAttachmentApi.get()));
|
||||||
|
|
||||||
|
attachments = volumeAttachmentApi.get().listAttachmentsOnServer(serverId).toImmutableSet();
|
||||||
|
assertNotNull(attachments);
|
||||||
|
assertEquals(attachments.size(), before + 1);
|
||||||
|
|
||||||
|
assertEquals(volumeApi.get().get(testVolume.getId()).getStatus(), Volume.Status.IN_USE);
|
||||||
|
|
||||||
|
boolean foundIt = false;
|
||||||
|
for (VolumeAttachment att : attachments) {
|
||||||
|
VolumeAttachment details = volumeAttachmentApi.get()
|
||||||
|
.getAttachmentForVolumeOnServer(att.getVolumeId(), serverId);
|
||||||
|
assertNotNull(details);
|
||||||
|
assertNotNull(details.getId());
|
||||||
|
assertNotNull(details.getServerId());
|
||||||
|
assertNotNull(details.getVolumeId());
|
||||||
|
if (Objects.equal(details.getVolumeId(), testVolume.getId())) {
|
||||||
|
foundIt = true;
|
||||||
|
assertEquals(details.getDevice(), "/dev/vdf");
|
||||||
|
assertEquals(details.getServerId(), serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(foundIt, "Failed to find the attachment we created in listAttachments() response");
|
||||||
|
|
||||||
|
volumeAttachmentApi.get().detachVolumeFromServer(testVolume.getId(), serverId);
|
||||||
|
assertTrue(new RetryablePredicate<VolumeAttachmentApi>(new Predicate<VolumeAttachmentApi>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeAttachmentApi volumeAttachmentApi) {
|
||||||
|
return volumeAttachmentApi.listAttachmentsOnServer(serverId).size() == before;
|
||||||
|
}
|
||||||
|
}, 60 * 1000L).apply(volumeAttachmentApi.get()));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (server_id != null)
|
||||||
|
novaContext.getApi().getServerApiForZone(zone).delete(server_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue