You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2015/08/24 10:53:49 UTC

[1/6] incubator-brooklyn git commit: LocationResource indentation

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 0b723a09f -> 6fe9fc762


LocationResource indentation


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/d6f2f387
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/d6f2f387
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/d6f2f387

Branch: refs/heads/master
Commit: d6f2f38754c3a63df1b5584b9cd87e7dde65468f
Parents: 2a3603b
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Tue Aug 18 18:04:12 2015 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Fri Aug 21 10:16:42 2015 +0100

----------------------------------------------------------------------
 .../rest/resources/LocationResource.java        | 25 ++++++++++----------
 1 file changed, 13 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d6f2f387/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/LocationResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/LocationResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/LocationResource.java
index 275dbe9..c6bf9e7 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/LocationResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/LocationResource.java
@@ -153,18 +153,19 @@ public class LocationResource extends AbstractBrooklynRestResource implements Lo
                 "",
                 "brooklyn.locations:",
                 "- type: "+locationSpec.getSpec());
-          if (locationSpec.getConfig().size() > 0) {
-              yaml.add("  brooklyn.config:");
-              for (Map.Entry<String, ?> entry : locationSpec.getConfig().entrySet()) {
-                  yaml.add("    "+entry.getKey()+": "+entry.getValue());
-              }
-          }
-
-          brooklyn().getCatalog().addItems(Joiner.on("\n").join(yaml.build()));
-          LocationDefinition l = brooklyn().getLocationRegistry().getDefinedLocationByName(name);
-          return Response.created(URI.create(name))
-                  .entity(LocationTransformer.newInstance(mgmt(), l, LocationDetailLevel.LOCAL_EXCLUDING_SECRET))
-                  .build();
+        if (locationSpec.getConfig().size() > 0) {
+            yaml.add("  brooklyn.config:");
+            for (Map.Entry<String, ?> entry : locationSpec.getConfig().entrySet()) {
+                yaml.add("    " + entry.getKey() + ": " + entry.getValue());
+            }
+        }
+
+        String locationBlueprint = Joiner.on("\n").join(yaml.build());
+        brooklyn().getCatalog().addItems(locationBlueprint);
+        LocationDefinition l = brooklyn().getLocationRegistry().getDefinedLocationByName(name);
+        return Response.created(URI.create(name))
+                .entity(LocationTransformer.newInstance(mgmt(), l, LocationDetailLevel.LOCAL_EXCLUDING_SECRET))
+                .build();
     }
 
     @Override


[4/6] incubator-brooklyn git commit: ByonLocationResolver handles non-lowercase values for osFamily

Posted by sj...@apache.org.
ByonLocationResolver handles non-lowercase values for osFamily


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/c3e027b8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/c3e027b8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/c3e027b8

Branch: refs/heads/master
Commit: c3e027b80826427d04e3b726bf9f71f24fc46103
Parents: d6f2f38
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Tue Aug 18 18:19:21 2015 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Fri Aug 21 10:16:43 2015 +0100

----------------------------------------------------------------------
 .../brooklyn/core/location/BasicLocationRegistry.java |  2 +-
 .../brooklyn/location/byon/ByonLocationResolver.java  |  9 +++++++--
 .../location/byon/ByonLocationResolverTest.java       | 14 ++++++++++----
 3 files changed, 18 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c3e027b8/core/src/main/java/org/apache/brooklyn/core/location/BasicLocationRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/BasicLocationRegistry.java b/core/src/main/java/org/apache/brooklyn/core/location/BasicLocationRegistry.java
