JCLOUDS-582: Enhancements to availability zones api

This commit is contained in:
Chris Custine 2014-06-02 16:07:04 -06:00 committed by Jeremy Daggett
parent ea68554244
commit 8c8fe83f3e
12 changed files with 61 additions and 23 deletions

View File

@ -21,7 +21,7 @@ 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.AvailabilityZoneAPI; import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneApi;
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;
@ -67,7 +67,7 @@ public interface NovaApi extends Closeable {
* Provides synchronous access to availability zone features * Provides synchronous access to availability zone features
*/ */
@Delegate @Delegate
AvailabilityZoneAPI getAvailabilityZoneApi( Optional<? extends AvailabilityZoneApi> getAvailabilityZoneApi(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone); @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/** /**

View File

@ -22,7 +22,7 @@ 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.AvailabilityZoneAPI; import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneAsyncApi;
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;
@ -72,7 +72,7 @@ public interface NovaAsyncApi extends Closeable {
* Provides asynchronous access to availability zone features * Provides asynchronous access to availability zone features
*/ */
@Delegate @Delegate
AvailabilityZoneAPI getAvailabilityZoneApi( Optional<? extends AvailabilityZoneAsyncApi> getAvailabilityZoneApi(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone); @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/** /**

View File

@ -31,7 +31,7 @@ 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.AvailabilityZoneAPI; import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneApi;
import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneAsyncApi;
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;
@ -98,7 +98,7 @@ public class NovaRestClientModule<S extends NovaApi, A extends NovaAsyncApi> ext
.put(ImageApi.class, ImageAsyncApi.class) .put(ImageApi.class, ImageAsyncApi.class)
.put(ExtensionApi.class, ExtensionAsyncApi.class) .put(ExtensionApi.class, ExtensionAsyncApi.class)
.put(FloatingIPApi.class, FloatingIPAsyncApi.class) .put(FloatingIPApi.class, FloatingIPAsyncApi.class)
.put(AvailabilityZoneAPI.class, AvailabilityZoneAsyncApi.class) .put(AvailabilityZoneApi.class, AvailabilityZoneAsyncApi.class)
.put(SecurityGroupApi.class, SecurityGroupAsyncApi.class) .put(SecurityGroupApi.class, SecurityGroupAsyncApi.class)
.put(KeyPairApi.class, KeyPairAsyncApi.class) .put(KeyPairApi.class, KeyPairAsyncApi.class)
.put(HostAdministrationApi.class, HostAdministrationAsyncApi.class) .put(HostAdministrationApi.class, HostAdministrationAsyncApi.class)
@ -160,6 +160,8 @@ public class NovaRestClientModule<S extends NovaApi, A extends NovaAsyncApi> ext
URI.create("http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1")) URI.create("http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUME_TYPES), .put(URI.create(ExtensionNamespaces.VOLUME_TYPES),
URI.create("http://docs.openstack.org/compute/ext/volume_types/api/v1.1")) URI.create("http://docs.openstack.org/compute/ext/volume_types/api/v1.1"))
.put(URI.create(ExtensionNamespaces.AVAILABILITY_ZONE),
URI.create("http://docs.openstack.org/compute/ext/availabilityzone/api/v1.1"))
.build(); .build();
} }

View File

@ -23,8 +23,8 @@ import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.services.Extension; import org.jclouds.openstack.v2_0.services.Extension;
@Beta @Beta
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS) @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.AVAILABILITY_ZONE)
public interface AvailabilityZoneAPI { public interface AvailabilityZoneApi {
/** /**
* @return all availability zones * @return all availability zones

View File

@ -35,7 +35,7 @@ import javax.ws.rs.core.MediaType;
@Beta @Beta
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS) @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.AVAILABILITY_ZONE)
@RequestFilters(AuthenticateRequest.class) @RequestFilters(AuthenticateRequest.class)
public interface AvailabilityZoneAsyncApi { public interface AvailabilityZoneAsyncApi {

View File

@ -66,6 +66,10 @@ public interface ExtensionNamespaces {
* Virtual interface support * Virtual interface support
*/ */
public static final String VIRTUAL_INTERFACES = "http://docs.openstack.org/ext/virtual_interfaces/api/v1.1"; public static final String VIRTUAL_INTERFACES = "http://docs.openstack.org/ext/virtual_interfaces/api/v1.1";
/**
* Availability zone extensions
*/
public static final String AVAILABILITY_ZONE = "http://docs.openstack.org/compute/ext/availabilityzone/api/v1.1";
/** /**
* Extended support to the Create Server v1.1 API * Extended support to the Create Server v1.1 API
*/ */

View File

@ -32,7 +32,7 @@ import static org.testng.Assert.assertTrue;
@Test(groups = "unit", testName = "AvailabilityZoneApiExpectTest") @Test(groups = "unit", testName = "AvailabilityZoneApiExpectTest")
public class AvailabilityZoneApiExpectTest extends BaseNovaApiExpectTest { public class AvailabilityZoneApiExpectTest extends BaseNovaApiExpectTest {
public void testLAvailabilityZonesList() throws Exception { public void testAvailabilityZonesList() throws Exception {
HttpRequest list = HttpRequest HttpRequest list = HttpRequest
.builder() .builder()
.method("GET") .method("GET")
@ -48,7 +48,7 @@ public class AvailabilityZoneApiExpectTest extends BaseNovaApiExpectTest {
assertEquals(availabilityZonesApi.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1", "az-2.region-a.geo-1", "az-3.region-a.geo-1")); assertEquals(availabilityZonesApi.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1", "az-2.region-a.geo-1", "az-3.region-a.geo-1"));
FluentIterable<? extends AvailabilityZone> zones = availabilityZonesApi.getAvailabilityZoneApi("az-1.region-a.geo-1").list(); FluentIterable<? extends AvailabilityZone> zones = availabilityZonesApi.getAvailabilityZoneApi("az-1.region-a.geo-1").get().list();
Optional<? extends AvailabilityZone> zone = zones.first(); Optional<? extends AvailabilityZone> zone = zones.first();

View File

@ -16,6 +16,7 @@
*/ */
package org.jclouds.openstack.nova.v2_0.extensions; package org.jclouds.openstack.nova.v2_0.extensions;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.AvailabilityZone; import org.jclouds.openstack.nova.v2_0.domain.zonescoped.AvailabilityZone;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest; import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
@ -29,12 +30,14 @@ public class AvailabilityZonesApiLiveTest extends BaseNovaApiLiveTest {
@Test @Test
public void testListAvailabilityZones() throws Exception { public void testListAvailabilityZones() throws Exception {
AvailabilityZoneAPI availabilityZoneApi = api.getAvailabilityZoneApi("RegionOne"); Optional<? extends AvailabilityZoneApi> availabilityZoneApi = api.getAvailabilityZoneApi("RegionOne");
FluentIterable<? extends AvailabilityZone> zones = availabilityZoneApi.list(); if (availabilityZoneApi.isPresent()) {
FluentIterable<? extends AvailabilityZone> zones = availabilityZoneApi.get().list();
for (AvailabilityZone zone : zones) { for (AvailabilityZone zone : zones) {
assertNotNull(zone.getName()); assertNotNull(zone.getName());
assertTrue(zone.getState().available(), "zone: " + zone.getName() + " is not available."); assertTrue(zone.getState().available(), "zone: " + zone.getName() + " is not available.");
}
} }
} }
} }

View File

@ -27,6 +27,7 @@ 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.domain.VolumeAttachment;
import org.jclouds.openstack.nova.v2_0.domain.VolumeSnapshot; import org.jclouds.openstack.nova.v2_0.domain.VolumeSnapshot;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest; import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
import org.jclouds.openstack.nova.v2_0.options.CreateVolumeOptions; import org.jclouds.openstack.nova.v2_0.options.CreateVolumeOptions;
import org.jclouds.openstack.nova.v2_0.options.CreateVolumeSnapshotOptions; import org.jclouds.openstack.nova.v2_0.options.CreateVolumeSnapshotOptions;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
@ -46,6 +47,7 @@ public class VolumeApiLiveTest extends BaseNovaApiLiveTest {
private Optional<? extends VolumeApi> volumeOption; private Optional<? extends VolumeApi> volumeOption;
private String zone; private String zone;
private String availabilityZone;
private Volume testVolume; private Volume testVolume;
private VolumeSnapshot testSnapshot; private VolumeSnapshot testSnapshot;
@ -56,6 +58,9 @@ public class VolumeApiLiveTest extends BaseNovaApiLiveTest {
super.setup(); super.setup();
zone = Iterables.getLast(api.getConfiguredZones(), "nova"); zone = Iterables.getLast(api.getConfiguredZones(), "nova");
volumeOption = api.getVolumeExtensionForZone(zone); volumeOption = api.getVolumeExtensionForZone(zone);
Optional<? extends AvailabilityZoneApi> availabilityZoneApi = api.getAvailabilityZoneApi(zone);
availabilityZone = availabilityZoneApi.isPresent() ? Iterables.getLast(availabilityZoneApi.get().list()).getName() : zone;
} }
@AfterClass(groups = { "integration", "live" }) @AfterClass(groups = { "integration", "live" })
@ -89,7 +94,7 @@ public class VolumeApiLiveTest extends BaseNovaApiLiveTest {
testVolume = volumeOption.get().create( testVolume = volumeOption.get().create(
1, 1,
CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume") CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume")
.availabilityZone(zone)); .availabilityZone(availabilityZone));
assertTrue(retry(new Predicate<VolumeApi>() { assertTrue(retry(new Predicate<VolumeApi>() {
public boolean apply(VolumeApi volumeApi) { public boolean apply(VolumeApi volumeApi) {
return volumeOption.get().get(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE; return volumeOption.get().get(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE;
@ -215,7 +220,8 @@ public class VolumeApiLiveTest extends BaseNovaApiLiveTest {
if (volumeOption.isPresent()) { if (volumeOption.isPresent()) {
String server_id = null; String server_id = null;
try { try {
final String serverId = server_id = createServerInZone(zone).getId(); CreateServerOptions createServerOptions = CreateServerOptions.Builder.availabilityZone(availabilityZone);
final String serverId = server_id = createServerInZone(zone, createServerOptions).getId();
Set<? extends VolumeAttachment> attachments = volumeOption.get().listAttachmentsOnServer(serverId).toSet(); Set<? extends VolumeAttachment> attachments = volumeOption.get().listAttachmentsOnServer(serverId).toSet();
assertNotNull(attachments); assertNotNull(attachments);
@ -236,7 +242,11 @@ public class VolumeApiLiveTest extends BaseNovaApiLiveTest {
assertNotNull(attachments); assertNotNull(attachments);
assertEquals(attachments.size(), before + 1); assertEquals(attachments.size(), before + 1);
assertEquals(volumeOption.get().get(testVolume.getId()).getStatus(), Volume.Status.IN_USE); assertTrue(retry(new Predicate<VolumeApi>() {
public boolean apply(VolumeApi volumeApi) {
return volumeApi.get(testVolume.getId()).getStatus() == Volume.Status.IN_USE;
}
}, 30 * 1000L).apply(volumeOption.get()), "Volume status did not show in-use after 30 seconds");
boolean foundIt = false; boolean foundIt = false;
for (VolumeAttachment att : attachments) { for (VolumeAttachment att : attachments) {

View File

@ -23,10 +23,12 @@ import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import com.google.common.base.Optional;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.nova.v2_0.domain.Network; import org.jclouds.openstack.nova.v2_0.domain.Network;
import org.jclouds.openstack.nova.v2_0.domain.Server; import org.jclouds.openstack.nova.v2_0.domain.Server;
import org.jclouds.openstack.nova.v2_0.domain.ServerCreated; import org.jclouds.openstack.nova.v2_0.domain.ServerCreated;
import org.jclouds.openstack.nova.v2_0.extensions.AvailabilityZoneApi;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest; import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions; import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
import org.jclouds.openstack.nova.v2_0.options.RebuildServerOptions; import org.jclouds.openstack.nova.v2_0.options.RebuildServerOptions;
@ -81,10 +83,14 @@ public class ServerApiLiveTest extends BaseNovaApiLiveTest {
@Test @Test
public void testCreateInAvailabilityZone() { public void testCreateInAvailabilityZone() {
String serverId = null; String serverId = null;
String availabilityZone;
for (String zoneId : zones) { for (String zoneId : zones) {
ServerApi serverApi = api.getServerApiForZone(zoneId); ServerApi serverApi = api.getServerApiForZone(zoneId);
Optional<? extends AvailabilityZoneApi> availabilityZoneApi = api.getAvailabilityZoneApi(zoneId);
availabilityZone = availabilityZoneApi.isPresent() ? Iterables.getLast(availabilityZoneApi.get().list()).getName() : "nova";
try { try {
serverId = createServer(zoneId, "nova").getId(); serverId = createServer(zoneId, availabilityZone).getId();
Server server = serverApi.get(serverId); Server server = serverApi.get(serverId);
assertEquals(server.getStatus(), ACTIVE); assertEquals(server.getStatus(), ACTIVE);
} finally { } finally {

View File

@ -34,6 +34,7 @@ import org.jclouds.openstack.nova.v2_0.domain.ServerCreated;
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;
import org.jclouds.openstack.nova.v2_0.features.ServerApi; import org.jclouds.openstack.nova.v2_0.features.ServerApi;
import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
import org.jclouds.openstack.v2_0.domain.Resource; import org.jclouds.openstack.v2_0.domain.Resource;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -82,10 +83,14 @@ public class BaseNovaApiLiveTest extends BaseApiLiveTest<NovaApi> {
setIfTestSystemPropertyPresent(props, NovaProperties.AUTO_ALLOCATE_FLOATING_IPS); setIfTestSystemPropertyPresent(props, NovaProperties.AUTO_ALLOCATE_FLOATING_IPS);
return props; return props;
} }
protected Server createServerInZone(String zoneId) { protected Server createServerInZone(String zoneId) {
return createServerInZone(zoneId, new CreateServerOptions());
}
protected Server createServerInZone(String zoneId, CreateServerOptions options) {
ServerApi serverApi = api.getServerApiForZone(zoneId); ServerApi serverApi = api.getServerApiForZone(zoneId);
ServerCreated server = serverApi.create(hostName, imageIdForZone(zoneId), flavorRefForZone(zoneId)); ServerCreated server = serverApi.create(hostName, imageIdForZone(zoneId), flavorRefForZone(zoneId), options);
blockUntilServerInState(server.getId(), serverApi, Status.ACTIVE); blockUntilServerInState(server.getId(), serverApi, Status.ACTIVE);
return serverApi.get(server.getId()); return serverApi.get(server.getId());
} }

View File

@ -269,5 +269,13 @@
"links": [], "links": [],
"namespace": "http://docs.openstack.org/compute/ext/floating_ips/api/v1.1", "namespace": "http://docs.openstack.org/compute/ext/floating_ips/api/v1.1",
"alias": "os-floating-ips", "alias": "os-floating-ips",
"description": "Floating IPs support"} "description": "Floating IPs support"
},
{
"updated": "2012-12-21T00:00:00+00:00",
"name": "AvailabilityZone",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/availabilityzone/api/v1.1",
"alias": "os-availability-zone",
"description": "1. Add availability_zone to the Create Server v1.1 API.\n 2. Add availability zones describing.\n "}
]} ]}