Issue 77: added list Image support

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1636 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-07-17 14:56:55 +00:00
parent f5e52178f9
commit 3fd5333732
9 changed files with 386 additions and 27 deletions

View File

@ -31,8 +31,10 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import org.jclouds.rackspace.cloudservers.domain.Flavor; import org.jclouds.rackspace.cloudservers.domain.Flavor;
import org.jclouds.rackspace.cloudservers.domain.Image;
import org.jclouds.rackspace.cloudservers.domain.Server; import org.jclouds.rackspace.cloudservers.domain.Server;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseImageListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseServerListFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseServerListFromGsonResponse;
import org.jclouds.rackspace.filters.AuthenticateRequest; import org.jclouds.rackspace.filters.AuthenticateRequest;
import org.jclouds.rest.Query; import org.jclouds.rest.Query;
@ -107,4 +109,32 @@ public interface CloudServersConnection {
// (400) // (400)
List<Flavor> listFlavorDetails(); List<Flavor> listFlavorDetails();
/**
*
* List available images (IDs and names only)
*
* @see #listImageDetails()
*/
@GET
@ResponseParser(ParseImageListFromGsonResponse.class)
@Query(key = "format", value = "json")
@Path("/images")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest (400)
List<Image> listImages();
/**
*
* This operation will list all images visible by the account.
*
* @see Image
*/
@GET
@ResponseParser(ParseImageListFromGsonResponse.class)
@Query(key = "format", value = "json")
@Path("/images/detail")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest (400)
List<Image> listImageDetails();
} }

View File

@ -25,18 +25,28 @@ package org.jclouds.rackspace.cloudservers.domain;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/**
* An image is a collection of files you use to create or rebuild a server. Rackspace provides
* pre-built OS images by default. You may also create custom images.
*
* @author Adrian Cole
*/
public class Image { public class Image {
private DateTime created; private DateTime created;
private Integer id; private int id;
private String name; private String name;
private Integer progress; private Integer progress;
private Integer serverId; private Integer serverId;
private ImageStatus status; private ImageStatus status;
private DateTime updated; private DateTime updated;
public Image(String name) { public Image() {
this.setName(name); }
public Image(int id, String name) {
this.id = id;
this.name = name;
} }
public void setCreated(DateTime created) { public void setCreated(DateTime created) {
@ -47,11 +57,11 @@ public class Image {
return created; return created;
} }
public void setId(Integer id) { public void setId(int id) {
this.id = id; this.id = id;
} }
public Integer getId() { public int getId() {
return id; return id;
} }
@ -95,4 +105,69 @@ public class Image {
return updated; return updated;
} }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((created == null) ? 0 : created.hashCode());
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((progress == null) ? 0 : progress.hashCode());
result = prime * result + ((serverId == null) ? 0 : serverId.hashCode());
result = prime * result + ((status == null) ? 0 : status.hashCode());
result = prime * result + ((updated == null) ? 0 : updated.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Image other = (Image) obj;
if (created == null) {
if (other.created != null)
return false;
} else if (!created.equals(other.created))
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (progress == null) {
if (other.progress != null)
return false;
} else if (!progress.equals(other.progress))
return false;
if (serverId == null) {
if (other.serverId != null)
return false;
} else if (!serverId.equals(other.serverId))
return false;
if (status == null) {
if (other.status != null)
return false;
} else if (!status.equals(other.status))
return false;
if (updated == null) {
if (other.updated != null)
return false;
} else if (!updated.equals(other.updated))
return false;
return true;
}
@Override
public String toString() {
return "Image [created=" + created + ", id=" + id + ", name=" + name + ", progress="
+ progress + ", serverId=" + serverId + ", status=" + status + ", updated="
+ updated + "]";
}
} }

View File

@ -24,22 +24,24 @@
package org.jclouds.rackspace.cloudservers.domain; package org.jclouds.rackspace.cloudservers.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, PREPARING, ACTIVE QUEUED, FAILED. Images with an ACTIVE status are
* available for install.
*
* @author Adrian Cole
*/
public enum ImageStatus { public enum ImageStatus {
UNKNOWN, UNKNOWN, ACTIVE, SAVING, PREPARING, QUEUED, FAILED;
ACTIVE,
SAVING,
PREPARING,
QUEUED,
FAILED;
public String value() { public String value() {
return name(); return name();
} }
public static ImageStatus fromValue(String v) { public static ImageStatus fromValue(String v) {
return valueOf(v); return valueOf(v);
} }
} }

