Issue 164: initial commit for slicehost. note this is not complete

This commit is contained in:
Adrian Cole 2010-07-26 02:38:18 -07:00
parent 7d1e4ff514
commit d120b139fc
42 changed files with 3689 additions and 0 deletions

View File

@ -47,6 +47,9 @@ ec2.propertiesbuilder=org.jclouds.aws.ec2.EC2PropertiesBuilder
rimuhosting.contextbuilder=org.jclouds.rimuhosting.miro.RimuHostingContextBuilder rimuhosting.contextbuilder=org.jclouds.rimuhosting.miro.RimuHostingContextBuilder
rimuhosting.propertiesbuilder=org.jclouds.rimuhosting.miro.RimuHostingPropertiesBuilder rimuhosting.propertiesbuilder=org.jclouds.rimuhosting.miro.RimuHostingPropertiesBuilder
slicehost.contextbuilder=org.jclouds.slicehost.SlicehostContextBuilder
slicehost.propertiesbuilder=org.jclouds.slicehost.SlicehostPropertiesBuilder
trmk-vcloudexpress.contextbuilder=org.jclouds.vcloud.terremark.TerremarkVCloudExpressContextBuilder trmk-vcloudexpress.contextbuilder=org.jclouds.vcloud.terremark.TerremarkVCloudExpressContextBuilder
trmk-vcloudexpress.propertiesbuilder=org.jclouds.vcloud.terremark.TerremarkVCloudExpressPropertiesBuilder trmk-vcloudexpress.propertiesbuilder=org.jclouds.vcloud.terremark.TerremarkVCloudExpressPropertiesBuilder

77
slicehost/pom.xml Normal file
View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath>
</parent>
<artifactId>jclouds-slicehost</artifactId>
<name>jclouds slicehost components</name>
<properties>
<jclouds.test.identity>${jclouds.slicehost.apikey}</jclouds.test.identity>
<jclouds.test.credential>${jclouds.slicehost.apikey}</jclouds.test.credential>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-jsch</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,204 @@
/**
*
* 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;
import java.util.Set;
import java.util.concurrent.ExecutionException;
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 javax.ws.rs.QueryParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.MapPayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
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.BindCreateSliceToXmlPayload;
import org.jclouds.slicehost.domain.Backup;
import org.jclouds.slicehost.domain.Flavor;
import org.jclouds.slicehost.domain.Image;
import org.jclouds.slicehost.domain.Slice;
import org.jclouds.slicehost.filters.SlicehostBasic;
import org.jclouds.slicehost.xml.BackupHandler;
import org.jclouds.slicehost.xml.BackupsHandler;
import org.jclouds.slicehost.xml.FlavorHandler;
import org.jclouds.slicehost.xml.FlavorsHandler;
import org.jclouds.slicehost.xml.ImageHandler;
import org.jclouds.slicehost.xml.ImagesHandler;
import org.jclouds.slicehost.xml.SliceHandler;
import org.jclouds.slicehost.xml.SlicesHandler;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Slicehost via their REST API.
* <p/>
* All commands return a ListenableFuture of the result from Slicehost. Any
* exceptions incurred during processing will be wrapped in an
* {@link ExecutionException} as documented in {@link ListenableFuture#get()}.
*
* @see SlicehostClient
* @see <a href="http://www.slicehost.com/docs/Slicehost_API.pdf" />
* @author Adrian Cole
*/
@SkipEncoding( { '/', '=' })
@RequestFilters(SlicehostBasic.class)
public interface SlicehostAsyncClient {
/**
* @see SlicehostClient#listSlices
*/
@GET
@Path("/slices.xml")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(SlicesHandler.class)
ListenableFuture<? extends Set<Slice>> listSlices();
/**
* @see SlicehostClient#getSlice
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("/slices/{id}.xml")
@XMLResponseParser(SliceHandler.class)
ListenableFuture<Slice> getSlice(@PathParam("id") int id);
/**
* @see SlicehostClient#destroySlice
*/
@DELETE
@Path("/slices/{id}/destroy.xml")
ListenableFuture<Void> destroySlice(@PathParam("id") int id);
/**
* @see SlicehostClient#rebootSlice
*/
@PUT
@Path("/slices/{id}/reboot.xml")
ListenableFuture<Void> rebootSlice(@PathParam("id") int id);
/**
* @see SlicehostClient#hardRebootSlice
*/
@PUT
@Path("/slices/{id}/hardReboot.xml")
ListenableFuture<Void> hardRebootSlice(@PathParam("id") int id);
/**
* @see SlicehostClient#createSlice
*/
@POST
@Path("/slices.xml")
@MapBinder(BindCreateSliceToXmlPayload.class)
@XMLResponseParser(SliceHandler.class)
ListenableFuture<Slice> createSlice(@MapPayloadParam("name") String name, @MapPayloadParam("image_id") int imageId,
@MapPayloadParam("flavor_id") int flavorId);
/**
* @see SlicehostClient#rebuildSliceFromImage
*/
@PUT
@Path("/slices/{id}/rebuild.xml")
ListenableFuture<Void> rebuildSliceFromImage(@PathParam("id") int id, @QueryParam("image_id") int imageId);
/**
* @see SlicehostClient#rebuildSliceFromBackup
*/
@PUT
@Path("/slices/{id}/rebuild.xml")
ListenableFuture<Void> rebuildSliceFromBackup(@PathParam("id") int id, @QueryParam("backup_id") int imageId);
/**
* @see SlicehostClient#listFlavors
*/
@GET
@Path("/flavors.xml")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(FlavorsHandler.class)
ListenableFuture<? extends Set<Flavor>> listFlavors();
/**
* @see SlicehostClient#getFlavor
*/
@GET
@Path("/flavors/{id}.xml")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@XMLResponseParser(FlavorHandler.class)
ListenableFuture<Flavor> getFlavor(@PathParam("id") int id);
/**
* @see SlicehostClient#listImages
*/
@GET
@Path("/images.xml")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(ImagesHandler.class)
ListenableFuture<? extends Set<Image>> listImages();
/**
* @see SlicehostClient#getImage
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("/images/{id}.xml")
@XMLResponseParser(ImageHandler.class)
ListenableFuture<Image> getImage(@PathParam("id") int id);
/**
* @see SlicehostClient#destroyBackup
*/
@DELETE
@Path("/backups/{id}/destroy.xml")
ListenableFuture<Void> destroyBackup(@PathParam("id") int id);
/**
* @see SlicehostClient#listBackups
*/
@GET
@Path("/backups.xml")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(BackupsHandler.class)
ListenableFuture<? extends Set<Backup>> listBackups();
/**
* @see SlicehostClient#getBackup
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("/backups/{id}.xml")
@XMLResponseParser(BackupHandler.class)
ListenableFuture<Backup> getBackup(@PathParam("id") int id);
/**
* @see SlicehostClient#createBackupFromSlice
*/
@PUT
@Path("/backups.xml")
@XMLResponseParser(BackupHandler.class)
ListenableFuture<Backup> createBackupFromSlice(@QueryParam("slice_id") int sliceId);
}

View File

