You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/14 05:42:38 UTC

[09/54] incubator-brooklyn git commit: [BROOKLYN-162] Renaming package brooklyn.location

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
index 3dba382..fe77f5e 100644
--- a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
+++ b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
@@ -33,12 +33,11 @@ import org.slf4j.LoggerFactory;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.BrooklynAppLiveTestSupport;
-import brooklyn.location.Location;
-import brooklyn.location.LocationSpec;
-import brooklyn.location.MachineProvisioningLocation;
-import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.policy.os.CreateUserPolicy;
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.location.LocationSpec;
+import org.apache.brooklyn.location.MachineProvisioningLocation;
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
 import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.text.Identifiers;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
index a89e089..4184163 100644
--- a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
+++ b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
@@ -37,9 +37,8 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.location.LocationSpec;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.policy.os.CreateUserPolicy;
+import org.apache.brooklyn.location.LocationSpec;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
 import brooklyn.util.internal.ssh.SshTool;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/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
new file mode 100644
index 0000000..b5f4dab
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.assertNotNull;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.util.exceptions.CompoundRuntimeException;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+public class AbstractJcloudsLiveTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractJcloudsLiveTest.class);
+
+    public static final String BROOKLYN_PROPERTIES_PREFIX = "brooklyn.location.jclouds.";
+    public static final String BROOKLYN_PROPERTIES_LEGACY_PREFIX = "brooklyn.jclouds.";
+    
+    public static final String AWS_EC2_PROVIDER = "aws-ec2";
+    public static final String AWS_EC2_MICRO_HARDWARE_ID = "t1.micro";
+    public static final String AWS_EC2_SMALL_HARDWARE_ID = "m1.small";
+    public static final String AWS_EC2_EUWEST_REGION_NAME = "eu-west-1";
+    public static final String AWS_EC2_USEAST_REGION_NAME = "us-east-1";
+
+    public static final String RACKSPACE_PROVIDER = "rackspace-cloudservers-uk";
+    
+    public static final String SOFTLAYER_PROVIDER = "softlayer";
+    public static final String SOFTLAYER_AMS01_REGION_NAME = "ams01";
+    
+    protected BrooklynProperties brooklynProperties;
+    protected LocalManagementContext managementContext;
+    
+    protected List<JcloudsSshMachineLocation> machines;
+    protected JcloudsLocation jcloudsLocation;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        machines = Lists.newCopyOnWriteArrayList();
+        managementContext = newManagementContext();
+        
+        // Don't let any defaults from brooklyn.properties (except credentials) interfere with test
+        brooklynProperties = managementContext.getBrooklynProperties();
+        stripBrooklynProperties(brooklynProperties);
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        List<Exception> exceptions = Lists.newArrayList();
+        try {
+            if (machines != null) {
+                for (JcloudsSshMachineLocation machine : machines) {
+                    try {
+                        releaseMachine(machine);
+                    } catch (Exception e) {
+                        LOG.warn("Error releasing machine "+machine+"; continuing...", e);
+                        exceptions.add(e);
+                    }
+                }
+                machines.clear();
+            }
+        } finally {
+            try {
+                if (managementContext != null) Entities.destroyAll(managementContext);
+            } catch (Exception e) {
+                LOG.warn("Error destroying management context", e);
+                exceptions.add(e);
+            }
+        }
+        
+        // TODO Debate about whether to:
+        //  - use destroyAllCatching (i.e. not propagating exception)
+        //    Benefit is that other tests in class will subsequently be run, rather than bailing out.
+        //  - propagate exceptions from tearDown
+        //    Benefit is that we don't hide errors; release(...) etc should not be throwing exceptions.
+        if (exceptions.size() > 0) {
+            throw new CompoundRuntimeException("Error in tearDown of "+getClass(), exceptions);
+        }
+    }
+
+    protected LocalManagementContext newManagementContext() {
+        // loads properties, by default, but not OSGi or anything else
+        return LocalManagementContextForTests.builder(true).useDefaultProperties().build();
+    }
+    
+    protected void stripBrooklynProperties(BrooklynProperties props) {
+        // remove all location properties except for identity and credential
+        // (so key, scripts, etc settings don't interfere with tests) 
+        for (String key : ImmutableSet.copyOf(props.asMapWithStringKeys().keySet())) {
+            if (key.startsWith(BROOKLYN_PROPERTIES_PREFIX) && !(key.endsWith("identity") || key.endsWith("credential"))) {
+                props.remove(key);
+            }
+            if (key.startsWith(BROOKLYN_PROPERTIES_LEGACY_PREFIX) && !(key.endsWith("identity") || key.endsWith("credential"))) {
+                props.remove(key);
+            }
+            
+            // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then that can cause "stdin: is not a tty")
+            if (key.startsWith("brooklyn.ssh")) {
+                props.remove(key);
+            }
+        }
+    }
+    
+    protected void assertSshable(SshMachineLocation machine) {
+        int result = machine.execScript("simplecommand", ImmutableList.of("true"));
+        assertEquals(result, 0);
+    }
+
+    // Use this utility method to ensure machines are released on tearDown
+    protected JcloudsSshMachineLocation obtainMachine(Map<?, ?> conf) throws Exception {
+        assertNotNull(jcloudsLocation);
+        JcloudsSshMachineLocation result = (JcloudsSshMachineLocation)jcloudsLocation.obtain(conf);
+        machines.add(checkNotNull(result, "result"));
+        return result;
+    }
+
+    protected JcloudsSshMachineLocation obtainMachine() throws Exception {
+        return obtainMachine(ImmutableMap.of());
+    }
+    
+    protected void releaseMachine(JcloudsSshMachineLocation machine) {
+        assertNotNull(jcloudsLocation);
+        machines.remove(machine);
+        jcloudsLocation.release(machine);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java
new file mode 100644
index 0000000..9c70305
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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 java.util.List;
+import java.util.Set;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.RunNodesException;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.options.TemplateOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+
+import brooklyn.util.config.ConfigBag;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * The VM creation is stubbed out, but it still requires live access (i.e. real account credentials)
+ * to generate the template etc.
+ * 
+ * We supply a ComputeServiceRegistry that delegates to the real instance for everything except
+ * VM creation and deletion. For those operations, it delegates to a NodeCreator that 
+ * returns a dummy NodeMetadata, recording all calls made to it.
+ */
+public abstract class AbstractJcloudsStubbedLiveTest extends AbstractJcloudsLiveTest {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractJcloudsStubbedLiveTest.class);
+
+    public static final String LOCATION_SPEC = "jclouds:" + SOFTLAYER_PROVIDER + ":" + SOFTLAYER_AMS01_REGION_NAME;
+    
+    public static abstract class NodeCreator {
+        public final List<NodeMetadata> created = Lists.newCopyOnWriteArrayList();
+        public final List<String> destroyed = Lists.newCopyOnWriteArrayList();
+        
+        public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, Template template) throws RunNodesException {
+            Set<NodeMetadata> result = Sets.newLinkedHashSet();
+            for (int i = 0; i < count; i++) {
+                NodeMetadata node = newNode(group, template);
+                created.add(node);
+                result.add(node);
+            }
+            return result;
+        }
+        public void destroyNode(String id) {
+            destroyed.add(id);
+        }
+        protected abstract NodeMetadata newNode(String group, Template template);
+    }
+    
+    public static class StubbedComputeService extends DelegatingComputeService {
+        private final NodeCreator nodeCreator;
+        
+        public StubbedComputeService(ComputeService delegate, NodeCreator nodeCreator) {
+            super(delegate);
+            this.nodeCreator = nodeCreator;
+        }
+        @Override
+        public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, Template template) throws RunNodesException {
+            return nodeCreator.createNodesInGroup(group, count, template);
+        }
+        @Override
+        public void destroyNode(String id) {
+            nodeCreator.destroyNode(id);
+        }
+        @Override
+        public Set<? extends NodeMetadata> createNodesInGroup(String group, int count) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, TemplateOptions templateOptions) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
+            throw new UnsupportedOperationException();
+        }
+    }
+    
+    protected NodeCreator nodeCreator;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        nodeCreator = newNodeCreator();
+        ComputeServiceRegistry computeServiceRegistry = new ComputeServiceRegistry() {
+            @Override
+            public ComputeService findComputeService(ConfigBag conf, boolean allowReuse) {
+                ComputeService delegate = ComputeServiceRegistryImpl.INSTANCE.findComputeService(conf, allowReuse);
+                return new StubbedComputeService(delegate, nodeCreator);
+            }
+        };
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(
+                LOCATION_SPEC, 
+                ImmutableMap.of(
+                        JcloudsLocationConfig.COMPUTE_SERVICE_REGISTRY, computeServiceRegistry,
+                        JcloudsLocationConfig.WAIT_FOR_SSHABLE, "false"));
+    }
+    
+    protected abstract NodeCreator newNodeCreator();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java
new file mode 100644
index 0000000..acf838e
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java
@@ -0,0 +1,188 @@
+/*
+ * 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 java.util.Collections;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.location.LocationSpec;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.Template;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.reflect.TypeToken;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.exceptions.CompoundRuntimeException;
+import brooklyn.util.exceptions.Exceptions;
+
+public class BailOutJcloudsLocation extends JcloudsLocation {
+
+    // Don't care which image; not actually provisioning
+    private static final String US_EAST_IMAGE_ID = "us-east-1/ami-7d7bfc14";
+    public static final RuntimeException BAIL_OUT_FOR_TESTING = new RuntimeException("early termination for test");
+
+    public static final ConfigKey<Function<ConfigBag, Void>> BUILD_TEMPLATE_INTERCEPTOR = ConfigKeys.newConfigKey(
+            new TypeToken<Function<ConfigBag, Void>>() {},
+            "buildtemplateinterceptor");
+
+    public static final ConfigKey<Boolean> BUILD_TEMPLATE = ConfigKeys.newBooleanConfigKey(
+            "buildtemplate");
+
+    private static final long serialVersionUID = -3373789512935057842L;
+
+    ConfigBag lastConfigBag;
+    Template template;
+
+    public BailOutJcloudsLocation() {
+        super();
+    }
+
+    public BailOutJcloudsLocation(Map<?, ?> conf) {
+        super(conf);
+    }
+
+    @Override
+    public Template buildTemplate(ComputeService computeService, ConfigBag config) {
+        lastConfigBag = config;
+        if (getConfig(BUILD_TEMPLATE_INTERCEPTOR) != null) {
+            getConfig(BUILD_TEMPLATE_INTERCEPTOR).apply(config);
+        }
+        if (Boolean.TRUE.equals(getConfig(BUILD_TEMPLATE))) {
+            template = super.buildTemplate(computeService, config);
+        }
+        throw BAIL_OUT_FOR_TESTING;
+    }
+
+    public Template getTemplate() {
+        return template;
+    }
+
+    public void tryObtain() {
+        tryObtain(Collections.emptyMap());
+    }
+
+    public void tryObtain(Map<?, ?> flags) {
+        tryObtainAndCheck(flags, Predicates.alwaysTrue());
+    }
+
+    public void tryObtainAndCheck(Map<?, ?> flags, Predicate<? super ConfigBag> test) {
+        try {
+            obtain(flags);
+        } catch (Exception e) {
+            if (e == BAIL_OUT_FOR_TESTING || e.getCause() == BAIL_OUT_FOR_TESTING
+                    || (e instanceof CompoundRuntimeException && ((CompoundRuntimeException) e).getAllCauses().contains(BAIL_OUT_FOR_TESTING))) {
+                test.apply(lastConfigBag);
+            } else {
+                throw Exceptions.propagate(e);
+            }
+        }
+    }
+
+    @Override
+    @VisibleForTesting
+    public UserCreation createUserStatements(@Nullable Image image, ConfigBag config) {
+        return super.createUserStatements(image, config);
+    }
+
+
+    public static BailOutJcloudsLocation newBailOutJcloudsLocation(ManagementContext mgmt) {
+        return newBailOutJcloudsLocation(mgmt, Collections.<ConfigKey<?>, Object>emptyMap());
+    }
+
+    public static BailOutJcloudsLocation newBailOutJcloudsLocation(ManagementContext mgmt, Map<ConfigKey<?>, ?> config) {
+        Map<ConfigKey<?>, ?> allConfig = MutableMap.<ConfigKey<?>, Object>builder()
+                .put(IMAGE_ID, "bogus")
+                .put(CLOUD_PROVIDER, "aws-ec2")
+                .put(ACCESS_IDENTITY, "bogus")
+                .put(CLOUD_REGION_ID, "bogus")
+                .put(ACCESS_CREDENTIAL, "bogus")
+                .put(USER, "fred")
+                .put(MIN_RAM, 16)
+                .put(JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 1)
+                .putAll(config)
+                .build();
+        return mgmt.getLocationManager().createLocation(
+                LocationSpec.create(BailOutJcloudsLocation.class).configure(allConfig));
+    }
+
+
+    // todo better name
+
+    /** As {@link BailOutJcloudsLocation}, counting the number of {@link #buildTemplate} calls. */
+    public static class CountingBailOutJcloudsLocation extends BailOutJcloudsLocation {
+        private static final long serialVersionUID = 2433684033045735773L;
+        int buildTemplateCount = 0;
+        @Override
+        public Template buildTemplate(ComputeService computeService, ConfigBag config) {
+            buildTemplateCount++;
+            return super.buildTemplate(computeService, config);
+        }
+    }
+
+    public static CountingBailOutJcloudsLocation newCountingBailOutJcloudsLocation(ManagementContext mgmt, Map flags) {
+        LocationSpec<CountingBailOutJcloudsLocation> spec = LocationSpec.create(CountingBailOutJcloudsLocation.class)
+                .configure(flags);
+        return mgmt.getLocationManager().createLocation(spec);
+    }
+
+    /** @see #newBailOutJcloudsLocationForLiveTest(LocalManagementContext, Map)} */
+    public static BailOutJcloudsLocation newBailOutJcloudsLocationForLiveTest(LocalManagementContext mgmt) {
+        return newBailOutJcloudsLocationForLiveTest(mgmt, Collections.<ConfigKey<?>, Object>emptyMap());
+    }
+
+    /**
+     * Takes identity and access credential from management context's Brooklyn properties and sets
+     * inbound ports to [22, 80, 9999].
+     */
+    public static BailOutJcloudsLocation newBailOutJcloudsLocationForLiveTest(LocalManagementContext mgmt, Map<ConfigKey<?>, ?> config) {
+        BrooklynProperties brooklynProperties = mgmt.getBrooklynProperties();
+        String identity = (String) brooklynProperties.get("brooklyn.location.jclouds.aws-ec2.identity");
+        if (identity == null) identity = (String) brooklynProperties.get("brooklyn.jclouds.aws-ec2.identity");
+        String credential = (String) brooklynProperties.get("brooklyn.location.jclouds.aws-ec2.credential");
+        if (credential == null) credential = (String) brooklynProperties.get("brooklyn.jclouds.aws-ec2.credential");
+
+        Map<ConfigKey<?>, ?> allConfig = MutableMap.<ConfigKey<?>, Object>builder()
+                .put(CLOUD_PROVIDER, AbstractJcloudsLiveTest.AWS_EC2_PROVIDER)
+                .put(CLOUD_REGION_ID, AbstractJcloudsLiveTest.AWS_EC2_USEAST_REGION_NAME)
+                .put(IMAGE_ID, US_EAST_IMAGE_ID) // so Brooklyn does not attempt to load all EC2 images
+                .put(ACCESS_IDENTITY, identity)
+                .put(ACCESS_CREDENTIAL, credential)
+                .put(INBOUND_PORTS, "[22, 80, 9999]")
+                .put(BUILD_TEMPLATE, true)
+                .putAll(config)
+                .build();
+
+        return newBailOutJcloudsLocation(mgmt, allConfig);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePoolLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePoolLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePoolLiveTest.java
new file mode 100644
index 0000000..3fda145
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePoolLiveTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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 org.apache.brooklyn.location.jclouds.pool.MachineSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.jclouds.pool.MachinePoolPredicates;
+import org.apache.brooklyn.location.jclouds.pool.ReusableMachineTemplate;
+import brooklyn.management.internal.LocalManagementContext;
+
+public class BrooklynMachinePoolLiveTest {
+
+    public static final Logger log = LoggerFactory.getLogger(BrooklynMachinePoolLiveTest.class);
+    
+    public static class SamplePool extends BrooklynMachinePool {
+        public SamplePool(JcloudsLocation l) {
+            super(l);
+        }
+
+        public final static ReusableMachineTemplate 
+            USUAL_VM = 
+                new ReusableMachineTemplate("usual").templateOwnedByMe().
+                tagOptional("tagForUsualVm").
+                metadataOptional("metadataForUsualVm", "12345").
+                minRam(1024).minCores(2);
+
+        public final static ReusableMachineTemplate 
+            ANYONE_NOT_TINY_VM = 
+                new ReusableMachineTemplate("anyone").
+                minRam(512).minCores(1).strict(false);
+
+        public static final ReusableMachineTemplate 
+            VM_LARGE1 = 
+                new ReusableMachineTemplate("vm.large1").templateOwnedByMe().
+                minRam(16384).minCores(4),
+            VM_SMALL1 = 
+                new ReusableMachineTemplate("vm.small1").templateOwnedByMe().smallest();
+        
+        { registerTemplates(USUAL_VM, ANYONE_NOT_TINY_VM, VM_LARGE1, VM_SMALL1); }
+    }
+
+
+    private LocalManagementContext managementContext;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        managementContext = new LocalManagementContext();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (managementContext != null) managementContext.terminate();
+    }
+    
+    @Test(groups="Live")
+    public void buildClaimAndDestroy() {
+        SamplePool p = new SamplePool(resolve("aws-ec2:us-west-1"));
+        log.info("buildClaimAndDestroy: created pool");
+        p.refresh();
+        log.info("buildClaimAndDestroy: refreshed pool");
+        p.ensureExists(2, SamplePool.USUAL_VM);
+        log.info("buildClaimAndDestroy: ensure have 2");
+        SshMachineLocation l = p.obtain(SamplePool.USUAL_VM);
+        Assert.assertNotNull(l);
+        log.info("buildClaimAndDestroy: claimed 1");
+        MachineSet unclaimedUsual = p.unclaimed(MachinePoolPredicates.matching(SamplePool.USUAL_VM));
+        log.info("buildClaimAndDestroy: unclaimed now "+unclaimedUsual);
+        Assert.assertTrue(!unclaimedUsual.isEmpty(), "should have been unclaimed machines (can fail if there are some we cannot connect to, ie blacklisted)");
+        p.destroy(unclaimedUsual);
+        p.destroy(l);
+        unclaimedUsual = p.unclaimed(MachinePoolPredicates.matching(SamplePool.USUAL_VM));
+        log.info("buildClaimAndDestroy: destroyed, unclaimed now "+unclaimedUsual);
+        log.info("end");
+    }
+    
+
+    private JcloudsLocation resolve(String spec) {
+        return (JcloudsLocation) managementContext.getLocationRegistry().resolve(new JcloudsLocationResolver().getPrefix() + ":" + spec);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/DelegatingComputeService.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/DelegatingComputeService.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/DelegatingComputeService.java
new file mode 100644
index 0000000..8e718e2
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/DelegatingComputeService.java
@@ -0,0 +1,229 @@
+/*
+ * 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 java.util.Map;
+import java.util.Set;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.RunNodesException;
+import org.jclouds.compute.RunScriptOnNodesException;
+import org.jclouds.compute.domain.ComputeMetadata;
+import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.extensions.ImageExtension;
+import org.jclouds.compute.extensions.SecurityGroupExtension;
+import org.jclouds.compute.options.RunScriptOptions;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Location;
+import org.jclouds.scriptbuilder.domain.Statement;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class DelegatingComputeService implements ComputeService {
+
+    private final ComputeService delegate;
+    
+    public DelegatingComputeService(ComputeService delegate) {
+        this.delegate = delegate;
+    }
+    
+    @Override
+    public ComputeServiceContext getContext() {
+        return delegate.getContext();
+    }
+
+    @Override
+    public TemplateBuilder templateBuilder() {
+        return delegate.templateBuilder();
+    }
+
+    @Override
+    public TemplateOptions templateOptions() {
+        return delegate.templateOptions();
+    }
+
+    @Override
+    public Set<? extends Hardware> listHardwareProfiles() {
+        return delegate.listHardwareProfiles();
+    }
+
+    @Override
+    public Set<? extends Image> listImages() {
+        return delegate.listImages();
+    }
+
+    @Override
+    public Image getImage(String id) {
+        return delegate.getImage(id);
+    }
+
+    @Override
+    public Set<? extends ComputeMetadata> listNodes() {
+        return delegate.listNodes();
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> listNodesByIds(Iterable<String> ids) {
+        return delegate.listNodesByIds(ids);
+    }
+
+    @Override
+    public Set<? extends Location> listAssignableLocations() {
+        return delegate.listAssignableLocations();
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, Template template) throws RunNodesException {
+        return delegate.createNodesInGroup(group, count, template);
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> createNodesInGroup(String group, int count, TemplateOptions templateOptions)
+            throws RunNodesException {
+        return delegate.createNodesInGroup(group, count, templateOptions);
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> createNodesInGroup(String group, int count) throws RunNodesException {
+        return delegate.createNodesInGroup(group, count);
+    }
+
+    @Override
+    public void resumeNode(String id) {
+        delegate.resumeNode(id);
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> resumeNodesMatching(Predicate<NodeMetadata> filter) {
+        return delegate.resumeNodesMatching(filter);
+    }
+
+    @Override
+    public void suspendNode(String id) {
+        delegate.suspendNode(id);
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> suspendNodesMatching(Predicate<NodeMetadata> filter) {
+        return delegate.suspendNodesMatching(filter);
+    }
+
+    @Override
+    public void destroyNode(String id) {
+        delegate.destroyNode(id);
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
+        return delegate.destroyNodesMatching(filter);
+    }
+
+    @Override
+    public void rebootNode(String id) {
+        delegate.rebootNode(id);
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> rebootNodesMatching(Predicate<NodeMetadata> filter) {
+        return delegate.rebootNodesMatching(filter);
+    }
+
+    @Override
+    public NodeMetadata getNodeMetadata(String id) {
+        return delegate.getNodeMetadata(id);
+    }
+
+    @Override
+    public Set<? extends NodeMetadata> listNodesDetailsMatching(Predicate<ComputeMetadata> filter) {
+        return delegate.listNodesDetailsMatching(filter);
+    }
+
+    @Override
+    public Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, String runScript)
+            throws RunScriptOnNodesException {
+        return delegate.runScriptOnNodesMatching(filter, runScript);
+    }
+
+    @Override
+    public Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter, Statement runScript)
+            throws RunScriptOnNodesException {
+        return delegate.runScriptOnNodesMatching(filter, runScript);
+    }
+
+    @Override
+    public Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter,
+            String runScript, RunScriptOptions options) throws RunScriptOnNodesException {
+        return delegate.runScriptOnNodesMatching(filter, runScript, options);
+    }
+
+    @Override
+    public Map<? extends NodeMetadata, ExecResponse> runScriptOnNodesMatching(Predicate<NodeMetadata> filter,
+            Statement runScript, RunScriptOptions options) throws RunScriptOnNodesException {
+        return delegate.runScriptOnNodesMatching(filter, runScript, options);
+    }
+
+    @Override
+    public ExecResponse runScriptOnNode(String id, Statement runScript, RunScriptOptions options) {
+        return delegate.runScriptOnNode(id, runScript, options);
+    }
+
+    @Override
+    public ListenableFuture<ExecResponse> submitScriptOnNode(String id, String runScript, RunScriptOptions options) {
+        return delegate.submitScriptOnNode(id, runScript, options);
+    }
+
+    @Override
+    public ListenableFuture<ExecResponse> submitScriptOnNode(String id, Statement runScript, RunScriptOptions options) {
+        return delegate.submitScriptOnNode(id, runScript, options);
+    }
+
+    @Override
+    public ExecResponse runScriptOnNode(String id, Statement runScript) {
+        return delegate.runScriptOnNode(id, runScript);
+    }
+
+    @Override
+    public ExecResponse runScriptOnNode(String id, String runScript, RunScriptOptions options) {
+        return delegate.runScriptOnNode(id, runScript, options);
+    }
+
+    @Override
+    public ExecResponse runScriptOnNode(String id, String runScript) {
+        return delegate.runScriptOnNode(id, runScript);
+    }
+
+    @Override
+    public Optional<ImageExtension> getImageExtension() {
+        return delegate.getImageExtension();
+    }
+
+    @Override
+    public Optional<SecurityGroupExtension> getSecurityGroupExtension() {
+        return delegate.getSecurityGroupExtension();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsAddressesLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsAddressesLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsAddressesLiveTest.java
new file mode 100644
index 0000000..2694ed5
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsAddressesLiveTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.location.LocationSpec;
+import org.apache.brooklyn.location.basic.Locations;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.stream.Streams;
+
+/**
+ * Tests that the correct address is advertised for the VM - for its public/private, 
+ * its subnet hostname, etc.
+ */
+public class JcloudsAddressesLiveTest extends AbstractJcloudsLiveTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JcloudsAddressesLiveTest.class);
+
+    public static final String AWS_EC2_REGION_NAME = AWS_EC2_USEAST_REGION_NAME;
+    public static final String AWS_EC2_LOCATION_SPEC = "jclouds:" + AWS_EC2_PROVIDER + (AWS_EC2_REGION_NAME == null ? "" : ":" + AWS_EC2_REGION_NAME);
+    
+    // Image: {id=us-east-1/ami-7d7bfc14, providerId=ami-7d7bfc14, name=RightImage_CentOS_6.3_x64_v5.8.8.5, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=centos, arch=paravirtual, version=6.0, description=rightscale-us-east/RightImage_CentOS_6.3_x64_v5.8.8.5.manifest.xml, is64Bit=true}, description=rightscale-us-east/RightImage_CentOS_6.3_x64_v5.8.8.5.manifest.xml, version=5.8.8.5, status=AVAILABLE[available], loginUser=root, userMetadata={owner=411009282317, rootDeviceType=instance-store, virtualizationType=paravirtual, hypervisor=xen}}
+    public static final String AWS_EC2_CENTOS_IMAGE_ID = "us-east-1/ami-7d7bfc14";
+
+    // Image: {id=us-east-1/ami-d0f89fb9, providerId=ami-d0f89fb9, name=ubuntu/images/ebs/ubuntu-precise-12.04-amd64-server-20130411.1, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=ubuntu, arch=paravirtual, version=12.04, description=099720109477/ubuntu/images/ebs/ubuntu-precise-12.04-amd64-server-20130411.1, is64Bit=true}, description=099720109477/ubuntu/images/ebs/ubuntu-precise-12.04-amd64-server-20130411.1, version=20130411.1, status=AVAILABLE[available], loginUser=ubuntu, userMetadata={owner=099720109477, rootDeviceType=ebs, virtualizationType=paravirtual, hypervisor=xen}}
+    public static final String AWS_EC2_UBUNTU_IMAGE_ID = "us-east-1/ami-d0f89fb9";
+    
+    // Image: {id=us-east-1/ami-5e008437, providerId=ami-5e008437, name=RightImage_Ubuntu_10.04_x64_v5.8.8.3, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=ubuntu, arch=paravirtual, version=10.04, description=rightscale-us-east/RightImage_Ubuntu_10.04_x64_v5.8.8.3.manifest.xml, is64Bit=true}, description=rightscale-us-east/RightImage_Ubuntu_10.04_x64_v5.8.8.3.manifest.xml, version=5.8.8.3, status=AVAILABLE[available], loginUser=root, userMetadata={owner=411009282317, rootDeviceType=instance-store, virtualizationType=paravirtual, hypervisor=xen}}
+    // Uses "root" as loginUser
+    public static final String AWS_EC2_UBUNTU_10_IMAGE_ID = "us-east-1/ami-5e008437";
+
+    public static final String RACKSPACE_LOCATION_SPEC = "jclouds:" + RACKSPACE_PROVIDER;
+    
+    // Image: {id=LON/c52a0ca6-c1f2-4cd1-b7d6-afbcd1ebda22, providerId=c52a0ca6-c1f2-4cd1-b7d6-afbcd1ebda22, name=CentOS 6.0, location={scope=ZONE, id=LON, description=LON, parent=rackspace-cloudservers-uk, iso3166Codes=[GB-SLG]}, os={family=centos, name=CentOS 6.0, version=6.0, description=CentOS 6.0, is64Bit=true}, description=CentOS 6.0, status=AVAILABLE, loginUser=root, userMetadata={os_distro=centos, com.rackspace__1__visible_core=1, com.rackspace__1__build_rackconnect=1, com.rackspace__1__options=0, image_type=base, cache_in_nova=True, com.rackspace__1__source=kickstart, org.openstack__1__os_distro=org.centos, com.rackspace__1__release_build_date=2013-07-25_18-56-29, auto_disk_config=True, com.rackspace__1__release_version=5, os_type=linux, com.rackspace__1__visible_rackconnect=1, com.rackspace__1__release_id=210, com.rackspace__1__visible_managed=0, com.rackspace__1__build_core=1, org.openstack__1__os_version=6.0, org.openstack__1__architecture=x64, com.rackspace__1__build_ma
 naged=0}}
