From d120b139fc331a66eca981ce18084050c6f36bfa Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Mon, 26 Jul 2010 02:38:18 -0700 Subject: [PATCH] Issue 164: initial commit for slicehost. note this is not complete --- core/src/main/resources/rest.properties | 3 + slicehost/pom.xml | 77 ++++ .../slicehost/SlicehostAsyncClient.java | 204 +++++++++++ .../jclouds/slicehost/SlicehostClient.java | 78 ++++ .../slicehost/SlicehostContextBuilder.java | 63 ++++ .../slicehost/SlicehostPropertiesBuilder.java | 46 +++ .../binders/BindCreateSliceToXmlPayload.java | 65 ++++ .../SlicehostComputeServiceContextModule.java | 333 +++++++++++++++++ .../functions/SliceToNodeMetadata.java | 111 ++++++ .../config/SlicehostRestClientModule.java | 51 +++ .../org/jclouds/slicehost/domain/Backup.java | 115 ++++++ .../org/jclouds/slicehost/domain/Flavor.java | 109 ++++++ .../org/jclouds/slicehost/domain/Image.java | 85 +++++ .../org/jclouds/slicehost/domain/Slice.java | 249 +++++++++++++ .../slicehost/filters/SlicehostBasic.java | 55 +++ .../ParseSlicehostErrorFromHttpResponse.java | 108 ++++++ .../slicehost/predicates/SliceActive.java | 46 +++ .../slicehost/predicates/SliceTerminated.java | 45 +++ .../jclouds/slicehost/xml/BackupHandler.java | 78 ++++ .../jclouds/slicehost/xml/BackupsHandler.java | 68 ++++ .../jclouds/slicehost/xml/ErrorHandler.java | 47 +++ .../jclouds/slicehost/xml/FlavorHandler.java | 65 ++++ .../jclouds/slicehost/xml/FlavorsHandler.java | 68 ++++ .../jclouds/slicehost/xml/ImageHandler.java | 62 ++++ .../jclouds/slicehost/xml/ImagesHandler.java | 68 ++++ .../jclouds/slicehost/xml/SliceHandler.java | 105 ++++++ .../jclouds/slicehost/xml/SlicesHandler.java | 68 ++++ .../slicehost/ProvidersInPropertiesTest.java | 46 +++ .../slicehost/SlicehostAsyncClientTest.java | 272 ++++++++++++++ .../slicehost/SlicehostClientLiveTest.java | 342 ++++++++++++++++++ .../SlicehostComputeServiceLiveTest.java | 82 +++++ .../slicehost/xml/FlavorHandlerTest.java | 50 +++ .../slicehost/xml/FlavorsHandlerTest.java | 54 +++ .../slicehost/xml/SliceHandlerTest.java | 62 ++++ .../slicehost/xml/SlicesHandlerTest.java | 55 +++ slicehost/src/test/resources/log4j.xml | 136 +++++++ slicehost/src/test/resources/test_errors.xml | 4 + .../src/test/resources/test_get_flavor.xml | 7 + .../src/test/resources/test_get_slice.xml | 17 + .../src/test/resources/test_list_flavors.xml | 27 ++ .../src/test/resources/test_list_images.xml | 47 +++ .../src/test/resources/test_new_slice.xml | 16 + 42 files changed, 3689 insertions(+) create mode 100644 slicehost/pom.xml create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/SlicehostAsyncClient.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/SlicehostClient.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/SlicehostContextBuilder.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/SlicehostPropertiesBuilder.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/binders/BindCreateSliceToXmlPayload.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/compute/config/SlicehostComputeServiceContextModule.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/compute/functions/SliceToNodeMetadata.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/config/SlicehostRestClientModule.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/domain/Backup.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/domain/Flavor.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/domain/Image.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/domain/Slice.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/filters/SlicehostBasic.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/handlers/ParseSlicehostErrorFromHttpResponse.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceActive.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceTerminated.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/BackupHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/BackupsHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/ErrorHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorsHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/ImageHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/ImagesHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/SliceHandler.java create mode 100644 slicehost/src/main/java/org/jclouds/slicehost/xml/SlicesHandler.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/ProvidersInPropertiesTest.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/SlicehostAsyncClientTest.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/SlicehostClientLiveTest.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/compute/SlicehostComputeServiceLiveTest.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorHandlerTest.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorsHandlerTest.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/xml/SliceHandlerTest.java create mode 100644 slicehost/src/test/java/org/jclouds/slicehost/xml/SlicesHandlerTest.java create mode 100755 slicehost/src/test/resources/log4j.xml create mode 100644 slicehost/src/test/resources/test_errors.xml create mode 100644 slicehost/src/test/resources/test_get_flavor.xml create mode 100644 slicehost/src/test/resources/test_get_slice.xml create mode 100644 slicehost/src/test/resources/test_list_flavors.xml create mode 100644 slicehost/src/test/resources/test_list_images.xml create mode 100644 slicehost/src/test/resources/test_new_slice.xml diff --git a/core/src/main/resources/rest.properties b/core/src/main/resources/rest.properties index 621be07b02..c50d2b83dd 100644 --- a/core/src/main/resources/rest.properties +++ b/core/src/main/resources/rest.properties @@ -47,6 +47,9 @@ ec2.propertiesbuilder=org.jclouds.aws.ec2.EC2PropertiesBuilder rimuhosting.contextbuilder=org.jclouds.rimuhosting.miro.RimuHostingContextBuilder 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.propertiesbuilder=org.jclouds.vcloud.terremark.TerremarkVCloudExpressPropertiesBuilder diff --git a/slicehost/pom.xml b/slicehost/pom.xml new file mode 100644 index 0000000000..d5a82a24e2 --- /dev/null +++ b/slicehost/pom.xml @@ -0,0 +1,77 @@ + + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.0-SNAPSHOT + ../project/pom.xml + + jclouds-slicehost + jclouds slicehost components + + ${jclouds.slicehost.apikey} + ${jclouds.slicehost.apikey} + + + + ${project.groupId} + jclouds-core + ${project.version} + test-jar + test + + + ${project.groupId} + jclouds-compute + ${project.version} + + + ${project.groupId} + jclouds-compute + ${project.version} + test-jar + test + + + log4j + log4j + 1.2.14 + test + + + ${project.groupId} + jclouds-log4j + ${project.version} + test + + + ${project.groupId} + jclouds-jsch + ${project.version} + test + + + + diff --git a/slicehost/src/main/java/org/jclouds/slicehost/SlicehostAsyncClient.java b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostAsyncClient.java new file mode 100644 index 0000000000..f25f683dea --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostAsyncClient.java @@ -0,0 +1,204 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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. + *