@ -0,0 +1,78 @@
/**
*
* 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;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.slicehost.domain.Backup;
import org.jclouds.slicehost.domain.Flavor;
import org.jclouds.slicehost.domain.Image;
import org.jclouds.slicehost.domain.Slice;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides access to Slicehost via their REST API.
* <p/>
* All commands return a ListenableFuture of the result from Slicehost. Any
* exceptions incurred during processing will be wrapped in an
* {@link ExecutionException} as documented in {@link ListenableFuture#get()}.
*
* @see SlicehostAsyncClient
* @see <a href="http://www.slicehost.com/docs/Slicehost_API.pdf" />
* @author Adrian Cole
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface SlicehostClient {
Set<Slice> listSlices();
Slice getSlice(int id);
Void destroySlice(int id);
Void rebootSlice(int id);
Void hardRebootSlice(int id);
Slice createSlice(String name, int imageId, int flavorId);
Void rebuildSliceFromImage(int id, int imageId);
Void rebuildSliceFromBackup(int id, int imageId);
Set<Flavor> listFlavors();
Flavor getFlavor(int id);
Set<Image> listImages();
Image getImage(int id);
Void destroyBackup(int id);
Set<Backup> listBackups();
Backup getBackup(int id);
Backup createBackupFromSlice(int sliceId);
}

View File

@ -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;
import java.util.List;
import java.util.Properties;
import org.jclouds.compute.ComputeServiceContextBuilder;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.slicehost.compute.config.SlicehostComputeServiceContextModule;
import org.jclouds.slicehost.config.SlicehostRestClientModule;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Creates {@link SlicehostComputeServiceContext} or {@link Injector} instances based on the most
* commonly requested arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole
* @see SlicehostComputeServiceContext
*/
public class SlicehostContextBuilder extends
ComputeServiceContextBuilder<SlicehostClient, SlicehostAsyncClient> {
public SlicehostContextBuilder(Properties props) {
super(SlicehostClient.class, SlicehostAsyncClient.class, props);
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new SlicehostComputeServiceContextModule());
}
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new SlicehostRestClientModule());
}
}

View File

@ -0,0 +1,46 @@
/**
*
* 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;
import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import java.util.Properties;
import org.jclouds.PropertiesBuilder;
/**
* Builds properties used in Slicehost Connections
*
* @author Adrian Cole
*/
public class SlicehostPropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ENDPOINT, "https://api.slicehost.com");
properties.setProperty(PROPERTY_API_VERSION, "1.0");
return properties;
}
public SlicehostPropertiesBuilder(Properties properties) {
super(properties);
}
}

View File

@ -0,0 +1,65 @@
/**
*
* 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 BindCreateSliceToXmlPayload implements MapBinder {
private final BindToStringPayload binder;
@Inject
BindCreateSliceToXmlPayload(BindToStringPayload binder) {
this.binder = binder;
}
public void bindToRequest(HttpRequest request, Map<String, String> postParams) {
String flavorId = checkNotNull(postParams.get("flavor_id"), "flavor_id");
String imageId = checkNotNull(postParams.get("image_id"), "image_id");
String name = checkNotNull(postParams.get("name"), "name");
StringBuilder builder = new StringBuilder();
builder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><slice>");
builder.append("<flavor-id type=\"integer\">").append(flavorId).append("</flavor-id>");
builder.append("<image-id type=\"integer\">").append(imageId).append("</image-id>");
builder.append("<name>").append(name).append("</name>");
builder.append("</slice>");
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");
}
}

View File

@ -0,0 +1,333 @@
/**
*
* 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.compute.config;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.domain.OsFamily.UBUNTU;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.LoadBalancerService;
import org.jclouds.compute.config.ComputeServiceTimeoutsModule;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.ImageImpl;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.compute.internal.BaseComputeService;
import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.predicates.ImagePredicates;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.DestroyNodeStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.logging.Logger;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.annotations.Provider;
import org.jclouds.rest.internal.RestContextImpl;
import org.jclouds.slicehost.SlicehostAsyncClient;
import org.jclouds.slicehost.SlicehostClient;
import org.jclouds.slicehost.compute.functions.SliceToNodeMetadata;
import org.jclouds.slicehost.domain.Flavor;
import org.jclouds.slicehost.domain.Slice;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Providers;
/**
* Configures the {@link SlicehostComputeServiceContext}; requires
* {@link BaseComputeService} bound.
*
* @author Adrian Cole
*/
public class SlicehostComputeServiceContextModule extends AbstractModule {
@Override
protected void configure() {
install(new ComputeServiceTimeoutsModule());
bind(new TypeLiteral<Function<Slice, NodeMetadata>>() {
}).to(SliceToNodeMetadata.class);
bind(LoadBalancerService.class).toProvider(Providers.<LoadBalancerService> of(null));
bind(new TypeLiteral<ComputeServiceContext>() {
}).to(new TypeLiteral<ComputeServiceContextImpl<SlicehostClient, SlicehostAsyncClient>>() {
}).in(Scopes.SINGLETON);
bind(new TypeLiteral<RestContext<SlicehostClient, SlicehostAsyncClient>>() {
}).to(new TypeLiteral<RestContextImpl<SlicehostClient, SlicehostAsyncClient>>() {
}).in(Scopes.SINGLETON);
bind(AddNodeWithTagStrategy.class).to(SlicehostAddNodeWithTagStrategy.class);
bind(ListNodesStrategy.class).to(SlicehostListNodesStrategy.class);
bind(GetNodeMetadataStrategy.class).to(SlicehostGetNodeMetadataStrategy.class);
bind(RebootNodeStrategy.class).to(SlicehostRebootNodeStrategy.class);
bind(DestroyNodeStrategy.class).to(SlicehostDestroyNodeStrategy.class);
}
@Provides
@Named("DEFAULT")
protected TemplateBuilder provideTemplate(TemplateBuilder template) {
return template.osFamily(UBUNTU).imageNameMatches(".*10\\.?04.*");
}
@Provides
@Named("NAMING_CONVENTION")
@Singleton
String provideNamingConvention(@Named(Constants.PROPERTY_IDENTITY) String identity) {
return identity + "-%s-%s";
}
@Singleton
public static class SlicehostRebootNodeStrategy implements RebootNodeStrategy {
private final SlicehostClient client;
private final GetNodeMetadataStrategy getNode;
@Inject
protected SlicehostRebootNodeStrategy(SlicehostClient client, GetNodeMetadataStrategy getNode) {
this.client = client;
this.getNode = getNode;
}
@Override
public NodeMetadata execute(String id) {
int sliceId = Integer.parseInt(id);
client.hardRebootSlice(sliceId);
return getNode.execute(id);
}
}
@Singleton
public static class SlicehostDestroyNodeStrategy implements DestroyNodeStrategy {
private final SlicehostClient client;
private final GetNodeMetadataStrategy getNode;
@Inject
protected SlicehostDestroyNodeStrategy(SlicehostClient client, GetNodeMetadataStrategy getNode) {
this.client = client;
this.getNode = getNode;
}
@Override
public NodeMetadata execute(String id) {
int sliceId = Integer.parseInt(id);
// if false slice wasn't around in the first place
client.destroySlice(sliceId);
return getNode.execute(id);
}
}
@Singleton
public static class SlicehostAddNodeWithTagStrategy implements AddNodeWithTagStrategy {
private final SlicehostClient client;
@Inject
protected SlicehostAddNodeWithTagStrategy(SlicehostClient client) {
this.client = checkNotNull(client, "client");
}
@Override
public NodeMetadata execute(String tag, String name, Template template) {
Slice slice = client.createSlice(name, Integer.parseInt(template.getImage().getProviderId()), Integer
.parseInt(template.getSize().getProviderId()));
return new NodeMetadataImpl(slice.getId() + "", name, slice.getId() + "", template.getLocation(), null,
ImmutableMap.<String, String> of(), tag, template.getImage(), NodeState.PENDING, Iterables.filter(slice
.getAddresses(), new Predicate<String>() {
@Override
public boolean apply(String input) {
return !input.startsWith("10.");
}
}), Iterables.filter(slice.getAddresses(), new Predicate<String>() {
@Override
public boolean apply(String input) {
return input.startsWith("10.");
}
}), ImmutableMap.<String, String> of(), new Credentials("root", slice.getRootPassword()));
}
}
@Singleton
public static class SlicehostListNodesStrategy implements ListNodesStrategy {
private final SlicehostClient client;
private final Function<Slice, NodeMetadata> sliceToNodeMetadata;
@Inject
protected SlicehostListNodesStrategy(SlicehostClient client, Function<Slice, NodeMetadata> sliceToNodeMetadata) {
this.client = client;
this.sliceToNodeMetadata = sliceToNodeMetadata;
}
@Override
public Iterable<? extends ComputeMetadata> list() {
return listDetailsOnNodesMatching(NodePredicates.all());
}
@Override
public Iterable<? extends NodeMetadata> listDetailsOnNodesMatching(Predicate<ComputeMetadata> filter) {
return Iterables.filter(Iterables.transform(client.listSlices(), sliceToNodeMetadata), filter);
}
}
@Singleton
public static class SlicehostGetNodeMetadataStrategy implements GetNodeMetadataStrategy {
private final SlicehostClient client;
private final Function<Slice, NodeMetadata> sliceToNodeMetadata;
@Inject
protected SlicehostGetNodeMetadataStrategy(SlicehostClient client,
Function<Slice, NodeMetadata> sliceToNodeMetadata) {
this.client = client;
this.sliceToNodeMetadata = sliceToNodeMetadata;
}
@Override
public NodeMetadata execute(String id) {
int sliceId = Integer.parseInt(id);
Slice slice = client.getSlice(sliceId);
return slice == null ? null : sliceToNodeMetadata.apply(slice);
}
}
@Singleton
@Provides
Map<Slice.Status, NodeState> provideSliceToNodeState() {
return ImmutableMap.<Slice.Status, NodeState> builder().put(Slice.Status.ACTIVE, NodeState.RUNNING)//
.put(Slice.Status.BUILD, NodeState.PENDING)//
.put(Slice.Status.REBOOT, NodeState.PENDING)//
.put(Slice.Status.HARD_REBOOT, NodeState.PENDING)//
.put(Slice.Status.TERMINATED, NodeState.TERMINATED)//
.build();
}
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getProviderId();
}
};
}
@Provides
@Singleton
protected Set<? extends Size> provideSizes(SlicehostClient sync, Set<? extends Image> images, Location location,
LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
Function<ComputeMetadata, String> indexer) throws InterruptedException, TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet();
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()));
}
holder.logger.debug("<< sizes(%d)", sizes.size());
return sizes;
}
private static class LogHolder {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
}
public static final Pattern SLICEHOST_PATTERN = Pattern.compile("(([^ ]*) .*)");
@Provides
@Singleton
Location getLocation(@Provider String name) {
return new LocationImpl(LocationScope.PROVIDER, name, name, null);
}
@Provides
@Singleton
Set<? extends Location> provideLocations(Location location) {
return ImmutableSet.of(location);
}
@Provides
@Singleton
protected Set<? extends Image> provideImages(final SlicehostClient sync, Location location, LogHolder holder,
Function<ComputeMetadata, String> indexer) throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
for (final org.jclouds.slicehost.domain.Image from : sync.listImages()) {
OsFamily os = null;
Architecture arch = Architecture.X86_64;
String osDescription = "";
String version = "";
Matcher matcher = SLICEHOST_PATTERN.matcher(from.getName());
osDescription = from.getName();
if (matcher.find()) {
try {
os = OsFamily.fromValue(matcher.group(2).toLowerCase());
} catch (IllegalArgumentException e) {
holder.logger.debug("<< didn't match os(%s)", matcher.group(2));
}
}
images
.add(new ImageImpl(from.getId() + "", from.getName(), from.getId() + "", location, null, ImmutableMap
.<String, String> of(), from.getName(), version, os, osDescription, arch, new Credentials("root",
null)));
}
holder.logger.debug("<< images(%d)", images.size());
return images;
}
}