+    public static final String RACKSPACE_CENTOS_IMAGE_NAME_REGEX = "CentOS 6.0";
+    
+    protected JcloudsSshMachineLocation machine;
+    
+    @Test(groups = {"Live"})
+    protected void testAwsEc2Addresses() throws Exception {
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+        
+        machine = createEc2Machine(ImmutableMap.<String,Object>of());
+        assertSshable(machine);
+
+        String locationAddress = machine.getAddress().getHostName();
+        InetAddress address = machine.getAddress();
+        Set<String> publicAddresses = machine.getPublicAddresses();
+        Set<String> privateAddresses = machine.getPrivateAddresses();
+        String subnetIp = machine.getSubnetIp();
+        String hostname = machine.getHostname();
+        String subnetHostname = machine.getSubnetHostname();
+        String msg = "locationAddress="+locationAddress+"; address="+address+"; publicAddrs="+publicAddresses+"; privateAddrs="+privateAddresses+"; subnetIp="+subnetIp+"; hostname="+hostname+"; subnetHostname="+subnetHostname;
+        LOG.info("node: "+msg);
+
+        // On AWS, machine advertises its FQ hostname that is accessible from inside and outside the region
+        assertReachable(machine, locationAddress, msg);
+        assertReachableFromMachine(machine, locationAddress, msg);
+
+        assertReachable(machine, address, msg);
+        
+        assertTrue(publicAddresses.size() > 0, msg);
+        for (String publicAddress: publicAddresses) {
+            assertReachable(machine, publicAddress, msg);
+        }
+        
+        // On AWS, private address is not reachable from outside.
+        // If you ran this test from the same AWS region, it would fail!
+        assertTrue(privateAddresses.size() > 0, msg);
+        for (String privateAddress: privateAddresses) {
+            assertReachableFromMachine(machine, privateAddress, msg);
+            assertNotReachable(machine, privateAddress, msg);
+        }
+        
+        assertNotNull(subnetIp, msg);
+        assertReachableFromMachine(machine, subnetIp, msg);
+
+        // hostname is reachable from inside; not necessarily reachable from outside
+        assertNotNull(hostname, msg);
+        assertReachableFromMachine(machine, hostname, msg);
+        
+        assertNotNull(subnetHostname, msg);
+        assertReachableFromMachine(machine, subnetHostname, msg);
+    }
+
+    @Test(groups = {"Live"})
+    protected void testRackspaceAddresses() throws Exception {
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+        
+        machine = createRackspaceMachine(ImmutableMap.<String,Object>of());
+        assertSshable(machine);
+
+        String locationAddress = machine.getAddress().getHostAddress();
+        InetAddress address = machine.getAddress();
+        Set<String> publicAddresses = machine.getPublicAddresses();
+        Set<String> privateAddresses = machine.getPrivateAddresses();
+        String subnetIp = machine.getSubnetIp();
+        String hostname = machine.getHostname();
+        String subnetHostname = machine.getSubnetHostname();
+        String msg = "locationAddress="+locationAddress+"; address="+address+"; publicAddrs="+publicAddresses+"; privateAddrs="+privateAddresses+"; subnetIp="+subnetIp+"; hostname="+hostname+"; subnetHostname="+subnetHostname;
+        LOG.info("node: "+msg);
+
+        // On Rackspace, IP is accessible from inside and outside.
+        assertReachable(machine, locationAddress, msg);
+        assertReachableFromMachine(machine, locationAddress, msg);
+
+        assertReachable(machine, address, msg);
+        
+        assertTrue(publicAddresses.size() > 0, msg);
+        for (String publicAddress: publicAddresses) {
+            assertReachable(machine, publicAddress, msg);
+        }
+        
+        // On Rackspace, don't care if no private addresses
+        for (String privateAddress: privateAddresses) {
+            assertReachableFromMachine(machine, privateAddress, msg);
+            assertNotReachable(machine, privateAddress, msg);
+        }
+        
+        assertNotNull(subnetIp, msg);
+        assertReachableFromMachine(machine, subnetIp, msg);
+
+        // hostname is reachable from inside; not necessarily reachable from outside
+        assertNotNull(hostname, msg);
+        assertReachableFromMachine(machine, hostname, msg);
+        
+        assertNotNull(subnetHostname, msg);
+        assertReachableFromMachine(machine, subnetHostname, msg);
+    }
+
+    private void assertReachable(SshMachineLocation machine, InetAddress addr, String msg) {
+        assertReachable(machine, addr.getHostAddress(), msg);
+    }
+
+    private void assertReachable(SshMachineLocation machine, String addr, String msg) {
+        assertReachability(true, machine, addr, msg);
+    }
+    
+    private void assertNotReachable(SshMachineLocation machine, String addr, String msg) {
+        assertReachability(false, machine, addr, msg);
+    }
+
+    private void assertReachability(boolean expectedReachable, SshMachineLocation machine, String addr, String msg) {
+        SshMachineLocation tmpMachine = managementContext.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
+                .configure(machine.config().getBag().getAllConfig())
+                .configure("address", addr));
+        try {
+            boolean sshable = tmpMachine.isSshable();
+            assertEquals(sshable, expectedReachable, addr+" not sshable; "+msg);
+        } finally {
+            Locations.unmanage(tmpMachine);
+        }
+    }
+
+    // TODO Assumes that "ping" will work; i.e. that ICMP is not firewall'ed
+    private void assertReachableFromMachine(SshMachineLocation machine, String addr, String msg) {
+        OutputStream outStream = new ByteArrayOutputStream();
+        OutputStream errStream = new ByteArrayOutputStream();
+        int result = machine.execScript(MutableMap.of("out", outStream, "err", errStream), "reach "+addr, ImmutableList.of("ping -c 1 "+addr));
+        String outString = outStream.toString();
+        String errString = errStream.toString();
+        assertEquals(result, 0, "result="+0+"; err="+errString+"; out="+outString+"; msg="+msg);
+    }
+
+    @Override
+    protected void releaseMachine(JcloudsSshMachineLocation machine) {
+        jcloudsLocation.release(machine);
+    }
+    
+    private JcloudsSshMachineLocation createEc2Machine(Map<String,? extends Object> conf) throws Exception {
+        return obtainMachine(MutableMap.<String,Object>builder()
+                .putAll(conf)
+                .putIfAbsent("imageId", AWS_EC2_CENTOS_IMAGE_ID)
+                .putIfAbsent("hardwareId", AWS_EC2_SMALL_HARDWARE_ID)
+                .putIfAbsent("inboundPorts", ImmutableList.of(22))
+                .build());
+    }
+    
+    private JcloudsSshMachineLocation createRackspaceMachine(Map<String,? extends Object> conf) throws Exception {
+        return obtainMachine(MutableMap.<String,Object>builder()
+                .putAll(conf)
+                .putIfAbsent("inboundPorts", ImmutableList.of(22))
+                .build());
+    }
+    
+    protected void assertSshable(Map<?,?> machineConfig) {
+        SshMachineLocation machineWithThatConfig = managementContext.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
+                .configure(machineConfig));
+        try {
+            assertSshable(machineWithThatConfig);
+        } finally {
+            Streams.closeQuietly(machineWithThatConfig);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
new file mode 100644
index 0000000..2f708f3
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.net.InetAddress;
+import java.util.Map;
+import java.util.Set;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.location.basic.FixedListMachineProvisioningLocation;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class JcloudsByonLocationResolverAwsLiveTest extends AbstractJcloudsLiveTest {
+
+    private static final String AWS_REGION = "eu-west-1";
+    private static final String AWS_LOCATION_SPEC = "jclouds:aws-ec2:"+AWS_REGION;
+    
+    private String awsVmUser;
+    private String awsVmInstanceId;
+    private String awsVmIp;
+    private String awsVmHostname;
+     
+    private LocalManagementContext classManagementContext;
+    private JcloudsLocation classEc2Loc;
+    private JcloudsSshMachineLocation classEc2Vm;
+
+    @BeforeClass(groups="Live")
+    public void setUpClass() throws Exception {
+        classManagementContext = newManagementContext();
+        classEc2Loc = (JcloudsLocation) classManagementContext.getLocationRegistry().resolve(AWS_LOCATION_SPEC);
+        classEc2Vm = (JcloudsSshMachineLocation)classEc2Loc.obtain(MutableMap.<String,Object>builder()
+                .put("hardwareId", AWS_EC2_SMALL_HARDWARE_ID)
+                .put("inboundPorts", ImmutableList.of(22))
+                .build());
+        awsVmUser = classEc2Vm.getUser();
+        awsVmInstanceId = classEc2Vm.getNode().getProviderId(); // id without region (e.g. "i-6ff96d2f" instead of "eu-west-1/i-6ff96d2f")
+        awsVmIp = classEc2Vm.getAddress().getHostAddress();
+        awsVmHostname = classEc2Vm.getAddress().getHostName();
+    }
+    
+    @AfterClass(alwaysRun=true)
+    public void tearDownClass() throws Exception {
+        try {
+            if (classEc2Vm != null) {
+                classEc2Loc.release(classEc2Vm);
+            }
+        } finally {
+            if (classManagementContext != null) classManagementContext.terminate();
+        }
+    }
+
+    // TODO Requires that a VM already exists; could create that VM first to make test more robust
+    @Test(groups={"Live"})
+    public void testResolvesJcloudsByonAws() throws Exception {
+        String spec = "jcloudsByon:(provider=\"aws-ec2\",region=\""+AWS_REGION+"\",user=\""+awsVmUser+"\",hosts=\""+awsVmInstanceId+"\",anotherprop=myval)";
+
+        FixedListMachineProvisioningLocation<JcloudsSshMachineLocation> loc = resolve(spec);
+        
+        Set<JcloudsSshMachineLocation> machines = loc.getAllMachines();
+        JcloudsSshMachineLocation machine = Iterables.getOnlyElement(machines);
+        assertEquals(machine.getParent().getProvider(), "aws-ec2");
+        assertEquals(machine.getAddress().getHostAddress(), awsVmIp);
+        assertEquals(machine.getAddress().getHostName(), awsVmHostname);
+        assertEquals(machine.getUser(), awsVmUser);
+        assertEquals(machine.config().getBag().getStringKey("anotherprop"), "myval");
+        
+        assertTrue(machine.isSshable());
+    }
+
+    @Test(groups={"Live"})
+    public void testResolvesNamedJcloudsByon() throws Exception {
+        String spec = "jcloudsByon:(provider=\"aws-ec2\",region=\""+AWS_REGION+"\",user=\""+awsVmUser+"\",hosts=\""+awsVmInstanceId+"\")";
+        brooklynProperties.put("brooklyn.location.named.mynamed", spec);
+        
+        FixedListMachineProvisioningLocation<JcloudsSshMachineLocation> loc = resolve("named:mynamed");
+        assertEquals(loc.obtain().getAddress(), InetAddress.getByName(awsVmHostname));
+    }
+
+    @Test(groups={"Live"})
+    public void testJcloudsPropertiesPrecedence() throws Exception {
+        String spec = "jcloudsByon:(provider=\"aws-ec2\",region=\""+AWS_REGION+"\",user=\""+awsVmUser+"\",hosts=\""+awsVmInstanceId+"\")";
+        brooklynProperties.put("brooklyn.location.named.mynamed", spec);
+        
+        // prefer those in spec string over everything else
+        brooklynProperties.put("brooklyn.location.named.mynamed.user", "user-inNamed");
+        brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.user", "user-inProviderSpecific");
+        brooklynProperties.put("brooklyn.jclouds.aws-ec2.user", "user-inProviderSpecificDeprecated");
+        brooklynProperties.put("brooklyn.location.jclouds.user", "user-inJcloudsGeneric");
+        brooklynProperties.put("brooklyn.jclouds.user", "user-inJcloudsGenericDeprecated");
+        brooklynProperties.put("brooklyn.location.user", "user-inLocationGeneric");
+
+        // prefer those in "named" over everything else (except spec string itself)
+        brooklynProperties.put("brooklyn.location.named.mynamed.privateKeyFile", "privateKeyFile-inNamed");
+        brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyFile", "privateKeyFile-inProviderSpecific");
+        brooklynProperties.put("brooklyn.jclouds.aws-ec2.privateKeyFile", "privateKeyFile-inProviderSpecificDeprecated");
+        brooklynProperties.put("brooklyn.location.jclouds.privateKeyFile", "privateKeyFile-inJcloudsGeneric");
+        brooklynProperties.put("brooklyn.jclouds.privateKeyFile", "privateKeyFile-inJcloudsGenericDeprecated");
+        brooklynProperties.put("brooklyn.location.privateKeyFile", "privateKeyFile-inLocationGeneric");
+
+        // prefer those in provider-specific over generic
+        brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.publicKeyFile", "publicKeyFile-inProviderSpecific");
+        brooklynProperties.put("brooklyn.jclouds.aws-ec2.publicKeyFile", "publicKeyFile-inProviderSpecificDeprecated");
+        brooklynProperties.put("brooklyn.location.jclouds.publicKeyFile", "publicKeyFile-inJcloudsGeneric");
+        brooklynProperties.put("brooklyn.jclouds.publicKeyFile", "publicKeyFile-inJcloudsGenericDeprecated");
+        brooklynProperties.put("brooklyn.location.publicKeyFile", "publicKeyFile-inLocationGeneric");
+        
+        // prefer those in provider-specific (deprecated scope) over generic
+        brooklynProperties.put("brooklyn.jclouds.aws-ec2.securityGroups", "securityGroups-inProviderSpecificDeprecated");
+        brooklynProperties.put("brooklyn.location.jclouds.securityGroups", "securityGroups-inJcloudsGeneric");
+        brooklynProperties.put("brooklyn.jclouds.securityGroups", "securityGroups-inJcloudsGenericDeprecated");
+        brooklynProperties.put("brooklyn.location.securityGroups", "securityGroups-inLocationGeneric");
+
+        // prefer those in jclouds-generic over location-generic
+        brooklynProperties.put("brooklyn.location.jclouds.loginUser", "loginUser-inJcloudsGeneric");
+        brooklynProperties.put("brooklyn.jclouds.loginUser", "loginUser-inJcloudsGenericDeprecated");
+        brooklynProperties.put("brooklyn.location.loginUser", "loginUser-inLocationGeneric");
+
+        // prefer those in jclouds-generic (deprecated) over location-generic
+        brooklynProperties.put("brooklyn.jclouds.imageId", "imageId-inJcloudsGenericDeprecated");
+        brooklynProperties.put("brooklyn.location.imageId", "imageId-inLocationGeneric");
+
+        // prefer location-generic if nothing else
+        brooklynProperties.put("brooklyn.location.keyPair", "keyPair-inLocationGeneric");
+
+        // prefer deprecated properties in "named" over those less specific
+        brooklynProperties.put("brooklyn.location.named.mynamed.private-key-data", "privateKeyData-inNamed");
+        brooklynProperties.put("brooklyn.jclouds.aws-ec2.privateKeyData", "privateKeyData-inProviderSpecific");
+        brooklynProperties.put("brooklyn.jclouds.privateKeyData", "privateKeyData-inJcloudsGeneric");
+
+        // prefer "named" over everything else: confirm deprecated don't get transformed to overwrite it accidentally
+        brooklynProperties.put("brooklyn.location.named.mynamed.privateKeyPassphrase", "privateKeyPassphrase-inNamed");
+        brooklynProperties.put("brooklyn.jclouds.aws-ec2.private-key-passphrase", "privateKeyPassphrase-inProviderSpecific");
+        brooklynProperties.put("brooklyn.jclouds.private-key-passphrase", "privateKeyPassphrase-inJcloudsGeneric");
+
+        Map<String, Object> conf = resolve("named:mynamed").obtain().config().getBag().getAllConfig();
+        
+        assertEquals(conf.get("user"), awsVmUser);
+        assertEquals(conf.get("privateKeyFile"), "privateKeyFile-inNamed");
+        assertEquals(conf.get("publicKeyFile"), "publicKeyFile-inProviderSpecific");
+        assertEquals(conf.get("securityGroups"), "securityGroups-inProviderSpecificDeprecated");
+        assertEquals(conf.get("loginUser"), "loginUser-inJcloudsGeneric");
+        assertEquals(conf.get("imageId"), "imageId-inJcloudsGenericDeprecated");
+        assertEquals(conf.get("keyPair"), "keyPair-inLocationGeneric");
+        assertEquals(conf.get("privateKeyData"), "privateKeyData-inNamed");
+        assertEquals(conf.get("privateKeyPassphrase"), "privateKeyPassphrase-inNamed");
+    }
+    
+    @SuppressWarnings("unchecked")
+    private FixedListMachineProvisioningLocation<JcloudsSshMachineLocation> resolve(String spec) {
+        return (FixedListMachineProvisioningLocation<JcloudsSshMachineLocation>) managementContext.getLocationRegistry().resolve(spec);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
new file mode 100644
index 0000000..31831a8
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.apache.brooklyn.location.basic.FixedListMachineProvisioningLocation;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class JcloudsByonLocationResolverSoftlayerLiveTest extends AbstractJcloudsLiveTest {
+
+    private static final String SOFTLAYER_REGION = "dal05";
+    private static final String SOFTLAYER_LOCATION_SPEC = "jclouds:softlayer:"+SOFTLAYER_REGION;
+    
+    private String slVmUser;
+    private String slVmInstanceId;
+    private String slVmIp;
+    private String slVmHostname;
+    
+    private LocalManagementContext classManagementContext;
+    private JcloudsLocation classEc2Loc;
+    private JcloudsSshMachineLocation classVm;
+
+    @BeforeClass(groups="Live")
+    public void setUpClass() throws Exception {
+        classManagementContext = newManagementContext();
+        classEc2Loc = (JcloudsLocation) classManagementContext.getLocationRegistry().resolve(SOFTLAYER_LOCATION_SPEC);
+        classVm = (JcloudsSshMachineLocation)classEc2Loc.obtain(MutableMap.<String,Object>builder()
+                .put("inboundPorts", ImmutableList.of(22))
+                .build());
+        slVmUser = classVm.getUser();
+        slVmInstanceId = classVm.getJcloudsId();
+        slVmIp = classVm.getAddress().getHostAddress();
+        slVmHostname = classVm.getNode().getHostname();
+    }
+    
+    @AfterClass(alwaysRun=true)
+    public void tearDownClass() throws Exception {
+        try {
+            if (classVm != null) {
+                classEc2Loc.release(classVm);
+            }
+        } finally {
+            if (classManagementContext != null) classManagementContext.terminate();
+        }
+    }
+
+    @Test(groups={"Live"})
+    public void testResolvesJcloudsByonSoftlayer() throws Exception {
+        checkSoftlayer("jcloudsByon:(provider=\"softlayer\",region=\""+SOFTLAYER_REGION+"\",hosts=\""+slVmInstanceId+"\",user=\""+slVmUser+"\")");
+        checkSoftlayer("jcloudsByon:(provider=\"softlayer\",region=\""+SOFTLAYER_REGION+"\",hosts=\""+slVmHostname+"\")");
+        checkSoftlayer("jcloudsByon:(provider=\"softlayer\",region=\""+SOFTLAYER_REGION+"\",hosts=\""+slVmIp+"\")");
+        checkSoftlayer("jcloudsByon:(provider=\"softlayer\",hosts=\""+slVmIp+"\")");
+    }
+    
+    private void checkSoftlayer(String spec) {
+        FixedListMachineProvisioningLocation<JcloudsSshMachineLocation> loc = resolve(spec);
+        
+        Set<JcloudsSshMachineLocation> machines = loc.getAllMachines();
+        JcloudsSshMachineLocation machine = Iterables.getOnlyElement(machines);
+        assertEquals(machine.getParent().getProvider(), "softlayer");
+        assertEquals(machine.getNode().getId(), slVmInstanceId);
+        assertEquals(machine.getAddress().getHostAddress(), slVmIp);
+        assertTrue(slVmHostname.equals(machine.getAddress().getHostName()) || slVmIp.equals(machine.getAddress().getHostName()), 
+            "address hostname is: "+machine.getAddress().getHostName());
+        assertTrue(slVmHostname.equals(machine.getNode().getHostname()) || slVmIp.equals(machine.getNode().getHostname()), 
+            "node hostname is: "+machine.getNode().getHostname());
+        
+        // could also assert this, given a user credential, but not currently set up
+//        assertTrue(machine.isSshable());
+    }
+
+    @SuppressWarnings("unchecked")
+    private FixedListMachineProvisioningLocation<JcloudsSshMachineLocation> resolve(String spec) {
+        return (FixedListMachineProvisioningLocation<JcloudsSshMachineLocation>) managementContext.getLocationRegistry().resolve(spec);
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverTest.java
new file mode 100644
index 0000000..3f7c837
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolverTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.fail;
+
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.location.basic.FixedListMachineProvisioningLocation;
+import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.management.internal.LocalManagementContext;
+
+public class JcloudsByonLocationResolverTest {
+
+    private LocalManagementContext managementContext;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        managementContext = LocalManagementContextForTests.newInstance();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (managementContext != null) Entities.destroyAll(managementContext);
+    }
+
+    @Test
+    public void testThrowsOnInvalid() throws Exception {
+        assertThrowsNoSuchElement("wrongprefix:(hosts=\"1.1.1.1\")");
+        assertThrowsIllegalArgument("jcloudsByon"); // no hosts
+        assertThrowsIllegalArgument("jcloudsByon:()"); // no hosts
+        assertThrowsIllegalArgument("jcloudsByon:(hosts=\"\")"); // empty hosts
+        assertThrowsIllegalArgument("jcloudsByon:(hosts=\"i-72b1b132\""); // no closing bracket
+        assertThrowsIllegalArgument("jcloudsByon:(hosts=\"i-72b1b132\", name)"); // no value for name
+        assertThrowsIllegalArgument("jcloudsByon:(hosts=\"i-72b1b132\", name=)"); // no value for name
+    }
+
+    @SuppressWarnings("unchecked")
+    private FixedListMachineProvisioningLocation<JcloudsSshMachineLocation> resolve(String spec) {
+        return (FixedListMachineProvisioningLocation<JcloudsSshMachineLocation>) managementContext.getLocationRegistry().resolve(spec);
+    }
+    
+    private void assertThrowsNoSuchElement(String val) {
+        try {
+            resolve(val);
+            fail();
+        } catch (NoSuchElementException e) {
+            // success
+        }
+    }
+    
+    private void assertThrowsIllegalArgument(String val) {
+        try {
+            resolve(val);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // success
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsHardwareProfilesStubbedLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsHardwareProfilesStubbedLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsHardwareProfilesStubbedLiveTest.java
new file mode 100644
index 0000000..8f9b1ea
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsHardwareProfilesStubbedLiveTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.domain.LoginCredentials;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.ImmutableList;
+
+public class JcloudsHardwareProfilesStubbedLiveTest extends AbstractJcloudsStubbedLiveTest {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(JcloudsHardwareProfilesStubbedLiveTest.class);
+    
+    private Template template;
+    
+    @Override
+    protected NodeCreator newNodeCreator() {
+        return new NodeCreator() {
+            @Override protected NodeMetadata newNode(String group, Template template) {
+                JcloudsHardwareProfilesStubbedLiveTest.this.template = template;
+                
+                NodeMetadata result = new NodeMetadataBuilder()
+                        .id("myid")
+                        .credentials(LoginCredentials.builder().identity("myuser").credential("mypassword").build())
+                        .loginPort(22)
+                        .status(Status.RUNNING)
+                        .publicAddresses(ImmutableList.of("173.194.32.123"))
+                        .privateAddresses(ImmutableList.of("172.168.10.11"))
+                        .build();
+                return result;
+            }
+        };
+    }
+
+    @Test(groups={"Live", "Live-sanity"})
+    public void testJcloudsCreateWithHardwareProfiles() throws Exception {
+        obtainMachine(MutableMap.of(JcloudsLocationConfig.MIN_RAM, "4096"));
+        assertTrue(template.getHardware().getRam() >= 4096, "template="+template);
+        
+        obtainMachine(MutableMap.of(JcloudsLocationConfig.MIN_CORES, "4"));
+        assertTrue(template.getHardware().getProcessors().get(0).getCores() >= 4, "template="+template);
+
+        obtainMachine(MutableMap.of(JcloudsLocationConfig.MIN_DISK, "51"));
+        assertTrue(template.getHardware().getVolumes().get(0).getSize() >= 51, "template="+template);
+        
+        String hardwareId = "cpu=1,memory=6144,disk=25,type=LOCAL";
+        obtainMachine(MutableMap.of(JcloudsLocationConfig.HARDWARE_ID, hardwareId));
+        assertEquals(template.getHardware().getId(), hardwareId, "template="+template);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationMetadataTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationMetadataTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationMetadataTest.java
new file mode 100644
index 0000000..7bce1ab
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationMetadataTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.assertEquals;
+
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.location.basic.LocationConfigKeys;
+import brooklyn.management.internal.LocalManagementContext;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * @author Shane Witbeck
+ */
+public class JcloudsLocationMetadataTest implements JcloudsLocationConfig {
+
+    protected BrooklynProperties brooklynProperties;
+    protected LocalManagementContext managementContext;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        managementContext = LocalManagementContextForTests.newInstance(BrooklynProperties.Factory.builderEmpty().build());
+        brooklynProperties = managementContext.getBrooklynProperties();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (managementContext != null) Entities.destroyAll(managementContext);
+    }
+
+
+    @Test
+    public void testGetsDefaultAwsEc2Metadata() throws Exception {
+        Location loc = managementContext.getLocationRegistry().resolve("jclouds:aws-ec2:us-west-1");
+        
+        assertEquals(loc.getConfig(LocationConfigKeys.LATITUDE), 40.0d);
+        assertEquals(loc.getConfig(LocationConfigKeys.LONGITUDE), -120.0d);
+        assertEquals(loc.getConfig(LocationConfigKeys.ISO_3166), ImmutableSet.of("US-CA"));
+    }
+
+    @Test
+    public void testCanOverrideDefaultAwsEc2Metadata() throws Exception {
+        brooklynProperties.put("brooklyn.location.jclouds.aws-ec2@us-west-1.latitude", "41.2");
+        Location loc = managementContext.getLocationRegistry().resolve("jclouds:aws-ec2:us-west-1");
+        
+        assertEquals(loc.getConfig(LocationConfigKeys.LATITUDE), 41.2d);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/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
new file mode 100644
index 0000000..006f62e
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationRebindMachineLiveTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.basic.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.rebindMachine(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));
+    }
+}