From 55d4a579c01ecd9761f33ecb92364bea4c823c13 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Wed, 22 Dec 2010 18:03:51 +0100 Subject: [PATCH] Issue 427: support all instance commands --- sandbox/deltacloud/pom.xml | 6 + .../deltacloud/DeltacloudAsyncClient.java | 42 ++- .../jclouds/deltacloud/DeltacloudClient.java | 34 ++- .../jclouds/deltacloud/domain/Instance.java | 241 ++++++++++++++++++ .../deltacloud/domain/InstanceAction.java | 57 +++++ .../deltacloud/domain/InstanceState.java | 59 +++++ .../deltacloud/xml/InstanceHandler.java | 135 ++++++++++ .../deltacloud/xml/InstancesHandler.java | 69 +++++ .../deltacloud/DeltacloudAsyncClientTest.java | 74 +++++- .../deltacloud/DeltacloudClientLiveTest.java | 138 ++++++++-- .../deltacloud/xml/InstanceHandlerTest.java | 74 ++++++ .../deltacloud/xml/InstancesHandlerTest.java | 63 +++++ .../{handlers => xml}/LinksHandlerTest.java | 12 +- .../deltacloud/src/test/resources/log4j.xml | 170 ++++++++++++ .../src/test/resources/test_get_instance.xml | 20 ++ .../test/resources/test_list_instances.xml | 22 ++ 16 files changed, 1188 insertions(+), 28 deletions(-) create mode 100644 sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/Instance.java create mode 100644 sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceAction.java create mode 100644 sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceState.java create mode 100644 sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceHandler.java create mode 100644 sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstancesHandler.java create mode 100644 sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceHandlerTest.java create mode 100644 sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstancesHandlerTest.java rename sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/{handlers => xml}/LinksHandlerTest.java (86%) create mode 100644 sandbox/deltacloud/src/test/resources/log4j.xml create mode 100644 sandbox/deltacloud/src/test/resources/test_get_instance.xml create mode 100644 sandbox/deltacloud/src/test/resources/test_list_instances.xml diff --git a/sandbox/deltacloud/pom.xml b/sandbox/deltacloud/pom.xml index d66b991628..140ca063d6 100644 --- a/sandbox/deltacloud/pom.xml +++ b/sandbox/deltacloud/pom.xml @@ -71,6 +71,12 @@ test-jar test + + ${project.groupId} + jclouds-jsch + ${project.version} + test + log4j log4j diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudAsyncClient.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudAsyncClient.java index 86dac7b9e8..5392910222 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudAsyncClient.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudAsyncClient.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -34,9 +35,12 @@ import org.jclouds.deltacloud.collections.DeltacloudCollection; import org.jclouds.deltacloud.collections.Images; import org.jclouds.deltacloud.collections.Instances; import org.jclouds.deltacloud.domain.Image; +import org.jclouds.deltacloud.domain.Instance; import org.jclouds.deltacloud.options.CreateInstanceOptions; import org.jclouds.deltacloud.xml.ImageHandler; import org.jclouds.deltacloud.xml.ImagesHandler; +import org.jclouds.deltacloud.xml.InstanceHandler; +import org.jclouds.deltacloud.xml.InstancesHandler; import org.jclouds.deltacloud.xml.LinksHandler; import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.rest.annotations.Endpoint; @@ -46,6 +50,7 @@ import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.XMLResponseParser; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import com.google.common.util.concurrent.ListenableFuture; @@ -88,12 +93,47 @@ public interface DeltacloudAsyncClient { @XMLResponseParser(ImageHandler.class) ListenableFuture getImage(@EndpointParam URI imageHref); + /** + * @see DeltacloudClient#listInstances + */ + @GET + @Endpoint(Instances.class) + @Path("") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + @XMLResponseParser(InstancesHandler.class) + ListenableFuture> listInstances(); + + /** + * @see DeltacloudClient#getInstance + */ + @GET + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Path("") + @XMLResponseParser(InstanceHandler.class) + ListenableFuture getInstance(@EndpointParam URI instanceHref); + /** * @see DeltacloudClient#createInstance */ @POST @Endpoint(Instances.class) @Path("") - ListenableFuture createInstance(@FormParam("image_id") String imageId, CreateInstanceOptions... options); + @XMLResponseParser(InstanceHandler.class) + ListenableFuture createInstance(@FormParam("image_id") String imageId, CreateInstanceOptions... options); + + /** + * @see DeltacloudClient#performInstanceAction + */ + @POST + @Path("") + ListenableFuture performAction(@EndpointParam URI actionRef); + + /** + * @see DeltacloudClient#deleteResource + */ + @DELETE + @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + @Path("") + ListenableFuture deleteResource(@EndpointParam URI resourceHref); } diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudClient.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudClient.java index a993777a56..9b13dff82b 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudClient.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudClient.java @@ -27,7 +27,9 @@ import java.util.concurrent.TimeUnit; import org.jclouds.concurrent.Timeout; import org.jclouds.deltacloud.collections.DeltacloudCollection; import org.jclouds.deltacloud.domain.Image; +import org.jclouds.deltacloud.domain.Instance; import org.jclouds.deltacloud.options.CreateInstanceOptions; +import org.jclouds.rest.annotations.EndpointParam; /** * Provides synchronous access to deltacloud. @@ -61,6 +63,20 @@ public interface DeltacloudClient { */ Image getImage(URI imageHref); + /** + * The instances collection will return a set of all instances available to the current user. + * + * @return instances viewable to the user or empty set + */ + Set listInstances(); + + /** + * + * @param instanceHref + * @return instance or null, if not found + */ + Instance getInstance(URI instanceHref); + /** * Create a new Instance * @@ -76,5 +92,21 @@ public interface DeltacloudClient { * includes realm, hardware profile, etc. * @return newly-created instance including a URL to retrieve the instance in the future. */ - String createInstance(String imageId, CreateInstanceOptions... options); + Instance createInstance(String imageId, CreateInstanceOptions... options); + + /** + * perform a specific action. + * + * @param actionRef + * reference from {@link Instance#getActions()} + */ + void performAction(@EndpointParam URI actionRef); + + /** + * delete a resource, such as {@link Instance} + * + * @param resourceHref + * reference from {@link Instance#getHref()} + */ + void deleteResource(@EndpointParam URI resourceHref); } diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/Instance.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/Instance.java new file mode 100644 index 0000000000..becca4aa70 --- /dev/null +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/Instance.java @@ -0,0 +1,241 @@ +/** + * + * 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.deltacloud.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +/** + * An instance is a concrete machine realized from an image. + * + * @author Adrian Cole + */ +public class Instance { + private final URI href; + private final String id; + private final String ownerId; + @Nullable + private final String name; + private final URI image; + private final URI hardwareProfile; + private final URI realm; + private final InstanceState state; + private final Map actions; + private final Set publicAddresses; + private final Set privateAddresses; + + public Instance(URI href, String id, String ownerId, @Nullable String name, URI image, URI hardwareProfile, + URI realm, InstanceState state, Map actions, Set publicAddresses, + Set privateAddresses) { + this.href = checkNotNull(href, "href"); + this.id = checkNotNull(id, "id"); + this.ownerId = checkNotNull(ownerId, "ownerId"); + this.name = name; + this.image = checkNotNull(image, "image"); + this.hardwareProfile = checkNotNull(hardwareProfile, "hardwareProfile"); + this.realm = checkNotNull(realm, "realm"); + this.state = checkNotNull(state, "state"); + this.actions = ImmutableMap.copyOf(checkNotNull(actions, "actions")); + this.publicAddresses = ImmutableSet.copyOf(checkNotNull(publicAddresses, "publicAddresses")); + this.privateAddresses = ImmutableSet.copyOf(checkNotNull(privateAddresses, "privateAddresses")); + } + + /** + * + * @return URL to manipulate a specific instance + */ + public URI getHref() { + return href; + } + + /** + * + * @return A unique identifier for the instance + */ + public String getId() { + return id; + } + + /** + * + * @return An opaque identifier which indicates the owner of an instance + */ + public String getOwnerId() { + return ownerId; + } + + /** + * + * @return An optional short label describing the instance + */ + @Nullable + public String getName() { + return name; + } + + /** + * + * @return + */ + public URI getImage() { + return image; + } + + /** + * + * @return a link to the hardware profile in use by the instance + */ + public URI getHardwareProfile() { + return hardwareProfile; + } + + /** + * + * @return a link to the realm where the instance is deployed + */ + public URI getRealm() { + return realm; + } + + /** + * + * @return indicator of the instance's current state + */ + public InstanceState getState() { + return state; + } + + /** + * + * @return valid actions for the instance, along with the URL which may be used to perform the + * action + */ + public Map getActions() { + return actions; + } + + /** + * + * @return publicly routable IP addresses or names for the instance + */ + public Set getPublicAddresses() { + return publicAddresses; + } + + /** + * + * @return Private network IP addresses or names for the instance + */ + public Set getPrivateAddresses() { + return privateAddresses; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((actions == null) ? 0 : actions.hashCode()); + result = prime * result + ((hardwareProfile == null) ? 0 : hardwareProfile.hashCode()); + result = prime * result + ((href == null) ? 0 : href.hashCode()); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((image == null) ? 0 : image.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((privateAddresses == null) ? 0 : privateAddresses.hashCode()); + result = prime * result + ((publicAddresses == null) ? 0 : publicAddresses.hashCode()); + result = prime * result + ((realm == null) ? 0 : realm.hashCode()); + result = prime * result + ((state == null) ? 0 : state.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; + Instance other = (Instance) obj; + if (actions == null) { + if (other.actions != null) + return false; + } else if (!actions.equals(other.actions)) + return false; + if (hardwareProfile == null) { + if (other.hardwareProfile != null) + return false; + } else if (!hardwareProfile.equals(other.hardwareProfile)) + return false; + if (href == null) { + if (other.href != null) + return false; + } else if (!href.equals(other.href)) + return false; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (image == null) { + if (other.image != null) + return false; + } else if (!image.equals(other.image)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (privateAddresses == null) { + if (other.privateAddresses != null) + return false; + } else if (!privateAddresses.equals(other.privateAddresses)) + return false; + if (publicAddresses == null) { + if (other.publicAddresses != null) + return false; + } else if (!publicAddresses.equals(other.publicAddresses)) + return false; + if (realm == null) { + if (other.realm != null) + return false; + } else if (!realm.equals(other.realm)) + return false; + if (state != other.state) + return false; + return true; + } + + @Override + public String toString() { + return "[href=" + href + ", id=" + id + ", name=" + name + ", image=" + image + ", hardwareProfile=" + + hardwareProfile + ", realm=" + realm + ", state=" + state + ", actions=" + actions + ", publicAddresses=" + + publicAddresses + ", privateAddresses=" + privateAddresses + "]"; + } + +} diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceAction.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceAction.java new file mode 100644 index 0000000000..7f43b00ada --- /dev/null +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceAction.java @@ -0,0 +1,57 @@ +/** + * + * 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.deltacloud.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * + * Indicator of the instance's current action + * + * @author Adrian Cole + * + */ +public enum InstanceAction { + + REBOOT, + + START, + + STOP, + + UNRECOGNIZED; + + public String value() { + return name().toLowerCase(); + } + + @Override + public String toString() { + return value(); + } + + public static InstanceAction fromValue(String action) { + try { + return valueOf(checkNotNull(action, "action").toUpperCase()); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } +} \ No newline at end of file diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceState.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceState.java new file mode 100644 index 0000000000..aeded33830 --- /dev/null +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceState.java @@ -0,0 +1,59 @@ +/** + * + * 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.deltacloud.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * + * Indicator of the instance's current state + * + * @author Adrian Cole + * + */ +public enum InstanceState { + + /** + * the instance is in the process of being launched + */ + PENDING, + + /** + * the instance is stopped + */ + STOPPED, + /** + * the instance launched (although the boot process might not be completed) + */ + RUNNING, + + /** + * state returned as something besides the above. + */ + UNRECOGNIZED; + + public static InstanceState fromValue(String state) { + try { + return valueOf(checkNotNull(state, "state")); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } +} \ No newline at end of file diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceHandler.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceHandler.java new file mode 100644 index 0000000000..cf2d6ae2ea --- /dev/null +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceHandler.java @@ -0,0 +1,135 @@ +/** + * + * 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.deltacloud.xml; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import org.jclouds.deltacloud.domain.Instance; +import org.jclouds.deltacloud.domain.InstanceAction; +import org.jclouds.deltacloud.domain.InstanceState; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.util.Utils; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * @author Adrian Cole + */ +public class InstanceHandler extends ParseSax.HandlerWithResult { + private StringBuilder currentText = new StringBuilder(); + + private URI href; + private String id; + private String ownerId; + private String name; + private URI image; + private URI hardwareProfile; + private URI realm; + private InstanceState state; + private Map actions = Maps.newLinkedHashMap(); + private Set publicAddresses = Sets.newLinkedHashSet(); + private Set privateAddresses = Sets.newLinkedHashSet(); + + private boolean inPublicAddresses; + private boolean inPrivateAddresses; + + private Instance instance; + + public Instance getResult() { + return instance; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { + Map attributes = Utils.cleanseAttributes(attrs); + if (qName.equals("public_addresses")) { + inPublicAddresses = true; + } else if (qName.equals("private_addresses")) { + inPrivateAddresses = true; + } else if (qName.equals("instance")) { + String href = attributes.get("href"); + if (href != null) { + this.href = URI.create(href); + } + this.id = attributes.get("id"); + } else if (qName.equals("link")) { + String rel = attributes.get("rel"); + if (rel != null) { + InstanceAction action = InstanceAction.fromValue(rel); + if (action != InstanceAction.UNRECOGNIZED) { + actions.put(action, URI.create(attributes.get("href"))); + } + } + } else if (attributes.containsKey("href")) { + URI href = URI.create(attributes.get("href")); + if (qName.equals("image")) + this.image = href; + else if (qName.equals("hardware_profile")) + this.hardwareProfile = href; + else if (qName.equals("realm")) + this.realm = href; + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (qName.endsWith("public_addresses")) { + inPublicAddresses = false; + } else if (qName.endsWith("private_addresses")) { + inPrivateAddresses = false; + } + if (qName.equalsIgnoreCase("owner_id")) { + this.ownerId = currentText.toString().trim(); + } else if (qName.equalsIgnoreCase("name")) { + this.name = currentText.toString().trim(); + } else if (qName.equalsIgnoreCase("state")) { + this.state = InstanceState.fromValue(currentText.toString().trim()); + } else if (qName.equalsIgnoreCase("address")) { + if (inPublicAddresses) + this.publicAddresses.add(currentText.toString().trim()); + else if (inPrivateAddresses) + this.privateAddresses.add(currentText.toString().trim()); + } else if (qName.equalsIgnoreCase("instance")) { + this.instance = new Instance(href, id, ownerId, name, image, hardwareProfile, realm, state, actions, + publicAddresses, privateAddresses); + this.href = null; + this.id = null; + this.ownerId = null; + this.name = null; + this.image = null; + this.hardwareProfile = null; + this.realm = null; + this.state = null; + this.actions = Maps.newLinkedHashMap(); + this.publicAddresses = Sets.newLinkedHashSet(); + this.privateAddresses = Sets.newLinkedHashSet(); + } + currentText = new StringBuilder(); + } + + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } +} diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstancesHandler.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstancesHandler.java new file mode 100644 index 0000000000..cc83b0bfc1 --- /dev/null +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstancesHandler.java @@ -0,0 +1,69 @@ +/** + * + * 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.deltacloud.xml; + +import java.util.Set; + +import javax.inject.Inject; + +import org.jclouds.deltacloud.domain.Instance; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +import com.google.common.collect.Sets; + +/** + * @author Adrian Cole + */ +public class InstancesHandler extends ParseSax.HandlerWithResult> { + private StringBuilder currentText = new StringBuilder(); + + private Set instances = Sets.newLinkedHashSet(); + private final InstanceHandler instanceHandler; + + @Inject + public InstancesHandler(InstanceHandler locationHandler) { + this.instanceHandler = locationHandler; + } + + public Set getResult() { + return instances; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + instanceHandler.startElement(uri, localName, qName, attributes); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + instanceHandler.endElement(uri, localName, qName); + if (qName.equals("instance") && currentText.toString().trim().equals("")) { + this.instances.add(instanceHandler.getResult()); + } + currentText = new StringBuilder(); + } + + public void characters(char ch[], int start, int length) { + instanceHandler.characters(ch, start, length); + currentText.append(ch, start, length); + } +} diff --git a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudAsyncClientTest.java b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudAsyncClientTest.java index 4455b7497b..95e5e775c4 100644 --- a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudAsyncClientTest.java +++ b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudAsyncClientTest.java @@ -32,18 +32,22 @@ import org.jclouds.deltacloud.config.DeltacloudRestClientModule; import org.jclouds.deltacloud.options.CreateInstanceOptions; import org.jclouds.deltacloud.xml.ImageHandler; import org.jclouds.deltacloud.xml.ImagesHandler; +import org.jclouds.deltacloud.xml.InstanceHandler; +import org.jclouds.deltacloud.xml.InstancesHandler; import org.jclouds.deltacloud.xml.LinksHandler; import org.jclouds.http.HttpRequest; import org.jclouds.http.RequiresHttp; import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.http.functions.ParseSax; -import org.jclouds.http.functions.ReturnStringIf2xx; +import org.jclouds.http.functions.ReleasePayloadAndReturn; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.RestClientTest; import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextSpec; +import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.RestAnnotationProcessor; import org.testng.annotations.Test; @@ -117,6 +121,36 @@ public class DeltacloudAsyncClientTest extends RestClientTest socketTester; protected void setupCredentials() { - identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity"); - credential = System.getProperty("test." + provider + ".credential"); - endpoint = System.getProperty("test." + provider + ".endpoint"); + identity = System.getProperty("test." + provider + ".identity", "mockuser"); + credential = System.getProperty("test." + provider + ".credential", "mockpassword"); + endpoint = System.getProperty("test." + provider + ".endpoint", "http://localhost:3001/api"); apiversion = System.getProperty("test." + provider + ".apiversion"); } @@ -88,12 +106,7 @@ public class DeltacloudClientLiveTest { overrides); client = context.getApi(); - } - - @AfterGroups(groups = "live") - void tearDown() { - if (context != null) - context.close(); + socketTester = new RetryablePredicate(new InetSocketAddressConnect(), 180, 1, TimeUnit.SECONDS); } @Test @@ -115,14 +128,109 @@ public class DeltacloudClientLiveTest { } } - @Test - public void testCreateInstance() throws Exception { - // TODO + public void testListAndGetInstances() throws Exception { + Set response = client.listInstances(); + assert null != response; + long instanceCount = response.size(); + assertTrue(instanceCount >= 0); + for (Instance instance : response) { + Instance newDetails = client.getInstance(instance.getHref()); + assertEquals(instance, newDetails); + } } - @Test - public void testCreateInstanceWithOptions() throws Exception { + protected String prefix = System.getProperty("user.name") + ".test"; + protected Instance instance; + + public void testCreateInstance() throws Exception { + Logger.getAnonymousLogger().info("starting instance"); + instance = client.createInstance(Iterables.get(client.listImages(), 0).getId(), + CreateInstanceOptions.Builder.named(prefix)); + instance = client.getInstance(instance.getHref()); + checkStartedInstance(); + + Instance newInfo = client.getInstance(instance.getHref()); + checkInstanceMatchesGet(newInfo); + + } + + protected void checkInstanceMatchesGet(Instance newInfo) { + assertEquals(newInfo.getHref(), instance.getHref()); + } + + protected void checkStartedInstance() { + System.out.println(new Gson().toJson(instance)); + assertEquals(instance.getName(), prefix); + assertEquals(instance.getState(), InstanceState.RUNNING); + } + + @Test(dependsOnMethods = "testCreateInstance") + public void testConnectivity() throws Exception { + Logger.getAnonymousLogger().info("awaiting ssh"); // TODO + // assert socketTester.apply(new IPSocket(Iterables.get(instance.getPublicAddresses(), 0), + // 22)) : instance; + // doConnectViaSsh(instance, getSshCredentials(instance)); + } + + private Credentials getSshCredentials(Instance instance2) { + // TODO + return null; + } + + public URI refreshInstanceAndGetAction(InstanceAction action) { + return client.getInstance(instance.getHref()).getActions().get(action); + } + + @Test(dependsOnMethods = "testConnectivity") + public void testLifeCycle() throws Exception { + client.performAction(refreshInstanceAndGetAction(InstanceAction.STOP)); + assertEquals(client.getInstance(instance.getHref()).getState(), InstanceState.STOPPED); + + client.performAction(refreshInstanceAndGetAction(InstanceAction.START)); + assertEquals(client.getInstance(instance.getHref()).getState(), InstanceState.RUNNING); + + client.performAction(refreshInstanceAndGetAction(InstanceAction.REBOOT)); + assertEquals(client.getInstance(instance.getHref()).getState(), InstanceState.RUNNING); + + } + + @Test(dependsOnMethods = "testLifeCycle") + public void testDestroyInstance() throws Exception { + try { + client.deleteResource(instance.getHref()); + } catch (IllegalArgumentException e) { + client.performAction(refreshInstanceAndGetAction(InstanceAction.STOP)); + client.deleteResource(instance.getHref()); + assertEquals(client.getInstance(instance.getHref()), null); + } + } + + protected void doConnectViaSsh(Instance instance, Credentials creds) throws IOException { + SshClient ssh = Guice.createInjector(new JschSshClientModule()).getInstance(SshClient.Factory.class) + .create(new IPSocket(Iterables.get(instance.getPublicAddresses(), 0), 22), creds); + try { + ssh.connect(); + ExecResponse hello = ssh.exec("echo hello"); + assertEquals(hello.getOutput().trim(), "hello"); + System.err.println(ssh.exec("df -k").getOutput()); + System.err.println(ssh.exec("mount").getOutput()); + System.err.println(ssh.exec("uname -a").getOutput()); + } finally { + if (ssh != null) + ssh.disconnect(); + } + } + + @AfterGroups(groups = "live") + protected void tearDown() { + try { + client.deleteResource(instance.getHref()); + } catch (Exception e) { + // no need to check null or anything as we swallow all + } + if (context != null) + context.close(); } } diff --git a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceHandlerTest.java b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceHandlerTest.java new file mode 100644 index 0000000000..f07847e87d --- /dev/null +++ b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceHandlerTest.java @@ -0,0 +1,74 @@ +/** + * + * 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.deltacloud.xml; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; +import java.net.URI; + +import org.jclouds.deltacloud.domain.Instance; +import org.jclouds.deltacloud.domain.InstanceAction; +import org.jclouds.deltacloud.domain.InstanceState; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.http.functions.config.SaxParserModule; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * Tests behavior of {@code InstanceHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class InstanceHandlerTest { + + static ParseSax createParser() { + Injector injector = Guice.createInjector(new SaxParserModule()); + ParseSax parser = injector.getInstance(ParseSax.Factory.class).create( + injector.getInstance(InstanceHandler.class)); + return parser; + } + + public static Instance parseInstance() { + return parseInstance("/test_get_instance.xml"); + } + + public static Instance parseInstance(String resource) { + InputStream is = InstanceHandlerTest.class.getResourceAsStream(resource); + return createParser().parse(is); + } + + public void test() { + Instance expects = new Instance(URI.create("http://fancycloudprovider.com/api/instances/inst1"), "inst1", "larry", + "Production JBoss Instance", URI.create("http://fancycloudprovider.com/api/images/img3"), + URI.create("http://fancycloudprovider.com/api/hardware_profiles/m1-small"), + URI.create("http://fancycloudprovider.com/api/realms/us"), InstanceState.RUNNING, ImmutableMap.of( + InstanceAction.REBOOT, URI.create("http://fancycloudprovider.com/api/instances/inst1/reboot"), + InstanceAction.STOP, URI.create("http://fancycloudprovider.com/api/instances/inst1/stop")), + ImmutableSet.of("inst1.larry.fancycloudprovider.com"), ImmutableSet.of("inst1.larry.internal")); + assertEquals(parseInstance(), expects); + } + +} diff --git a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstancesHandlerTest.java b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstancesHandlerTest.java new file mode 100644 index 0000000000..08a9497494 --- /dev/null +++ b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstancesHandlerTest.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.deltacloud.xml; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; +import java.net.URI; +import java.util.Set; + +import org.jclouds.deltacloud.domain.Instance; +import org.jclouds.deltacloud.domain.InstanceAction; +import org.jclouds.deltacloud.domain.InstanceState; +import org.jclouds.http.functions.BaseHandlerTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +/** + * Tests behavior of {@code InstancesHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class InstancesHandlerTest extends BaseHandlerTest { + + @Test + public void test() { + InputStream is = getClass().getResourceAsStream("/test_list_instances.xml"); + Set expects = ImmutableSet.of(new Instance(URI + .create("http://fancycloudprovider.com/api/instances/inst1"), "inst1", "larry", + "Production JBoss Instance", URI.create("http://fancycloudprovider.com/api/images/img3"), URI + .create("http://fancycloudprovider.com/api/hardware_profiles/m1-small"), URI + .create("http://fancycloudprovider.com/api/realms/us"), InstanceState.RUNNING, ImmutableMap.of( + InstanceAction.REBOOT, URI.create("http://fancycloudprovider.com/api/instances/inst1/reboot"), + InstanceAction.STOP, URI.create("http://fancycloudprovider.com/api/instances/inst1/stop")), + ImmutableSet.of("inst1.larry.fancycloudprovider.com"), ImmutableSet.of("inst1.larry.internal"))); + System.out.println(factory); + System.out.println(injector); + + // not sure why this isn't always automatically called from surefire. + setUpInjector(); + assertEquals(factory.create(injector.getInstance(InstancesHandler.class)).parse(is), expects); + } +} diff --git a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/handlers/LinksHandlerTest.java b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/LinksHandlerTest.java similarity index 86% rename from sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/handlers/LinksHandlerTest.java rename to sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/LinksHandlerTest.java index ebe6705ecc..4f8d6da1f6 100644 --- a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/handlers/LinksHandlerTest.java +++ b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/LinksHandlerTest.java @@ -17,7 +17,7 @@ * ==================================================================== */ -package org.jclouds.deltacloud.handlers; +package org.jclouds.deltacloud.xml; import static org.testng.Assert.assertEquals; @@ -26,7 +26,6 @@ import java.net.URI; import java.util.Map; import org.jclouds.deltacloud.collections.DeltacloudCollection; -import org.jclouds.deltacloud.xml.LinksHandler; import org.jclouds.http.functions.BaseHandlerTest; import org.testng.annotations.Test; @@ -42,16 +41,17 @@ public class LinksHandlerTest extends BaseHandlerTest { public void test() { InputStream is = getClass().getResourceAsStream("/links.xml"); - - Map result = factory.create(injector.getInstance(LinksHandler.class)).parse(is); - assertEquals(result, ImmutableMap.of(// + Map expects = ImmutableMap.of(// DeltacloudCollection.HARDWARE_PROFILES, URI.create("http://fancycloudprovider.com/api/hardware_profiles"),// DeltacloudCollection.INSTANCE_STATES, URI.create("http://fancycloudprovider.com/api/instance_states"),// DeltacloudCollection.REALMS, URI.create("http://fancycloudprovider.com/api/realms"),// DeltacloudCollection.IMAGES, URI.create("http://fancycloudprovider.com/api/images"),// DeltacloudCollection.INSTANCES, URI.create("http://fancycloudprovider.com/api/instances") - )); + ); + // not sure why this isn't always automatically called from surefire. + setUpInjector(); + assertEquals(factory.create(injector.getInstance(LinksHandler.class)).parse(is), expects); } diff --git a/sandbox/deltacloud/src/test/resources/log4j.xml b/sandbox/deltacloud/src/test/resources/log4j.xml new file mode 100644 index 0000000000..7343ec00e2 --- /dev/null +++ b/sandbox/deltacloud/src/test/resources/log4j.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sandbox/deltacloud/src/test/resources/test_get_instance.xml b/sandbox/deltacloud/src/test/resources/test_get_instance.xml new file mode 100644 index 0000000000..c3d2245eab --- /dev/null +++ b/sandbox/deltacloud/src/test/resources/test_get_instance.xml @@ -0,0 +1,20 @@ + + larry + Production JBoss Instance + + + + + RUNNING + + + + + +
inst1.larry.fancycloudprovider.com
+
+ + +
inst1.larry.internal
+
+
\ No newline at end of file diff --git a/sandbox/deltacloud/src/test/resources/test_list_instances.xml b/sandbox/deltacloud/src/test/resources/test_list_instances.xml new file mode 100644 index 0000000000..c8f2dd5eed --- /dev/null +++ b/sandbox/deltacloud/src/test/resources/test_list_instances.xml @@ -0,0 +1,22 @@ + + + larry + Production JBoss Instance + + + + + RUNNING + + + + + +
inst1.larry.fancycloudprovider.com
+
+ + +
inst1.larry.internal
+
+
+
\ No newline at end of file