Issue 77: create image and all backup schedule support

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1832 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-07-23 07:26:38 +00:00
parent fd9e281069
commit 2436c68578
12 changed files with 636 additions and 17 deletions

View File

@ -36,16 +36,20 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import org.jclouds.http.functions.ReturnFalseOn404; import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.rackspace.cloudservers.binders.BackupScheduleBinder;
import org.jclouds.rackspace.cloudservers.binders.ChangeAdminPassBinder; import org.jclouds.rackspace.cloudservers.binders.ChangeAdminPassBinder;
import org.jclouds.rackspace.cloudservers.binders.ChangeServerNameBinder; import org.jclouds.rackspace.cloudservers.binders.ChangeServerNameBinder;
import org.jclouds.rackspace.cloudservers.binders.CreateImageBinder;
import org.jclouds.rackspace.cloudservers.binders.ShareIpBinder; import org.jclouds.rackspace.cloudservers.binders.ShareIpBinder;
import org.jclouds.rackspace.cloudservers.domain.Addresses; import org.jclouds.rackspace.cloudservers.domain.Addresses;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
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.Image;
import org.jclouds.rackspace.cloudservers.domain.Server; import org.jclouds.rackspace.cloudservers.domain.Server;
import org.jclouds.rackspace.cloudservers.domain.SharedIpGroup; import org.jclouds.rackspace.cloudservers.domain.SharedIpGroup;
import org.jclouds.rackspace.cloudservers.functions.IpAddress; import org.jclouds.rackspace.cloudservers.functions.IpAddress;
import org.jclouds.rackspace.cloudservers.functions.ParseAddressesFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseAddressesFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseBackupScheduleFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseFlavorFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseImageFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseImageFromGsonResponse;
@ -220,7 +224,8 @@ public interface CloudServersConnection {
@DELETE @DELETE
@ExceptionParser(ReturnFalseOn404.class) @ExceptionParser(ReturnFalseOn404.class)
@Path("/servers/{id}/ips/public/{address}") @Path("/servers/{id}/ips/public/{address}")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized(401), badRequest (400), // TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized(401), badRequest
// (400),
// badMediaType(415), overLimit (413) // badMediaType(415), overLimit (413)
boolean unshareIp( boolean unshareIp(
@PathParam("address") @ParamParser(IpAddress.class) InetAddress addressToShare, @PathParam("address") @ParamParser(IpAddress.class) InetAddress addressToShare,
@ -319,6 +324,37 @@ public interface CloudServersConnection {
// (400) // (400)
Image getImage(@PathParam("id") int id); Image getImage(@PathParam("id") int id);
/**
*
* This operation creates a new image for the given server ID. Once complete, a new image will be
* available that can be used to rebuild or create servers. Specifying the same image name as an
* existing custom image replaces the image. The image creation status can be queried by
* performing a GET on /images/id and examining the status and progress attributes.
*
* Status Transition:
* <p/>
* QUEUED - PREPARING - SAVING - ACTIVE
* <p/>
* QUEUED - PREPARING - SAVING - FAILED (on error)
* <p/>
* Note: At present, image creation is an asynchronous operation, so coordinating the creation
* with data quiescence, etc. is currently not possible.
*
* @return {@link Image#NOT_FOUND} if the server is not found
* @see Image
*/
@POST
@ResponseParser(ParseImageFromGsonResponse.class)
@Query(key = "format", value = "json")
@ExceptionParser(ReturnImageNotFoundOn404.class)
@MapBinder(CreateImageBinder.class)
@Path("/images")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), serverCapacityUnavailable (503), overLimit
// (413), resizeNotAllowed (403), backupOrResizeInProgress (409)
Image createImageFromServer(@MapEntityParam("imageName") String imageName,
@MapEntityParam("serverId") int serverId);
/** /**
* *
* List shared IP groups (IDs and names only) * List shared IP groups (IDs and names only)
@ -381,6 +417,45 @@ public interface CloudServersConnection {
// (400) // (400)
boolean deleteSharedIpGroup(@PathParam("id") int id); boolean deleteSharedIpGroup(@PathParam("id") int id);
/**
* List the backup schedule for the specified server
*/
@GET
@ResponseParser(ParseBackupScheduleFromGsonResponse.class)
@Query(key = "format", value = "json")
@Path("/servers/{id}/backup_schedule")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), itemNotFound (404)
BackupSchedule listBackupSchedule(@PathParam("id") int serverId);
/**
* Delete backup schedule for the specified server.
* <p/>
* Web Hosting #119571 currently disables the schedule, not deletes it.
*
* @return false if the server is not found
*/
@DELETE
@ExceptionParser(ReturnFalseOn404.class)
@Path("/servers/{id}/backup_schedule")
// TODO:cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), buildInProgress (409), serverCapacityUnavailable (503), backupOrResizeInProgress(409)
boolean deleteBackupSchedule(@PathParam("id") int serverId);
/**
* Enable/update the backup schedule for the specified server
*
* @return false if the server is not found
*/
@POST
@ExceptionParser(ReturnFalseOn404.class)
@Path("/servers/{id}/backup_schedule")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), serverCapacityUnavailable (503),
// backupOrResizeInProgress(409), resizeNotAllowed (403). overLimit (413)
boolean replaceBackupSchedule(@PathParam("id") int id,
@EntityParam(BackupScheduleBinder.class) BackupSchedule backupSchedule);
/** /**
* List all server addresses * List all server addresses
*/ */

View File

@ -0,0 +1,55 @@
/**
*
* 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 com.google.common.base.Preconditions.checkArgument;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.binders.JsonBinder;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
import com.google.common.collect.ImmutableMap;
/**
*
* @author Adrian Cole
*
*/
public class BackupScheduleBinder extends JsonBinder {
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
throw new IllegalStateException(
"Replace Backup Schedule needs an BackupSchedule object, not a Map");
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
checkArgument(toBind instanceof BackupSchedule,
"this binder is only valid for BackupSchedules!");
super.addEntityToRequest(ImmutableMap.of("backupSchedule", toBind), request);
}
}