+ * 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 + * @author Adrian Cole + */ +@SkipEncoding( { '/', '=' }) +@RequestFilters(SlicehostBasic.class) +public interface SlicehostAsyncClient { + + /** + * @see SlicehostClient#listSlices + */ + @GET + @Path("/slices.xml") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + @XMLResponseParser(SlicesHandler.class) + ListenableFuture> listSlices(); + + /** + * @see SlicehostClient#getSlice + */ + @GET + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Path("/slices/{id}.xml") + @XMLResponseParser(SliceHandler.class) + ListenableFuture getSlice(@PathParam("id") int id); + + /** + * @see SlicehostClient#destroySlice + */ + @DELETE + @Path("/slices/{id}/destroy.xml") + ListenableFuture destroySlice(@PathParam("id") int id); + + /** + * @see SlicehostClient#rebootSlice + */ + @PUT + @Path("/slices/{id}/reboot.xml") + ListenableFuture rebootSlice(@PathParam("id") int id); + + /** + * @see SlicehostClient#hardRebootSlice + */ + @PUT + @Path("/slices/{id}/hardReboot.xml") + ListenableFuture hardRebootSlice(@PathParam("id") int id); + + /** + * @see SlicehostClient#createSlice + */ + @POST + @Path("/slices.xml") + @MapBinder(BindCreateSliceToXmlPayload.class) + @XMLResponseParser(SliceHandler.class) + ListenableFuture 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 rebuildSliceFromImage(@PathParam("id") int id, @QueryParam("image_id") int imageId); + + /** + * @see SlicehostClient#rebuildSliceFromBackup + */ + @PUT + @Path("/slices/{id}/rebuild.xml") + ListenableFuture rebuildSliceFromBackup(@PathParam("id") int id, @QueryParam("backup_id") int imageId); + + /** + * @see SlicehostClient#listFlavors + */ + @GET + @Path("/flavors.xml") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + @XMLResponseParser(FlavorsHandler.class) + ListenableFuture> listFlavors(); + + /** + * @see SlicehostClient#getFlavor + */ + @GET + @Path("/flavors/{id}.xml") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @XMLResponseParser(FlavorHandler.class) + ListenableFuture getFlavor(@PathParam("id") int id); + + /** + * @see SlicehostClient#listImages + */ + @GET + @Path("/images.xml") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + @XMLResponseParser(ImagesHandler.class) + ListenableFuture> listImages(); + + /** + * @see SlicehostClient#getImage + */ + @GET + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Path("/images/{id}.xml") + @XMLResponseParser(ImageHandler.class) + ListenableFuture getImage(@PathParam("id") int id); + + /** + * @see SlicehostClient#destroyBackup + */ + @DELETE + @Path("/backups/{id}/destroy.xml") + ListenableFuture destroyBackup(@PathParam("id") int id); + + /** + * @see SlicehostClient#listBackups + */ + @GET + @Path("/backups.xml") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + @XMLResponseParser(BackupsHandler.class) + ListenableFuture> listBackups(); + + /** + * @see SlicehostClient#getBackup + */ + @GET + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Path("/backups/{id}.xml") + @XMLResponseParser(BackupHandler.class) + ListenableFuture getBackup(@PathParam("id") int id); + + /** + * @see SlicehostClient#createBackupFromSlice + */ + @PUT + @Path("/backups.xml") + @XMLResponseParser(BackupHandler.class) + ListenableFuture createBackupFromSlice(@QueryParam("slice_id") int sliceId); + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/SlicehostClient.java b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostClient.java new file mode 100644 index 0000000000..e91452fcdc --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostClient.java @@ -0,0 +1,78 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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. + *

+ * 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 + * @author Adrian Cole + */ +@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) +public interface SlicehostClient { + Set 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 listFlavors(); + + Flavor getFlavor(int id); + + Set listImages(); + + Image getImage(int id); + + Void destroyBackup(int id); + + Set listBackups(); + + Backup getBackup(int id); + + Backup createBackupFromSlice(int sliceId); + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/SlicehostContextBuilder.java b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostContextBuilder.java new file mode 100644 index 0000000000..6a77d0df3a --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostContextBuilder.java @@ -0,0 +1,63 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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. + *

+ * Note that Threadsafe objects will be bound as singletons to the Injector or Context provided. + *

+ *

+ * If no Modules 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 { + + public SlicehostContextBuilder(Properties props) { + super(SlicehostClient.class, SlicehostAsyncClient.class, props); + } + + @Override + protected void addContextModule(List modules) { + modules.add(new SlicehostComputeServiceContextModule()); + } + + @Override + protected void addClientModule(List modules) { + modules.add(new SlicehostRestClientModule()); + } + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/SlicehostPropertiesBuilder.java b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostPropertiesBuilder.java new file mode 100644 index 0000000000..3cf79eedb0 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/SlicehostPropertiesBuilder.java @@ -0,0 +1,46 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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); + } + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/binders/BindCreateSliceToXmlPayload.java b/slicehost/src/main/java/org/jclouds/slicehost/binders/BindCreateSliceToXmlPayload.java new file mode 100644 index 0000000000..83ad8e93a2 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/binders/BindCreateSliceToXmlPayload.java @@ -0,0 +1,65 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 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(""); + builder.append("").append(flavorId).append(""); + builder.append("").append(imageId).append(""); + builder.append("").append(name).append(""); + builder.append(""); + 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"); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/compute/config/SlicehostComputeServiceContextModule.java b/slicehost/src/main/java/org/jclouds/slicehost/compute/config/SlicehostComputeServiceContextModule.java new file mode 100644 index 0000000000..398403e2bb --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/compute/config/SlicehostComputeServiceContextModule.java @@ -0,0 +1,333 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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>() { + }).to(SliceToNodeMetadata.class); + bind(LoadBalancerService.class).toProvider(Providers. of(null)); + bind(new TypeLiteral() { + }).to(new TypeLiteral>() { + }).in(Scopes.SINGLETON); + bind(new TypeLiteral>() { + }).to(new TypeLiteral>() { + }).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. of(), tag, template.getImage(), NodeState.PENDING, Iterables.filter(slice + .getAddresses(), new Predicate() { + + @Override + public boolean apply(String input) { + return !input.startsWith("10."); + } + + }), Iterables.filter(slice.getAddresses(), new Predicate() { + + @Override + public boolean apply(String input) { + return input.startsWith("10."); + } + + }), ImmutableMap. of(), new Credentials("root", slice.getRootPassword())); + } + + } + + @Singleton + public static class SlicehostListNodesStrategy implements ListNodesStrategy { + private final SlicehostClient client; + private final Function sliceToNodeMetadata; + + @Inject + protected SlicehostListNodesStrategy(SlicehostClient client, Function sliceToNodeMetadata) { + this.client = client; + this.sliceToNodeMetadata = sliceToNodeMetadata; + } + + @Override + public Iterable list() { + return listDetailsOnNodesMatching(NodePredicates.all()); + } + + @Override + public Iterable listDetailsOnNodesMatching(Predicate filter) { + return Iterables.filter(Iterables.transform(client.listSlices(), sliceToNodeMetadata), filter); + } + } + + @Singleton + public static class SlicehostGetNodeMetadataStrategy implements GetNodeMetadataStrategy { + + private final SlicehostClient client; + private final Function sliceToNodeMetadata; + + @Inject + protected SlicehostGetNodeMetadataStrategy(SlicehostClient client, + Function 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 provideSliceToNodeState() { + return ImmutableMap. 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 indexer() { + return new Function() { + @Override + public String apply(ComputeMetadata from) { + return from.getProviderId(); + } + }; + } + + @Provides + @Singleton + protected Set provideSizes(SlicehostClient sync, Set images, Location location, + LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, + Function indexer) throws InterruptedException, TimeoutException, ExecutionException { + final Set 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 + . 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 provideLocations(Location location) { + return ImmutableSet.of(location); + } + + @Provides + @Singleton + protected Set provideImages(final SlicehostClient sync, Location location, LogHolder holder, + Function indexer) throws InterruptedException, ExecutionException, TimeoutException { + final Set 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 + . of(), from.getName(), version, os, osDescription, arch, new Credentials("root", + null))); + } + holder.logger.debug("<< images(%d)", images.size()); + return images; + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/compute/functions/SliceToNodeMetadata.java b/slicehost/src/main/java/org/jclouds/slicehost/compute/functions/SliceToNodeMetadata.java new file mode 100644 index 0000000000..0094283fc1 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/compute/functions/SliceToNodeMetadata.java @@ -0,0 +1,111 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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 sliceToNodeState; + private final Set images; + + @Resource + protected Logger logger = Logger.NULL; + + private static class FindImageForSlice implements Predicate { + 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 sliceStateToNodeState, Set 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 + . of(), tag, image, sliceToNodeState.get(from.getStatus()), Iterables.filter(from + .getAddresses(), new Predicate() { + + @Override + public boolean apply(String input) { + return !input.startsWith("10."); + } + + }), Iterables.filter(from.getAddresses(), new Predicate() { + + @Override + public boolean apply(String input) { + return input.startsWith("10."); + } + + }), ImmutableMap. of(), null); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/config/SlicehostRestClientModule.java b/slicehost/src/main/java/org/jclouds/slicehost/config/SlicehostRestClientModule.java new file mode 100644 index 0000000000..29f707ce6c --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/config/SlicehostRestClientModule.java @@ -0,0 +1,51 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + + 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); + } + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/domain/Backup.java b/slicehost/src/main/java/org/jclouds/slicehost/domain/Backup.java new file mode 100644 index 0000000000..1274c63d20 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/domain/Backup.java @@ -0,0 +1,115 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 + "]"; + } + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/domain/Flavor.java b/slicehost/src/main/java/org/jclouds/slicehost/domain/Flavor.java new file mode 100644 index 0000000000..d7575aa6bc --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/domain/Flavor.java @@ -0,0 +1,109 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 + "]"; + } + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/domain/Image.java b/slicehost/src/main/java/org/jclouds/slicehost/domain/Image.java new file mode 100644 index 0000000000..5c1785b6b3 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/domain/Image.java @@ -0,0 +1,85 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 + "]"; + } + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/domain/Slice.java b/slicehost/src/main/java/org/jclouds/slicehost/domain/Slice.java new file mode 100644 index 0000000000..481dfbf6c6 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/domain/Slice.java @@ -0,0 +1,249 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 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 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 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) + "]"; + } + +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/filters/SlicehostBasic.java b/slicehost/src/main/java/org/jclouds/slicehost/filters/SlicehostBasic.java new file mode 100644 index 0000000000..b3a658dd52 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/filters/SlicehostBasic.java @@ -0,0 +1,55 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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())))); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/handlers/ParseSlicehostErrorFromHttpResponse.java b/slicehost/src/main/java/org/jclouds/slicehost/handlers/ParseSlicehostErrorFromHttpResponse.java new file mode 100644 index 0000000000..88bd0650b7 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/handlers/ParseSlicehostErrorFromHttpResponse.java @@ -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 errorHandlerProvider; + @Resource + protected Logger logger = Logger.NULL; + + @Inject + ErrorParser(Factory factory, Provider 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; + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceActive.java b/slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceActive.java new file mode 100644 index 0000000000..5306dcd6ec --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceActive.java @@ -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 { + + 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()); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceTerminated.java b/slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceTerminated.java new file mode 100644 index 0000000000..f476827e4e --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/predicates/SliceTerminated.java @@ -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 { + + 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()); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/BackupHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/BackupHandler.java new file mode 100644 index 0000000000..1f6faefe9f --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/BackupHandler.java @@ -0,0 +1,78 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/BackupsHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/BackupsHandler.java new file mode 100644 index 0000000000..097db20de2 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/BackupsHandler.java @@ -0,0 +1,68 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> { + private StringBuilder currentText = new StringBuilder(); + + private Set backups = Sets.newLinkedHashSet(); + private final BackupHandler locationHandler; + + @Inject + public BackupsHandler(BackupHandler locationHandler) { + this.locationHandler = locationHandler; + } + + public Set 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/ErrorHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/ErrorHandler.java new file mode 100644 index 0000000000..eb24351e05 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/ErrorHandler.java @@ -0,0 +1,47 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorHandler.java new file mode 100644 index 0000000000..9c20e0f150 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorHandler.java @@ -0,0 +1,65 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorsHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorsHandler.java new file mode 100644 index 0000000000..1ff2e7983c --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/FlavorsHandler.java @@ -0,0 +1,68 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> { + private StringBuilder currentText = new StringBuilder(); + + private Set slices = Sets.newLinkedHashSet(); + private final FlavorHandler locationHandler; + + @Inject + public FlavorsHandler(FlavorHandler locationHandler) { + this.locationHandler = locationHandler; + } + + public Set 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/ImageHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/ImageHandler.java new file mode 100644 index 0000000000..62756d8506 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/ImageHandler.java @@ -0,0 +1,62 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/ImagesHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/ImagesHandler.java new file mode 100644 index 0000000000..92041449f7 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/ImagesHandler.java @@ -0,0 +1,68 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> { + private StringBuilder currentText = new StringBuilder(); + + private Set images = Sets.newLinkedHashSet(); + private final ImageHandler locationHandler; + + @Inject + public ImagesHandler(ImageHandler locationHandler) { + this.locationHandler = locationHandler; + } + + public Set 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/SliceHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/SliceHandler.java new file mode 100644 index 0000000000..6cb7927056 --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/SliceHandler.java @@ -0,0 +1,105 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + 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 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); + } +} diff --git a/slicehost/src/main/java/org/jclouds/slicehost/xml/SlicesHandler.java b/slicehost/src/main/java/org/jclouds/slicehost/xml/SlicesHandler.java new file mode 100644 index 0000000000..b485143cce --- /dev/null +++ b/slicehost/src/main/java/org/jclouds/slicehost/xml/SlicesHandler.java @@ -0,0 +1,68 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> { + private StringBuilder currentText = new StringBuilder(); + + private Set slices = Sets.newLinkedHashSet(); + private final SliceHandler locationHandler; + + @Inject + public SlicesHandler(SliceHandler locationHandler) { + this.locationHandler = locationHandler; + } + + public Set 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); + } +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/ProvidersInPropertiesTest.java b/slicehost/src/test/java/org/jclouds/slicehost/ProvidersInPropertiesTest.java new file mode 100644 index 0000000000..f59aac7099 --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/ProvidersInPropertiesTest.java @@ -0,0 +1,46 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 providers = ComputeServiceUtils.getSupportedProviders(); + assert Iterables.contains(providers, "slicehost") : providers; + } + + @Test + public void testSupportedProviders() { + Iterable providers = Utils.getSupportedProviders(); + assert Iterables.contains(providers, "slicehost") : providers; + } +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/SlicehostAsyncClientTest.java b/slicehost/src/test/java/org/jclouds/slicehost/SlicehostAsyncClientTest.java new file mode 100644 index 0000000000..6df242ebb7 --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/SlicehostAsyncClientTest.java @@ -0,0 +1,272 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 { + + 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, + "12ralphie", + "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> createTypeLiteral() { + return new TypeLiteral>() { + }; + } + + @Override + protected void checkFilters(HttpRequest request) { + assertEquals(request.getFilters().size(), 1); + assertEquals(request.getFilters().get(0).getClass(), SlicehostBasic.class); + + } + + @Override + public ContextSpec createContextSpec() { + return new RestContextFactory().createContextSpec("slicehost", "apikey", null, new Properties()); + } + +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/SlicehostClientLiveTest.java b/slicehost/src/test/java/org/jclouds/slicehost/SlicehostClientLiveTest.java new file mode 100644 index 0000000000..021d5ea4d6 --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/SlicehostClientLiveTest.java @@ -0,0 +1,342 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 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. 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(socketOpen, 120, 1, TimeUnit.SECONDS); + injector.injectMembers(socketOpen); // add logger + } + + public void testListSlices() throws Exception { + + Set response = client.listSlices(); + assert null != response; + long initialContainerCount = response.size(); + assertTrue(initialContainerCount >= 0); + + } + + public void testListSlicesDetail() throws Exception { + Set response = client.listSlices(); + assert null != response; + long initialContainerCount = response.size(); + assertTrue(initialContainerCount >= 0); + } + + public void testListImages() throws Exception { + Set 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 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 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 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 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 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 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() { + + @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 + 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); + } + + } +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/compute/SlicehostComputeServiceLiveTest.java b/slicehost/src/test/java/org/jclouds/slicehost/compute/SlicehostComputeServiceLiveTest.java new file mode 100644 index 0000000000..cde6d51a15 --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/compute/SlicehostComputeServiceLiveTest.java @@ -0,0 +1,82 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 tmContext = new ComputeServiceContextFactory() + .createContext(provider, identity, credential).getProviderSpecificContext(); + } + + @Override + protected void checkNodes(Iterable nodes, String tag) throws IOException { + super.checkNodes(nodes, tag); + for (NodeMetadata node : nodes) { + assertEquals(node.getLocation().getScope(), LocationScope.HOST); + } + } +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorHandlerTest.java b/slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorHandlerTest.java new file mode 100644 index 0000000000..15b9c9b505 --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorHandlerTest.java @@ -0,0 +1,50 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 createParser() { + ParseSax parser = (ParseSax) 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); + } + +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorsHandlerTest.java b/slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorsHandlerTest.java new file mode 100644 index 0000000000..8afd674d1e --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/xml/FlavorsHandlerTest.java @@ -0,0 +1,54 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> createParser() { + ParseSax> parser = (ParseSax>) factory.create(injector + .getInstance(FlavorsHandler.class)); + return parser; + } + + public void test() { + InputStream is = getClass().getResourceAsStream("/test_list_flavors.xml"); + Set 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); + } + +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/xml/SliceHandlerTest.java b/slicehost/src/test/java/org/jclouds/slicehost/xml/SliceHandlerTest.java new file mode 100644 index 0000000000..4350e10fe2 --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/xml/SliceHandlerTest.java @@ -0,0 +1,62 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 createParser() { + ParseSax parser = (ParseSax) 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. 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. of( + "10.176.168.15", "67.23.20.114"), "fooadfa1231"); + + assertEquals(createParser().parse(is), expects); + + } + +} diff --git a/slicehost/src/test/java/org/jclouds/slicehost/xml/SlicesHandlerTest.java b/slicehost/src/test/java/org/jclouds/slicehost/xml/SlicesHandlerTest.java new file mode 100644 index 0000000000..76769134d7 --- /dev/null +++ b/slicehost/src/test/java/org/jclouds/slicehost/xml/SlicesHandlerTest.java @@ -0,0 +1,55 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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> createParser() { + ParseSax> parser = (ParseSax>) factory.create(injector + .getInstance(SlicesHandler.class)); + return parser; + } + + public void test() { + InputStream is = getClass().getResourceAsStream("/test_get_slice.xml"); + Set expects = ImmutableSet.of(new Slice(1, "jclouds-foo", 1, 10, null, Slice.Status.BUILD, 0, 0, + 0, ImmutableSet. of("174.143.212.229", "10.176.164.199"), null)); + + assertEquals(createParser().parse(is), expects); + } + +} diff --git a/slicehost/src/test/resources/log4j.xml b/slicehost/src/test/resources/log4j.xml new file mode 100755 index 0000000000..f7337defb9 --- /dev/null +++ b/slicehost/src/test/resources/log4j.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/slicehost/src/test/resources/test_errors.xml b/slicehost/src/test/resources/test_errors.xml new file mode 100644 index 0000000000..6555aa11d5 --- /dev/null +++ b/slicehost/src/test/resources/test_errors.xml @@ -0,0 +1,4 @@ + + + Slice parameters are not properly nested + diff --git a/slicehost/src/test/resources/test_get_flavor.xml b/slicehost/src/test/resources/test_get_flavor.xml new file mode 100644 index 0000000000..d15457e55a --- /dev/null +++ b/slicehost/src/test/resources/test_get_flavor.xml @@ -0,0 +1,7 @@ + + + 1 + 256 slice + 2000 + 256 + \ No newline at end of file diff --git a/slicehost/src/test/resources/test_get_slice.xml b/slicehost/src/test/resources/test_get_slice.xml new file mode 100644 index 0000000000..dbe8d32fd1 --- /dev/null +++ b/slicehost/src/test/resources/test_get_slice.xml @@ -0,0 +1,17 @@ + + + jclouds-foo + 10 + +