View File

@ -0,0 +1,111 @@
/**
*
* 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.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import org.jclouds.slicehost.domain.Slice;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
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]+");
private final Location location;
private final Map<Slice.Status, NodeState> sliceToNodeState;
private final Set<? extends Image> images;
@Resource
protected Logger logger = Logger.NULL;
private static class FindImageForSlice implements Predicate<Image> {
private final Location location;
private final Slice instance;
private FindImageForSlice(Location location, Slice instance) {
this.location = location;
this.instance = instance;
}
@Override
public boolean apply(Image input) {
return input.getProviderId().equals(instance.getImageId() + "")
&& (input.getLocation() == null || input.getLocation().equals(location.getParent()));
}
}
@Inject
SliceToNodeMetadata(Map<Slice.Status, NodeState> sliceStateToNodeState, Set<? extends Image> images,
Location location) {
this.sliceToNodeState = checkNotNull(sliceStateToNodeState, "sliceStateToNodeState");
this.images = checkNotNull(images, "images");
this.location = checkNotNull(location, "location");
}
@Override
public NodeMetadata apply(Slice from) {
Matcher matcher = SECOND_FIELD_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));
} catch (NoSuchElementException e) {
logger.warn("could not find a matching image for slice %s in location %s", from, location);
}
return new NodeMetadataImpl(from.getId() + "", from.getName(), from.getId() + "", location, null, ImmutableMap
.<String, String> of(), tag, image, sliceToNodeState.get(from.getStatus()), Iterables.filter(from
.getAddresses(), new Predicate<String>() {
@Override
public boolean apply(String input) {
return !input.startsWith("10.");
}
}), Iterables.filter(from.getAddresses(), new Predicate<String>() {
@Override
public boolean apply(String input) {
return input.startsWith("10.");
}
}), ImmutableMap.<String, String> of(), null);
}
}

View File

@ -0,0 +1,51 @@
/**
*
* 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.config;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.slicehost.SlicehostAsyncClient;
import org.jclouds.slicehost.SlicehostClient;
import org.jclouds.slicehost.handlers.ParseSlicehostErrorFromHttpResponse;
/**
*
* @author Adrian Cole
*/
@ConfiguresRestClient
@RequiresHttp
public class SlicehostRestClientModule extends RestClientModule<SlicehostClient, SlicehostAsyncClient> {
public SlicehostRestClientModule() {
super(SlicehostClient.class, SlicehostAsyncClient.class);
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseSlicehostErrorFromHttpResponse.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseSlicehostErrorFromHttpResponse.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseSlicehostErrorFromHttpResponse.class);
}
}

View File

@ -0,0 +1,115 @@
/**
*
* 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.domain;
import java.util.Date;
/**
*
*
* @author Adrian Cole
*/
public class Backup {
private final int id;
private final String name;
private final String sliceId;
private final Date date;
public Backup(int id, String name, String sliceId, Date date) {
this.id = id;
this.name = name;
this.sliceId = sliceId;
this.date = date;
}
/**
* @return id of the backup
*/
public int getId() {
return id;
}
/**
* @return Examples: weekly, my snapshot
*/
public String getName() {
return name;
}
/**
* @return The Slice this backup was made from
*/
public String getSliceId() {
return sliceId;
}
/**
* @return The time the backup was taken
*/
public Date getDate() {
return date;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((date == null) ? 0 : date.hashCode());
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((sliceId == null) ? 0 : sliceId.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;
Backup other = (Backup) obj;
if (date == null) {
if (other.date != null)
return false;
} else if (!date.equals(other.date))
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sliceId == null) {
if (other.sliceId != null)
return false;
} else if (!sliceId.equals(other.sliceId))
return false;
return true;
}
@Override
public String toString() {
return "[date=" + date + ", id=" + id + ", name=" + name + ", sliceId=" + sliceId + "]";
}
}