View File

@ -0,0 +1,66 @@
/**
*
* 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 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 CreateImageBinder extends JsonBinder {
@SuppressWarnings("unused")
private class CreateImageRequest {
final int serverId;
final String name;
private CreateImageRequest(int serverId, String name) {
this.serverId = serverId;
this.name = name;
}
}
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
CreateImageRequest createRequest = new CreateImageRequest(Integer
.parseInt(checkNotNull(postParams.get("serverId"))), checkNotNull(postParams
.get("imageName")));
super.addEntityToRequest(ImmutableMap.of("image", createRequest), request);
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
throw new IllegalArgumentException("image is needs parameters");
}
}

View File

@ -30,10 +30,18 @@ package org.jclouds.rackspace.cloudservers.domain;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class BackupSchedule { public class BackupSchedule {
protected DailyBackup daily = DailyBackup.DISABLED;
protected DailyBackup daily;
protected boolean enabled; protected boolean enabled;
protected String weekly; protected WeeklyBackup weekly = WeeklyBackup.DISABLED;
public BackupSchedule() {
}
public BackupSchedule(WeeklyBackup weekly, DailyBackup daily, boolean enabled) {
this.weekly = weekly;
this.daily = daily;
this.enabled = enabled;
}
public DailyBackup getDaily() { public DailyBackup getDaily() {
return daily; return daily;
@ -51,12 +59,51 @@ public class BackupSchedule {
this.enabled = value; this.enabled = value;
} }
public String getWeekly() { public WeeklyBackup getWeekly() {
return weekly; return weekly;
} }
public void setWeekly(String value) { public void setWeekly(WeeklyBackup value) {
this.weekly = value; this.weekly = value;
} }
@Override
public String toString() {
return "BackupSchedule [daily=" + daily + ", enabled=" + enabled + ", weekly=" + weekly + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((daily == null) ? 0 : daily.hashCode());
result = prime * result + (enabled ? 1231 : 1237);
result = prime * result + ((weekly == null) ? 0 : weekly.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;
BackupSchedule other = (BackupSchedule) obj;
if (daily == null) {
if (other.daily != null)
return false;
} else if (!daily.equals(other.daily))
return false;
if (enabled != other.enabled)
return false;
if (weekly == null) {
if (other.weekly != null)
return false;
} else if (!weekly.equals(other.weekly))
return false;
return true;
}
} }

View File

@ -25,6 +25,23 @@ package org.jclouds.rackspace.cloudservers.domain;
import org.jclouds.http.HttpMethod; import org.jclouds.http.HttpMethod;
/**
*
* RateLimit.
* <p/>
* we specify rate limits in terms of both a human readable wild-card URI and a machine processable
* regular expression. The regular expression boundary matcher '^' takes affect after the root URI
* path. For example, the regular expression ^/servers would match the bolded portion of the
* following URI: https://servers.api.rackspacecloud.com/v1.0/3542812 /servers .
* <p/>
* Rate limits are applied in order relative to the verb, going from least to most specific. For
* example, although the threshold for POST to /servers is 25 per day, one cannot POST to /servers
* more than 10 times within a single minute because the rate limits for any POST is 10/min. In the
* event you exceed the thresholds established for your account, a 413 Rate Control HTTP response
* will be returned with a Reply-After header to notify the client when theyagain.
*
* @author Adrian Cole
*/
public class RateLimit { public class RateLimit {
private final String uri; private final String uri;

View File

@ -0,0 +1,39 @@
/**
*
* 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.domain;
public enum WeeklyBackup {
DISABLED, SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
public String value() {
return name();
}
public static WeeklyBackup fromValue(String v) {
return valueOf(v);
}
}

View File

@ -0,0 +1,60 @@
/**
*
* 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 org.jclouds.http.functions.ParseJson;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
import com.google.gson.Gson;
import com.google.inject.Inject;
/**
* This parses {@link BackupSchedule} from a gson string.
*
* @author Adrian Cole
*/
public class ParseBackupScheduleFromGsonResponse extends ParseJson<BackupSchedule> {
@Inject
public ParseBackupScheduleFromGsonResponse(Gson gson) {
super(gson);
}
private static class BackupScheduleResponse {
BackupSchedule backupSchedule;
}
public BackupSchedule apply(InputStream stream) {
try {
return gson.fromJson(new InputStreamReader(stream, "UTF-8"), BackupScheduleResponse.class).backupSchedule;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
}
}

View File

@ -42,11 +42,15 @@ import java.util.Map;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
import org.jclouds.rackspace.cloudservers.domain.DailyBackup;
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.Image;
import org.jclouds.rackspace.cloudservers.domain.ImageStatus;
import org.jclouds.rackspace.cloudservers.domain.Server; import org.jclouds.rackspace.cloudservers.domain.Server;
import org.jclouds.rackspace.cloudservers.domain.ServerStatus; import org.jclouds.rackspace.cloudservers.domain.ServerStatus;
import org.jclouds.rackspace.cloudservers.domain.SharedIpGroup; import org.jclouds.rackspace.cloudservers.domain.SharedIpGroup;
import org.jclouds.rackspace.cloudservers.domain.WeeklyBackup;
import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshConnection; import org.jclouds.ssh.SshConnection;
import org.jclouds.ssh.SshException; import org.jclouds.ssh.SshException;
@ -303,10 +307,10 @@ public class CloudServersConnectionLiveTest {
adminPass = server.getAdminPass(); adminPass = server.getAdminPass();
ip = server.getAddresses().getPublicAddresses().iterator().next(); ip = server.getAddresses().getPublicAddresses().iterator().next();
assertEquals(server.getStatus(), ServerStatus.BUILD); assertEquals(server.getStatus(), ServerStatus.BUILD);
blockUntilActive(serverId); blockUntilServerActive(serverId);
} }
private void blockUntilActive(int serverId) throws InterruptedException { private void blockUntilServerActive(int serverId) throws InterruptedException {
Server currentDetails = null; Server currentDetails = null;
for (currentDetails = connection.getServer(serverId); currentDetails.getStatus() != ServerStatus.ACTIVE; currentDetails = connection for (currentDetails = connection.getServer(serverId); currentDetails.getStatus() != ServerStatus.ACTIVE; currentDetails = connection
.getServer(serverId)) { .getServer(serverId)) {
@ -320,6 +324,15 @@ public class CloudServersConnectionLiveTest {
Thread.sleep(10 * 1000); Thread.sleep(10 * 1000);
} }
private void blockUntilImageActive(int imageId) throws InterruptedException {
Image currentDetails = null;
for (currentDetails = connection.getImage(imageId); currentDetails.getStatus() != ImageStatus.ACTIVE; currentDetails = connection
.getImage(imageId)) {
System.out.printf("blocking on status active%n%s%n", currentDetails);
Thread.sleep(5 * 1000);
}
}
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer") @Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer")
public void testServerDetails() throws Exception { public void testServerDetails() throws Exception {
Server server = connection.getServer(serverId); Server server = connection.getServer(serverId);
@ -342,8 +355,7 @@ public class CloudServersConnectionLiveTest {
// check metadata // check metadata
assertEquals(server.getMetadata(), metadata); assertEquals(server.getMetadata(), metadata);
// [Web Hosting #119335] ssh timeouts after server changes status to ACTIVE checkPassOk(server, adminPass);
// checkPassOk(server, adminPass);
} }
/** /**
@ -392,14 +404,14 @@ public class CloudServersConnectionLiveTest {
Server server = connection.getServer(serverId); Server server = connection.getServer(serverId);
String oldName = server.getName(); String oldName = server.getName();
assertTrue(connection.renameServer(serverId, oldName + "new")); assertTrue(connection.renameServer(serverId, oldName + "new"));
blockUntilActive(serverId); blockUntilServerActive(serverId);
assertEquals(oldName + "new", connection.getServer(serverId).getName()); assertEquals(oldName + "new", connection.getServer(serverId).getName());
} }
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer") @Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServer")
public void testChangePassword() throws Exception { public void testChangePassword() throws Exception {
assertTrue(connection.changeAdminPass(serverId, "elmo")); assertTrue(connection.changeAdminPass(serverId, "elmo"));
blockUntilActive(serverId); blockUntilServerActive(serverId);
checkPassOk(connection.getServer(serverId), "elmo"); checkPassOk(connection.getServer(serverId), "elmo");
this.adminPass = "elmo"; this.adminPass = "elmo";
} }
@ -425,7 +437,7 @@ public class CloudServersConnectionLiveTest {
assertNotNull(server.getAdminPass()); assertNotNull(server.getAdminPass());
serverId2 = server.getId(); serverId2 = server.getId();
adminPass2 = server.getAdminPass(); adminPass2 = server.getAdminPass();
blockUntilActive(serverId2); blockUntilServerActive(serverId2);
assertIpConfigured(server, adminPass2); assertIpConfigured(server, adminPass2);
assert server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses() assert server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses()
+ " doesn't contain " + ip; + " doesn't contain " + ip;
@ -447,7 +459,7 @@ public class CloudServersConnectionLiveTest {
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServerIp") @Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateServerIp")
public void testUnshare() throws Exception { public void testUnshare() throws Exception {
connection.unshareIp(ip, serverId2); connection.unshareIp(ip, serverId2);
blockUntilActive(serverId2); blockUntilServerActive(serverId2);
Server server = connection.getServer(serverId2); Server server = connection.getServer(serverId2);
assert !server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses(); assert !server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses();
assertIpNotConfigured(server, adminPass2); assertIpNotConfigured(server, adminPass2);
@ -468,7 +480,7 @@ public class CloudServersConnectionLiveTest {
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testUnshare") @Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testUnshare")
public void testShareConfig() throws Exception { public void testShareConfig() throws Exception {
connection.shareIp(ip, serverId2, sharedIpGroupId, true); connection.shareIp(ip, serverId2, sharedIpGroupId, true);
blockUntilActive(serverId2); blockUntilServerActive(serverId2);
Server server = connection.getServer(serverId2); Server server = connection.getServer(serverId2);
assert server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses(); assert server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses();
assertIpConfigured(server, adminPass2); assertIpConfigured(server, adminPass2);
@ -478,15 +490,37 @@ public class CloudServersConnectionLiveTest {
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testShareConfig") @Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testShareConfig")
public void testShareNoConfig() throws Exception { public void testShareNoConfig() throws Exception {
connection.shareIp(ip, serverId2, sharedIpGroupId, false); connection.shareIp(ip, serverId2, sharedIpGroupId, false);
blockUntilActive(serverId2); blockUntilServerActive(serverId2);
Server server = connection.getServer(serverId2); Server server = connection.getServer(serverId2);
assert server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses(); assert server.getAddresses().getPublicAddresses().contains(ip) : server.getAddresses();
assertIpNotConfigured(server, adminPass2); assertIpNotConfigured(server, adminPass2);
testUnshare(); testUnshare();
} }
// must be last!. do not rely on positional order.
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testShareNoConfig") @Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testShareNoConfig")
public void testBackup() throws Exception {
assertEquals(new BackupSchedule(), connection.listBackupSchedule(serverId));
BackupSchedule dailyWeekly = new BackupSchedule();
dailyWeekly.setEnabled(true);
dailyWeekly.setWeekly(WeeklyBackup.FRIDAY);
dailyWeekly.setDaily(DailyBackup.H_0400_0600);
assertEquals(true, connection.replaceBackupSchedule(serverId, dailyWeekly));
connection.deleteBackupSchedule(serverId);
// disables, doesn't delete: Web Hosting #119571
assertEquals(connection.listBackupSchedule(serverId).isEnabled(), false);
}
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testBackup")
public void testCreateImage() throws Exception {
Image image = connection.createImageFromServer("hoofie", serverId);
assertEquals("hoofie", image.getName());
assertEquals(new Integer(serverId), image.getServerId());
int imageId = image.getId();
blockUntilImageActive(imageId);
}
// must be last!. do not rely on positional order.
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateImage")
void deleteServers() { void deleteServers() {
if (serverId > 0) { if (serverId > 0) {
connection.deleteServer(serverId); connection.deleteServer(serverId);

View File

@ -49,7 +49,11 @@ import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.ReturnFalseOn404; import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.http.functions.ReturnTrueIf2xx; import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.rackspace.Authentication; import org.jclouds.rackspace.Authentication;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
import org.jclouds.rackspace.cloudservers.domain.DailyBackup;
import org.jclouds.rackspace.cloudservers.domain.WeeklyBackup;
import org.jclouds.rackspace.cloudservers.functions.ParseAddressesFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseAddressesFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseBackupScheduleFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseFlavorFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseFlavorListFromGsonResponse;
import org.jclouds.rackspace.cloudservers.functions.ParseImageFromGsonResponse; import org.jclouds.rackspace.cloudservers.functions.ParseImageFromGsonResponse;
@ -467,6 +471,41 @@ public class CloudServersConnectionTest {
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class); assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
} }
public void testReplaceBackupSchedule() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("replaceBackupSchedule", int.class,
BackupSchedule.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { 2,
new BackupSchedule(WeeklyBackup.MONDAY, DailyBackup.H_0800_1000, true) });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/servers/2/backup_schedule");
assertEquals(httpMethod.getMethod(), HttpMethod.POST);
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(
"{\"backupSchedule\":{\"daily\":\"H_0800_1000\",\"enabled\":true,\"weekly\":\"MONDAY\"}}",
httpMethod.getEntity());
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnFalseOn404.class);
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
}
public void testDeleteBackupSchedule() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("deleteBackupSchedule", 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(), "/servers/2/backup_schedule");
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 { public void testChangeAdminPass() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("changeAdminPass", int.class, Method method = CloudServersConnection.class.getMethod("changeAdminPass", int.class,
String.class); String.class);
@ -679,6 +718,41 @@ public class CloudServersConnectionTest {
ParseInetAddressListFromGsonResponse.class); ParseInetAddressListFromGsonResponse.class);
} }
public void testListBackupSchedule() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("listBackupSchedule", 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(), "/servers/2/backup_schedule");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method).getClass(),
ParseBackupScheduleFromGsonResponse.class);
}
public void testCreateImageWithIpGroup() throws SecurityException, NoSuchMethodException {
Method method = CloudServersConnection.class.getMethod("createImageFromServer", String.class,
int.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "ralphie",
2 });
assertEquals("{\"image\":{\"serverId\":2,\"name\":\"ralphie\"}}", httpMethod.getEntity());
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/images");
assertEquals(httpMethod.getEndpoint().getQuery(), "format=json");
assertEquals(httpMethod.getMethod(), HttpMethod.POST);
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(processor.createResponseParser(method).getClass(),
ParseImageFromGsonResponse.class);
assertNotNull(processor.createExceptionParserOrNullIfNotFound(method));
assertNotNull(processor.getMapEntityBinderOrNull(method, new Object[] { "", 2 }));
}
JaxrsAnnotationProcessor processor; JaxrsAnnotationProcessor processor;
@BeforeClass @BeforeClass

View File

@ -0,0 +1,75 @@
/**
*
* 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.CreateImageBinder;
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 CreateImageBinder}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudservers.CreateImageBinderTest")
public class CreateImageBinderTest {
Injector injector = Guice.createInjector(new ParserModule());
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeMap() {
CreateImageBinder binder = new CreateImageBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("/"));
binder.addEntityToRequest(new File("foo"), request);
}
@Test
public void testCorrect() {
CreateImageBinder binder = new CreateImageBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("/"));
binder.addEntityToRequest(ImmutableMap.of("imageName", "foo", "serverId", "2"), request);
assertEquals("{\"image\":{\"serverId\":2,\"name\":\"foo\"}}", request.getEntity());
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() {
CreateImageBinder binder = new CreateImageBinder();
injector.injectMembers(binder);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("/"));
binder.addEntityToRequest(null, request);
}
}

View File

@ -0,0 +1,70 @@
/**
*
* 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 org.apache.commons.io.IOUtils;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
import org.jclouds.rackspace.cloudservers.domain.DailyBackup;
import org.jclouds.rackspace.cloudservers.domain.WeeklyBackup;
import org.testng.annotations.Test;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseBackupScheduleFromGsonResponse}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudservers.ParseBackupScheduleFromGsonResponseTest")
public class ParseBackupScheduleFromGsonResponseTest {
Injector i = Guice.createInjector(new ParserModule());
public void testApplyInputStreamDetails() throws UnknownHostException {
InputStream is = getClass().getResourceAsStream("/test_list_backupschedule.json");
ParseBackupScheduleFromGsonResponse parser = new ParseBackupScheduleFromGsonResponse(i
.getInstance(Gson.class));
BackupSchedule response = parser.apply(is);
assertEquals(new BackupSchedule(WeeklyBackup.THURSDAY, DailyBackup.H_0400_0600, true),
response);
}
public void testNoSchedule() throws UnknownHostException {
ParseBackupScheduleFromGsonResponse parser = new ParseBackupScheduleFromGsonResponse(i
.getInstance(Gson.class));
BackupSchedule response = parser.apply(IOUtils
.toInputStream("{\"backupSchedule\":{\"enabled\" : false}}"));
assertEquals(new BackupSchedule(), response);
}
}

View File

@ -0,0 +1,7 @@
{
"backupSchedule" : {
"enabled" : true,
"weekly" : "THURSDAY",
"daily" : "H_0400_0600"
}
}