Incremental support for Image, Flavor and Floating IPs

This commit is contained in:
Jeremy Daggett 2012-02-22 17:24:44 -08:00
parent bfe5f45ee2
commit df70d34bf7
16 changed files with 769 additions and 63 deletions

View File

@ -25,6 +25,7 @@ import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPClient;
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
@ -63,6 +64,13 @@ public interface NovaAsyncClient {
FlavorClient getFlavorClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides asynchronous access to Image features.
*/
@Delegate
ImageClient getImageClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides asynchronous access to Floating IP features.
*/

View File

@ -27,6 +27,7 @@ import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPClient;
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
@ -65,6 +66,13 @@ public interface NovaClient {
FlavorClient getFlavorClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides synchronous access to Image features.
*/
@Delegate
ImageClient getImageClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides synchronous access to Floating IP features.
*/

View File

@ -30,6 +30,10 @@ import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.features.FlavorAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPClient;
import org.jclouds.openstack.nova.v1_1.features.ImageAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.openstack.nova.v1_1.handlers.NovaErrorHandler;
@ -50,6 +54,8 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
.put(ServerClient.class, ServerAsyncClient.class)//
.put(FlavorClient.class, FlavorAsyncClient.class)
.put(ImageClient.class, ImageAsyncClient.class)
.put(FloatingIPClient.class, FloatingIPAsyncClient.class)
.build();
public NovaRestClientModule() {

View File

@ -0,0 +1,188 @@
/**
* 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.v1_1.domain;
import static com.google.common.base.Objects.toStringHelper;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.ImageStatus;
import com.google.common.collect.Maps;
/**
* An image is a collection of files you use to create or rebuild a server.
* Operators provide pre-built OS images by default. You may also create custom
* images.
*
* @author Jeremy Daggett
* @see <a href=
* "http://docs.openstack.org/api/openstack-compute/1.1/content/Images-d1e4427.html"
* />
*/
public class Image extends Resource {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromImage(this);
}
public static class Builder extends Resource.Builder {
private ImageStatus status;
private Date updated;
private Date created;
private int progress;
private String serverRef;
private Map<String, String> metadata = Maps.newHashMap();
public Builder status(ImageStatus status) {
this.status = status;
return this;
}
public Builder updated(Date updated) {
this.updated = updated;
return this;
}
public Builder created(Date created) {
this.created = created;
return this;
}
public Builder progress(int progress) {
this.progress = progress;
return this;
}
public Builder serverRef(String serverRef) {
this.serverRef = serverRef;
return this;
}
public Builder metadata(Map<String, String> metadata) {
this.metadata = metadata;
return this;
}
public Image build() {
return new Image(id, name, links, status, updated, created, progress,
serverRef, metadata);
}
public Builder fromImage(Image in) {
return fromResource(in).status(in.getStatus())
.updated(in.getUpdated()).created(in.getCreated())
.progress(in.getProgress()).serverRef(in.getServerRef())
.metadata(in.getMetadata());
}
/**
* {@inheritDoc}
*/
@Override
public Builder id(String id) {
return Builder.class.cast(super.id(id));
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Set<Link> links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromResource(Resource in) {
return Builder.class.cast(super.fromResource(in));
}
}
private ImageStatus status;
private Date updated;
private Date created;
private int progress;
private String serverRef;
private Map<String, String> metadata = Maps.newHashMap();
protected Image(String id, String name, Set<Link> links, ImageStatus status,
Date updated, Date created, int progress, String serverRef,
Map<String, String> metadata) {
super(id, name, links);
this.status = status;
this.updated = updated;
this.created = created;
this.progress = progress;
this.serverRef = serverRef;
this.metadata = metadata;
}
public ImageStatus getStatus() {
return this.status;
}
public Date getUpdated() {
return this.updated;
}
public Date getCreated() {
return this.created;
}
public int getProgress() {
return this.progress;
}
public String getServerRef() {
return this.serverRef;
}
public Map<String, String> getMetadata() {
return this.metadata;
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("name", name)
.add("links", links).add("status", status).add("updated", updated)
.add("created", created).add("progress", progress).add("serverRef", serverRef)
.add("metadata", metadata).toString();
}
}

View File

@ -0,0 +1,47 @@
/**
* 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.v1_1.domain;
/**
* In-flight images will have the status attribute set to SAVING and the
* conditional progress element (0-100% completion) will also be returned. Other
* possible values for the status attribute include: UNKNOWN, ACTIVE, SAVING,
* ERROR, and DELETED. Images with an ACTIVE status are available for install.
* The optional minDisk and minRam attributes set the minimum disk and RAM
* requirements needed to create a server with the image.
*
* @author Adrian Cole
*/
public enum ImageStatus {
UNRECOGNIZED, UNKNOWN, ACTIVE, SAVING, ERROR, DELETED;
public String value() {
return name();
}
public static ImageStatus fromValue(String v) {
try {
return valueOf(v);
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}

View File

@ -23,17 +23,15 @@ import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.Flavor;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding;
/**
* Provides asynchronous access to Flavors via their REST API.
* <p/>
*
* @see FlavorClient
* @see <a href="http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
* @see <a href=
* "http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
* />
* @author Jeremy Daggett
*/
@ -59,7 +57,7 @@ public interface FlavorClient {
*
* @param id
* id of the flavor
* @return flavorr or null if not found
* @return flavor or null if not found
*/
Flavor getFlavor(String id);

View File

@ -21,14 +21,19 @@ package org.jclouds.openstack.nova.v1_1.features;
import java.util.Set;
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.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
@ -52,9 +57,9 @@ public interface FloatingIPAsyncClient {
* @see FloatingIPClient#listFloatingIPs
*/
@GET
@Path("/os-floating-ips")
@SelectJson("floating_ips")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/os-floating-ips")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<FloatingIP>> listFloatingIPs();
@ -62,28 +67,31 @@ public interface FloatingIPAsyncClient {
* @see FloatingIPClient#getFloatingIP
*/
@GET
@Path("/os-floating-ips/{id}")
@SelectJson("floating_ip")
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<FloatingIP> getFloatingIP(@PathParam("id") String id);
/**
* @see FloatingIPClient#allocate
*/
@POST
@Path("/os-floating-ips")
@SelectJson("floating_ip")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Payload("{}")
ListenableFuture<FloatingIP> allocate();
/**
* @see FloatingIPClient#deallocate
*/
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("/os-floating-ips/{id}")
ListenableFuture<FloatingIP> getFloatingIP(@PathParam("id") String id);
/** SHOULD THIS GO IN ServerAsyncClient???
*
@POST
@Path("/servers/{server}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"addFloatingIp\":%7B\"server\":\"{server}\",\"address\":\"{address}\"%7D%7D")
ListenableFuture<Void> addFloatingIP(@PayloadParam("server") String server, @PayloadParam("address") String address);
ListenableFuture<Void> deallocate(@PathParam("id") String id);
@POST
@Path("/servers/{server}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"removeFloatingIp\":%7B\"server\":\"{server}\",\"address\":\"{address}\"%7D%7D")
ListenableFuture<Void> removeFloatingIP(@PayloadParam("server") String serverId, @PayloadParam("address") String address);
*
*/
}

View File

@ -25,12 +25,10 @@ import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
/**
* Provides asynchronous access to Flavors via their REST API.
* Provides synchronous access to Floating IPs.
* <p/>
*
* @see FlavorClient
* @see <a href="http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
* />
* @see FloatingIPAsyncClient
* @author Jeremy Daggett
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
@ -42,12 +40,27 @@ public interface FloatingIPClient {
* @return all Floating IPs
*/
Set<FloatingIP> listFloatingIPs();
/**
* Get a specific Floating IP address
*
* @return all Floating IPs
*/
FloatingIP getFloatingIP(String id);
/**
* Allocate a Floating IP address
*
* @return a newly allocated FloatingIP
*/
FloatingIP allocate();
/**
* Deallocate a Floating IP address
*
* @param id
* the Floating IP id
*/
void deallocate(String id);
}

View File

@ -0,0 +1,93 @@
/**
* 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.v1_1.features;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Images via the REST API.
* <p/>
*
* @see ImageClient
* @author Jeremy Daggett
*/
@SkipEncoding({ '/', '=' })
@RequestFilters(AuthenticateRequest.class)
public interface ImageAsyncClient {
/**
* @see ImageClient#listImages
*/
@GET
@SelectJson("images")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Resource>> listImages();
/**
* @see ImageClient#listImagesInDetail
*/
@GET
@SelectJson("images")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images/detail")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Image>> listImagesInDetail();
/**
* @see ImageClient#getImage
*/
@GET
@SelectJson("flavor")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images/{id}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Image> getImage(@PathParam("id") String id);
/**
* @see ImageClient#deleteImage
*/
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images/{id}")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteImage(@PathParam("id") String id);
}

View File

@ -0,0 +1,71 @@
/**
* 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.v1_1.features;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Image;
/**
* Provides synchronous access to Images.
* <p/>
*
* @see ImageAsyncClient
* @see <a href="http://docs.openstack.org/api/openstack-compute/1.1/content/Servers-d1e2073.html"
* />
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ImageClient {
/**
* List all images (IDs, names, links)
*
* @return all images (IDs, names, links)
*/
Set<Resource> listImages();
/**
* List all images (all details)
*
* @return all images (all details)
*/
Set<Image> listImagesInDetail();
/**
* List details of the specified image
*
* @param id
* id of the server
* @return server or null if not found
*/
Image getImage(String id);
/**
* Delete the specified image
*
* @param id id of the image
* @return server or null if not found
*/
void deleteImage(String id);
}

View File

@ -1,6 +1,7 @@
package org.jclouds.openstack.nova.v1_1.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.net.URI;
@ -21,56 +22,102 @@ import com.google.common.collect.ImmutableSet;
*
* @author Jeremy Daggett
*/
@Test(groups = "unit", testName = "FlavorAsyncClientTest")
@Test(groups = "unit", testName = "FlavorClientExpectTest")
public class FlavorClientExpectTest extends BaseNovaRestClientExpectTest {
public void testListFlavorsWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpRequest listFlavors = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/flavor_list.json")).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/flavor_list.json")).build();
NovaClient clientWhenFlavorsExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listServers, listFlavorsResponse);
NovaClient clientWhenFlavorsExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
listFlavors, listFlavorsResponse);
assertEquals(clientWhenFlavorsExist.getConfiguredRegions(), ImmutableSet.of("North"));
assertEquals(clientWhenFlavorsExist.getConfiguredRegions(),
ImmutableSet.of("North"));
assertEquals(clientWhenFlavorsExist.getFlavorClientForRegion("North").listFlavors().toString(),
new ParseFlavorListTest().expected().toString());
assertEquals(clientWhenFlavorsExist.getFlavorClientForRegion("North")
.listFlavors().toString(), new ParseFlavorListTest().expected()
.toString());
}
public void testListFlavorsWhenReponseIs404IsEmpty() throws Exception {
HttpRequest listFlavors = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpRequest listFlavors = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(404).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(404)
.build();
NovaClient clientWhenNoServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listFlavors, listFlavorsResponse);
NovaClient clientWhenNoServersExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
listFlavors, listFlavorsResponse);
assertTrue(clientWhenNoServersExist.getFlavorClientForRegion("North").listFlavors().isEmpty());
assertTrue(clientWhenNoServersExist.getFlavorClientForRegion("North")
.listFlavors().isEmpty());
}
// TODO: gson deserializer for Multimap
public void testGetFlavorWhenResponseIs2xx() throws Exception {
HttpRequest getFlavor = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors/foo")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse getFlavorResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/flavor_details.json")).build();
HttpRequest getFlavor = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors/52415800-8b69-11e0-9b19-734f1195ff37"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, getFlavor, getFlavorResponse);
HttpResponse getFlavorResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/flavor_details.json")).build();
NovaClient clientWhenFlavorsExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
getFlavor, getFlavorResponse);
assertEquals(clientWhenFlavorsExist.getFlavorClientForRegion("North")
.getFlavor("52415800-8b69-11e0-9b19-734f1195ff37").toString(),
new ParseFlavorTest().expected().toString());
}
public void testGetFlavorWhenResponseIs404() throws Exception {
HttpRequest getFlavor = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors/123"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
HttpResponse getFlavorResponse = HttpResponse.builder().statusCode(404)
.payload(payloadFromResource("/flavor_details.json")).build();
NovaClient clientWhenNoFlavorsExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
getFlavor, getFlavorResponse);
assertNull(clientWhenNoFlavorsExist.getFlavorClientForRegion("North").getFlavor("123"));
assertEquals(clientWhenServersExist.getFlavorClientForRegion("North").getFlavor("foo").toString(),
new ParseFlavorTest().expected().toString());
}
}