View File

@ -0,0 +1,109 @@
/**
*
* 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.domain;
/**
*
* A flavor is an available hardware configuration for a slice.
*
* @author Adrian Cole
*/
public class Flavor {
private final int id;
private final String name;
private final int price;
private final int ram;
public Flavor(int id, String name, int price, int ram) {
this.id = id;
this.name = name;
this.price = price;
this.ram = ram;
}
/**
* @return id of the flavor
*/
public int getId() {
return id;
}
/**
* @return Verbose name for the flavor, e.g. Ò256 sliceÓ
*/
public String getName() {
return name;
}
/**
* @return The price as an integer of cents. For example: 2000 equals $20.00.
* Note that all prices are in USD
*/
public int getPrice() {
return price;
}
/**
* @return The amount of RAM (in Megabytes) included with the plan
*/
public int getRam() {
return ram;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + Float.floatToIntBits(price);
result = prime * result + ram;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Flavor other = (Flavor) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Float.floatToIntBits(price) != Float.floatToIntBits(other.price))
return false;
if (ram != other.ram)
return false;
return true;
}
@Override
public String toString() {
return "[id=" + id + ", name=" + name + ", price=" + price + ", ram=" + ram + "]";
}
}

View File

@ -0,0 +1,85 @@
/**
*
* 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.domain;
/**
*
*
* @author Adrian Cole
*/
public class Image {
private final int id;
private final String name;
public Image(int id, String name) {
this.id = id;
this.name = name;
}
/**
* @return id of the image
*/
public int getId() {
return id;
}
/**
* @return Example: Ubuntu 8.04 LTS (hardy)
*/
public String getName() {
return name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Image other = (Image) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "[id=" + id + ", name=" + name + "]";
}
}

View File

@ -0,0 +1,249 @@
/**
*
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.base.CaseFormat;
/**
* A slice is a virtual machine instance in the Slicehost system. Flavor and
* image are requisite elements when creating a slice.
*
* @author Adrian Cole
*/
public class Slice {
/**
* The current status of the slice
*
*/
public enum Status {
ACTIVE, BUILD, REBOOT, HARD_REBOOT, TERMINATED;
public String value() {
return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_UNDERSCORE, name()));
}
@Override
public String toString() {
return value();
}
public static Status fromValue(String state) {
return valueOf(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(state, "state")));
}
}
private final int id;
private final String name;
private final int flavorId;
@Nullable
private final Integer imageId;
@Nullable
private final Integer backupId;
private final Status status;
@Nullable
private final Integer progress;
private final float bandwidthIn;
private final float bandwidthOut;
private final Set<String> addresses;
@Nullable
private final String rootPassword;
public Slice(int id, String name, int flavorId, @Nullable Integer imageId, @Nullable Integer backupId,
Status status, @Nullable Integer progress, float bandwidthIn, float bandwidthOut, Set<String> addresses,
@Nullable String rootPassword) {
this.id = id;
this.name = name;
this.flavorId = flavorId;
this.imageId = imageId;
this.backupId = backupId;
this.status = status;
this.progress = progress;
this.bandwidthIn = bandwidthIn;
this.bandwidthOut = bandwidthOut;
this.addresses = addresses;
this.rootPassword = rootPassword;
}
/**
* @return unique id within slicehost
*/
public int getId() {
return id;
}
/**
* @return A string to identify the slice
*/
public String getName() {
return name;
}
/**
* @return the flavor of a slice
*/
public int getFlavorId() {
return flavorId;
}
/**
* @return the image used to create the slice or null
*/
public Integer getImageId() {
return imageId;
}
/**
* @return The current status of the slice
*/
public Status getStatus() {
return status;
}
/**
* @return The percentage of current action in percentage
*/
public Integer getProgress() {
return progress;
}
/**
* @return The incoming bandwidth total for this billing cycle, in Gigabytes
*/
public float getBandwidthIn() {
return bandwidthIn;
}
/**
* @return The outgoing bandwidth total for this billing cycle, in Gigabytes
*/
public float getBandwidthOut() {
return bandwidthOut;
}
/**
* @return an array of strings representing the Slice's IPs, including
* private IPs
*/
public Set<String> getAddresses() {
return addresses;
}
/**
* @return root password, if just created
*/
public String getRootPassword() {
return rootPassword;
}
/**
* @return backup used to create this instance or null
*/
public Integer getBackupId() {
return backupId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((addresses == null) ? 0 : addresses.hashCode());
result = prime * result + ((backupId == null) ? 0 : backupId.hashCode());
result = prime * result + Float.floatToIntBits(bandwidthIn);
result = prime * result + Float.floatToIntBits(bandwidthOut);
result = prime * result + flavorId;
result = prime * result + id;
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((progress == null) ? 0 : progress.hashCode());
result = prime * result + ((rootPassword == null) ? 0 : rootPassword.hashCode());
result = prime * result + ((status == null) ? 0 : status.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;
Slice other = (Slice) obj;
if (addresses == null) {
if (other.addresses != null)
return false;
} else if (!addresses.equals(other.addresses))
return false;
if (backupId == null) {
if (other.backupId != null)
return false;
} else if (!backupId.equals(other.backupId))
return false;
if (Float.floatToIntBits(bandwidthIn) != Float.floatToIntBits(other.bandwidthIn))
return false;
if (Float.floatToIntBits(bandwidthOut) != Float.floatToIntBits(other.bandwidthOut))
return false;
if (flavorId != other.flavorId)
return false;
if (id != other.id)
return false;
if (imageId == null) {
if (other.imageId != null)
return false;
} else if (!imageId.equals(other.imageId))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (progress == null) {
if (other.progress != null)
return false;
} else if (!progress.equals(other.progress))
return false;
if (rootPassword == null) {
if (other.rootPassword != null)
return false;
} else if (!rootPassword.equals(other.rootPassword))
return false;
if (status == null) {
if (other.status != null)
return false;
} else if (!status.equals(other.status))
return false;
return true;
}
@Override
public String toString() {
return "[id=" + id + ", name=" + name + ", flavorId=" + flavorId + ", imageId=" + imageId + ", backupId="
+ backupId + ", status=" + status + ", progress=" + progress + ", bandwidthIn=" + bandwidthIn
+ ", bandwidthOut=" + bandwidthOut + ", addresses=" + addresses + ", rootPassword="
+ (rootPassword != null) + "]";
}
}

View File

@ -0,0 +1,55 @@
/**
*
* 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.filters;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
/**
*
* @author Adrian Cole
*/
@Singleton
public class SlicehostBasic implements HttpRequestFilter {
private final String apikey;
private final EncryptionService encryptionService;
@Inject
public SlicehostBasic(@Named(Constants.PROPERTY_IDENTITY) String apikey, EncryptionService encryptionService) {
this.apikey = checkNotNull(apikey, "apikey");
this.encryptionService = checkNotNull(encryptionService, "encryptionService");
}
@Override
public void filter(HttpRequest request) throws HttpException {
request.getHeaders().replaceValues("Authorization",
Collections.singleton(String.format("Basic %s", encryptionService.base64(apikey.getBytes()))));
}
}

View File