View File

@ -0,0 +1,62 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.rackspace.cloudservers.functions;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rackspace.cloudservers.domain.Image;
import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.internal.Lists;
/**
* This parses {@link Image} from a gson string.
*
* @author Adrian Cole
*/
public class ParseImageListFromGsonResponse extends ParseJson<List<Image>> {
@Inject
public ParseImageListFromGsonResponse(Gson gson) {
super(gson);
}
private static class ImageListResponse {
List<Image> images = Lists.newArrayList();
}
public List<Image> apply(InputStream stream) {
try {
return gson.fromJson(new InputStreamReader(stream, "UTF-8"), ImageListResponse.class).images;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
}
}

View File

@ -25,12 +25,12 @@ package org.jclouds.rackspace.cloudservers;
import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_KEY; import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_KEY;
import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_USER; import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_USER;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import java.util.List; import java.util.List;
import org.jclouds.rackspace.cloudservers.domain.Flavor; import org.jclouds.rackspace.cloudservers.domain.Flavor;
import org.jclouds.rackspace.cloudservers.domain.Image;
import org.jclouds.rackspace.cloudservers.domain.Server; import org.jclouds.rackspace.cloudservers.domain.Server;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -50,7 +50,7 @@ public class CloudServersConnectionLiveTest {
CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser, CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser,
sysRackspaceKey).withJsonDebug().buildContext().getConnection(); sysRackspaceKey).withJsonDebug().buildContext().getConnection();
List<Server> response = connection.listServers(); List<Server> response = connection.listServers();
assertNotNull(response); assert null != response;
long initialContainerCount = response.size(); long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0); assertTrue(initialContainerCount >= 0);
@ -61,7 +61,7 @@ public class CloudServersConnectionLiveTest {
CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser, CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser,
sysRackspaceKey).withJsonDebug().buildContext().getConnection(); sysRackspaceKey).withJsonDebug().buildContext().getConnection();
List<Server> response = connection.listServerDetails(); List<Server> response = connection.listServerDetails();
assertNotNull(response); assert null != response;
long initialContainerCount = response.size(); long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0); assertTrue(initialContainerCount >= 0);
} }
@ -71,12 +71,12 @@ public class CloudServersConnectionLiveTest {
CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser, CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser,
sysRackspaceKey).withJsonDebug().buildContext().getConnection(); sysRackspaceKey).withJsonDebug().buildContext().getConnection();
List<Flavor> response = connection.listFlavors(); List<Flavor> response = connection.listFlavors();
assertNotNull(response); assert null != response;
long flavorCount = response.size(); long flavorCount = response.size();
assertTrue(flavorCount >= 1); assertTrue(flavorCount >= 1);
for (Flavor flavor : response) { for (Flavor flavor : response) {
assertTrue(flavor.getId() >= 0); assertTrue(flavor.getId() >= 0);
assertNotNull(flavor.getName()); assert null != flavor.getName() : flavor;
} }
} }
@ -86,14 +86,47 @@ public class CloudServersConnectionLiveTest {
CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser, CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser,
sysRackspaceKey).withJsonDebug().buildContext().getConnection(); sysRackspaceKey).withJsonDebug().buildContext().getConnection();
List<Flavor> response = connection.listFlavorDetails(); List<Flavor> response = connection.listFlavorDetails();
assertNotNull(response); assert null != response;
long flavorCount = response.size(); long flavorCount = response.size();
assertTrue(flavorCount >= 0); assertTrue(flavorCount >= 0);
for (Flavor flavor : response) { for (Flavor flavor : response) {
assertTrue(flavor.getId() >= 1); assertTrue(flavor.getId() >= 1);
assertNotNull(flavor.getName()); assert null != flavor.getName() : flavor;
assertNotNull(flavor.getDisk()); assert null != flavor.getDisk() : flavor;
assertNotNull(flavor.getRam()); assert null != flavor.getRam() : flavor;
}
}
@Test
public void testListImages() throws Exception {
CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser,
sysRackspaceKey).withJsonDebug().buildContext().getConnection();
List<Image> response = connection.listImages();
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 1);
for (Image image : response) {
assertTrue(image.getId() >= 0);
assert null != image.getName() : image;
}
}
@Test
public void testListImagesDetail() throws Exception {
CloudServersConnection connection = CloudServersContextBuilder.newBuilder(sysRackspaceUser,
sysRackspaceKey).withJsonDebug().buildContext().getConnection();
List<Image> response = connection.listImageDetails();
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 0);
for (Image image : response) {
assertTrue(image.getId() >= 1);
assert null != image.getName() : image;
// TODO: Web Hosting #118779
// assert null != image.getCreated() : image;
// assert null != image.getUpdated() : image;
assert null != image.getStatus() : image;
} }
} }
} }