174.143.212.229
+
10.176.164.199
+ + 0 + 1 + 0.0 + 0.0 + 1 + build + 174.143.212.229 + + diff --git a/slicehost/src/test/resources/test_list_flavors.xml b/slicehost/src/test/resources/test_list_flavors.xml new file mode 100644 index 0000000000..fc1651c386 --- /dev/null +++ b/slicehost/src/test/resources/test_list_flavors.xml @@ -0,0 +1,27 @@ + + + + 1 + 256 slice + 2000 + 256 + + + 2 + 512 slice + 3800 + 512 + + + 3 + 1GB slice + 7000 + 1024 + + + 4 + 2GB slice + 13000 + 2048 + + diff --git a/slicehost/src/test/resources/test_list_images.xml b/slicehost/src/test/resources/test_list_images.xml new file mode 100644 index 0000000000..f87b4e7301 --- /dev/null +++ b/slicehost/src/test/resources/test_list_images.xml @@ -0,0 +1,47 @@ + + + + CentOS 5.2 + 2 + + + Gentoo 2008.0 + 3 + + + Debian 5.0 (lenny) + 4 + + + Fedora 10 (Cambridge) + 5 + + + CentOS 5.3 + 7 + + + Ubuntu 9.04 (jaunty) + 8 + + + Arch 2009.02 + 9 + + + Ubuntu 8.04.2 LTS (hardy) + 10 + + + Ubuntu 8.10 (intrepid) + 11 + + + Red Hat EL 5.3 + 12 + + + Fedora 11 (Leonidas) + 13 + + diff --git a/slicehost/src/test/resources/test_new_slice.xml b/slicehost/src/test/resources/test_new_slice.xml new file mode 100644 index 0000000000..2257f2660d --- /dev/null +++ b/slicehost/src/test/resources/test_new_slice.xml @@ -0,0 +1,16 @@ + + slicetest + 11 + +
10.176.168.15
+
67.23.20.114
+
+ fooadfa1231 + 0 + 71907 + 0.0 + 0.0 + 1 + build + 10.176.168.15 +