View File

@ -36,7 +36,11 @@ import org.testng.annotations.Test;
@Test(groups = "live", testName = "FlavorClientLiveTest")
public class FlavorClientLiveTest extends BaseNovaClientLiveTest {
/**
* Tests the listing of Flavors (getFlavor() is tested too!)
*
* @throws Exception
*/
@Test
public void testListFlavors() throws Exception {
for (String regionId : context.getApi().getConfiguredRegions()) {
@ -53,4 +57,29 @@ public class FlavorClientLiveTest extends BaseNovaClientLiveTest {
}
}
/**
* Tests the listing of Flavors in detail (getFlavor() is tested too!)
*
* @throws Exception
*/
@Test
public void testListFlavorsInDetail() throws Exception {
for (String regionId : context.getApi().getConfiguredRegions()) {
FlavorClient client = context.getApi().getFlavorClientForRegion(regionId);
Set<Flavor> response = client.listFlavorsInDetail();
assert null != response;
assertTrue(response.size() >= 0);
for (Flavor flavor : response) {
Flavor newDetails = client.getFlavor(flavor.getId());
assertEquals(newDetails.getId(), flavor.getId());
assertEquals(newDetails.getName(), flavor.getName());
assertEquals(newDetails.getLinks(), flavor.getLinks());
assertEquals(newDetails.getRam(), flavor.getRam());
assertEquals(newDetails.getDisk(), flavor.getDisk());
assertEquals(newDetails.getVcpus(), flavor.getVcpus());
}
}
}
}

View File

@ -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.v1_1.features;
import static java.lang.System.out;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code ServerClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "FloatingIPClientLiveTest")
public class FloatingIPClientLiveTest extends BaseNovaClientLiveTest {
@Test
public void testListFloatingIPs() throws Exception {
for (String regionId : context.getApi().getConfiguredRegions()) {
FloatingIPClient client = context.getApi().getFloatingIPClientForRegion(regionId);
Set<FloatingIP> response = client.listFloatingIPs();
assert null != response;
assertTrue(response.size() >= 0);
for (FloatingIP ip : response) {
FloatingIP newDetails = client.getFloatingIP(ip.getId());
assertEquals(newDetails.getId(), ip.getId());
assertEquals(newDetails.getIp(), ip.getIp());
assertEquals(newDetails.getFixedIp(), ip.getFixedIp());
assertEquals(newDetails.getInstanceId(), ip.getInstanceId());
//checkServer(newDetails);
}
}
}
/*
out.println("Allocating a new floating ip address");
FloatingIP newIP = ipClient.allocate();
out.println(newIP);
out.println("List of floating ips after allocate");
floatingIPs = ipClient.listFloatingIPs();
for (FloatingIP ip : floatingIPs) {
System.out.println("Floating IP: " + ip);
}
out.println("Get floating ip address 3815");
FloatingIP getIP = ipClient.getFloatingIP("3815");
out.println(getIP);
out.println("Deallocating the floating ip address");
ipClient.deallocate(newIP.getId());
out.println("List of floating ips after deallocate");
floatingIPs = ipClient.listFloatingIPs();
for (FloatingIP ip : floatingIPs) {
System.out.println("Floating IP: " + ip);
}
*/
private void checkServer(Server server) {
assert server.getAddresses().size() > 0 : server;
}
}

