Issue 77: more support on cloud servers including password change

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1654 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-07-19 18:54:58 +00:00
parent 3d5d31f037
commit 3c0547c7df
18 changed files with 1018 additions and 159 deletions

View File

@ -60,8 +60,8 @@ public class JschSshConnection implements SshConnection {
}
private void checkConnected() {
checkState(sftp.isConnected(), String.format("%s@%s:%d: SFTP not connected!", username, host
.getHostAddress(), port));
checkState(sftp != null && sftp.isConnected(), String.format("%s@%s:%d: SFTP not connected!",
username, host.getHostAddress(), port));
}
@PostConstruct

View File

@ -30,10 +30,13 @@ import java.util.concurrent.Future;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.rackspace.cloudservers.binders.ChangeAdminPassBinder;
import org.jclouds.rackspace.cloudservers.binders.ChangeServerNameBinder;
import org.jclouds.rackspace.cloudservers.domain.Flavor;
import org.jclouds.rackspace.cloudservers.domain.Image;
import org.jclouds.rackspace.cloudservers.domain.Server;
@ -47,7 +50,9 @@ import org.jclouds.rackspace.cloudservers.functions.ReturnFlavorNotFoundOn404;
import org.jclouds.rackspace.cloudservers.functions.ReturnImageNotFoundOn404;
import org.jclouds.rackspace.cloudservers.functions.ReturnServerNotFoundOn404;
import org.jclouds.rackspace.cloudservers.options.CreateServerOptions;
import org.jclouds.rackspace.cloudservers.options.ListOptions;
import org.jclouds.rackspace.filters.AuthenticateRequest;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.PostBinder;
import org.jclouds.rest.PostParam;
@ -73,7 +78,11 @@ public interface CloudServersConnection {
*
* List all servers (IDs and names only)
*
* @see #listServerDetails()
* This operation provides a list of servers associated with your account. Servers that have been
* deleted are not included in this list.
* <p/>
* in order to retrieve all details, pass the option {@link ListOptions#withDetails()
* withDetails()}
*/
@GET
@ResponseParser(ParseServerListFromGsonResponse.class)
@ -81,24 +90,13 @@ public interface CloudServersConnection {
@Path("/servers")
// TODO: Error Response Code(s): cloudServersFault (400, 500), serviceUnavailable (503),
// unauthorized (401), badRequest (400), overLimit (413)
List<Server> listServers();
/**
* This operation provides a list of servers associated with your account. Servers that have been
* deleted are not included in this list.
*/
@GET
@ResponseParser(ParseServerListFromGsonResponse.class)
@Query(key = "format", value = "json")
@Path("/servers/detail")
// TODO: Error Response Code(s): cloudServersFault (400, 500), serviceUnavailable (503),
// unauthorized (401), badRequest (400), overLimit (413)
List<Server> listServerDetails();
List<Server> listServers(ListOptions... options);
/**
*
* This operation returns details of the specified server.
*
* @return {@link Server#NOT_FOUND} if the server is not found
* @see Server
*/
@GET
@ -108,7 +106,7 @@ public interface CloudServersConnection {
@Path("/servers/{id}")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400)
Server getServerDetails(@PathParam("id") int id);
Server getServer(@PathParam("id") int id);
/**
*
@ -116,7 +114,7 @@ public interface CloudServersConnection {
* <p/>
* Note: When a server is deleted, all images created from that server are also removed.
*
*
* @return false if the server is not found
* @see Server
*/
@DELETE
@ -126,6 +124,25 @@ public interface CloudServersConnection {
// (400), itemNotFound (404), buildInProgress (409), overLimit (413)
boolean deleteServer(@PathParam("id") int id);
/**
* The reboot function allows for either a soft or hard reboot of a server. With a soft reboot,
* the operating system is signaled to restart, which allows for a graceful shutdown of all
* processes. A hard reboot is the equivalent of power cycling the server.
*/
/**
* The rebuild function removes all data on the server and replaces it with the specified image.
* Server ID and IP addresses remain the same.
*/
/**
* The resize function converts an existing server to a different flavor, in essence, scaling the
* server up or down. The original server is saved for a period of time to allow rollback if
* there is a problem. All resizes should be tested and explicitly confirmed, at which time the
* original server is removed. All resizes are automatically confirmed after 24 hours if they are
* not confirmed or reverted.
*/
/**
* This operation asynchronously provisions a new server. The progress of this operation depends
* on several factors including location of the requested image, network i/o, host load, and the
@ -133,6 +150,9 @@ public interface CloudServersConnection {
* which will return a progress attribute (0-100% completion). A password will be randomly
* generated for you and returned in the response object. For security reasons, it will not be
* returned in subsequent GET calls against a given server ID.
*
* @param options
* - used to specify extra files, metadata, or ip parameters during server creation.
*/
@POST
@ResponseParser(ParseServerFromGsonResponse.class)
@ -142,13 +162,45 @@ public interface CloudServersConnection {
// TODO:cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401),
// badMediaType(415), badRequest (400), serverCapacityUnavailable (503), overLimit (413)
Server createServer(@PostParam("name") String name, @PostParam("imageId") int imageId,
@PostParam("flavorId") int flavorId);
@PostParam("flavorId") int flavorId, CreateServerOptions... options);
/**
* This operation allows you to change the administrative password.
* <p/>
* Status Transition: ACTIVE - PASSWORD - ACTIVE
*
* @return false if the server is not found
*/
@PUT
@ExceptionParser(ReturnFalseOn404.class)
@Path("/servers/{id}")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), overLimit (413)
boolean changeAdminPass(@PathParam("id") int id,
@EntityParam(ChangeAdminPassBinder.class) String adminPass);
/**
* This operation allows you to update the name of the server. This operation changes the name of
* the server in the Cloud Servers system and does not change the server host name itself.
* <p/>
* Status Transition: ACTIVE - PASSWORD - ACTIVE
*
* @return false if the server is not found
*/
@PUT
@ExceptionParser(ReturnFalseOn404.class)
@Path("/servers/{id}")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), overLimit (413)
boolean renameServer(@PathParam("id") int id,
@EntityParam(ChangeServerNameBinder.class) String newName);
/**
*
* List available flavors (IDs and names only)
*
* @see #listFlavorDetails()
* in order to retrieve all details, pass the option {@link ListOptions#withDetails()
* withDetails()}
*/
@GET
@ResponseParser(ParseFlavorListFromGsonResponse.class)
@ -156,27 +208,14 @@ public interface CloudServersConnection {
@Path("/flavors")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400)
List<Flavor> listFlavors();
/**
*
* List available flavors (all details)
*
* @see Flavor
*/
@GET
@ResponseParser(ParseFlavorListFromGsonResponse.class)
@Query(key = "format", value = "json")
@Path("/flavors/detail")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400)
List<Flavor> listFlavorDetails();
List<Flavor> listFlavors(ListOptions... options);
/**
*
* List available images (IDs and names only)
*
* @see #listImageDetails()
* in order to retrieve all details, pass the option {@link ListOptions#withDetails()
* withDetails()}
*/
@GET
@ResponseParser(ParseImageListFromGsonResponse.class)
@ -184,26 +223,13 @@ public interface CloudServersConnection {
@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();
List<Image> listImages(ListOptions... options);
/**
*
* This operation returns details of the specified image.
*
* @return {@link Image#NOT_FOUND} if the image is not found
* @see Image
*/
@GET
@ -213,12 +239,13 @@ public interface CloudServersConnection {
@Path("/images/{id}")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400)
Image getImageDetails(@PathParam("id") int id);
Image getImage(@PathParam("id") int id);
/**
*
* This operation returns details of the specified flavor.
*
* @return {@link Flavor#NOT_FOUND} if the flavor is not found
* @see Flavor
*/
@GET
@ -228,6 +255,6 @@ public interface CloudServersConnection {
@Path("/flavors/{id}")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400)
Flavor getFlavorDetails(@PathParam("id") int id);
Flavor getFlavor(@PathParam("id") int id);
}