@ -0,0 +1,108 @@
package org.jclouds.slicehost.handlers;
import static org.jclouds.http.HttpUtils.releasePayload;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ParseSax.Factory;
import org.jclouds.io.Payload;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.slicehost.xml.ErrorHandler;
/**
* This will parse and set an appropriate exception on the command object.
*
* @author Adrian Cole
*
*/
@Singleton
public class ParseSlicehostErrorFromHttpResponse implements HttpErrorHandler {
@Resource
protected Logger logger = Logger.NULL;
public static final Pattern RESOURCE_PATTERN = Pattern.compile("^/v1[^/]*/[0-9]+/([^/]+)/([0-9]+)");
private final ErrorParser errorParser;
@Inject
ParseSlicehostErrorFromHttpResponse(ErrorParser errorParser) {
this.errorParser = errorParser;
}
public void handleError(HttpCommand command, HttpResponse response) {
Exception exception = new HttpResponseException(command, response);
try {
String content = response.getStatusCode() != 401 ? parseErrorFromContentOrNull(command, response) : null;
switch (response.getStatusCode()) {
case 401:
exception = new AuthorizationException(command.getRequest(), content);
break;
case 403:
case 404:
if (!command.getRequest().getMethod().equals("DELETE")) {
String path = command.getRequest().getEndpoint().getPath();
Matcher matcher = RESOURCE_PATTERN.matcher(path);
String message;
if (matcher.find()) {
message = String.format("%s %s not found", matcher.group(1), matcher.group(2));
} else {
message = path;
}
exception = new ResourceNotFoundException(message);
}
break;
default:
exception = new HttpResponseException(command, response, content);
}
} finally {
releasePayload(response);
command.setException(exception);
}
}
@Singleton
static class ErrorParser {
final ParseSax.Factory factory;
final Provider<ErrorHandler> errorHandlerProvider;
@Resource
protected Logger logger = Logger.NULL;
@Inject
ErrorParser(Factory factory, Provider<ErrorHandler> errorHandlerProvider) {
this.factory = factory;
this.errorHandlerProvider = errorHandlerProvider;
}
String parse(Payload in) {
try {
return factory.create(errorHandlerProvider.get()).parse(in.getInput());
} catch (HttpException e) {
logger.warn(e, "error parsing error");
return null;
} finally {
in.release();
}
}
}
String parseErrorFromContentOrNull(HttpCommand command, HttpResponse response) {
if (response.getPayload() != null) {
return errorParser.parse(response.getPayload());
}
return null;
}
}

View File

@ -0,0 +1,46 @@
package org.jclouds.slicehost.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.slicehost.SlicehostClient;
import org.jclouds.slicehost.domain.Slice;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class SliceActive implements Predicate<Slice> {
private final SlicehostClient client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public SliceActive(SlicehostClient client) {
this.client = client;
}
public boolean apply(Slice slice) {
logger.trace("looking for state on slice %s", checkNotNull(slice, "slice"));
slice = refresh(slice);
if (slice == null)
return false;
logger.trace("%s: looking for slice state %s: currently: %s", slice.getId(), Slice.Status.ACTIVE, slice
.getStatus());
return slice.getStatus() == Slice.Status.ACTIVE;
}
private Slice refresh(Slice slice) {
return client.getSlice(slice.getId());
}
}

View File

@ -0,0 +1,45 @@
package org.jclouds.slicehost.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.slicehost.SlicehostClient;
import org.jclouds.slicehost.domain.Slice;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
* @author Adrian Cole
*/
@Singleton
public class SliceTerminated implements Predicate<Slice> {
private final SlicehostClient client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public SliceTerminated(SlicehostClient client) {
this.client = client;
}
public boolean apply(Slice slice) {
logger.trace("looking for state on slice %s", checkNotNull(slice, "slice"));
slice = refresh(slice);
if (slice == null)
return true;
logger.trace("%s: looking for slice state %s: currently: %s", slice.getId(), Slice.Status.TERMINATED, slice
.getStatus());
return slice.getStatus() == Slice.Status.TERMINATED;
}
private Slice refresh(Slice slice) {
return client.getSlice(slice.getId());
}
}

View File

