mirror of https://github.com/apache/jclouds.git
deltacloud: added state handling
This commit is contained in:
parent
e8b2303ba1
commit
fced69c15f
|
@ -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<? extends Set<? extends DeltacloudCollection>> getCollections();
|
||||
|
||||
/**
|
||||
* @see DeltacloudClient#getInstanceStates
|
||||
*/
|
||||
@GET
|
||||
@Endpoint(InstanceStates.class)
|
||||
@Path("")
|
||||
@ExceptionParser(ReturnEmptyMultimapOnNotFoundOr404.class)
|
||||
@XMLResponseParser(InstanceStatesHandler.class)
|
||||
ListenableFuture<? extends Multimap<InstanceState, ? extends Transition>> getInstanceStates();
|
||||
|
||||
/**
|
||||
* @see DeltacloudClient#listRealms
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
* <p/>
|
||||
|
@ -50,6 +54,12 @@ public interface DeltacloudClient {
|
|||
*/
|
||||
Set<? extends DeltacloudCollection> getCollections();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The possible states of an instance, and how to traverse between them
|
||||
*/
|
||||
Multimap<InstanceState, ? extends Transition> getInstanceStates();
|
||||
|
||||
/**
|
||||
* The realms collection will return a set of all realms available to the current user.
|
||||
*
|
||||
|
|
|
@ -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<DeltacloudClien
|
|||
protected URI provideRealmCollection(Supplier<Set<? extends DeltacloudCollection>> collectionSupplier) {
|
||||
return findCollectionWithRel(collectionSupplier.get(), "realms").getHref();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@InstanceStates
|
||||
protected URI provideInstanceStateCollection(Supplier<Set<? extends DeltacloudCollection>> collectionSupplier) {
|
||||
return findCollectionWithRel(collectionSupplier.get(), "instance_states").getHref();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,12 +30,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
*/
|
||||
public enum InstanceAction {
|
||||
|
||||
CREATE,
|
||||
|
||||
REBOOT,
|
||||
|
||||
START,
|
||||
|
||||
STOP,
|
||||
|
||||
DESTROY,
|
||||
|
||||
UNRECOGNIZED;
|
||||
|
||||
public String value() {
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Multimap<I
|
|||
else
|
||||
states.put(
|
||||
state,
|
||||
new TransitionOnAction(attributes.get("action"), InstanceState.valueOf(attributes.get("to")
|
||||
.toUpperCase())));
|
||||
new TransitionOnAction(InstanceAction.fromValue(attributes.get("action")), InstanceState
|
||||
.valueOf(attributes.get("to").toUpperCase())));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,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;
|
||||
|
@ -49,6 +50,7 @@ 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.ReturnEmptyMultimapOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
|
@ -89,12 +91,27 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
|
|||
|
||||
assertResponseParserClassEquals(method, httpRequest, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, DeltacloudCollectionsHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(httpRequest);
|
||||
|
||||
}
|
||||
|
||||
public void testGetInstanceStates() throws IOException, SecurityException, NoSuchMethodException {
|
||||
Method method = DeltacloudAsyncClient.class.getMethod("getInstanceStates");
|
||||
HttpRequest request = processor.createRequest(method);
|
||||
|
||||
assertRequestLineEquals(request, "GET http://localhost:3001/api/instance_states HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "Accept: application/xml\n");
|
||||
assertPayloadEquals(request, null, null, false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, InstanceStatesHandler.class);
|
||||
assertExceptionParserClassEquals(method, ReturnEmptyMultimapOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testListRealms() throws IOException, SecurityException, NoSuchMethodException {
|
||||
Method method = DeltacloudAsyncClient.class.getMethod("listRealms");
|
||||
HttpRequest request = processor.createRequest(method);
|
||||
|
@ -326,6 +343,10 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
|
|||
return URI.create("http://localhost:3001/api/realms");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URI provideInstanceStateCollection(Supplier<Set<? extends DeltacloudCollection>> collectionSupplier) {
|
||||
return URI.create("http://localhost:3001/api/instance_states");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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<InstanceState, ? extends Transition> states = client.getInstanceStates();
|
||||
assertNotNull(states);
|
||||
Iterable<Transition> fromStart = findChainToFinish(InstanceState.START, states);
|
||||
assert Iterables.size(fromStart) > 0 : fromStart;
|
||||
}
|
||||
|
||||
Iterable<Transition> findChainToFinish(InstanceState currentState,
|
||||
Multimap<InstanceState, ? extends Transition> states) {
|
||||
for (Transition transition : states.get(currentState)) {
|
||||
if (currentState.ordinal() >= transition.getTo().ordinal())
|
||||
continue;
|
||||
if (transition.getTo() == InstanceState.FINISH)
|
||||
return ImmutableSet.<Transition> of(transition);
|
||||
Iterable<Transition> transitions = findChainToFinish(transition.getTo(), states);
|
||||
if (Iterables.size(transitions) > 0)
|
||||
return Iterables.concat(ImmutableSet.of(transition), transitions);
|
||||
}
|
||||
return ImmutableSet.<Transition> of();
|
||||
}
|
||||
|
||||
public void testListAndGetRealms() throws Exception {
|
||||
Set<? extends Realm> response = client.listRealms();
|
||||
assert null != response;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.jclouds.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<InstanceState, ? extends Transition> expects = ImmutableMultimap
|
||||
.<InstanceState, Transition> 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());
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<states>
|
||||
<state name='start'>
|
||||
<transition action='create' to='pending'></transition>
|
||||
</state>
|
||||
<state name='pending'>
|
||||
<transition auto='true' to='running'></transition>
|
||||
</state>
|
||||
<state name='running'>
|
||||
<transition action='reboot' to='running'></transition>
|
||||
<transition action='stop' to='stopped'></transition>
|
||||
</state>
|
||||
<state name='stopped'>
|
||||
<transition action='start' to='running'></transition>
|
||||
<transition action='destroy' to='finish'></transition>
|
||||
</state>
|
||||
<state name='finish'>
|
||||
</state>
|
||||
</states>
|
Loading…
Reference in New Issue