View File

@ -0,0 +1,31 @@
package org.jclouds.rackspace.cloudservers.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.binders.JsonBinder;
import com.google.common.collect.ImmutableMap;
/**
*
* @author Adrian Cole
*
*/
public class ChangeAdminPassBinder extends JsonBinder {
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
throw new IllegalStateException("Change Admin Pass is a PUT operation");
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
checkArgument(toBind instanceof String, "this binder is only valid for Strings!");
super.addEntityToRequest(ImmutableMap.of("server", ImmutableMap.of("adminPass", checkNotNull(
toBind, "adminPass"))), request);
}
}

View File

@ -0,0 +1,31 @@
package org.jclouds.rackspace.cloudservers.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.binders.JsonBinder;
import com.google.common.collect.ImmutableMap;
/**
*
* @author Adrian Cole
*
*/
public class ChangeServerNameBinder extends JsonBinder {
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
throw new IllegalStateException("Change Server Name is a PUT operation");
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
checkArgument(toBind instanceof String, "this binder is only valid for Strings!");
super.addEntityToRequest(ImmutableMap.of("server", ImmutableMap.of("name", checkNotNull(
toBind, "name"))), request);
}
}

View File

@ -23,12 +23,18 @@
*/
package org.jclouds.rackspace.cloudservers.domain;
/**
* A backup schedule can be defined to create server images at regular intervals (daily and weekly).
* Backup schedules are configurable per server.
*
* @author Adrian Cole
*/
public class BackupSchedule {
protected DailyBackup daily;
protected boolean enabled;
protected String weekly;
public DailyBackup getDaily() {
return daily;
}
@ -40,6 +46,7 @@ public class BackupSchedule {
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean value) {
this.enabled = value;
}

View File

@ -27,7 +27,7 @@ package org.jclouds.rackspace.cloudservers.domain;
/**
*
* A flavor is an available hardware configuration for a server. Each flavor has a unique
* combination of disk space, memory capacity.
* combination of disk space and memory capacity.
*
* @author Adrian Cole
*/

View File

@ -26,15 +26,17 @@ package org.jclouds.rackspace.cloudservers.domain;
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.
* An image is a collection of files used to create or rebuild a server. Rackspace provides a number
* of pre-built OS images by default. You may also create custom images from cloud servers you have
* launched. These custom images are useful for backup purposes or for producing ÒgoldÓ server
* images if you plan to deploy a particular server configuration frequently.
*
* @author Adrian Cole
*/
public class Image {
public static final Image NOT_FOUND = new Image(-1,"NOT_FOUND");
public static final Image NOT_FOUND = new Image(-1, "NOT_FOUND");
private DateTime created;
private int id;
private String name;

View File

@ -28,8 +28,8 @@ import java.util.Map;
import com.google.inject.internal.Maps;
/**
*
* Server.
* A server is a virtual machine instance in the Cloud Servers system. Flavor and image are
* requisite elements when creating a server.
*
* @author Adrian Cole
* @since 4.0

View File

@ -117,6 +117,12 @@ public class CreateServerOptions extends JsonBinder {
}
/**
* A shared IP group is a collection of servers that can share IPs with other members of the
* group. Any server in a group can share one or more public IPs with any other server in the
* group. With the exception of the first server in a shared IP group, servers must be launched
* into shared IP groups. A server may only be a member of one shared IP group.
*
* <p/>
* Servers in the same shared IP group can share public IPs for various high availability and
* load balancing configurations. To launch an HA server, include the optional sharedIpGroupId
* element and the server will be launched into that shared IP group.
@ -160,6 +166,14 @@ public class CreateServerOptions extends JsonBinder {
}
/**
* Public IP addresses can be shared across multiple servers for use in various high availability
* scenarios. When an IP address is shared to another server, the cloud network restrictions are
* modified to allow each server to listen to and respond on that IP address (you may optionally
* specify that the target server network configuration be modified). Shared IP addresses can be
* used with many standard heartbeat facilities (e.g. keepalived) that monitor for failure and
* manage IP failover.
*
* <p/>
* If you intend to use a shared IP on the server being created and have no need for a separate
* public IP address, you may launch the server into a shared IP group and specify an IP address
* from that shared IP group to be used as its public IP. You can accomplish this by specifying

View File

@ -0,0 +1,90 @@
package org.jclouds.rackspace.cloudservers.options;
import org.jclouds.rackspace.options.BaseListOptions;
import org.joda.time.DateTime;
/**
* Options used to control the amount of detail in the request.
*
* @see BaseListOptions
* @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
* @author Adrian Cole
*/
public class ListOptions extends BaseListOptions {
public static final ListOptions NONE = new ListOptions();
/**
* unless used, only the name and id will be returned per row.
*
* @return
*/
public ListOptions withDetails() {
this.pathSuffix = "/detail";
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ListOptions changesSince(DateTime ifModifiedSince) {
super.changesSince(ifModifiedSince);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ListOptions maxResults(int limit) {
super.maxResults(limit);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ListOptions startAt(long offset) {
super.startAt(offset);
return this;
}
public static class Builder {
/**
* @see ListOptions#withDetails()
*/
public static ListOptions withDetails() {
ListOptions options = new ListOptions();
return options.withDetails();
}
/**
* @see BaseListOptions#startAt(long)
*/
public static ListOptions startAt(long prefix) {
ListOptions options = new ListOptions();
return options.startAt(prefix);
}
/**
* @see BaseListOptions#maxResults(long)
*/
public static ListOptions maxResults(int maxKeys) {
ListOptions options = new ListOptions();
return options.maxResults(maxKeys);
}
/**
* @see BaseListOptions#changesSince(DateTime)
*/
public static ListOptions changesSince(DateTime since) {
ListOptions options = new ListOptions();
return options.changesSince(since);
}
}
}

View File

@ -23,15 +23,22 @@
*/
package org.jclouds.rackspace.cloudservers;
import static org.jclouds.rackspace.cloudservers.options.CreateServerOptions.Builder.withFile;
import static org.jclouds.rackspace.cloudservers.options.ListOptions.Builder.withDetails;
import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_KEY;
import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_USER;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.SecureRandom;
import java.util.List;
import java.util.Map;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rackspace.cloudservers.domain.Flavor;
import org.jclouds.rackspace.cloudservers.domain.Image;
@ -43,6 +50,7 @@ import org.jclouds.util.Utils;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Injector;
/**
@ -50,13 +58,13 @@ import com.google.inject.Injector;
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "cloudservers.CloudServersConnectionLiveTest")
@Test(groups = "live", sequential = true, testName = "cloudservers.CloudServersConnectionLiveTest")
public class CloudServersConnectionLiveTest {
protected static final String sysRackspaceUser = System.getProperty(PROPERTY_RACKSPACE_USER);
protected static final String sysRackspaceKey = System.getProperty(PROPERTY_RACKSPACE_KEY);
CloudServersConnection connection;
SshConnection.Factory sshFactory;
protected CloudServersConnection connection;
protected SshConnection.Factory sshFactory;
@BeforeGroups(groups = { "live" })
public void setupConnection() {
@ -80,7 +88,7 @@ public class CloudServersConnectionLiveTest {
@Test
public void testListServersDetail() throws Exception {
List<Server> response = connection.listServerDetails();
List<Server> response = connection.listServers(withDetails());
assert null != response;
long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0);
@ -101,7 +109,7 @@ public class CloudServersConnectionLiveTest {
@Test
public void testListFlavorsDetail() throws Exception {
List<Flavor> response = connection.listFlavorDetails();
List<Flavor> response = connection.listFlavors(withDetails());
assert null != response;
long flavorCount = response.size();
assertTrue(flavorCount >= 0);
@ -128,7 +136,7 @@ public class CloudServersConnectionLiveTest {
@Test
public void testListImagesDetail() throws Exception {
List<Image> response = connection.listImageDetails();
List<Image> response = connection.listImages(withDetails());
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 0);
@ -144,13 +152,13 @@ public class CloudServersConnectionLiveTest {
@Test(enabled = false)
// Rackspace Web Hosting issue #118856
public void testGetImageDetails() throws Exception {
List<Image> response = connection.listImageDetails();
public void testGetImagesDetail() throws Exception {
List<Image> response = connection.listImages(withDetails());
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 0);
for (Image image : response) {
Image newDetails = connection.getImageDetails(image.getId());
Image newDetails = connection.getImage(image.getId());
assertEquals(image, newDetails);
}
}
@ -158,79 +166,147 @@ public class CloudServersConnectionLiveTest {
@Test(enabled = false)
// Rackspace Web Hosting issue #118856
public void testGetImageDetailsNotFound() throws Exception {
Image newDetails = connection.getImageDetails(12312987);
Image newDetails = connection.getImage(12312987);
assertEquals(Image.NOT_FOUND, newDetails);
}
@Test
public void testGetFlavorDetails() throws Exception {
List<Flavor> response = connection.listFlavorDetails();
public void testGetFlavorsDetail() throws Exception {
List<Flavor> response = connection.listFlavors(withDetails());
assert null != response;
long flavorCount = response.size();
assertTrue(flavorCount >= 0);
for (Flavor flavor : response) {
Flavor newDetails = connection.getFlavorDetails(flavor.getId());
Flavor newDetails = connection.getFlavor(flavor.getId());
assertEquals(flavor, newDetails);
}
}
public void testGetFlavorDetailsNotFound() throws Exception {
Flavor newDetails = connection.getFlavorDetails(12312987);
Flavor newDetails = connection.getFlavor(12312987);
assertEquals(Flavor.NOT_FOUND, newDetails);
}
public void testGetServerDetailsNotFound() throws Exception {
Server newDetails = connection.getServerDetails(12312987);
Server newDetails = connection.getServer(12312987);
assertEquals(Server.NOT_FOUND, newDetails);
}
public void testGetServerDetails() throws Exception {
List<Server> response = connection.listServerDetails();
public void testGetServersDetail() throws Exception {
List<Server> response = connection.listServers(withDetails());
assert null != response;
long serverCount = response.size();
assertTrue(serverCount >= 0);
for (Server server : response) {
Server newDetails = connection.getServerDetails(server.getId());
Server newDetails = connection.getServer(server.getId());
assertEquals(server, newDetails);
}
}
private String serverPrefix = System.getProperty("user.name") + ".cs";
private int serverId;
private String adminPass;
Map<String, String> metadata = ImmutableMap.of("jclouds", "rackspace");
@Test(timeOut = 5 * 60 * 1000)
public void testCreateServer() throws Exception {
Server newDetails = connection.createServer(serverPrefix + "createserver", 2, 1);
System.err.print(newDetails);
assertNotNull(newDetails.getAdminPass());
assertNotNull(newDetails.getHostId());
assertEquals(newDetails.getStatus(), ServerStatus.BUILD);
assert newDetails.getProgress() >= 0 : "newDetails.getProgress()" + newDetails.getProgress();
assertEquals(new Integer(2), newDetails.getImageId());
assertEquals(new Integer(1), newDetails.getFlavorId());
assertNotNull(newDetails.getAddresses());
assertEquals(newDetails.getAddresses().getPublicAddresses().size(), 1);
assertEquals(newDetails.getAddresses().getPrivateAddresses().size(), 1);
int imageId = 2;
int flavorId = 1;
Server server = null;
while (server == null) {
String serverName = serverPrefix + "createserver" + new SecureRandom().nextInt();
try {
server = connection.createServer(serverName, imageId, flavorId, withFile(
"/etc/jclouds.txt", "rackspace".getBytes()).withMetadata(metadata));
} catch (UndeclaredThrowableException e) {
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
if (htpe.getResponse().getStatusCode() == 400)
continue;
throw e;
}
}
assertNotNull(server.getAdminPass());
serverId = server.getId();
adminPass = server.getAdminPass();
assertEquals(server.getStatus(), ServerStatus.BUILD);
blockUntilActive(server);
}
int serverId = newDetails.getId();
ServerStatus currentStatus = newDetails.getStatus();
Server currentDetails = newDetails;
private void blockUntilActive(Server server) throws InterruptedException {
ServerStatus currentStatus = server.getStatus();
Server currentDetails = server;
while (currentStatus != ServerStatus.ACTIVE) {
Thread.sleep(5 * 1000);
currentDetails = connection.getServerDetails(serverId);
currentDetails = connection.getServer(serverId);
System.out.println(currentDetails);
currentStatus = currentDetails.getStatus();
}
}
InputStream etcPasswd = sshFactory.create(
newDetails.getAddresses().getPublicAddresses().get(0), 22, "root",
newDetails.getAdminPass()).get("/etc/passwd");
String etcPasswdContents = Utils.toStringAndClose(etcPasswd);
assert etcPasswdContents.indexOf("root") >= 0 : etcPasswdContents;
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer")
public void testServerDetails() throws Exception {
Server server = connection.getServer(serverId);
connection.deleteServer(serverId);
assertNotNull(server.getHostId());
assertEquals(server.getStatus(), ServerStatus.ACTIVE);
assert server.getProgress() >= 0 : "newDetails.getProgress()" + server.getProgress();
assertEquals(new Integer(2), server.getImageId());
assertEquals(new Integer(1), server.getFlavorId());
assertNotNull(server.getAddresses());
assertEquals(server.getAddresses().getPublicAddresses().size(), 1);
assertEquals(server.getAddresses().getPrivateAddresses().size(), 1);
currentDetails = connection.getServerDetails(serverId);
assertEquals(ServerStatus.DELETED, currentDetails.getStatus());
// check metadata
assertEquals(server.getMetadata(), metadata);
checkPassOk(server, adminPass);
}
/**
* this tests "personality" as the file looked up was sent during server creation
*/
private void checkPassOk(Server newDetails, String pass) throws IOException {
SshConnection connection = sshFactory.create(newDetails.getAddresses().getPublicAddresses()
.get(0), 22, "root", pass);
try {
connection.connect();
InputStream etcPasswd = connection.get("/etc/jclouds.txt");
String etcPasswdContents = Utils.toStringAndClose(etcPasswd);
assertEquals("rackspace", etcPasswdContents.trim());
} finally {
if (connection != null)
connection.disconnect();
}
}
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer")
public void testRenameServer() throws Exception {
Server server = connection.getServer(serverId);
String oldName = server.getName();
assertTrue(connection.renameServer(serverId, oldName + "new"));
blockUntilActive(server);
assertEquals(oldName + "new", connection.getServer(serverId).getName());
}
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer")
public void testChangePassword() throws Exception {
Server server = connection.getServer(serverId);
assertTrue(connection.changeAdminPass(serverId, "elmo"));
blockUntilActive(server);
checkPassOk(connection.getServer(serverId), "elmo");
this.adminPass = "elmo";
}
// TODO test createServer.withSharedIpGroup
// TODO test createServer.withSharedIp
// must be last!
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = {"testChangePassword","testRenameServer"})
void deleteServer() {
if (serverId > 0) {
connection.deleteServer(serverId);
Server server = connection.getServer(serverId);
assertEquals(server, Server.NOT_FOUND);
}
}
}

View File

@ -23,10 +23,17 @@
*/
package org.jclouds.rackspace.cloudservers;
import static org.testng.Assert.assertEquals;
import static org.jclouds.rackspace.cloudservers.options.CreateServerOptions.Builder.withFile;
import static org.jclouds.rackspace.cloudservers.options.CreateServerOptions.Builder.withMetadata;
import static org.jclouds.rackspace.cloudservers.options.CreateServerOptions.Builder.withSharedIpGroup;
import static org.jclouds.rackspace.cloudservers.options.ListOptions.Builder.changesSince;
import static org.jclouds.rackspace.cloudservers.options.ListOptions.Builder.withDetails;
import static org.testng.Assert.*;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Collections;
import javax.ws.rs.core.HttpHeaders;
@ -37,6 +44,8 @@ import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.rackspace.Authentication;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse;
@ -44,11 +53,18 @@ import org.jclouds.rackspace.cloudservers.functions.ParseImageFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseImageListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseServerFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseServerListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ReturnFlavorNotFoundOn404;
import org.jclouds.rackspace.cloudservers.functions.ReturnImageNotFoundOn404;
import org.jclouds.rackspace.cloudservers.functions.ReturnServerNotFoundOn404;
import org.jclouds.rackspace.cloudservers.options.CreateServerOptions;
import org.jclouds.rackspace.cloudservers.options.ListOptions;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.joda.time.DateTime;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Provides;
@ -63,174 +79,368 @@ public class CloudServersConnectionTest {
JaxrsAnnotationProcessor.Factory factory;
private static final Class<? extends ListOptions[]> listOptionsVarargsClass = new ListOptions[] {}
.getClass();
private static final Class<? extends CreateServerOptions[]> createServerOptionsVarargsClass = new CreateServerOptions[] {}
.getClass();
public void testCreateServer() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("createServer", String.class,
int.class, int.class);
int.class, int.class, createServerOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] { "ralphie", 2, 1 });
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "ralphie",
2, 1 });
assertEquals("{\"server\":{\"name\":\"ralphie\",\"imageId\":2,\"flavorId\":1}}", httpMethod
.getEntity());
validateCreateServer(method, httpMethod);
}
public void testCreateServerWithFile() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("createServer", String.class,
int.class, int.class, createServerOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "ralphie",
2, 1, new CreateServerOptions[] { withFile("/etc/jclouds", "foo".getBytes()) } });
assertEquals(
"{\"server\":{\"name\":\"ralphie\",\"imageId\":2,\"flavorId\":1,\"personality\":[{\"path\":\"/etc/jclouds\",\"contents\":\"Zm9v\"}]}}",
httpMethod.getEntity());
validateCreateServer(method, httpMethod);
}
public void testCreateServerWithMetadata() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("createServer", String.class,
int.class, int.class, createServerOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "ralphie",
2, 1, withMetadata(ImmutableMap.of("foo", "bar")) });
assertEquals(
"{\"server\":{\"name\":\"ralphie\",\"imageId\":2,\"flavorId\":1,\"metadata\":{\"foo\":\"bar\"}}}",
httpMethod.getEntity());
validateCreateServer(method, httpMethod);
}
public void testCreateServerWithIpGroup() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("createServer", String.class,
int.class, int.class, createServerOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "ralphie",
2, 1, withSharedIpGroup(2) });
assertEquals(
"{\"server\":{\"name\":\"ralphie\",\"imageId\":2,\"flavorId\":1,\"sharedIpGroupId\":2}}",
httpMethod.getEntity());
validateCreateServer(method, httpMethod);
}
public void testCreateServerWithIpGroupAndSharedIp() throws SecurityException,
NoSuchMethodException, UnknownHostException {
Method method = CloudServersConnection.class.getMethod("createServer", String.class,
int.class, int.class, createServerOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] {
"ralphie",
2,
1,
withSharedIpGroup(2).withSharedIp(
InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 })) });
assertEquals(
"{\"server\":{\"name\":\"ralphie\",\"imageId\":2,\"flavorId\":1,\"sharedIpGroupId\":2,\"addresses\":{\"public\":[\"127.0.0.1\"]}}}",
httpMethod.getEntity());
validateCreateServer(method, httpMethod);
}
private void validateCreateServer(Method method, HttpRequest httpMethod) {
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.POST);
assertEquals("{\"server\":{\"name\":\"ralphie\",\"imageId\":2,\"flavorId\":1}}", httpMethod
.getEntity());
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(httpMethod.getEntity().toString().getBytes().length + ""));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList(MediaType.APPLICATION_JSON));
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseServerFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
assertNotNull(processor.getPostEntityBinderOrNull(method, new Object[] { "", 1, 2,
new CreateServerOptions[] { CreateServerOptions.Builder.withSharedIpGroup(1) } }));
}
public void testListServers() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listServers");
Method method = CloudServersConnection.class
.getMethod("listServers", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] {});
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseServerListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
DateTime now = new DateTime();
public void testListServersOptions() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class
.getMethod("listServers", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { changesSince(now).maxResults(1).startAt(2) });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json" + "&limit=1&changes-since="
+ now.getMillis() / 1000 + "&offset=2");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method).getClass(),
ParseServerListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListServersDetail() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listServerDetails");
Method method = CloudServersConnection.class
.getMethod("listServers", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { withDetails() });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers/detail");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseServerListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListFlavors() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listFlavors");
Method method = CloudServersConnection.class
.getMethod("listFlavors", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] {});
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/flavors");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseFlavorListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListFlavorsOptions() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class
.getMethod("listFlavors", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { changesSince(now).maxResults(1).startAt(2) });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/flavors");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json" + "&limit=1&changes-since="
+ now.getMillis() / 1000 + "&offset=2");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method).getClass(),
ParseFlavorListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListFlavorsDetail() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listFlavorDetails");
Method method = CloudServersConnection.class
.getMethod("listFlavors", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { withDetails() });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/flavors/detail");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseFlavorListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListImages() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listImages");
Method method = CloudServersConnection.class.getMethod("listImages", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
HttpRequest httpMethod = processor.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);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseImageListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListImagesDetail() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listImageDetails");
Method method = CloudServersConnection.class.getMethod("listImages", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] {});
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { withDetails() });
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);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseImageListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testGetImageDetails() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("getImageDetails", int.class);
public void testListFlavorsDetailOptions() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class
.getMethod("listFlavors", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] { 2 });
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { withDetails().changesSince(now).maxResults(1).startAt(2) });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/flavors/detail");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json" + "&limit=1&changes-since="
+ now.getMillis() / 1000 + "&offset=2");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method).getClass(),
ParseFlavorListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListImagesOptions() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listImages", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { changesSince(now).maxResults(1).startAt(2) });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/images");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json" + "&limit=1&changes-since="
+ now.getMillis() / 1000 + "&offset=2");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method).getClass(),
ParseImageListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListImagesDetailOptions() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listImages", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method,
new Object[] { withDetails().changesSince(now).maxResults(1).startAt(2) });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/images/detail");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json" + "&limit=1&changes-since="
+ now.getMillis() / 1000 + "&offset=2");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method).getClass(),
ParseImageListFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testGetImage() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("getImage", int.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { 2 });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/images/2");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseImageFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnImageNotFoundOn404.class);
}
public void testGetFlavorDetails() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("getFlavorDetails", int.class);
public void testGetFlavor() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("getFlavor", int.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] { 2 });
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { 2 });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/flavors/2");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseFlavorFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnFlavorNotFoundOn404.class);
}
public void testGetServerDetails() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("getServerDetails", int.class);
public void testGetServer() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("getServer", int.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] { 2 });
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { 2 });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers/2");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(JaxrsAnnotationProcessor.getParserOrThrowException(method),
assertEquals(processor.createResponseParser(method).getClass(),
ParseServerFromGsonResponse.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnServerNotFoundOn404.class);
}
public void testDeleteServer() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("deleteServer", int.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = factory.create(CloudServersConnection.class).createRequest(endpoint,
method, new Object[] { 2 });
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { 2 });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers/2");
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnFalseOn404.class);
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
}
public void testChangeAdminPass() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("changeAdminPass", int.class,
String.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { 2, "foo" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers/2");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(httpMethod.getEntity().toString().getBytes().length + ""));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList(MediaType.APPLICATION_JSON));
assertEquals("{\"server\":{\"adminPass\":\"foo\"}}", httpMethod.getEntity());
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnFalseOn404.class);
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
}
public void testChangeServerName() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("renameServer", int.class,
String.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { 2, "foo" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers/2");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(httpMethod.getEntity().toString().getBytes().length + ""));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList(MediaType.APPLICATION_JSON));
assertEquals("{\"server\":{\"name\":\"foo\"}}", httpMethod.getEntity());
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnFalseOn404.class);
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
}
JaxrsAnnotationProcessor processor;
@BeforeClass
void setupFactory() {
factory = Guice.createInjector(new AbstractModule() {
@ -248,6 +458,7 @@ public class CloudServersConnectionTest {
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule()).getInstance(
JaxrsAnnotationProcessor.Factory.class);
processor = factory.create(CloudServersConnection.class);
}
}

View File

@ -0,0 +1,83 @@
/**
*
* 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.binders;
import static org.testng.Assert.assertEquals;
import java.io.File;
import java.net.URI;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.rackspace.cloudservers.binders.ChangeAdminPassBinder;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ChangeAdminPassBinder}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudservers.ChangeAdminPassBinderTest")
public class ChangeAdminPassBinderTest {
Injector injector = Guice.createInjector(new ParserModule());
@Test(expectedExceptions = IllegalStateException.class)
public void testPostIsIncorrect() {
ChangeAdminPassBinder binder = new ChangeAdminPassBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("/"));
binder.addEntityToRequest(ImmutableMap.of("adminPass", "foo"), request);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeString() {
ChangeAdminPassBinder binder = new ChangeAdminPassBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("/"));
binder.addEntityToRequest(new File("foo"), request);
}
@Test
public void testCorrect() {
ChangeAdminPassBinder binder = new ChangeAdminPassBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("/"));
binder.addEntityToRequest("foo", request);
assertEquals("{\"server\":{\"adminPass\":\"foo\"}}", request.getEntity());
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() {
ChangeAdminPassBinder binder = new ChangeAdminPassBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("/"));
binder.addEntityToRequest(null, request);
}
}

View File

@ -0,0 +1,83 @@
/**
*
* 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.binders;
import static org.testng.Assert.assertEquals;
import java.io.File;
import java.net.URI;
import org.jclouds.http.HttpMethod;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.rackspace.cloudservers.binders.ChangeServerNameBinder;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ChangeServerNameBinder}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudservers.ChangeServerNameBinderTest")
public class ChangeServerNameBinderTest {
Injector injector = Guice.createInjector(new ParserModule());
@Test(expectedExceptions = IllegalStateException.class)
public void testPostIsIncorrect() {
ChangeServerNameBinder binder = new ChangeServerNameBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("/"));
binder.addEntityToRequest(ImmutableMap.of("name", "foo"), request);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeString() {
ChangeServerNameBinder binder = new ChangeServerNameBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("/"));
binder.addEntityToRequest(new File("foo"), request);
}
@Test
public void testCorrect() {
ChangeServerNameBinder binder = new ChangeServerNameBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("/"));
binder.addEntityToRequest("foo", request);
assertEquals("{\"server\":{\"name\":\"foo\"}}", request.getEntity());
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() {
ChangeServerNameBinder binder = new ChangeServerNameBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("/"));
binder.addEntityToRequest(null, request);
}
}

View File

@ -0,0 +1,66 @@
package org.jclouds.rackspace.cloudservers.options;
import static org.jclouds.rackspace.cloudservers.options.ListOptions.Builder.*;
import static org.testng.Assert.assertEquals;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests behavior of {@code ListOptions}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "rackspace.ListOptionsTest")
public class ListOptionsTest {
public void testWithDetails() {
ListOptions options = new ListOptions().withDetails();
assertEquals(options.buildPathSuffix(), "/detail");
}
public void testWithDetailsStatic() {
ListOptions options = withDetails();
assertEquals(options.buildPathSuffix(), "/detail");
}
public void testChangesSince() {
DateTime ifModifiedSince = new DateTime();
ListOptions options = new ListOptions().changesSince(ifModifiedSince);
assertEquals(ImmutableList.of(ifModifiedSince.getMillis() / 1000 + ""), options
.buildQueryParameters().get("changes-since"));
}
public void testStartAt() {
long offset = 1;
ListOptions options = new ListOptions().startAt(offset);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
}
public void testMaxResults() {
int limit = 1;
ListOptions options = new ListOptions().maxResults(limit);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
}
public void testChangesSinceStatic() {
DateTime ifModifiedSince = new DateTime();
ListOptions options = changesSince(ifModifiedSince);
assertEquals(ImmutableList.of(ifModifiedSince.getMillis() / 1000 + ""), options
.buildQueryParameters().get("changes-since"));
}
public void testStartAtStatic() {
long offset = 1;
ListOptions options = startAt(offset);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
}
public void testMaxResultsStatic() {
int limit = 1;
ListOptions options = maxResults(limit);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
}
}

View File

@ -38,7 +38,6 @@ import org.jclouds.rest.ResponseParser;
* <p/>
*
* @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
* @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
* @author Adrian Cole
*/

View File

@ -0,0 +1,81 @@
package org.jclouds.rackspace.options;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.joda.time.DateTime;
/**
* Options used to control paginated results (aka list commands).
*
* @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
* @author Adrian Cole
*/
public class BaseListOptions extends BaseHttpRequestOptions {
public static final BaseListOptions NONE = new BaseListOptions();
/**
* Only return objects changed since this time.
*/
public BaseListOptions changesSince(DateTime ifModifiedSince) {
this.queryParameters.put("changes-since", checkNotNull(ifModifiedSince, "ifModifiedSince")
.getMillis()
/ 1000 + "");
return this;
}
/**
* Indicates where to begin listing. The list will only include objects that occur after the
* offset. This is convenient for pagination: To get the next page of results use the last result
* number of the current page + current page offset as the offset.
*/
public BaseListOptions startAt(long offset) {
checkState(offset >= 0, "offset must be >= 0");
queryParameters.put("offset", Long.toString(checkNotNull(offset, "offset")));
return this;
}
/**
* To reduce load on the service, list operations will return a maximum of 1,000 items at a time.
* To navigate the collection, the parameters limit and offset can be set in the URI
* (e.g.?limit=0&offset=0). If an offset is given beyond the end of a list an empty list will be
* returned.
* <p/>
* Note that list operations never return itemNotFound (404) faults.
*/
public BaseListOptions maxResults(int limit) {
checkState(limit >= 0, "limit must be >= 0");
checkState(limit <= 10000, "limit must be <= 10000");
queryParameters.put("limit", Integer.toString(limit));
return this;
}
public static class Builder {
/**
* @see BaseListOptions#startAt(long)
*/
public static BaseListOptions startAt(long prefix) {
BaseListOptions options = new BaseListOptions();
return options.startAt(prefix);
}
/**
* @see BaseListOptions#maxResults(long)
*/
public static BaseListOptions maxResults(int maxKeys) {
BaseListOptions options = new BaseListOptions();
return options.maxResults(maxKeys);
}
/**
* @see BaseListOptions#changesSince(DateTime)
*/
public static BaseListOptions changesSince(DateTime since) {
BaseListOptions options = new BaseListOptions();
return options.changesSince(since);
}
}
}

View File

@ -0,0 +1,58 @@
package org.jclouds.rackspace.options;
import static org.jclouds.rackspace.options.BaseListOptions.Builder.changesSince;
import static org.jclouds.rackspace.options.BaseListOptions.Builder.maxResults;
import static org.jclouds.rackspace.options.BaseListOptions.Builder.startAt;
import static org.testng.Assert.assertEquals;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests behavior of {@code ListOptions}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "rackspace.ListOptionsTest")
public class BaseListOptionsTest {
public void testChangesSince() {
DateTime ifModifiedSince = new DateTime();
BaseListOptions options = new BaseListOptions().changesSince(ifModifiedSince);
assertEquals(ImmutableList.of(ifModifiedSince.getMillis() / 1000 + ""), options
.buildQueryParameters().get("changes-since"));
}
public void testStartAt() {
long offset = 1;
BaseListOptions options = new BaseListOptions().startAt(offset);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
}
public void testMaxResults() {
int limit = 1;
BaseListOptions options = new BaseListOptions().maxResults(limit);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
}
public void testChangesSinceStatic() {
DateTime ifModifiedSince = new DateTime();
BaseListOptions options = changesSince(ifModifiedSince);
assertEquals(ImmutableList.of(ifModifiedSince.getMillis() / 1000 + ""), options
.buildQueryParameters().get("changes-since"));
}
public void testStartAtStatic() {
long offset = 1;
BaseListOptions options = startAt(offset);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
}
public void testMaxResultsStatic() {
int limit = 1;
BaseListOptions options = maxResults(limit);
assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
}
}