@ -0,0 +1,78 @@
/**
*
* 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.xml;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import javax.annotation.Resource;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger;
import org.jclouds.slicehost.domain.Backup;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class BackupHandler extends ParseSax.HandlerWithResult<Backup> {
private StringBuilder currentText = new StringBuilder();
private int id;
private String name;
private String sliceId;
private Date date;
private Backup backup;
@Resource
protected Logger logger = Logger.NULL;
public Backup getResult() {
return backup;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("id")) {
id = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("name")) {
this.name = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("slice_id")) {
sliceId = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("date")) {
try {
date = DateFormat.getInstance().parse(currentText.toString().trim());
} catch (ParseException e) {
logger.warn(e, "error parsing: %s", currentText.toString().trim());
}
} else if (qName.equalsIgnoreCase("backup")) {
this.backup = new Backup(id, name, sliceId, date);
this.id = -1;
this.name = null;
this.sliceId = null;
this.date = null;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,68 @@
/**
*
* 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.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Backup;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
public class BackupsHandler extends ParseSax.HandlerWithResult<Set<? extends Backup>> {
private StringBuilder currentText = new StringBuilder();
private Set<Backup> backups = Sets.newLinkedHashSet();
private final BackupHandler locationHandler;
@Inject
public BackupsHandler(BackupHandler locationHandler) {
this.locationHandler = locationHandler;
}
public Set<? extends Backup> getResult() {
return backups;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
locationHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
locationHandler.endElement(uri, localName, qName);
if (qName.equals("backup") && currentText.toString().trim().equals("")) {
this.backups.add(locationHandler.getResult());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
locationHandler.characters(ch, start, length);
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,47 @@
/**
*
* 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.xml;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class ErrorHandler extends ParseSax.HandlerWithResult<String> {
private StringBuilder currentText = new StringBuilder();
private String error;
public String getResult() {
return error;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("error")) {
this.error = currentText.toString().trim();
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,65 @@
/**
*
* 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.xml;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Flavor;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class FlavorHandler extends ParseSax.HandlerWithResult<Flavor> {
private StringBuilder currentText = new StringBuilder();
private int id;
private String name;
private int price;
private int ram;
private Flavor flavor;
public Flavor getResult() {
return flavor;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("id")) {
id = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("name")) {
this.name = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("ram")) {
ram = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("price")) {
price = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("flavor")) {
this.flavor = new Flavor(id, name, price, ram);
this.id = -1;
this.name = null;
this.ram = -1;
this.price = 0;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,68 @@
/**
*
* 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.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Flavor;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
public class FlavorsHandler extends ParseSax.HandlerWithResult<Set<? extends Flavor>> {
private StringBuilder currentText = new StringBuilder();
private Set<Flavor> slices = Sets.newLinkedHashSet();
private final FlavorHandler locationHandler;
@Inject
public FlavorsHandler(FlavorHandler locationHandler) {
this.locationHandler = locationHandler;
}
public Set<? extends Flavor> getResult() {
return slices;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
locationHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
locationHandler.endElement(uri, localName, qName);
if (qName.equals("flavor") && currentText.toString().trim().equals("")) {
this.slices.add(locationHandler.getResult());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
locationHandler.characters(ch, start, length);
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,62 @@
/**
*
* 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.xml;
import javax.annotation.Resource;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger;
import org.jclouds.slicehost.domain.Image;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class ImageHandler extends ParseSax.HandlerWithResult<Image> {
private StringBuilder currentText = new StringBuilder();
private int id;
private String name;
private Image image;
@Resource
protected Logger logger = Logger.NULL;
public Image getResult() {
return image;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("id")) {
id = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("name")) {
this.name = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("image")) {
this.image = new Image(id, name);
this.id = -1;
this.name = null;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,68 @@
/**
*
* 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.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Image;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
public class ImagesHandler extends ParseSax.HandlerWithResult<Set<? extends Image>> {
private StringBuilder currentText = new StringBuilder();
private Set<Image> images = Sets.newLinkedHashSet();
private final ImageHandler locationHandler;
@Inject
public ImagesHandler(ImageHandler locationHandler) {
this.locationHandler = locationHandler;
}
public Set<? extends Image> getResult() {
return images;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
locationHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
locationHandler.endElement(uri, localName, qName);
if (qName.equals("image") && currentText.toString().trim().equals("")) {
this.images.add(locationHandler.getResult());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
locationHandler.characters(ch, start, length);
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,105 @@
/**
*
* 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.xml;
import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Slice;
import org.jclouds.slicehost.domain.Slice.Status;
import org.xml.sax.SAXException;
import com.google.inject.internal.Sets;
/**
* @author Adrian Cole
*/
public class SliceHandler extends ParseSax.HandlerWithResult<Slice> {
private StringBuilder currentText = new StringBuilder();
private int id;
private String name;
private int flavorId;
@Nullable
private Integer imageId;
@Nullable
private Integer backupId;
private Status status;
@Nullable
private Integer progress;
private float bandwidthIn;
private float bandwidthOut;
private Set<String> addresses = Sets.newLinkedHashSet();
@Nullable
private String rootPassword;
private Slice slice;
public Slice getResult() {
return slice;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("id")) {
id = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("name")) {
this.name = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("flavor-id")) {
flavorId = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("image-id")) {
imageId = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("backup-id")) {
backupId = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("status")) {
this.status = Slice.Status.fromValue(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("progress")) {
progress = Integer.parseInt(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("bw-in")) {
bandwidthIn = Float.parseFloat(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("bw-out")) {
bandwidthOut = Float.parseFloat(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("address")) {
this.addresses.add(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("root-password")) {
this.rootPassword = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("slice")) {
this.slice = new Slice(id, name, flavorId, imageId, backupId, status, progress, bandwidthIn, bandwidthOut,
addresses, rootPassword);
this.id = -1;
this.name = null;
this.flavorId = -1;
this.imageId = null;
this.backupId = null;
this.status = null;
this.progress = null;
this.bandwidthIn = 0;
this.bandwidthOut = 0;
this.addresses = Sets.newLinkedHashSet();
this.rootPassword = null;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,68 @@
/**
*
* 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.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Slice;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
public class SlicesHandler extends ParseSax.HandlerWithResult<Set<? extends Slice>> {
private StringBuilder currentText = new StringBuilder();
private Set<Slice> slices = Sets.newLinkedHashSet();
private final SliceHandler locationHandler;
@Inject
public SlicesHandler(SliceHandler locationHandler) {
this.locationHandler = locationHandler;
}
public Set<? extends Slice> getResult() {
return slices;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
locationHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
locationHandler.endElement(uri, localName, qName);
if (qName.equals("slice") && currentText.toString().trim().equals("")) {
this.slices.add(locationHandler.getResult());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
locationHandler.characters(ch, start, length);
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,46 @@
/**
*
* 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;
import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*
*/
@Test(groups = "unit")
public class ProvidersInPropertiesTest {
@Test
public void testSupportedComputeServiceProviders() {
Iterable<String> providers = ComputeServiceUtils.getSupportedProviders();
assert Iterables.contains(providers, "slicehost") : providers;
}
@Test
public void testSupportedProviders() {
Iterable<String> providers = Utils.getSupportedProviders();
assert Iterables.contains(providers, "slicehost") : providers;
}
}

View File

@ -0,0 +1,272 @@
/**
*
* 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;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
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.FlavorHandler;
import org.jclouds.slicehost.xml.FlavorsHandler;
import org.jclouds.slicehost.xml.ImageHandler;
import org.jclouds.slicehost.xml.ImagesHandler;
import org.jclouds.slicehost.xml.SliceHandler;
import org.jclouds.slicehost.xml.SlicesHandler;
import org.testng.annotations.Test;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code SlicehostClient}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "slicehost.SlicehostClientTest")
public class SlicehostAsyncClientTest extends RestClientTest<SlicehostAsyncClient> {
public void testCreateSlice() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("createSlice", String.class, int.class, int.class);
HttpRequest request = processor.createRequest(method, "ralphie", 2, 1);
assertRequestLineEquals(request, "POST https://api.slicehost.com/slices.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(
request,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><slice><flavor-id type=\"integer\">1</flavor-id><image-id type=\"integer\">2</image-id><name>ralphie</name></slice>",
"application/xml", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, SliceHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testDestroySlice() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("destroySlice", int.class);
HttpRequest request = processor.createRequest(method, 2);
assertRequestLineEquals(request, "DELETE https://api.slicehost.com/slices/2/destroy.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testListSlices() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("listSlices");
HttpRequest request = processor.createRequest(method);
assertRequestLineEquals(request, "GET https://api.slicehost.com/slices.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, SlicesHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testGetSlice() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("getSlice", int.class);
HttpRequest request = processor.createRequest(method, 2);
assertRequestLineEquals(request, "GET https://api.slicehost.com/slices/2.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, SliceHandler.class);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(request);
}
public void testListFlavors() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("listFlavors");
HttpRequest request = processor.createRequest(method);
assertRequestLineEquals(request, "GET https://api.slicehost.com/flavors.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, FlavorsHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testGetFlavor() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("getFlavor", int.class);
HttpRequest request = processor.createRequest(method, 2);
assertRequestLineEquals(request, "GET https://api.slicehost.com/flavors/2.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, FlavorHandler.class);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(request);
}
public void testListImages() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("listImages");
HttpRequest request = processor.createRequest(method);
assertRequestLineEquals(request, "GET https://api.slicehost.com/images.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, ImagesHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testGetImage() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("getImage", int.class);
HttpRequest request = processor.createRequest(method, 2);
assertRequestLineEquals(request, "GET https://api.slicehost.com/images/2.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, ImageHandler.class);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(request);
}
public void testDestroyBackup() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("destroyBackup", int.class);
HttpRequest request = processor.createRequest(method, 2);
assertRequestLineEquals(request, "DELETE https://api.slicehost.com/backups/2/destroy.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testRebuildSliceFromImage() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("rebuildSliceFromImage", int.class, int.class);
HttpRequest request = processor.createRequest(method, 3, 1);
assertRequestLineEquals(request, "PUT https://api.slicehost.com/slices/3/rebuild.xml?image_id=1 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testRebuildSliceFromBackup() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("rebuildSliceFromBackup", int.class, int.class);
HttpRequest request = processor.createRequest(method, 3, 1);
assertRequestLineEquals(request, "PUT https://api.slicehost.com/slices/3/rebuild.xml?backup_id=1 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testReboot() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("rebootSlice", int.class);
HttpRequest request = processor.createRequest(method, 2);
assertRequestLineEquals(request, "PUT https://api.slicehost.com/slices/2/reboot.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testHardReboot() throws IOException, SecurityException, NoSuchMethodException {
Method method = SlicehostAsyncClient.class.getMethod("hardRebootSlice", int.class);
HttpRequest request = processor.createRequest(method, 2);
assertRequestLineEquals(request, "PUT https://api.slicehost.com/slices/2/hardReboot.xml HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<SlicehostAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<SlicehostAsyncClient>>() {
};
}
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), SlicehostBasic.class);
}
@Override
public ContextSpec<SlicehostClient, SlicehostAsyncClient> createContextSpec() {
return new RestContextFactory().createContextSpec("slicehost", "apikey", null, new Properties());
}
}

View File

@ -0,0 +1,342 @@
/**
*
* 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;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.SecureRandom;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.http.HttpResponseException;
import org.jclouds.io.Payloads;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.slicehost.domain.Backup;
import org.jclouds.slicehost.domain.Flavor;
import org.jclouds.slicehost.domain.Image;
import org.jclouds.slicehost.domain.Slice;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Tests behavior of {@code SlicehostClient}
*
* @author Adrian Cole
*/
// disabled [Web Hosting #129069
@Test(groups = "live", sequential = true, testName = "slicehost.SlicehostClientLiveTest")
public class SlicehostClientLiveTest {
protected SlicehostClient client;
protected SshClient.Factory sshFactory;
private Predicate<IPSocket> socketTester;
@BeforeGroups(groups = { "live" })
public void setupClient() {
String identity = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity");
Injector injector = new RestContextFactory().createContextBuilder("slicehost", identity, null,
ImmutableSet.<Module> of(new Log4JLoggingModule(), new JschSshClientModule()), new Properties())
.buildInjector();
client = injector.getInstance(SlicehostClient.class);
sshFactory = injector.getInstance(SshClient.Factory.class);
SocketOpen socketOpen = injector.getInstance(SocketOpen.class);
socketTester = new RetryablePredicate<IPSocket>(socketOpen, 120, 1, TimeUnit.SECONDS);
injector.injectMembers(socketOpen); // add logger
}
public void testListSlices() throws Exception {
Set<Slice> response = client.listSlices();
assert null != response;
long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0);
}
public void testListSlicesDetail() throws Exception {
Set<Slice> response = client.listSlices();
assert null != response;
long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0);
}
public void testListImages() throws Exception {
Set<Image> response = client.listImages();
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 1);
for (Image image : response) {
assertTrue(image.getId() >= 0);
assert null != image.getName() : image;
}
}
public void testListImagesDetail() throws Exception {
Set<Image> response = client.listImages();
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 0);
for (Image image : response) {
assertTrue(image.getId() >= 1);
assert null != image.getName() : image;
}
}
public void testGetImagesDetail() throws Exception {
Set<Image> response = client.listImages();
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 0);
for (Image image : response) {
try {
Image newDetails = client.getImage(image.getId());
assertEquals(image, newDetails);
} catch (HttpResponseException e) {// Ticket #9867
if (e.getResponse().getStatusCode() != 400)
throw e;
}
}
}
@Test
public void testGetImageDetailsNotFound() throws Exception {
assert client.getImage(12312987) == null;
}
@Test
public void testGetSliceDetailsNotFound() throws Exception {
assert client.getSlice(12312987) == null;
}
public void testGetSlicesDetail() throws Exception {
Set<Slice> response = client.listSlices();
assert null != response;
long sliceCount = response.size();
assertTrue(sliceCount >= 0);
for (Slice slice : response) {
Slice newDetails = client.getSlice(slice.getId());
assertEquals(slice, newDetails);
}
}
public void testListFlavors() throws Exception {
Set<Flavor> response = client.listFlavors();
assert null != response;
long flavorCount = response.size();
assertTrue(flavorCount >= 1);
for (Flavor flavor : response) {
assertTrue(flavor.getId() >= 0);
assert null != flavor.getName() : flavor;
}
}
public void testListFlavorsDetail() throws Exception {
Set<Flavor> response = client.listFlavors();
assert null != response;
long flavorCount = response.size();
assertTrue(flavorCount >= 0);
for (Flavor flavor : response) {
assertTrue(flavor.getId() >= 1);
assert null != flavor.getName() : flavor;
assert -1 != flavor.getRam() : flavor;
}
}
public void testGetFlavorsDetail() throws Exception {
Set<Flavor> response = client.listFlavors();
assert null != response;
long flavorCount = response.size();
assertTrue(flavorCount >= 0);
for (Flavor flavor : response) {
Flavor newDetails = client.getFlavor(flavor.getId());
assertEquals(flavor, newDetails);
}
}
@Test
public void testGetFlavorDetailsNotFound() throws Exception {
assert client.getFlavor(12312987) == null;
}
private String slicePrefix = System.getProperty("user.name") + ".sh";
private int sliceId;
private String rootPassword;
private int backupId;
@Test(enabled = false)
public void testCreateSlice() throws Exception {
int imageId = 14362;
int flavorId = 1;
Slice slice = null;
while (slice == null) {
String sliceName = slicePrefix + "createslice" + new SecureRandom().nextInt();
try {
slice = client.createSlice(sliceName, imageId, flavorId);
} catch (UndeclaredThrowableException e) {
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
if (htpe.getResponse().getStatusCode() == 400)
continue;
throw e;
}
}
assertNotNull(slice.getRootPassword());
sliceId = slice.getId();
rootPassword = slice.getRootPassword();
assertEquals(slice.getStatus(), Slice.Status.BUILD);
blockUntilSliceActive(sliceId);
}
private void blockUntilSliceActive(int sliceId) throws InterruptedException {
Slice currentDetails = null;
for (currentDetails = client.getSlice(sliceId); currentDetails.getStatus() != Slice.Status.ACTIVE; currentDetails = client
.getSlice(sliceId)) {
System.out.printf("blocking on status active%n%s%n", currentDetails);
Thread.sleep(5 * 1000);
}
}
@Test(enabled = false, timeOut = 5 * 60 * 1000, dependsOnMethods = "testCreateSlice")
public void testSliceDetails() throws Exception {
Slice slice = client.getSlice(sliceId);
assertEquals(slice.getStatus(), Slice.Status.ACTIVE);
assert slice.getProgress() >= 0 : "newDetails.getProgress()" + slice.getProgress();
assertEquals(new Integer(14362), slice.getImageId());
assertEquals(1, slice.getFlavorId());
assertNotNull(slice.getAddresses());
checkPassOk(slice, rootPassword);
}
private void checkPassOk(Slice newDetails, String pass) throws IOException {
try {
doCreateMarkerFile(newDetails, pass);
} catch (SshException e) {// try twice in case there is a network timeout
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e1) {
}
doCreateMarkerFile(newDetails, pass);
}
}
private void doCreateMarkerFile(Slice newDetails, String pass) throws IOException {
String ip = getIp(newDetails);
IPSocket socket = new IPSocket(ip, 22);
socketTester.apply(socket);
SshClient client = sshFactory.create(socket, "root", pass);
try {
client.connect();
client.put("/etc/jclouds.txt", Payloads.newStringPayload("slicehost"));
} finally {
if (client != null)
client.disconnect();
}
}
private String getIp(Slice newDetails) {
String ip = Iterables.find(newDetails.getAddresses(), new Predicate<String>() {
@Override
public boolean apply(String input) {
return !input.startsWith("10.");
}
});
return ip;
}
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testSliceDetails")
public void testCreateBackup() throws Exception {
Backup backup = client.createBackupFromSlice(sliceId);
// TODO validate our request, as the above returns <nil-classes
// type="array"/>
assertEquals("hoofie", backup.getName());
assertEquals(new Integer(sliceId), backup.getSliceId());
backupId = backup.getId();
}
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testCreateBackup")
public void testRebuildSlice() throws Exception {
client.rebuildSliceFromBackup(sliceId, backupId);
blockUntilSliceActive(sliceId);
// issue Web Hosting #119580 imageId comes back incorrect after rebuild
// assertEquals(new Integer(imageId),
// client.getSlice(sliceId).getImageId());
}
@Test(enabled = false, 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")
public void testRebootSoft() throws Exception {
client.rebootSlice(sliceId);
blockUntilSliceActive(sliceId);
}
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testRebootSoft")
void testDeleteBackup() {
if (backupId > 0) {
client.destroyBackup(backupId);
assert client.getBackup(backupId) == null;
}
}
@Test(enabled = false, timeOut = 10 * 60 * 1000, dependsOnMethods = "testDeleteBackup")
void destroySlice1() {
if (sliceId > 0) {
client.destroySlice(sliceId);
assert client.getSlice(sliceId) == null;
}
}
@AfterTest
void destroySlicesOnEnd() {
if (sliceId > 0) {
client.destroySlice(sliceId);
}
}
}

View File

@ -0,0 +1,82 @@
/**
*
* 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.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.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;
/**
*
* Generally disabled, as it incurs higher fees.
*
* @author Adrian Cole
*/
@Test(groups = "live", enabled = true, sequential = true, testName = "slicehost.SlicehostComputeServiceLiveTest")
public class SlicehostComputeServiceLiveTest extends BaseComputeServiceLiveTest {
@BeforeClass
@Override
public void setServiceDefaults() {
provider = "slicehost";
}
@Test
public void testTemplateBuilder() {
Template defaultTemplate = client.templateBuilder().build();
assertEquals(defaultTemplate.getImage().getArchitecture(), Architecture.X86_64);
assertEquals(defaultTemplate.getImage().getOsFamily(), OsFamily.UBUNTU);
assertEquals(defaultTemplate.getLocation().getId(), "slicehost");
assertEquals(defaultTemplate.getSize().getCores(), 0.25d);
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
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);
}
}
}