View File

@ -35,6 +35,7 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.rackspace.Authentication; import org.jclouds.rackspace.Authentication;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseImageListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseServerListFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseServerListFromGsonResponse;
import org.jclouds.rest.JaxrsAnnotationProcessor; import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule; import org.jclouds.rest.config.JaxrsModule;
@ -119,6 +120,39 @@ public class CloudServersConnectionTest {
} }
public void testListImages() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listImages");
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/images");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
factory.create(CloudServersConnection.class);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
ParseImageListFromGsonResponse.class);
}
public void testListImagesDetail() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listImageDetails");
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/images/detail");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
factory.create(CloudServersConnection.class);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
ParseImageListFromGsonResponse.class);
}
@BeforeClass @BeforeClass
void setupFactory() { void setupFactory() {
factory = Guice.createInjector(new AbstractModule() { factory = Guice.createInjector(new AbstractModule() {

View File

@ -0,0 +1,91 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.rackspace.cloudservers.functions;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.util.List;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.rackspace.cloudservers.domain.Image;
import org.jclouds.rackspace.cloudservers.domain.ImageStatus;
import org.jclouds.util.DateService;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseImageListFromGsonResponseTest}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudImages.ParseImageListFromGsonResponseTest")
public class ParseImageListFromGsonResponseTest {
Injector i = Guice.createInjector(new ParserModule());
DateService dateService = new DateService();
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_list_images.json");
List<Image> expects = ImmutableList.of(new Image(2, "CentOS 5.2"), new Image(743,
"My Server Backup"));
ParseImageListFromGsonResponse parser = new ParseImageListFromGsonResponse(i
.getInstance(Gson.class));
assertEquals(parser.apply(is), expects);
}
public void testApplyInputStreamDetails() throws UnknownHostException {
InputStream is = getClass().getResourceAsStream("/test_list_images_detail.json");
ParseImageListFromGsonResponse parser = new ParseImageListFromGsonResponse(i
.getInstance(Gson.class));
List<Image> response = parser.apply(is);
assertEquals(response.get(0).getId(), 2);
assertEquals(response.get(0).getName(), "CentOS 5.2");
// Web Hosting #118779
assertEquals(null, response.get(0).getCreated());
assertEquals(response.get(0).getProgress(), null);
assertEquals(response.get(0).getServerId(), null);
assertEquals(response.get(0).getStatus(), ImageStatus.ACTIVE);
assertEquals(response.get(0).getUpdated(), dateService
.iso8601DateParse("2010-10-10T12:00:00Z"));
assertEquals(response.get(1).getId(), 743);
assertEquals(response.get(1).getName(), "My Server Backup");
assertEquals(response.get(1).getCreated(), dateService
.iso8601DateParse("2010-08-10T12:00:00Z"));
assertEquals(response.get(1).getProgress(), new Integer(80));
assertEquals(response.get(1).getServerId(), new Integer(12));
assertEquals(response.get(1).getStatus(), ImageStatus.SAVING);
assertEquals(response.get(1).getUpdated(), dateService
.iso8601DateParse("2010-10-10T12:00:00Z"));
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"id" : 2,
"name" : "CentOS 5.2"
},
{
"id" : 743,
"name" : "My Server Backup"
}
]
}

View File

@ -0,0 +1,20 @@
{
"images" : [
{
"id" : 2,
"name" : "CentOS 5.2",
"updated" : "2010-10-10T12:00:00Z",
"created" : "2010-08-10T12:00:00Z",
"status" : "ACTIVE"
},
{
"id" : 743,
"name" : "My Server Backup",
"serverId" : 12,
"updated" : "2010-10-10T12:00:00Z",
"created" : "2009-07-07T09:56:16-05:00",
"status" : "SAVING",
"progress" : 80
}
]
}