mirror of https://github.com/apache/jclouds.git
Issue 165: compute service now works in gogrid
This commit is contained in:
parent
0612e5e1ba
commit
9ff4f84783
|
@ -37,6 +37,7 @@ import org.jclouds.rest.annotations.SkipEncoding;
|
|||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.slicehost.binders.BindCreateBackupToXmlPayload;
|
||||
import org.jclouds.slicehost.binders.BindCreateSliceToXmlPayload;
|
||||
import org.jclouds.slicehost.domain.Backup;
|
||||
import org.jclouds.slicehost.domain.Flavor;
|
||||
|
@ -194,11 +195,12 @@ public interface SlicehostAsyncClient {
|
|||
ListenableFuture<Backup> getBackup(@PathParam("id") int id);
|
||||
|
||||
/**
|
||||
* @see SlicehostClient#createBackupFromSlice
|
||||
* @see BackuphostClient#createBackup
|
||||
*/
|
||||
@PUT
|
||||
@Path("/backups.xml")
|
||||
@POST
|
||||
@Path("/slices.xml")
|
||||
@MapBinder(BindCreateBackupToXmlPayload.class)
|
||||
@XMLResponseParser(BackupHandler.class)
|
||||
ListenableFuture<Backup> createBackupFromSlice(@QueryParam("slice_id") int sliceId);
|
||||
ListenableFuture<Backup> createBackup(@MapPayloadParam("name") String name, @MapPayloadParam("slice_id") int sliceId);
|
||||
|
||||
}
|
||||
|
|
|
@ -73,6 +73,6 @@ public interface SlicehostClient {
|
|||
|
||||
Backup getBackup(int id);
|
||||
|
||||
Backup createBackupFromSlice(int sliceId);
|
||||
Backup createBackup(String name, int sliceId);
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ public class SlicehostPropertiesBuilder extends PropertiesBuilder {
|
|||
protected Properties defaultProperties() {
|
||||
Properties properties = super.defaultProperties();
|
||||
properties.setProperty(PROPERTY_ENDPOINT, "https://api.slicehost.com");
|
||||
properties.setProperty(PROPERTY_API_VERSION, "1.0");
|
||||
properties.setProperty(PROPERTY_API_VERSION, "1.4.1.1");
|
||||
properties.setProperty("jclouds.ssh.max_retries", "8");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.slicehost.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.MapBinder;
|
||||
import org.jclouds.rest.binders.BindToStringPayload;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class BindCreateBackupToXmlPayload implements MapBinder {
|
||||
private final BindToStringPayload binder;
|
||||
|
||||
@Inject
|
||||
BindCreateBackupToXmlPayload(BindToStringPayload binder) {
|
||||
this.binder = binder;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Map<String, String> postParams) {
|
||||
String sliceId = checkNotNull(postParams.get("slice_id"), "slice_id");
|
||||
String name = checkNotNull(postParams.get("name"), "name");
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><backup>");
|
||||
builder.append("<slice-id type=\"integer\">").append(sliceId).append("</slice-id>");
|
||||
builder.append("<name>").append(name).append("</name>");
|
||||
builder.append("</backup>");
|
||||
binder.bindToRequest(request, builder.toString());
|
||||
request.getPayload().setContentType(MediaType.APPLICATION_XML);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindToRequest(HttpRequest request, Object input) {
|
||||
throw new UnsupportedOperationException("should use map params");
|
||||
}
|
||||
}
|
|
@ -122,8 +122,8 @@ public class SlicehostComputeServiceContextModule extends AbstractModule {
|
|||
@Provides
|
||||
@Named("NAMING_CONVENTION")
|
||||
@Singleton
|
||||
String provideNamingConvention(@Named(Constants.PROPERTY_IDENTITY) String identity) {
|
||||
return identity + "-%s-%s";
|
||||
String provideNamingConvention() {
|
||||
return "%s-%s";
|
||||
}
|
||||
|
||||
@Singleton
|
||||
|
@ -275,8 +275,8 @@ public class SlicehostComputeServiceContextModule extends AbstractModule {
|
|||
holder.logger.debug(">> providing sizes");
|
||||
for (final Flavor from : sync.listFlavors()) {
|
||||
sizes.add(new SizeImpl(from.getId() + "", from.getName(), from.getId() + "", location, null, ImmutableMap
|
||||
.<String, String> of(), from.getRam() / 1024.0, from.getRam(), (from.getRam() * 4) / 1024, ImagePredicates
|
||||
.any()));
|
||||
.<String, String> of(), from.getRam() / 1024.0, from.getRam(), (from.getRam() * 4) / 1024,
|
||||
ImagePredicates.any()));
|
||||
}
|
||||
holder.logger.debug("<< sizes(%d)", sizes.size());
|
||||
return sizes;
|
||||
|
|
|
@ -46,8 +46,7 @@ import com.google.common.collect.Iterables;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class SliceToNodeMetadata implements Function<Slice, NodeMetadata> {
|
||||
public static final Pattern SECOND_FIELD_DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX = Pattern
|
||||
.compile("[^-]+-([^-]+)-[0-9a-f]+");
|
||||
public static final Pattern DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX = Pattern.compile("([^-]+)-[0-9a-f]+");
|
||||
private final Location location;
|
||||
private final Map<Slice.Status, NodeState> sliceToNodeState;
|
||||
private final Set<? extends Image> images;
|
||||
|
@ -56,18 +55,15 @@ public class SliceToNodeMetadata implements Function<Slice, NodeMetadata> {
|
|||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private static class FindImageForSlice implements Predicate<Image> {
|
||||
private final Location location;
|
||||
private final Slice instance;
|
||||
private final Slice slice;
|
||||
|
||||
private FindImageForSlice(Location location, Slice instance) {
|
||||
this.location = location;
|
||||
this.instance = instance;
|
||||
private FindImageForSlice(Slice slice) {
|
||||
this.slice = slice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Image input) {
|
||||
return input.getProviderId().equals(instance.getImageId() + "")
|
||||
&& (input.getLocation() == null || input.getLocation().equals(location.getParent()));
|
||||
return input.getProviderId().equals(slice.getImageId() + "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,11 +77,11 @@ public class SliceToNodeMetadata implements Function<Slice, NodeMetadata> {
|
|||
|
||||
@Override
|
||||
public NodeMetadata apply(Slice from) {
|
||||
Matcher matcher = SECOND_FIELD_DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX.matcher(from.getName());
|
||||
Matcher matcher = DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX.matcher(from.getName());
|
||||
final String tag = matcher.find() ? matcher.group(1) : null;
|
||||
Image image = null;
|
||||
try {
|
||||
image = Iterables.find(images, new FindImageForSlice(location, from));
|
||||
image = Iterables.find(images, new FindImageForSlice(from));
|
||||
} catch (NoSuchElementException e) {
|
||||
logger.warn("could not find a matching image for slice %s in location %s", from, location);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,9 @@ public class ParseSlicehostErrorFromHttpResponse implements HttpErrorHandler {
|
|||
exception = new ResourceNotFoundException(message);
|
||||
}
|
||||
break;
|
||||
case 422:
|
||||
exception = new IllegalStateException(content);
|
||||
break;
|
||||
default:
|
||||
exception = new HttpResponseException(command, response, content);
|
||||
}
|
||||
|
@ -100,7 +103,8 @@ public class ParseSlicehostErrorFromHttpResponse implements HttpErrorHandler {
|
|||
}
|
||||
|
||||
String parseErrorFromContentOrNull(HttpCommand command, HttpResponse response) {
|
||||
if (response.getPayload() != null) {
|
||||
// slicehost returns " " which is unparsable
|
||||
if (response.getPayload() != null && response.getPayload().getContentLength() != 1) {
|
||||
return errorParser.parse(response.getPayload());
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
|
|||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.slicehost.filters.SlicehostBasic;
|
||||
import org.jclouds.slicehost.xml.BackupHandler;
|
||||
import org.jclouds.slicehost.xml.FlavorHandler;
|
||||
import org.jclouds.slicehost.xml.FlavorsHandler;
|
||||
import org.jclouds.slicehost.xml.ImageHandler;
|
||||
|
@ -251,6 +252,25 @@ public class SlicehostAsyncClientTest extends RestClientTest<SlicehostAsyncClien
|
|||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testCreateBackup() throws IOException, SecurityException, NoSuchMethodException {
|
||||
Method method = SlicehostAsyncClient.class.getMethod("createBackup", String.class, int.class);
|
||||
HttpRequest request = processor.createRequest(method, "ralphie", 2);
|
||||
|
||||
assertRequestLineEquals(request, "POST https://api.slicehost.com/slices.xml HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><backup><slice-id type=\"integer\">2</slice-id><name>ralphie</name></backup>",
|
||||
"application/xml", false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, BackupHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
checkFilters(request);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeLiteral<RestAnnotationProcessor<SlicehostAsyncClient>> createTypeLiteral() {
|
||||
return new TypeLiteral<RestAnnotationProcessor<SlicehostAsyncClient>>() {
|
||||
|
|
|
@ -203,7 +203,7 @@ public class SlicehostClientLiveTest {
|
|||
private String rootPassword;
|
||||
private int backupId;
|
||||
|
||||
@Test(enabled = false)
|
||||
@Test(enabled = true)
|
||||
public void testCreateSlice() throws Exception {
|
||||
int imageId = 14362;
|
||||
int flavorId = 1;
|
||||
|
@ -235,7 +235,7 @@ public class SlicehostClientLiveTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test(enabled = false, timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateSlice")
|
||||
@Test(enabled = true, timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateSlice")
|
||||
public void testSliceDetails() throws Exception {
|
||||
Slice slice = client.getSlice(sliceId);
|
||||
assertEquals(slice.getStatus(), Slice.Status.ACTIVE);
|
||||
|
@ -285,9 +285,9 @@ public class SlicehostClientLiveTest {
|
|||
return ip;
|
||||
}
|
||||
|
||||
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testSliceDetails")
|
||||
@Test(enabled = true, timeOut = 10 * 60 * 1000, dependsOnMethods = "testSliceDetails")
|
||||
public void testCreateBackup() throws Exception {
|
||||
Backup backup = client.createBackupFromSlice(sliceId);
|
||||
Backup backup = client.createBackup("hoofie", sliceId);
|
||||
// TODO validate our request, as the above returns <nil-classes
|
||||
// type="array"/>
|
||||
assertEquals("hoofie", backup.getName());
|
||||
|
@ -295,7 +295,7 @@ public class SlicehostClientLiveTest {
|
|||
backupId = backup.getId();
|
||||
}
|
||||
|
||||
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testCreateBackup")
|
||||
@Test(enabled = true, timeOut = 10 * 60 * 1000, dependsOnMethods = "testCreateBackup")
|
||||
public void testRebuildSlice() throws Exception {
|
||||
client.rebuildSliceFromBackup(sliceId, backupId);
|
||||
blockUntilSliceActive(sliceId);
|
||||
|
@ -304,19 +304,19 @@ public class SlicehostClientLiveTest {
|
|||
// client.getSlice(sliceId).getImageId());
|
||||
}
|
||||
|
||||
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebuildSlice")
|
||||
@Test(enabled = true, timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebuildSlice")
|
||||
public void testRebootHard() throws Exception {
|
||||
client.hardRebootSlice(sliceId);
|
||||
blockUntilSliceActive(sliceId);
|
||||
}
|
||||
|
||||
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootHard")
|
||||
@Test(enabled = true, timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootHard")
|
||||
public void testRebootSoft() throws Exception {
|
||||
client.rebootSlice(sliceId);
|
||||
blockUntilSliceActive(sliceId);
|
||||
}
|
||||
|
||||
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootSoft")
|
||||
@Test(enabled = true, timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootSoft")
|
||||
void testDeleteBackup() {
|
||||
if (backupId > 0) {
|
||||
client.destroyBackup(backupId);
|
||||
|
@ -324,7 +324,7 @@ public class SlicehostClientLiveTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testDeleteBackup")
|
||||
@Test(enabled = true, timeOut = 10 * 60 * 1000, dependsOnMethods = "testDeleteBackup")
|
||||
void destroySlice1() {
|
||||
if (sliceId > 0) {
|
||||
client.destroySlice(sliceId);
|
||||
|
|
|
@ -21,18 +21,14 @@ package org.jclouds.slicehost.compute;
|
|||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jclouds.compute.BaseComputeServiceLiveTest;
|
||||
import org.jclouds.compute.ComputeServiceContextFactory;
|
||||
import org.jclouds.compute.domain.Architecture;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.slicehost.SlicehostAsyncClient;
|
||||
import org.jclouds.slicehost.SlicehostClient;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
@ -68,15 +64,7 @@ public class SlicehostComputeServiceLiveTest extends BaseComputeServiceLiveTest
|
|||
|
||||
public void testAssignability() throws Exception {
|
||||
@SuppressWarnings("unused")
|
||||
RestContext<SlicehostClient, SlicehostAsyncClient> tmContext = new ComputeServiceContextFactory()
|
||||
.createContext(provider, identity, credential).getProviderSpecificContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkNodes(Iterable<? extends NodeMetadata> nodes, String tag) throws IOException {
|
||||
super.checkNodes(nodes, tag);
|
||||
for (NodeMetadata node : nodes) {
|
||||
assertEquals(node.getLocation().getScope(), LocationScope.HOST);
|
||||
}
|
||||
RestContext<SlicehostClient, SlicehostAsyncClient> tmContext = new ComputeServiceContextFactory().createContext(
|
||||
provider, identity, credential).getProviderSpecificContext();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<slices type="array">
|
||||
<slice>
|
||||
<name>slicehost-1</name>
|
||||
<image-id type="integer">50</image-id>
|
||||
<addresses type="array">
|
||||
<address>10.179.78.86</address>
|
||||
<address>173.203.51.27</address>
|
||||
</addresses>
|
||||
<progress type="integer">100</progress>
|
||||
<id type="integer">281343</id>
|
||||
<bw-out type="float">0.0</bw-out>
|
||||
<bw-in type="float">0.07</bw-in>
|
||||
<flavor-id type="integer">1</flavor-id>
|
||||
<status>active</status>
|
||||
<ip-address>10.179.78.86</ip-address>
|
||||
</slice>
|
||||
<slice>
|
||||
<name>slicehost-602</name>
|
||||
<image-id type="integer">50</image-id>
|
||||
<addresses type="array">
|
||||
<address>10.179.78.89</address>
|
||||
<address>173.203.51.32</address>
|
||||
</addresses>
|
||||
<progress type="integer">100</progress>
|
||||
<id type="integer">281347</id>
|
||||
<bw-out type="float">0.0</bw-out>
|
||||
<bw-in type="float">0.07</bw-in>
|
||||
<flavor-id type="integer">1</flavor-id>
|
||||
<status>active</status>
|
||||
<ip-address>10.179.78.89</ip-address>
|
||||
</slice>
|
||||
<slice>
|
||||
<name>slicehostblock-a7</name>
|
||||
<image-id type="integer">50</image-id>
|
||||
<addresses type="array">
|
||||
<address>10.179.78.91</address>
|
||||
<address>173.203.51.33</address>
|
||||
</addresses>
|
||||
<progress type="integer">100</progress>
|
||||
<id type="integer">281357</id>
|
||||
<bw-out type="float">0.0</bw-out>
|
||||
<bw-in type="float">0.0</bw-in>
|
||||
<flavor-id type="integer">1</flavor-id>
|
||||
<status>build</status>
|
||||
<ip-address>10.179.78.91</ip-address>
|
||||
</slice>
|
||||
</slices>
|
Loading…
Reference in New Issue