View File

@ -0,0 +1,50 @@
/**
*
* 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.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Flavor;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code FlavorHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "slicehost.FlavorHandler")
public class FlavorHandlerTest extends BaseHandlerTest {
ParseSax<Flavor> createParser() {
ParseSax<Flavor> parser = (ParseSax<Flavor>) factory.create(injector.getInstance(FlavorHandler.class));
return parser;
}
public void test() {
InputStream is = getClass().getResourceAsStream("/test_get_flavor.xml");
Flavor expects = new Flavor(1, "256 slice", 2000, 256);
assertEquals(createParser().parse(is), expects);
}
}

View File

@ -0,0 +1,54 @@
/**
*
* 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.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.Set;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Flavor;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code FlavorsHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "slicehost.FlavorsHandler")
public class FlavorsHandlerTest extends BaseHandlerTest {
ParseSax<Set<? extends Flavor>> createParser() {
ParseSax<Set<? extends Flavor>> parser = (ParseSax<Set<? extends Flavor>>) factory.create(injector
.getInstance(FlavorsHandler.class));
return parser;
}
public void test() {
InputStream is = getClass().getResourceAsStream("/test_list_flavors.xml");
Set<? extends Flavor> expects = ImmutableSet.of(new Flavor(1, "256 slice", 2000, 256), new Flavor(2, "512 slice",
3800, 512), new Flavor(3, "1GB slice", 7000, 1024), new Flavor(4, "2GB slice", 13000, 2048));
assertEquals(createParser().parse(is), expects);
}
}

View File

@ -0,0 +1,62 @@
/**
*
* 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.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Slice;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code SliceHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "slicehost.SliceHandler")
public class SliceHandlerTest extends BaseHandlerTest {
ParseSax<Slice> createParser() {
ParseSax<Slice> parser = (ParseSax<Slice>) factory.create(injector.getInstance(SliceHandler.class));
return parser;
}
public void test() {
InputStream is = getClass().getResourceAsStream("/test_get_slice.xml");
Slice expects = new Slice(1, "jclouds-foo", 1, 10, null, Slice.Status.BUILD, 0, 0, 0, ImmutableSet.<String> of(
"174.143.212.229", "10.176.164.199"), null);
assertEquals(createParser().parse(is), expects);
}
public void testNew() {
InputStream is = getClass().getResourceAsStream("/test_new_slice.xml");
Slice expects = new Slice(71907, "slicetest", 1, 11, null, Slice.Status.BUILD, 0, 0, 0, ImmutableSet.<String> of(
"10.176.168.15", "67.23.20.114"), "fooadfa1231");
assertEquals(createParser().parse(is), expects);
}
}

View File

@ -0,0 +1,55 @@
/**
*
* 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.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.Set;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.slicehost.domain.Slice;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code SlicesHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "slicehost.SlicesHandler")
public class SlicesHandlerTest extends BaseHandlerTest {
ParseSax<Set<? extends Slice>> createParser() {
ParseSax<Set<? extends Slice>> parser = (ParseSax<Set<? extends Slice>>) factory.create(injector
.getInstance(SlicesHandler.class));
return parser;
}
public void test() {
InputStream is = getClass().getResourceAsStream("/test_get_slice.xml");
Set<? extends Slice> expects = ImmutableSet.of(new Slice(1, "jclouds-foo", 1, 10, null, Slice.Status.BUILD, 0, 0,
0, ImmutableSet.<String> of("174.143.212.229", "10.176.164.199"), null));
assertEquals(createParser().parse(is), expects);
}
}

View File

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache
Log4j website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
<!-- A time/date based rolling appender -->
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-wire.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="COMPUTEFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-compute.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="COMPUTEFILE" />
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="WIREFILE" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
<category name="jclouds.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.wire">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.compute">
<priority value="TRACE" />
<appender-ref ref="ASYNCCOMPUTE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<errors>
<error>Slice parameters are not properly nested</error>
</errors>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<flavor>
<id type="integer">1</id>
<name>256 slice</name>
<price type="integer">2000</price>
<ram type="integer">256</ram>
</flavor>

View File

@ -0,0 +1,17 @@
<slices type="array">
<slice>
<name>jclouds-foo</name>
<image-id type="integer">10</image-id>
<addresses type="array">
<address>174.143.212.229</address>
<address>10.176.164.199</address>
</addresses>
<progress type="integer">0</progress>
<id type="integer">1</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>174.143.212.229</ip-address>
</slice>
</slices>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<flavors type="array">
<flavor>
<id type="integer">1</id>
<name>256 slice</name>
<price type="integer">2000</price>
<ram type="integer">256</ram>
</flavor>
<flavor>
<id type="integer">2</id>
<name>512 slice</name>
<price type="integer">3800</price>
<ram type="integer">512</ram>
</flavor>
<flavor>
<id type="integer">3</id>
<name>1GB slice</name>
<price type="integer">7000</price>
<ram type="integer">1024</ram>
</flavor>
<flavor>
<id type="integer">4</id>
<name>2GB slice</name>
<price type="integer">13000</price>
<ram type="integer">2048</ram>
</flavor>
</flavors>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<images type="array">
<image>
<name>CentOS 5.2</name>
<id type="integer">2</id>
</image>
<image>
<name>Gentoo 2008.0</name>
<id type="integer">3</id>
</image>
<image>
<name>Debian 5.0 (lenny)</name>
<id type="integer">4</id>
</image>
<image>
<name>Fedora 10 (Cambridge)</name>
<id type="integer">5</id>
</image>
<image>
<name>CentOS 5.3</name>
<id type="integer">7</id>
</image>
<image>
<name>Ubuntu 9.04 (jaunty)</name>
<id type="integer">8</id>
</image>
<image>
<name>Arch 2009.02</name>
<id type="integer">9</id>
</image>
<image>
<name>Ubuntu 8.04.2 LTS (hardy)</name>
<id type="integer">10</id>
</image>
<image>
<name>Ubuntu 8.10 (intrepid)</name>
<id type="integer">11</id>
</image>
<image>
<name>Red Hat EL 5.3</name>
<id type="integer">12</id>
</image>
<image>
<name>Fedora 11 (Leonidas)</name>
<id type="integer">13</id>
</image>
</images>

View File

@ -0,0 +1,16 @@
<slice>
<name>slicetest</name>
<image-id type="integer">11</image-id>
<addresses type="array">
<address>10.176.168.15</address>
<address>67.23.20.114</address>
</addresses>
<root-password>fooadfa1231</root-password>
<progress type="integer">0</progress>
<id type="integer">71907</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.176.168.15</ip-address>
</slice>