View File

@ -0,0 +1,37 @@
{
"image" : {
"id" : "52415800-8b69-11e0-9b19-734f5736d2a2",
"name" : "My Server Backup",
"updated" : "2010-10-10T12:00:00Z",
"created" : "2010-08-10T12:00:00Z",
"tenant_id" : "12345",
"user_id" : "joe",
"status" : "SAVING",
"progress" : 80,
"minDisk" : 5,
"minRam" : 256,
"server" : {
"id": "52415800-8b69-11e0-9b19-734f335aa7b3",
"links": [
{
"rel": "self",
"href": "http://servers.api.openstack.org/v1.1/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3"
},
{
"rel": "bookmark",
"href": "http://servers.api.openstack.org/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3"
}
]
},
"links": [
{
"rel" : "self",
"href" : "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
},
{
"rel" : "bookmark",
"href" : "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
}
]
}
}

View File

@ -0,0 +1,62 @@
{
"images": [
{
"id": "52415800-8b69-11e0-9b19-734f6f006e54",
"name": "CentOS 5.2",
"updated": "2010-10-10T12:00:00Z",
"created": "2010-08-10T12:00:00Z",
"tenant_id" : "12345",
"user_id" : "joe",
"status": "ACTIVE",
"metadata": {
"ImageType": "Gold",
"ImageVersion": "1.5"
},
"links": [
{
"rel": "self",
"href": "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
},
{
"rel": "bookmark",
"href": "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
}
]
},
{
"id" : "52415800-8b69-11e0-9b19-734f5736d2a2",
"name" : "My Server Backup",
"updated" : "2010-10-10T12:00:00Z",
"created" : "2010-08-10T12:00:00Z",
"tenant_id" : "12345",
"user_id" : "joe",
"status" : "SAVING",
"progress" : 80,
"minDisk" : 5,
"minRam" : 256,
"server" : {
"id": "52415800-8b69-11e0-9b19-734f335aa7b3",
"links": [
{
"rel": "self",
"href": "http://servers.api.openstack.org/v1.1/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3"
},
{
"rel": "bookmark",
"href": "http://servers.api.openstack.org/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3"
}
]
},
"links": [
{
"rel" : "self",
"href" : "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
},
{
"rel" : "bookmark",
"href" : "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
}
]
}
]
}