From fced69c15fb3122969d1449853398e2aa5778795 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Wed, 29 Dec 2010 11:12:36 +0100 Subject: [PATCH] deltacloud: added state handling --- .../deltacloud/DeltacloudAsyncClient.java | 17 +++++ .../jclouds/deltacloud/DeltacloudClient.java | 10 +++ .../config/DeltacloudRestClientModule.java | 7 +++ .../domain/DeltacloudCollection.java | 42 ------------- .../deltacloud/domain/InstanceAction.java | 4 ++ .../deltacloud/domain/InstanceState.java | 15 +++-- .../deltacloud/domain/TransitionOnAction.java | 6 +- .../xml/DeltacloudCollectionHandler.java | 2 +- .../deltacloud/xml/InstanceStatesHandler.java | 5 +- .../deltacloud/DeltacloudAsyncClientTest.java | 23 ++++++- .../deltacloud/DeltacloudClientLiveTest.java | 24 +++++++ .../xml/DeltacloudCollectionsHandlerTest.java | 2 +- .../xml/InstanceStatesHandlerTest.java | 62 +++++++++++++++++++ .../src/test/resources/test_get_states.xml | 18 ++++++ 14 files changed, 182 insertions(+), 55 deletions(-) create mode 100644 sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceStatesHandlerTest.java create mode 100644 sandbox/deltacloud/src/test/resources/test_get_states.xml 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 d3d6eb128b..e6cc8999dc 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudAsyncClient.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudAsyncClient.java @@ -32,13 +32,16 @@ import javax.ws.rs.core.MediaType; import org.jclouds.deltacloud.collections.HardwareProfiles; import org.jclouds.deltacloud.collections.Images; +import org.jclouds.deltacloud.collections.InstanceStates; import org.jclouds.deltacloud.collections.Instances; import org.jclouds.deltacloud.collections.Realms; import org.jclouds.deltacloud.domain.DeltacloudCollection; import org.jclouds.deltacloud.domain.HardwareProfile; import org.jclouds.deltacloud.domain.Image; import org.jclouds.deltacloud.domain.Instance; +import org.jclouds.deltacloud.domain.InstanceState; import org.jclouds.deltacloud.domain.Realm; +import org.jclouds.deltacloud.domain.Transition; import org.jclouds.deltacloud.options.CreateInstanceOptions; import org.jclouds.deltacloud.xml.DeltacloudCollectionsHandler; import org.jclouds.deltacloud.xml.HardwareProfileHandler; @@ -46,6 +49,7 @@ import org.jclouds.deltacloud.xml.HardwareProfilesHandler; import org.jclouds.deltacloud.xml.ImageHandler; import org.jclouds.deltacloud.xml.ImagesHandler; import org.jclouds.deltacloud.xml.InstanceHandler; +import org.jclouds.deltacloud.xml.InstanceStatesHandler; import org.jclouds.deltacloud.xml.InstancesHandler; import org.jclouds.deltacloud.xml.RealmHandler; import org.jclouds.deltacloud.xml.RealmsHandler; @@ -55,10 +59,12 @@ import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.XMLResponseParser; +import org.jclouds.rest.functions.ReturnEmptyMultimapOnNotFoundOr404; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; +import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; /** @@ -78,9 +84,20 @@ public interface DeltacloudAsyncClient { */ @GET @Path("") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) @XMLResponseParser(DeltacloudCollectionsHandler.class) ListenableFuture> getCollections(); + /** + * @see DeltacloudClient#getInstanceStates + */ + @GET + @Endpoint(InstanceStates.class) + @Path("") + @ExceptionParser(ReturnEmptyMultimapOnNotFoundOr404.class) + @XMLResponseParser(InstanceStatesHandler.class) + ListenableFuture> getInstanceStates(); + /** * @see DeltacloudClient#listRealms */ 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 f38ebbbb95..4eea005d81 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudClient.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/DeltacloudClient.java @@ -28,10 +28,14 @@ import org.jclouds.deltacloud.domain.DeltacloudCollection; import org.jclouds.deltacloud.domain.HardwareProfile; import org.jclouds.deltacloud.domain.Image; import org.jclouds.deltacloud.domain.Instance; +import org.jclouds.deltacloud.domain.InstanceState; import org.jclouds.deltacloud.domain.Realm; +import org.jclouds.deltacloud.domain.Transition; import org.jclouds.deltacloud.options.CreateInstanceOptions; import org.jclouds.rest.annotations.EndpointParam; +import com.google.common.collect.Multimap; + /** * Provides synchronous access to deltacloud. *

@@ -50,6 +54,12 @@ public interface DeltacloudClient { */ Set getCollections(); + /** + * + * @return The possible states of an instance, and how to traverse between them + */ + Multimap getInstanceStates(); + /** * The realms collection will return a set of all realms available to the current user. * diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/config/DeltacloudRestClientModule.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/config/DeltacloudRestClientModule.java index 66f075e358..a5a57ea8af 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/config/DeltacloudRestClientModule.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/config/DeltacloudRestClientModule.java @@ -33,6 +33,7 @@ import org.jclouds.deltacloud.DeltacloudAsyncClient; import org.jclouds.deltacloud.DeltacloudClient; import org.jclouds.deltacloud.collections.HardwareProfiles; import org.jclouds.deltacloud.collections.Images; +import org.jclouds.deltacloud.collections.InstanceStates; import org.jclouds.deltacloud.collections.Instances; import org.jclouds.deltacloud.collections.Realms; import org.jclouds.deltacloud.domain.DeltacloudCollection; @@ -135,4 +136,10 @@ public class DeltacloudRestClientModule extends RestClientModule> collectionSupplier) { return findCollectionWithRel(collectionSupplier.get(), "realms").getHref(); } + + @Provides + @InstanceStates + protected URI provideInstanceStateCollection(Supplier> collectionSupplier) { + return findCollectionWithRel(collectionSupplier.get(), "instance_states").getHref(); + } } diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/DeltacloudCollection.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/DeltacloudCollection.java index 2590feb81c..1c08d74aaf 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/DeltacloudCollection.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/DeltacloudCollection.java @@ -79,46 +79,4 @@ public class DeltacloudCollection { public String toString() { return "[href=" + href + ", rel=" + rel + ", features=" + features + "]"; } - - public static class Feature { - private final String name; - - public Feature(String name) { - this.name = checkNotNull(name, "name"); - } - - public String getName() { - return name; - } - - @Override - public String toString() { - return "[name=" + name + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - 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; - Feature other = (Feature) obj; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; - } - } } \ No newline at end of file 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 index 7f43b00ada..44393a6d11 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceAction.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceAction.java @@ -30,12 +30,16 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public enum InstanceAction { + CREATE, + REBOOT, START, STOP, + DESTROY, + UNRECOGNIZED; public String value() { 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 index aeded33830..2609b9f582 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceState.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/InstanceState.java @@ -29,21 +29,26 @@ import static com.google.common.base.Preconditions.checkNotNull; * */ public enum InstanceState { - + /** + * initial state, before instance is created. + */ + START, /** * the instance is in the process of being launched */ PENDING, - + /** + * the instance launched (although the boot process might not be completed) + */ + RUNNING, /** * the instance is stopped */ STOPPED, /** - * the instance launched (although the boot process might not be completed) + * the instance is terminated */ - RUNNING, - + FINISH, /** * state returned as something besides the above. */ diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/TransitionOnAction.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/TransitionOnAction.java index 654738ad1a..d933f9ffcd 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/TransitionOnAction.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/domain/TransitionOnAction.java @@ -26,10 +26,10 @@ import static com.google.common.base.Preconditions.checkNotNull; * @author Adrian Cole */ public class TransitionOnAction implements Transition { - private final String action; + private final InstanceAction action; private final InstanceState to; - public TransitionOnAction(String action, InstanceState to) { + public TransitionOnAction(InstanceAction action, InstanceState to) { this.to = checkNotNull(to, "to"); this.action = checkNotNull(action, "action"); } @@ -38,7 +38,7 @@ public class TransitionOnAction implements Transition { return to; } - public String getAction() { + public InstanceAction getAction() { return action; } diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/DeltacloudCollectionHandler.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/DeltacloudCollectionHandler.java index 307f23520c..5fb06589fa 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/DeltacloudCollectionHandler.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/DeltacloudCollectionHandler.java @@ -24,7 +24,7 @@ import java.util.Map; import java.util.Set; import org.jclouds.deltacloud.domain.DeltacloudCollection; -import org.jclouds.deltacloud.domain.DeltacloudCollection.Feature; +import org.jclouds.deltacloud.domain.Feature; import org.jclouds.http.functions.ParseSax; import org.jclouds.util.Utils; import org.xml.sax.Attributes; diff --git a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceStatesHandler.java b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceStatesHandler.java index f4ef37b139..ef3b8370bd 100644 --- a/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceStatesHandler.java +++ b/sandbox/deltacloud/src/main/java/org/jclouds/deltacloud/xml/InstanceStatesHandler.java @@ -21,6 +21,7 @@ package org.jclouds.deltacloud.xml; import java.util.Map; +import org.jclouds.deltacloud.domain.InstanceAction; import org.jclouds.deltacloud.domain.InstanceState; import org.jclouds.deltacloud.domain.Transition; import org.jclouds.deltacloud.domain.TransitionAutomatically; @@ -56,8 +57,8 @@ public class InstanceStatesHandler extends ParseSax.HandlerWithResult> collectionSupplier) { + return URI.create("http://localhost:3001/api/instance_states"); + } } @Override diff --git a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudClientLiveTest.java b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudClientLiveTest.java index 4abfe6160f..912cc13e9d 100644 --- a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudClientLiveTest.java +++ b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/DeltacloudClientLiveTest.java @@ -38,6 +38,7 @@ import org.jclouds.deltacloud.domain.Instance; import org.jclouds.deltacloud.domain.InstanceAction; import org.jclouds.deltacloud.domain.InstanceState; import org.jclouds.deltacloud.domain.Realm; +import org.jclouds.deltacloud.domain.Transition; import org.jclouds.deltacloud.options.CreateInstanceOptions; import org.jclouds.domain.Credentials; import org.jclouds.logging.log4j.config.Log4JLoggingModule; @@ -56,6 +57,7 @@ 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.common.collect.Multimap; import com.google.gson.Gson; import com.google.inject.Guice; import com.google.inject.Module; @@ -116,6 +118,28 @@ public class DeltacloudClientLiveTest { assertNotNull(links); } + @Test + public void testGetInstanceStatesCanGoFromStartToFinish() throws Exception { + Multimap states = client.getInstanceStates(); + assertNotNull(states); + Iterable fromStart = findChainToFinish(InstanceState.START, states); + assert Iterables.size(fromStart) > 0 : fromStart; + } + + Iterable findChainToFinish(InstanceState currentState, + Multimap states) { + for (Transition transition : states.get(currentState)) { + if (currentState.ordinal() >= transition.getTo().ordinal()) + continue; + if (transition.getTo() == InstanceState.FINISH) + return ImmutableSet. of(transition); + Iterable transitions = findChainToFinish(transition.getTo(), states); + if (Iterables.size(transitions) > 0) + return Iterables.concat(ImmutableSet.of(transition), transitions); + } + return ImmutableSet. of(); + } + public void testListAndGetRealms() throws Exception { Set response = client.listRealms(); assert null != response; diff --git a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/DeltacloudCollectionsHandlerTest.java b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/DeltacloudCollectionsHandlerTest.java index 9bf65539e8..4c82814a70 100644 --- a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/DeltacloudCollectionsHandlerTest.java +++ b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/DeltacloudCollectionsHandlerTest.java @@ -26,7 +26,7 @@ import java.net.URI; import java.util.Set; import org.jclouds.deltacloud.domain.DeltacloudCollection; -import org.jclouds.deltacloud.domain.DeltacloudCollection.Feature; +import org.jclouds.deltacloud.domain.Feature; import org.jclouds.http.functions.BaseHandlerTest; import org.testng.annotations.Test; diff --git a/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceStatesHandlerTest.java b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceStatesHandlerTest.java new file mode 100644 index 0000000000..a94fdcf953 --- /dev/null +++ b/sandbox/deltacloud/src/test/java/org/jclouds/deltacloud/xml/InstanceStatesHandlerTest.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.deltacloud.xml; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; + +import org.jclouds.deltacloud.domain.InstanceAction; +import org.jclouds.deltacloud.domain.InstanceState; +import org.jclouds.deltacloud.domain.Transition; +import org.jclouds.deltacloud.domain.TransitionAutomatically; +import org.jclouds.deltacloud.domain.TransitionOnAction; +import org.jclouds.http.functions.BaseHandlerTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; + +/** + * Tests behavior of {@code InstanceStatesHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class InstanceStatesHandlerTest extends BaseHandlerTest { + + public void test() { + InputStream is = getClass().getResourceAsStream("/test_get_states.xml"); + Multimap expects = ImmutableMultimap + . builder() + .put(InstanceState.START, new TransitionOnAction(InstanceAction.CREATE, InstanceState.PENDING)) + .put(InstanceState.PENDING, new TransitionAutomatically(InstanceState.RUNNING)) + .putAll(InstanceState.RUNNING, new TransitionOnAction(InstanceAction.REBOOT, InstanceState.RUNNING), + new TransitionOnAction(InstanceAction.STOP, InstanceState.STOPPED)) + .putAll(InstanceState.STOPPED, new TransitionOnAction(InstanceAction.START, InstanceState.RUNNING), + new TransitionOnAction(InstanceAction.DESTROY, InstanceState.FINISH)).build(); + + // not sure why this isn"t always automatically called from surefire. + setUpInjector(); + assertEquals(factory.create(injector.getInstance(InstanceStatesHandler.class)).parse(is).entries(), + expects.entries()); + + } +} diff --git a/sandbox/deltacloud/src/test/resources/test_get_states.xml b/sandbox/deltacloud/src/test/resources/test_get_states.xml new file mode 100644 index 0000000000..3f0efacab5 --- /dev/null +++ b/sandbox/deltacloud/src/test/resources/test_get_states.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file