index f8b7c73..573da76 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/BasicLocationRegistry.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/BasicLocationRegistry.java
@@ -334,7 +334,7 @@ public class BasicLocationRegistry implements LocationRegistry {
                 try {
                     return Maybe.of(resolver.newLocationFromString(locationFlags, spec, this));
                 } catch (RuntimeException e) {
-                    return Maybe.absent(Suppliers.ofInstance(e));
+                     return Maybe.absent(Suppliers.ofInstance(e));
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c3e027b8/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
index 2705f65..bef0046 100644
--- a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
@@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 
 import java.net.InetAddress;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import org.apache.brooklyn.api.location.Location;
@@ -98,7 +99,7 @@ public class ByonLocationResolver extends AbstractLocationResolver {
         config.remove("hosts");
         String user = (String) config.getStringKey("user");
         Integer port = (Integer) TypeCoercions.coerce(config.getStringKey("port"), Integer.class);
-        Class<? extends MachineLocation> locationClass = OS_TO_MACHINE_LOCATION_TYPE.get(config.get(OS_FAMILY));
+        Class<? extends MachineLocation> locationClass = getLocationClass(config.get(OS_FAMILY));
 
         MutableMap<String, Object> defaultProps = MutableMap.of();
         defaultProps.addIfNotNull("user", user);
@@ -199,12 +200,16 @@ public class ByonLocationResolver extends AbstractLocationResolver {
         
         Class<? extends MachineLocation> locationClassHere = locationClass;
         if (osfamily != null) {
-            locationClassHere = OS_TO_MACHINE_LOCATION_TYPE.get(osfamily);
+            locationClassHere = getLocationClass(osfamily);
         }
 
         return LocationSpec.create(locationClassHere).configure(machineConfig);
     }
 
+    private Class<? extends MachineLocation> getLocationClass(String osFamily) {
+        return osFamily == null ? null : OS_TO_MACHINE_LOCATION_TYPE.get(osFamily.toLowerCase(Locale.ENGLISH));
+    }
+
     protected LocationSpec<? extends MachineLocation> parseMachine(String val, Class<? extends MachineLocation> locationClass, Map<String, ?> defaults, String specForErrMsg) {
         Map<String, Object> machineConfig = Maps.newLinkedHashMap();
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c3e027b8/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java b/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
index 8e4e71a..51120e0 100644
--- a/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
@@ -56,6 +56,7 @@ import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Function;
@@ -332,14 +333,19 @@ public class ByonLocationResolverTest {
         Assert.assertEquals("1.1.1.1", location1.getAddress().getHostAddress());
     }
 
-    @Test
-    public void testWindowsMachines() throws Exception {
+    @DataProvider(name = "windowsOsFamilies")
+    public Object[][] getWindowsOsFamilies() {
+        return new Object[][]{{"windows"}, {"WINDOWS"}, {"wInDoWs"}};
+    }
+
+    @Test(dataProvider = "windowsOsFamilies")
+    public void testWindowsMachines(String osFamily) throws Exception {
         brooklynProperties.put("brooklyn.location.byon.user", "myuser");
         brooklynProperties.put("brooklyn.location.byon.password", "mypassword");
         String spec = "byon";
         Map<String, ?> flags = ImmutableMap.of(
                 "hosts", ImmutableList.of("1.1.1.1", "2.2.2.2"),
-                "osfamily", "windows"
+                "osfamily", osFamily
         );
         MachineProvisioningLocation<MachineLocation> provisioner = resolve(spec, flags);
         WinRmMachineLocation location = (WinRmMachineLocation) provisioner.obtain(ImmutableMap.of());
@@ -350,7 +356,7 @@ public class ByonLocationResolverTest {
     }
 
     @Test
-    public void testNoneWindowsMachines() throws Exception {
+    public void testNonWindowsMachines() throws Exception {
         String spec = "byon";
         Map<String, ?> flags = ImmutableMap.of(
                 "hosts", ImmutableList.of("1.1.1.1", "2.2.2.2"),


[6/6] incubator-brooklyn git commit: This closes #852

Posted by sj...@apache.org.
This closes #852


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/6fe9fc76
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/6fe9fc76
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/6fe9fc76

Branch: refs/heads/master
Commit: 6fe9fc7620ae74e7c0b7d741ce0229548f4c1d09
Parents: 0b723a0 6012a4e
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Mon Aug 24 09:53:22 2015 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Mon Aug 24 09:53:22 2015 +0100

----------------------------------------------------------------------
 .../api/location/MachineManagementMixins.java   |   5 +-
 .../core/location/BasicLocationRegistry.java    |   2 +-
 .../location/byon/ByonLocationResolver.java     |   9 +-
 .../location/byon/ByonLocationResolverTest.java |  14 +-
 .../location/jclouds/JcloudsLocation.java       | 169 ++++++++++++++-----
 .../jclouds/AbstractJcloudsLiveTest.java        |  15 ++
 .../JcloudsLocationRebindMachineLiveTest.java   | 138 ---------------
 .../JcloudsLocationRegisterMachineLiveTest.java | 144 ++++++++++++++++
 ...udsLocationSuspendResumeMachineLiveTest.java |  62 +++++++
 .../rest/resources/LocationResource.java        |  25 +--
 10 files changed, 380 insertions(+), 203 deletions(-)
----------------------------------------------------------------------



[3/6] incubator-brooklyn git commit: Deprecate JcloudsLocation#rebindMachine in favour of registerMachine

Posted by sj...@apache.org.
Deprecate JcloudsLocation#rebindMachine in favour of registerMachine

Return type now MachineLocation instead of JcloudsSshMachineLocation.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/cb36537b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/cb36537b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/cb36537b

Branch: refs/heads/master
Commit: cb36537b393f70b81b8aed4e64bd0cb6cc403b9c
Parents: c3e027b
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Tue Aug 18 18:27:51 2015 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Fri Aug 21 10:16:43 2015 +0100

----------------------------------------------------------------------
 .../location/jclouds/JcloudsLocation.java       | 45 +++++++++++++++++---
 1 file changed, 39 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cb36537b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
index 9167587..867d349 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
@@ -1861,16 +1861,41 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
     }
 
 
-    // ----------------- rebinding to existing machine ------------------------
+    // ----------------- registering existing machines ------------------------
 
+    /**
+     * @deprecated since 0.8.0 use {@link #registerMachine(NodeMetadata)} instead.
+     */
+    @Deprecated
     public JcloudsSshMachineLocation rebindMachine(NodeMetadata metadata) throws NoMachinesAvailableException {
-        return rebindMachine(MutableMap.of(), metadata);
+        return (JcloudsSshMachineLocation) registerMachine(metadata);
     }
+
+    public MachineLocation registerMachine(NodeMetadata metadata) throws NoMachinesAvailableException {
+        return registerMachine(MutableMap.of(), metadata);
+    }
+
+    /**
+     * @deprecated since 0.8.0 use {@link #registerMachine(Map, NodeMetadata)} instead.
+     */
+    @Deprecated
     public JcloudsSshMachineLocation rebindMachine(Map<?,?> flags, NodeMetadata metadata) throws NoMachinesAvailableException {
+        return (JcloudsSshMachineLocation) registerMachine(flags, metadata);
+    }
+
+    public MachineLocation registerMachine(Map<?, ?> flags, NodeMetadata metadata) throws NoMachinesAvailableException {
         ConfigBag setup = ConfigBag.newInstanceExtending(config().getBag(), flags);
         if (!setup.containsKey("id")) setup.putStringKey("id", metadata.getId());
         setHostnameUpdatingCredentials(setup, metadata);
-        return rebindMachine(setup);
+        return registerMachine(setup);
+    }
+
+    /**
+     * @deprecated since 0.8.0 use {@link #registerMachine(ConfigBag)} instead.
+     */
+    @Deprecated
+    public JcloudsSshMachineLocation rebindMachine(ConfigBag setup) throws NoMachinesAvailableException {
+        return (JcloudsSshMachineLocation) registerMachine(setup);
     }
 
     /**
@@ -1883,7 +1908,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
      *   <li>userName: the username for ssh'ing into the machine
      * <ul>
      */
-    public JcloudsSshMachineLocation rebindMachine(ConfigBag setup) throws NoMachinesAvailableException {
+    public MachineLocation registerMachine(ConfigBag setup) throws NoMachinesAvailableException {
         try {
             if (setup.getDescription() == null) setCreationString(setup);
             String user = checkNotNull(getUser(setup), "user");
@@ -1923,9 +1948,17 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         }
     }
 
-    public JcloudsSshMachineLocation rebindMachine(Map<?,?> flags) throws NoMachinesAvailableException {
+    /**
+     * @deprecated since 0.8.0 use {@link #registerMachine(Map)} instead.
+     */
+    @Deprecated
+    public JcloudsSshMachineLocation rebindMachine(Map<?, ?> flags) throws NoMachinesAvailableException {
+        return (JcloudsSshMachineLocation) registerMachine(flags);
+    }
+
+    public MachineLocation registerMachine(Map<?,?> flags) throws NoMachinesAvailableException {
         ConfigBag setup = ConfigBag.newInstanceExtending(config().getBag(), flags);
-        return rebindMachine(setup);
+        return registerMachine(setup);
     }
 
     /**


[2/6] incubator-brooklyn git commit: JcloudsLocation#registerMachine handles Windows machines

Posted by sj...@apache.org.
JcloudsLocation#registerMachine handles Windows machines


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/1a5e5e7f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/1a5e5e7f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/1a5e5e7f

Branch: refs/heads/master
Commit: 1a5e5e7f754c272b34c61e3f3a0debe731a42116
Parents: cb36537
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Tue Aug 18 18:32:40 2015 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Fri Aug 21 10:16:43 2015 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/location/jclouds/JcloudsLocation.java | 10 +++++++---
 .../jclouds/JcloudsLocationRebindMachineLiveTest.java     |  2 +-
 2 files changed, 8 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1a5e5e7f/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
index 867d349..21d4760 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
@@ -1903,9 +1903,9 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
      * <p>
      * Required fields are:
      * <ul>
-     *   <li>id: the jclouds VM id, e.g. "eu-west-1/i-5504f21d" (NB this is @see JcloudsSshMachineLocation#getJcloudsId() not #getId())
+     *   <li>id: the jclouds VM id, e.g. "eu-west-1/i-5504f21d" (NB this is {@see JcloudsMachineLocation#getJcloudsId()} not #getId())
      *   <li>hostname: the public hostname or IP of the machine, e.g. "ec2-176-34-93-58.eu-west-1.compute.amazonaws.com"
-     *   <li>userName: the username for ssh'ing into the machine
+     *   <li>userName: the username for sshing into the machine if it is not a Windows system
      * <ul>
      */
     public MachineLocation registerMachine(ConfigBag setup) throws NoMachinesAvailableException {
@@ -1941,7 +1941,11 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             // TODO confirm we can SSH ?
             // NB if rawHostname not set, get the hostname using getPublicHostname(node, Optional.<HostAndPort>absent(), setup);
 
-            return registerJcloudsSshMachineLocation(computeService, node, null, Optional.<HostAndPort>absent(), setup);
+            if (isWindows(node, setup)) {
+                return registerWinRmMachineLocation(computeService, node, null, Optional.<HostAndPort>absent(), setup);
+            } else {
+                return registerJcloudsSshMachineLocation(computeService, node, null, Optional.<HostAndPort>absent(), setup);
+            }
 
         } catch (IOException e) {
             throw Exceptions.propagate(e);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1a5e5e7f/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
index bf9ad59..6d891a6 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
@@ -52,7 +52,7 @@ public class JcloudsLocationRebindMachineLiveTest extends AbstractJcloudsLiveTes
     @Test(groups = { "Live", "Live-sanity" })
     public void testRebindWithIncorrectId() throws Exception {
         try {
-            jcloudsLocation.rebindMachine(ImmutableMap.of("id", "incorrectid", "hostname", "myhostname", "user", "myusername"));
+            jcloudsLocation.registerMachine(ImmutableMap.of("id", "incorrectid", "hostname", "myhostname", "user", "myusername"));
         } catch (IllegalArgumentException e) {
             if (e.getMessage().contains("node not found")) {
                 // success


[5/6] incubator-brooklyn git commit: JcloudsLocation implements SuspendResumeLocation

Posted by sj...@apache.org.
JcloudsLocation implements SuspendResumeLocation


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/6012a4e4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/6012a4e4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/6012a4e4

Branch: refs/heads/master
Commit: 6012a4e4cd27db1ccd1495ed1225fcc905d6b0f4
Parents: 1a5e5e7
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Fri Aug 21 10:21:23 2015 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Fri Aug 21 10:21:23 2015 +0100

----------------------------------------------------------------------
 .../api/location/MachineManagementMixins.java   |   5 +-
 .../location/jclouds/JcloudsLocation.java       | 130 +++++++++++------
 .../jclouds/AbstractJcloudsLiveTest.java        |  15 ++
 .../JcloudsLocationRebindMachineLiveTest.java   | 138 ------------------
 .../JcloudsLocationRegisterMachineLiveTest.java | 144 +++++++++++++++++++
 ...udsLocationSuspendResumeMachineLiveTest.java |  62 ++++++++
 6 files changed, 311 insertions(+), 183 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6012a4e4/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java b/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java
index b91aeb8..f7c091b 100644
--- a/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java
+++ b/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java
@@ -70,8 +70,7 @@ public class MachineManagementMixins {
      * Implement to indicate that a location can suspend and resume machines.
      */
     @Beta
-    public interface SuspendResumeLocation extends SuspendsMachines, ResumesMachines {};
-
+    public interface SuspendResumeLocation extends SuspendsMachines, ResumesMachines {}
 
     @Beta
     public interface SuspendsMachines {
@@ -86,7 +85,7 @@ public class MachineManagementMixins {
         /**
          * Resume the indicated machine.
          */
-        void resumeMachine(MachineLocation location);
+        MachineLocation resumeMachine(Map<?, ?> flags);
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6012a4e4/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
index 21d4760..6b960d3 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
@@ -189,7 +189,7 @@ import io.cloudsoft.winrm4j.pywinrm.WinRMFactory;
 @SuppressWarnings("serial")
 public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation implements
         JcloudsLocationConfig, MachineManagementMixins.RichMachineProvisioningLocation<MachineLocation>,
-        LocationWithObjectStore, MachineManagementMixins.SuspendsMachines {
+        LocationWithObjectStore, MachineManagementMixins.SuspendResumeLocation {
 
     // TODO After converting from Groovy to Java, this is now very bad code! It relies entirely on putting
     // things into and taking them out of maps; it's not type-safe, and it's thus very error-prone.
@@ -514,7 +514,11 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         ConfigBag conf = (flags==null || flags.isEmpty())
                 ? config().getBag()
                 : ConfigBag.newInstanceExtending(config().getBag(), flags);
-        return getConfig(COMPUTE_SERVICE_REGISTRY).findComputeService(conf, true);
+        return getComputeService(conf);
+    }
+
+    public ComputeService getComputeService(ConfigBag config) {
+        return getConfig(COMPUTE_SERVICE_REGISTRY).findComputeService(config, true);
     }
 
     /** @deprecated since 0.7.0 use {@link #listMachines()} */ @Deprecated
@@ -1054,6 +1058,32 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         }
     }
 
+    /**
+     * Brings an existing machine with the given details under management.
+     * <p/>
+     * Note that this method does <b>not</b> call the lifecycle methods of any
+     * {@link #getCustomizers(ConfigBag) customizers} attached to this location.
+     *
+     * @param flags See {@link #registerMachine(ConfigBag)} for a description of required fields.
+     * @see #registerMachine(ConfigBag)
+     */
+    @Override
+    public MachineLocation resumeMachine(Map<?, ?> flags) {
+        ConfigBag setup = ConfigBag.newInstanceExtending(config().getBag(), flags);
+        LOG.info("{} using resuming node matching properties: {}", this, setup);
+        ComputeService computeService = getComputeService(setup);
+        NodeMetadata node = findNodeOrThrow(setup);
+        LOG.debug("{} resuming {}", this, node);
+        computeService.resumeNode(node.getId());
+        // Load the node a second time once it is resumed to get an object with
+        // hostname and addresses populated.
+        node = findNodeOrThrow(setup);
+        LOG.debug("{} resumed {}", this, node);
+        MachineLocation registered = registerMachineLocation(setup, node);
+        LOG.info("{} resumed and registered {}", this, registered);
+        return registered;
+    }
+
     // ------------- constructing the template, etc ------------------------
 
     private static interface CustomizeTemplateBuilder {
@@ -1871,7 +1901,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         return (JcloudsSshMachineLocation) registerMachine(metadata);
     }
 
-    public MachineLocation registerMachine(NodeMetadata metadata) throws NoMachinesAvailableException {
+    protected MachineLocation registerMachine(NodeMetadata metadata) throws NoMachinesAvailableException {
         return registerMachine(MutableMap.of(), metadata);
     }
 
@@ -1883,7 +1913,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         return (JcloudsSshMachineLocation) registerMachine(flags, metadata);
     }
 
-    public MachineLocation registerMachine(Map<?, ?> flags, NodeMetadata metadata) throws NoMachinesAvailableException {
+    protected MachineLocation registerMachine(Map<?, ?> flags, NodeMetadata metadata) throws NoMachinesAvailableException {
         ConfigBag setup = ConfigBag.newInstanceExtending(config().getBag(), flags);
         if (!setup.containsKey("id")) setup.putStringKey("id", metadata.getId());
         setHostnameUpdatingCredentials(setup, metadata);
@@ -1891,6 +1921,9 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
     }
 
     /**
+     * Brings an existing machine with the given details under management.
+     * <p>
+     * This method will throw an exception if used to reconnect to a Windows VM.
      * @deprecated since 0.8.0 use {@link #registerMachine(ConfigBag)} instead.
      */
     @Deprecated
@@ -1905,54 +1938,67 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
      * <ul>
      *   <li>id: the jclouds VM id, e.g. "eu-west-1/i-5504f21d" (NB this is {@see JcloudsMachineLocation#getJcloudsId()} not #getId())
      *   <li>hostname: the public hostname or IP of the machine, e.g. "ec2-176-34-93-58.eu-west-1.compute.amazonaws.com"
-     *   <li>userName: the username for sshing into the machine if it is not a Windows system
+     *   <li>userName: the username for sshing into the machine (for use if it is not a Windows system)
      * <ul>
      */
     public MachineLocation registerMachine(ConfigBag setup) throws NoMachinesAvailableException {
-        try {
-            if (setup.getDescription() == null) setCreationString(setup);
-            String user = checkNotNull(getUser(setup), "user");
-            String rawId = (String) setup.getStringKey("id");
-            String rawHostname = (String) setup.getStringKey("hostname");
-            Predicate<ComputeMetadata> predicate = getRebindToMachinePredicate(setup);
-            LOG.info("Rebinding to VM {} ({}@{}), in jclouds location for provider {} matching {}", new Object[]{
-                    rawId != null ? rawId : "<lookup>",
-                    user,
-                    rawHostname != null ? rawHostname : "<unspecified>",
-                    getProvider(),
-                    predicate
-                    });
-            ComputeService computeService = getConfig(COMPUTE_SERVICE_REGISTRY).findComputeService(setup, true);
-            Set<? extends NodeMetadata> candidateNodes = computeService.listNodesDetailsMatching(predicate);
-            if (candidateNodes.isEmpty()) {
-                throw new IllegalArgumentException("Jclouds node not found for rebind with predicate " + predicate);
-            } else if (candidateNodes.size() > 1) {
-                throw new IllegalArgumentException("Jclouds node for rebind matched multiple with " + predicate + ": " + candidateNodes);
-            }
-
-            NodeMetadata node = Iterables.getOnlyElement(candidateNodes);
-            String pkd = LocationConfigUtils.getOsCredential(setup).checkNoErrors().logAnyWarnings().getPrivateKeyData();
-            if (Strings.isNonBlank(pkd)) {
-                LoginCredentials expectedCredentials = LoginCredentials.fromCredentials(new Credentials(user, pkd));
-                //override credentials
-                node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(expectedCredentials).build();
-            }
-
-            // TODO confirm we can SSH ?
-            // NB if rawHostname not set, get the hostname using getPublicHostname(node, Optional.<HostAndPort>absent(), setup);
+        NodeMetadata node = findNodeOrThrow(setup);
+        return registerMachineLocation(setup, node);
+    }
 
-            if (isWindows(node, setup)) {
-                return registerWinRmMachineLocation(computeService, node, null, Optional.<HostAndPort>absent(), setup);
-            } else {
+    protected MachineLocation registerMachineLocation(ConfigBag setup, NodeMetadata node) {
+        ComputeService computeService = getComputeService(setup);
+        if (isWindows(node, setup)) {
+            return registerWinRmMachineLocation(computeService, node, null, Optional.<HostAndPort>absent(), setup);
+        } else {
+            try {
                 return registerJcloudsSshMachineLocation(computeService, node, null, Optional.<HostAndPort>absent(), setup);
+            } catch (IOException e) {
+                throw Exceptions.propagate(e);
             }
-
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
         }
     }
 
     /**
+     * Finds a node matching the properties given in config or throws an exception.
+     * @param config
+     * @return
+     */
+    protected NodeMetadata findNodeOrThrow(ConfigBag config) {
+        if (config.getDescription() == null) {
+            setCreationString(config);
+        }
+        String user = checkNotNull(getUser(config), "user");
+        String rawId = (String) config.getStringKey("id");
+        String rawHostname = (String) config.getStringKey("hostname");
+        Predicate<ComputeMetadata> predicate = getRebindToMachinePredicate(config);
+        LOG.debug("Finding VM {} ({}@{}), in jclouds location for provider {} matching {}", new Object[]{
+                rawId != null ? rawId : "<lookup>",
+                user,
+                rawHostname != null ? rawHostname : "<unspecified>",
+                getProvider(),
+                predicate
+        });
+        ComputeService computeService = getComputeService(config);
+        Set<? extends NodeMetadata> candidateNodes = computeService.listNodesDetailsMatching(predicate);
+        if (candidateNodes.isEmpty()) {
+            throw new IllegalArgumentException("Jclouds node not found for rebind with predicate " + predicate);
+        } else if (candidateNodes.size() > 1) {
+            throw new IllegalArgumentException("Jclouds node for rebind matched multiple with " + predicate + ": " + candidateNodes);
+        }
+        NodeMetadata node = Iterables.getOnlyElement(candidateNodes);
+
+        String pkd = LocationConfigUtils.getOsCredential(config).checkNoErrors().logAnyWarnings().getPrivateKeyData();
+        if (Strings.isNonBlank(pkd)) {
+            LoginCredentials expectedCredentials = LoginCredentials.fromCredentials(new Credentials(user, pkd));
+            //override credentials
+            node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(expectedCredentials).build();
+        }
+
+        return node;
+    }
+
+    /**
      * @deprecated since 0.8.0 use {@link #registerMachine(Map)} instead.
      */
     @Deprecated

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6012a4e4/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
index 4061ea3..13138a5 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
+import org.apache.brooklyn.api.location.MachineLocation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -154,4 +155,18 @@ public class AbstractJcloudsLiveTest {
         machines.remove(machine);
         jcloudsLocation.release(machine);
     }
+
+    protected void suspendMachine(MachineLocation machine) {
+        assertNotNull(jcloudsLocation);
+        machines.remove(machine);
+        jcloudsLocation.suspendMachine(machine);
+    }
+
+    protected MachineLocation resumeMachine(Map<?, ?> flags) {
+        assertNotNull(jcloudsLocation);
+        MachineLocation location = jcloudsLocation.resumeMachine(flags);
+        machines.add((JcloudsSshMachineLocation) location);
+        return location;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6012a4e4/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
deleted file mode 100644
index 6d891a6..0000000
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.apache.brooklyn.location.jclouds;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-
-import java.net.InetAddress;
-import java.util.Collections;
-
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-public class JcloudsLocationRebindMachineLiveTest extends AbstractJcloudsLiveTest {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(JcloudsLocationRebindMachineLiveTest.class);
-    
-    private static final String EUWEST_IMAGE_ID = AWS_EC2_EUWEST_REGION_NAME+"/"+"ami-89def4fd";
-    private static final String IMAGE_OWNER = "411009282317";
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_PROVIDER+":"+AWS_EC2_EUWEST_REGION_NAME);
-    }
-
-    @Test(groups = { "Live", "Live-sanity" })
-    public void testRebindWithIncorrectId() throws Exception {
-        try {
-            jcloudsLocation.registerMachine(ImmutableMap.of("id", "incorrectid", "hostname", "myhostname", "user", "myusername"));
-        } catch (IllegalArgumentException e) {
-            if (e.getMessage().contains("node not found")) {
-                // success
-            } else {
-                throw e;
-            }
-        }
-    }
-    
-    @Test(groups = { "Live" })
-    public void testRebindVm() throws Exception {
-        // FIXME How to create a machine - go directly through jclouds instead?
-        //       Going through LocationRegistry.resolve, loc and loc2 might be same instance
-        
-        // Create a VM through jclouds
-        JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.of("imageId", EUWEST_IMAGE_ID, "imageOwner", IMAGE_OWNER));
-        assertTrue(machine.isSshable());
-        LOG.info("obtained "+machine);
-
-        String id = checkNotNull(machine.getJcloudsId(), "id");
-        InetAddress address = checkNotNull(machine.getAddress(), "address");
-        String hostname = checkNotNull(address.getHostName(), "hostname");
-        String user = checkNotNull(machine.getUser(), "user");
-        
-        // Create a new jclouds location, and re-bind the existing VM to that
-        JcloudsLocation loc2 = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_PROVIDER+":"+AWS_EC2_EUWEST_REGION_NAME);
-        SshMachineLocation machine2 = loc2.rebindMachine(ImmutableMap.of("id", id, "hostname", hostname, "user", user));
-        
-        LOG.info("rebinded to "+machine2);
-        
-        // Confirm the re-bound machine is wired up
-        assertTrue(machine2.isSshable());
-        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), ImmutableSet.of(machine2));
-        
-        // Confirm can release the re-bound machine via the new jclouds location
-        loc2.release(machine2);
-        assertFalse(machine.isSshable());
-        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), Collections.emptySet());
-    }
-    
-    @Test(groups = { "Live" })
-    public void testRebindVmDeprecated() throws Exception {
-        // FIXME See comments in testRebindVm
-
-        // Create a VM through jclouds
-        JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.of("imageId", EUWEST_IMAGE_ID, "imageOwner", IMAGE_OWNER));
-        assertTrue(machine.isSshable());
-
-        String id = machine.getJcloudsId();
-        InetAddress address = machine.getAddress();
-        String hostname = address.getHostName();
-        String username = machine.getUser();
-        
-        // Create a new jclouds location, and re-bind the existing VM to that
-        JcloudsLocation loc2 = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_PROVIDER+":"+AWS_EC2_EUWEST_REGION_NAME);
-        // pass deprecated userName
-        SshMachineLocation machine2 = loc2.rebindMachine(ImmutableMap.of("id", id, "hostname", hostname, "userName", username));
-        
-        // Confirm the re-bound machine is wired up
-        assertTrue(machine2.isSshable());
-        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), ImmutableSet.of(machine2));
-        
-        // Confirm can release the re-bound machine via the new jclouds location
-        loc2.release(machine2);
-        assertFalse(machine.isSshable());
-        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), Collections.emptySet());
-    }
-
-    // Useful for debugging; accesss a hard-coded existing instance so don't need to wait for provisioning a new one
-    @Test(enabled=false, groups = { "Live" })
-    public void testRebindVmToHardcodedInstance() throws Exception {
-        String id = "eu-west-1/i-5504f21d";
-        InetAddress address = InetAddress.getByName("ec2-176-34-93-58.eu-west-1.compute.amazonaws.com");
-        String hostname = address.getHostName();
-        String username = "root";
-        
-        SshMachineLocation machine = jcloudsLocation.rebindMachine(ImmutableMap.of("id", id, "hostname", hostname, "userName", username));
-        
-        // Confirm the re-bound machine is wired up
-        assertTrue(machine.isSshable());
-        assertEquals(ImmutableSet.copyOf(jcloudsLocation.getChildren()), ImmutableSet.of(machine));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6012a4e4/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRegisterMachineLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRegisterMachineLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRegisterMachineLiveTest.java
new file mode 100644
index 0000000..e7d7d36
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRegisterMachineLiveTest.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.brooklyn.location.jclouds;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.net.InetAddress;
+import java.util.Collections;
+
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class JcloudsLocationRegisterMachineLiveTest extends AbstractJcloudsLiveTest {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(JcloudsLocationRegisterMachineLiveTest.class);
+    
+    private static final String EUWEST_IMAGE_ID = AWS_EC2_EUWEST_REGION_NAME+"/"+"ami-ce7b6fba";
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_PROVIDER+":"+AWS_EC2_EUWEST_REGION_NAME);
+    }
+
+    @Test(groups = { "Live", "Live-sanity" })
+    public void testRegisterWithIncorrectId() throws Exception {
+        try {
+            jcloudsLocation.registerMachine(ImmutableMap.of("id", "incorrectid", "hostname", "myhostname", "user", "myusername"));
+        } catch (IllegalArgumentException e) {
+            if (e.getMessage().contains("node not found")) {
+                // success
+            } else {
+                throw e;
+            }
+        }
+    }
+    
+    @Test(groups = { "Live" })
+    public void testRegisterVm() throws Exception {
+        // FIXME How to create a machine - go directly through jclouds instead?
+        //       Going through LocationRegistry.resolve, loc and loc2 might be same instance
+        
+        // Create a VM through jclouds
+        JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.of("imageId", EUWEST_IMAGE_ID));
+        assertTrue(machine.isSshable());
+        LOG.info("obtained "+machine);
+
+        String id = checkNotNull(machine.getJcloudsId(), "id");
+        InetAddress address = checkNotNull(machine.getAddress(), "address");
+        String hostname = checkNotNull(address.getHostName(), "hostname");
+        String user = checkNotNull(machine.getUser(), "user");
+        
+        // Create a new jclouds location, and re-bind the existing VM to that
+        JcloudsLocation loc2 = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_PROVIDER+":"+AWS_EC2_EUWEST_REGION_NAME);
+        MachineLocation machineLocation = loc2.registerMachine(ImmutableMap.of("id", id, "hostname", hostname, "user", user));
+        assertTrue(machineLocation instanceof SshMachineLocation);
+        SshMachineLocation machine2 = (SshMachineLocation) machineLocation;
+
+        LOG.info("Registered " + machine2);
+        
+        // Confirm the re-bound machine is wired up
+        assertTrue(machine2.isSshable());
+        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), ImmutableSet.of(machine2));
+        
+        // Confirm can release the re-bound machine via the new jclouds location
+        loc2.release(machine2);
+        assertFalse(machine.isSshable());
+        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), Collections.emptySet());
+    }
+    
+    @Test(groups = { "Live" })
+    public void testRegisterVmDeprecated() throws Exception {
+        // FIXME See comments in testRegisterVm
+
+        // Create a VM through jclouds
+        JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.of("imageId", EUWEST_IMAGE_ID));
+        assertTrue(machine.isSshable());
+
+        String id = machine.getJcloudsId();
+        InetAddress address = machine.getAddress();
+        String hostname = address.getHostName();
+        String username = machine.getUser();
+        
+        // Create a new jclouds location, and re-bind the existing VM to that
+        JcloudsLocation loc2 = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_PROVIDER+":"+AWS_EC2_EUWEST_REGION_NAME);
+        // pass deprecated userName
+        MachineLocation machineLocation = loc2.registerMachine(ImmutableMap.of("id", id, "hostname", hostname, "userName", username));
+        assertTrue(machineLocation instanceof SshMachineLocation);
+        SshMachineLocation machine2 = (SshMachineLocation) machineLocation;
+
+        // Confirm the re-bound machine is wired up
+        assertTrue(machine2.isSshable());
+        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), ImmutableSet.of(machine2));
+        
+        // Confirm can release the re-bound machine via the new jclouds location
+        loc2.release(machine2);
+        assertFalse(machine.isSshable());
+        assertEquals(ImmutableSet.copyOf(loc2.getChildren()), Collections.emptySet());
+    }
+
+    // Useful for debugging; accesss a hard-coded existing instance so don't need to wait for provisioning a new one
+    @Test(enabled=false, groups = { "Live" })
+    public void testRegisterVmToHardcodedInstance() throws Exception {
+        String id = "eu-west-1/i-5504f21d";
+        InetAddress address = InetAddress.getByName("ec2-176-34-93-58.eu-west-1.compute.amazonaws.com");
+        String hostname = address.getHostName();
+        String username = "root";
+        
+        MachineLocation machineLocation = jcloudsLocation.registerMachine(ImmutableMap.of("id", id, "hostname", hostname, "userName", username));
+        assertTrue(machineLocation instanceof SshMachineLocation);
+        SshMachineLocation machine = (SshMachineLocation) machineLocation;
+
+        // Confirm the re-bound machine is wired up
+        assertTrue(machine.isSshable());
+        assertEquals(ImmutableSet.copyOf(jcloudsLocation.getChildren()), ImmutableSet.of(machine));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6012a4e4/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationSuspendResumeMachineLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationSuspendResumeMachineLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationSuspendResumeMachineLiveTest.java
new file mode 100644
index 0000000..048a563
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationSuspendResumeMachineLiveTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.brooklyn.location.jclouds;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class JcloudsLocationSuspendResumeMachineLiveTest extends AbstractJcloudsLiveTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JcloudsLocationSuspendResumeMachineLiveTest.class);
+
+    private static final String EUWEST_IMAGE_ID = AWS_EC2_EUWEST_REGION_NAME + "/" + "ami-ce7b6fba";
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry()
+                .resolve(AWS_EC2_PROVIDER + ":" + AWS_EC2_EUWEST_REGION_NAME);
+    }
+
+    @Test(groups = "Live")
+    public void testObtainThenSuspendThenResumeMachine() throws Exception {
+        MachineLocation machine = obtainMachine(ImmutableMap.of(
+                "imageId", EUWEST_IMAGE_ID));
+        JcloudsSshMachineLocation sshMachine = (JcloudsSshMachineLocation) machine;
+        assertTrue(sshMachine.isSshable(), "Cannot SSH to " + sshMachine);
+
+        suspendMachine(machine);
+        assertFalse(sshMachine.isSshable(), "Should not be able to SSH to suspended machine");
+
+        MachineLocation machine2 = resumeMachine(ImmutableMap.of("id", sshMachine.getJcloudsId()));
+        assertTrue(machine2 instanceof JcloudsSshMachineLocation);
+        assertTrue(((JcloudsSshMachineLocation) machine2).isSshable(), "Cannot SSH to " + machine2);
+    }
+
+}