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:37 UTC
[08/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/org/apache/brooklyn/location/jclouds/JcloudsLocationResolverTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolverTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolverTest.java
new file mode 100644
index 0000000..8cd20b9
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolverTest.java
@@ -0,0 +1,357 @@
+/*
+ * 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.fail;
+
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.brooklyn.location.basic.LocationInternal;
+import org.apache.brooklyn.location.cloud.CloudLocationConfig;
+import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
+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 brooklyn.config.BrooklynProperties;
+import brooklyn.event.basic.MapConfigKey;
+import brooklyn.event.basic.SetConfigKey;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
+
+public class JcloudsLocationResolverTest {
+
+ private static final Logger log = LoggerFactory.getLogger(JcloudsLocationResolverTest.class);
+
+ private LocalManagementContext managementContext;
+ private BrooklynProperties brooklynProperties;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() throws Exception {
+ managementContext = LocalManagementContextForTests.newInstance();
+ brooklynProperties = managementContext.getBrooklynProperties();
+
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.identity", "aws-ec2-id");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.credential", "aws-ec2-cred");
+ brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.identity", "cloudservers-uk-id");
+ brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.credential", "cloudservers-uk-cred");
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDown() throws Exception {
+ if (managementContext != null)
+ managementContext.terminate();
+ }
+
+ @Test
+ public void testJcloudsTakesDotSeparateProperty() {
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.loginUser.privateKeyFile", "myfile");
+ String file = resolve("jclouds:aws-ec2").getConfig(JcloudsLocation.LOGIN_USER_PRIVATE_KEY_FILE);
+ assertEquals(file, "myfile");
+ }
+
+ @Test
+ public void testJcloudsTakesProviderScopedProperties() {
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyFile", "myprivatekeyfile");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.publicKeyFile", "mypublickeyfile");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyData", "myprivateKeyData");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.publicKeyData", "myPublicKeyData");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyPassphrase", "myprivateKeyPassphrase");
+ Map<String, Object> conf = resolve("jclouds:aws-ec2").config().getBag().getAllConfig();
+
+ assertEquals(conf.get("privateKeyFile"), "myprivatekeyfile");
+ assertEquals(conf.get("publicKeyFile"), "mypublickeyfile");
+ assertEquals(conf.get("privateKeyData"), "myprivateKeyData");
+ assertEquals(conf.get("publicKeyData"), "myPublicKeyData");
+ assertEquals(conf.get("privateKeyPassphrase"), "myprivateKeyPassphrase");
+ }
+
+ @Test
+ public void testJcloudsTakesGenericScopedProperties() {
+ brooklynProperties.put("brooklyn.location.jclouds.privateKeyFile", "myprivatekeyfile");
+ brooklynProperties.put("brooklyn.location.jclouds.publicKeyFile", "mypublickeyfile");
+ brooklynProperties.put("brooklyn.location.jclouds.privateKeyData", "myprivateKeyData");
+ brooklynProperties.put("brooklyn.location.jclouds.publicKeyData", "myPublicKeyData");
+ brooklynProperties.put("brooklyn.location.jclouds.privateKeyPassphrase", "myprivateKeyPassphrase");
+ Map<String, Object> conf = resolve("jclouds:aws-ec2").config().getBag().getAllConfig();
+
+ assertEquals(conf.get("privateKeyFile"), "myprivatekeyfile");
+ assertEquals(conf.get("publicKeyFile"), "mypublickeyfile");
+ assertEquals(conf.get("privateKeyData"), "myprivateKeyData");
+ assertEquals(conf.get("publicKeyData"), "myPublicKeyData");
+ assertEquals(conf.get("privateKeyPassphrase"), "myprivateKeyPassphrase");
+ }
+
+ @Test
+ public void testJcloudsTakesDeprecatedProperties() {
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.private-key-file", "myprivatekeyfile");
+ brooklynProperties.put("brooklyn.location.jclouds.public-key-file", "mypublickeyfile");
+ brooklynProperties.put("brooklyn.location.jclouds.private-key-data", "myprivateKeyData");
+ brooklynProperties.put("brooklyn.location.jclouds.public-key-data", "myPublicKeyData");
+ brooklynProperties.put("brooklyn.location.jclouds.private-key-passphrase", "myprivateKeyPassphrase");
+ brooklynProperties.put("brooklyn.location.jclouds.image-id", "myimageid");
+ Map<String, Object> conf = resolve("jclouds:aws-ec2").config().getBag().getAllConfig();
+
+ assertEquals(conf.get("privateKeyFile"), "myprivatekeyfile");
+ assertEquals(conf.get("publicKeyFile"), "mypublickeyfile");
+ assertEquals(conf.get("privateKeyData"), "myprivateKeyData");
+ assertEquals(conf.get("publicKeyData"), "myPublicKeyData");
+ assertEquals(conf.get("privateKeyPassphrase"), "myprivateKeyPassphrase");
+ assertEquals(conf.get("imageId"), "myimageid");
+ }
+
+ @Test
+ public void testJcloudsPropertiesPrecedence() {
+ brooklynProperties.put("brooklyn.location.named.myaws-ec2", "jclouds:aws-ec2");
+
+ // prefer those in "named" over everything else
+ brooklynProperties.put("brooklyn.location.named.myaws-ec2.privateKeyFile", "privateKeyFile-inNamed");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyFile", "privateKeyFile-inProviderSpecific");
+ brooklynProperties.put("brooklyn.location.jclouds.privateKeyFile", "privateKeyFile-inJcloudsGeneric");
+
+ // prefer those in provider-specific over generic
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.publicKeyFile", "publicKeyFile-inProviderSpecific");
+ brooklynProperties.put("brooklyn.location.jclouds.publicKeyFile", "publicKeyFile-inJcloudsGeneric");
+
+ // prefer deprecated properties in "named" over those less specific
+ brooklynProperties.put("brooklyn.location.named.myaws-ec2.private-key-data", "privateKeyData-inNamed");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyData", "privateKeyData-inProviderSpecific");
+ brooklynProperties.put("brooklyn.location.jclouds.privateKeyData", "privateKeyData-inJcloudsGeneric");
+
+ // prefer generic if nothing else
+ brooklynProperties.put("brooklyn.location.jclouds.publicKeyData", "publicKeyData-inJcloudsGeneric");
+
+ // prefer "named" over everything else: confirm deprecated don't get
+ // transformed to overwrite it accidentally
+ brooklynProperties
+ .put("brooklyn.location.named.myaws-ec2.privateKeyPassphrase", "privateKeyPassphrase-inNamed");
+ brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.private-key-passphrase",
+ "privateKeyPassphrase-inProviderSpecific");
+ brooklynProperties.put("brooklyn.location.jclouds.private-key-passphrase", "privateKeyPassphrase-inJcloudsGeneric");
+
+ Map<String, Object> conf = resolve("named:myaws-ec2").config().getBag().getAllConfig();
+
+ assertEquals(conf.get("privateKeyFile"), "privateKeyFile-inNamed");
+ assertEquals(conf.get("publicKeyFile"), "publicKeyFile-inProviderSpecific");
+ assertEquals(conf.get("privateKeyData"), "privateKeyData-inNamed");
+ assertEquals(conf.get("publicKeyData"), "publicKeyData-inJcloudsGeneric");
+ assertEquals(conf.get("privateKeyPassphrase"), "privateKeyPassphrase-inNamed");
+ }
+
+ @Test
+ public void testJcloudsLoads() {
+ Assert.assertTrue(resolve("jclouds:aws-ec2") instanceof JcloudsLocation);
+ }
+
+ @Test
+ public void testJcloudsImplicitLoads() {
+ Assert.assertTrue(resolve("aws-ec2") instanceof JcloudsLocation);
+ }
+
+ @Test
+ public void testJcloudsLocationLoads() {
+ Assert.assertTrue(resolve("aws-ec2:eu-west-1") instanceof JcloudsLocation);
+ }
+
+ @Test
+ public void testJcloudsRegionOnlyLoads() {
+ Assert.assertTrue(resolve("eu-west-1") instanceof JcloudsLocation);
+ }
+
+ @Test
+ public void testJcloudsEndpointLoads() {
+ JcloudsLocation loc = resolve("jclouds:openstack-nova:http://foo/api");
+ assertEquals(loc.getProvider(), "openstack-nova");
+ assertEquals(loc.getEndpoint(), "http://foo/api");
+ }
+
+ @Test
+ public void testJcloudsEndpointLoadsAsProperty() {
+ brooklynProperties.put("brooklyn.location.jclouds.openstack-nova.endpoint", "myendpoint");
+ JcloudsLocation loc = resolve("jclouds:openstack-nova");
+ // just checking
+ Assert.assertEquals(loc.config().getLocalBag().getStringKey("endpoint"), "myendpoint");
+ Assert.assertEquals(loc.getConfig(CloudLocationConfig.CLOUD_ENDPOINT), "myendpoint");
+ // this is the one we really care about!:
+ assertEquals(loc.getEndpoint(), "myendpoint");
+ }
+
+ @Test
+ public void testJcloudsLegacyRandomProperty() {
+ brooklynProperties.put("brooklyn.location.jclouds.openstack-nova.foo", "bar");
+ JcloudsLocation loc = resolve("jclouds:openstack-nova");
+ Assert.assertEquals(loc.config().getLocalBag().getStringKey("foo"), "bar");
+ }
+
+ @Test
+ public void testJcloudsRandomProperty() {
+ brooklynProperties.put("brooklyn.location.jclouds.openstack-nova.foo", "bar");
+ JcloudsLocation loc = resolve("jclouds:openstack-nova");
+ Assert.assertEquals(loc.config().getLocalBag().getStringKey("foo"), "bar");
+ }
+
+ @Test
+ public void testThrowsOnInvalid() throws Exception {
+ // Tries to treat "wrongprefix" as a cloud provider
+ assertThrows("wrongprefix:aws-ec2:us-east-1", NoSuchElementException.class);
+
+ // no provider
+ assertThrows("jclouds", IllegalArgumentException.class);
+
+ // empty provider
+ assertThrows("jclouds:", IllegalArgumentException.class);
+
+ // invalid provider
+ assertThrows("jclouds:doesnotexist", NoSuchElementException.class);
+ }
+
+ @Test
+ public void testResolvesJclouds() throws Exception {
+ // test with provider + region
+ assertJcloudsEquals(resolve("jclouds:aws-ec2:us-east-1"), "aws-ec2", "us-east-1");
+
+ // test with provider that has no region
+ assertJcloudsEquals(resolve("jclouds:rackspace-cloudservers-uk"), "rackspace-cloudservers-uk", null);
+ }
+
+ @Test
+ public void testJcloudsRegionOverridesParent() {
+ Map<String, Object> conf;
+
+ brooklynProperties.put("brooklyn.location.named.softlayer-was", "jclouds:softlayer:was01");
+ brooklynProperties.put("brooklyn.location.named.softlayer-was2", "jclouds:softlayer:was01");
+ brooklynProperties.put("brooklyn.location.named.softlayer-was2.region", "was02");
+ conf = resolve("named:softlayer-was").config().getBag().getAllConfig();
+ assertEquals(conf.get("region"), "was01");
+
+ conf = resolve("named:softlayer-was2").config().getBag().getAllConfig();
+ assertEquals(conf.get("region"), "was02");
+
+ conf = ((LocationInternal) managementContext.getLocationRegistry().resolve("named:softlayer-was2", MutableMap.of("region", "was03")))
+ .config().getBag().getAllConfig();;
+ assertEquals(conf.get("region"), "was03");
+ }
+
+ // TODO Visual inspection test that it logs warnings
+ @Test
+ public void testLogsWarnings() throws Exception {
+ assertJcloudsEquals(resolve("jclouds:jclouds:aws-ec2:us-east-1"), "aws-ec2", "us-east-1");
+ assertJcloudsEquals(resolve("us-east-1"), "aws-ec2", "us-east-1");
+
+ // TODO Should we enforce a jclouds prefix? Currently we don't
+ // assertJcloudsEquals(resolve("aws-ec2:us-east-1"), "aws-ec2",
+ // "us-east-1");
+
+ }
+
+ @Test
+ public void testResolvesJcloudsFromNamedOfNamedWithPropertiesOverriddenCorrectly() throws Exception {
+ brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop1", "1");
+ brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop2", "1");
+ brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop3", "1");
+ brooklynProperties.put("brooklyn.location.named.foo", "jclouds:softlayer:138124");
+ brooklynProperties.put("brooklyn.location.named.foo.prop2", "2");
+ brooklynProperties.put("brooklyn.location.named.foo.prop3", "2");
+ brooklynProperties.put("brooklyn.location.named.bar", "named:foo");
+ brooklynProperties.put("brooklyn.location.named.bar.prop3", "3");
+
+ JcloudsLocation l = resolve("named:bar");
+ assertJcloudsEquals(l, "softlayer", "138124");
+ Assert.assertEquals(l.config().getLocalBag().getStringKey("prop3"), "3");
+ Assert.assertEquals(l.config().getLocalBag().getStringKey("prop2"), "2");
+ Assert.assertEquals(l.config().getLocalBag().getStringKey("prop1"), "1");
+ }
+
+ @Test
+ public void testResolvesListAndMapProperties() throws Exception {
+ brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop1", "[ a, b ]");
+ brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop2", "{ a: 1, b: 2 }");
+ brooklynProperties.put("brooklyn.location.named.foo", "jclouds:softlayer:ams01");
+
+ JcloudsLocation l = resolve("named:foo");
+ assertJcloudsEquals(l, "softlayer", "ams01");
+ assertEquals(l.config().get(new SetConfigKey<String>(String.class, "prop1")), MutableSet.of("a", "b"));
+ assertEquals(l.config().get(new MapConfigKey<String>(String.class, "prop2")), MutableMap.of("a", 1, "b", 2));
+ }
+
+ @Test
+ public void testResolvesListAndMapPropertiesWithoutMergeOnInheritance() throws Exception {
+ // when we have a yaml way to specify config we may wish to have different semantics;
+ // it could depend on the collection config key whether to merge on inheritance
+ brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop1", "[ a, b ]");
+ brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop2", "{ a: 1, b: 2 }");
+ brooklynProperties.put("brooklyn.location.named.foo", "jclouds:softlayer:ams01");
+
+ brooklynProperties.put("brooklyn.location.named.foo.prop1", "[ a: 1, c: 3 ]");
+ brooklynProperties.put("brooklyn.location.named.foo.prop2", "{ b: 3, c: 3 }");
+ brooklynProperties.put("brooklyn.location.named.bar", "named:foo");
+ brooklynProperties.put("brooklyn.location.named.bar.prop2", "{ c: 4, d: 4 }");
+
+ // these do NOT affect the maps
+ brooklynProperties.put("brooklyn.location.named.foo.prop2.z", "9");
+ brooklynProperties.put("brooklyn.location.named.foo.prop3.z", "9");
+
+ JcloudsLocation l = resolve("named:bar");
+ assertJcloudsEquals(l, "softlayer", "ams01");
+
+ Set<? extends String> prop1 = l.config().get(new SetConfigKey<String>(String.class, "prop1"));
+ log.info("prop1: "+prop1);
+ assertEquals(prop1, MutableSet.of("a: 1", "c: 3"));
+
+ Map<String, String> prop2 = l.config().get(new MapConfigKey<String>(String.class, "prop2"));
+ log.info("prop2: "+prop2);
+ assertEquals(prop2, MutableMap.of("c", 4, "d", 4));
+
+ Map<String, String> prop3 = l.config().get(new MapConfigKey<String>(String.class, "prop3"));
+ log.info("prop3: "+prop3);
+ assertEquals(prop3, null);
+ }
+
+ private void assertJcloudsEquals(JcloudsLocation loc, String expectedProvider, String expectedRegion) {
+ assertEquals(loc.getProvider(), expectedProvider);
+ assertEquals(loc.getRegion(), expectedRegion);
+ }
+
+ private void assertThrows(String val, Class<?> expectedExceptionType) throws Exception {
+ try {
+ resolve(val);
+ fail();
+ } catch (Exception e) {
+ if (!expectedExceptionType.isInstance(e))
+ throw e; // otherwise success
+
+ }
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class, IllegalArgumentException.class }, expectedExceptionsMessageRegExp = ".*insufficient.*")
+ public void testJcloudsOnlyFails() {
+ resolve("jclouds");
+ }
+
+ private JcloudsLocation resolve(String spec) {
+ return (JcloudsLocation) 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/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
new file mode 100644
index 0000000..f173646
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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 brooklyn.config.ConfigKey;
+import brooklyn.util.config.ConfigBag;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.ec2.domain.BlockDeviceMapping;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class JcloudsLocationTemplateOptionsCustomisersLiveTest extends AbstractJcloudsLiveTest {
+
+ private static final String LOCATION_SPEC = AWS_EC2_PROVIDER + ":" + AWS_EC2_USEAST_REGION_NAME;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ jcloudsLocation = resolve(LOCATION_SPEC);
+ }
+
+ // Doesn't actually do much with the cloud, but jclouds requires identity and credential before it will work
+ @Test(groups = "Live")
+ public void testGeneralPurposeTemplateOptionCustomisation() throws Exception {
+ ConfigKey<Map<String, Object>> key = JcloudsLocationConfig.TEMPLATE_OPTIONS;
+
+ ConfigBag config = ConfigBag.newInstance()
+ .configure(key, ImmutableMap.of("iamInstanceProfileName", (Object)"helloworld"));
+ AWSEC2TemplateOptions templateOptions = jcloudsLocation.getComputeService().templateOptions().as(AWSEC2TemplateOptions.class);
+
+ invokeCustomizeTemplateOptions(templateOptions, JcloudsLocationConfig.TEMPLATE_OPTIONS, config);
+
+ assertEquals(templateOptions.getIAMInstanceProfileName(), "helloworld");
+ }
+
+ // Doesn't actually do much with the cloud, but jclouds requires identity and credential before it will work
+ @Test(groups = "Live")
+ public void testGeneralPurposeTemplateOptionCustomisationWithList() throws Exception {
+ ConfigKey<Map<String, Object>> key = JcloudsLocationConfig.TEMPLATE_OPTIONS;
+
+ ConfigBag config = ConfigBag.newInstance()
+ .configure(key, ImmutableMap.of(
+ "iamInstanceProfileName", (Object) "helloworld",
+ "mapNewVolumeToDeviceName", (Object) ImmutableList.of("/dev/sda1/", 123, true)));
+ AWSEC2TemplateOptions templateOptions = jcloudsLocation.getComputeService().templateOptions().as(AWSEC2TemplateOptions.class);
+
+ invokeCustomizeTemplateOptions(templateOptions, JcloudsLocationConfig.TEMPLATE_OPTIONS, config);
+
+ assertEquals(templateOptions.getIAMInstanceProfileName(), "helloworld");
+ assertEquals(templateOptions.getBlockDeviceMappings().size(), 1);
+ BlockDeviceMapping blockDeviceMapping = templateOptions.getBlockDeviceMappings().iterator().next();
+ assertEquals(blockDeviceMapping.getDeviceName(), "/dev/sda1/");
+ assertEquals(blockDeviceMapping.getEbsVolumeSize(), (Integer)123);
+ assertTrue(blockDeviceMapping.getEbsDeleteOnTermination());
+ }
+
+ /**
+ * Invoke a specific template options customizer on a TemplateOptions instance.
+ *
+ * @param templateOptions the TemplateOptions instance that you expect the customizer to modify.
+ * @param keyToTest the config key that identifies the customizer. This must be present in both @{code locationConfig} and @{link JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES}.
+ * @param locationConfig simulated configuration for the location. This must contain at least an entry for @{code keyToTest}.
+ */
+ private void invokeCustomizeTemplateOptions(TemplateOptions templateOptions, ConfigKey<?> keyToTest, ConfigBag locationConfig) {
+ checkNotNull(templateOptions, "templateOptions");
+ checkNotNull(keyToTest, "keyToTest");
+ checkNotNull(locationConfig, "locationConfig");
+ checkState(JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES.containsKey(keyToTest),
+ "SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES does not contain a customiser for the key " + keyToTest.getName());
+ checkState(locationConfig.containsKey(keyToTest),
+ "location config does not contain the key " + keyToTest.getName());
+
+ JcloudsLocation.CustomizeTemplateOptions code = JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES.get(keyToTest);
+ code.apply(templateOptions, locationConfig, locationConfig.get(keyToTest));
+ }
+
+ private JcloudsLocation resolve(String spec) {
+ return (JcloudsLocation) managementContext.getLocationRegistry().resolve("jclouds:"+spec);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java
new file mode 100644
index 0000000..4c5788f
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java
@@ -0,0 +1,510 @@
+/*
+ * 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.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.location.MachineLocationCustomizer;
+import org.apache.brooklyn.location.cloud.names.CustomMachineNamer;
+import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
+import org.jclouds.scriptbuilder.domain.OsFamily;
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.mockito.Mockito;
+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 com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.reflect.TypeToken;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.location.LocationSpec;
+import org.apache.brooklyn.location.MachineLocation;
+import org.apache.brooklyn.location.NoMachinesAvailableException;
+import org.apache.brooklyn.location.basic.LocationConfigKeys;
+import org.apache.brooklyn.location.geo.HostGeoInfo;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation.UserCreation;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.exceptions.Exceptions;
+
+/**
+ * @author Shane Witbeck
+ */
+public class JcloudsLocationTest implements JcloudsLocationConfig {
+
+ private static final Logger log = LoggerFactory.getLogger(JcloudsLocationTest.class);
+
+ public static Predicate<ConfigBag> checkerFor(final String user, final Integer minRam, final Integer minCores) {
+ return new Predicate<ConfigBag>() {
+ @Override
+ public boolean apply(@Nullable ConfigBag input) {
+ Assert.assertEquals(input.get(USER), user);
+ Assert.assertEquals(input.get(MIN_RAM), minRam);
+ Assert.assertEquals(input.get(MIN_CORES), minCores);
+ return true;
+ }
+ };
+ }
+
+ public static Predicate<ConfigBag> templateCheckerFor(final String ports) {
+ return new Predicate<ConfigBag>() {
+ @Override
+ public boolean apply(@Nullable ConfigBag input) {
+ Assert.assertEquals(input.get(INBOUND_PORTS), ports);
+ return false;
+ }
+ };
+ }
+
+ private LocalManagementContext managementContext;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ managementContext = LocalManagementContextForTests.newInstance(BrooklynProperties.Factory.builderEmpty().build());
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearUp() throws Exception {
+ if (managementContext != null) Entities.destroyAll(managementContext);
+ }
+
+ @Test
+ public void testCreateWithFlagsDirectly() throws Exception {
+ BailOutJcloudsLocation jcl = BailOutJcloudsLocation.newBailOutJcloudsLocation(managementContext);
+ jcl.tryObtainAndCheck(MutableMap.of(MIN_CORES, 2), checkerFor("fred", 16, 2));
+ }
+
+ @Test
+ public void testCreateWithFlagsDirectlyAndOverride() throws Exception {
+ BailOutJcloudsLocation jcl = BailOutJcloudsLocation.newBailOutJcloudsLocation(managementContext);
+ jcl.tryObtainAndCheck(MutableMap.of(MIN_CORES, 2, MIN_RAM, 8), checkerFor("fred", 8, 2));
+ }
+
+ @Test
+ public void testCreateWithFlagsSubLocation() throws Exception {
+ BailOutJcloudsLocation jcl = BailOutJcloudsLocation.newBailOutJcloudsLocation(managementContext);
+ jcl = (BailOutJcloudsLocation) jcl.newSubLocation(MutableMap.of(USER, "jon", MIN_CORES, 2));
+ jcl.tryObtainAndCheck(MutableMap.of(MIN_CORES, 3), checkerFor("jon", 16, 3));
+ }
+
+ @Test
+ public void testStringListToIntArray() {
+ String listString = "[1, 2, 3, 4]";
+ int[] intArray = new int[] {1, 2, 3, 4};
+ Assert.assertEquals(JcloudsLocation.toIntArray(listString), intArray);
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testMalformedStringListToIntArray() {
+ String listString = "1, 2, 3, 4";
+ JcloudsLocation.toIntArray(listString);
+ }
+
+ @Test
+ public void testEmptyStringListToIntArray() {
+ String listString = "[]";
+ int[] intArray = new int[] {};
+ Assert.assertEquals(JcloudsLocation.toIntArray(listString), intArray);
+ }
+
+ @Test
+ public void testIntArrayToIntArray() {
+ int[] intArray = new int[] {1, 2, 3, 4};
+ Assert.assertEquals(JcloudsLocation.toIntArray(intArray), intArray);
+ }
+
+ @Test
+ public void testObjectArrayToIntArray() {
+ Object[] longArray = new Object[] {1, 2, 3, 4};
+ int[] intArray = new int[] {1, 2, 3, 4};
+ Assert.assertEquals(JcloudsLocation.toIntArray(longArray), intArray);
+ }
+
+ @Test(expectedExceptions = ClassCastException.class)
+ public void testInvalidObjectArrayToIntArray() {
+ String[] stringArray = new String[] {"1", "2", "3"};
+ JcloudsLocation.toIntArray(stringArray);
+ }
+
+ @Test
+ public void testVMCreationIsRetriedOnFailure() {
+ final AtomicInteger count = new AtomicInteger();
+ Function<ConfigBag, Void> countingInterceptor = new Function<ConfigBag, Void>() {
+ @Override public Void apply(ConfigBag input) {
+ count.incrementAndGet();
+ return null;
+ }
+ };
+ BailOutJcloudsLocation loc = BailOutJcloudsLocation.newBailOutJcloudsLocation(managementContext, ImmutableMap.<ConfigKey<?>, Object>of(
+ MACHINE_CREATE_ATTEMPTS, 3,
+ BailOutJcloudsLocation.BUILD_TEMPLATE_INTERCEPTOR, countingInterceptor));
+ loc.tryObtain();
+ Assert.assertEquals(count.get(), 3);
+ }
+
+ @Test(groups={"Live", "Live-sanity"})
+ public void testCreateWithInboundPorts() {
+ BailOutJcloudsLocation jcloudsLocation = BailOutJcloudsLocation.newBailOutJcloudsLocationForLiveTest(managementContext);
+ jcloudsLocation = (BailOutJcloudsLocation) jcloudsLocation.newSubLocation(MutableMap.of());
+ jcloudsLocation.tryObtainAndCheck(MutableMap.of(), templateCheckerFor("[22, 80, 9999]"));
+ int[] ports = new int[] {22, 80, 9999};
+ Assert.assertEquals(jcloudsLocation.getTemplate().getOptions().getInboundPorts(), ports);
+ }
+
+ @Test(groups={"Live", "Live-sanity"})
+ public void testCreateWithInboundPortsOverride() {
+ BailOutJcloudsLocation jcloudsLocation = BailOutJcloudsLocation.newBailOutJcloudsLocationForLiveTest(managementContext);
+ jcloudsLocation = (BailOutJcloudsLocation) jcloudsLocation.newSubLocation(MutableMap.of());
+ jcloudsLocation.tryObtainAndCheck(MutableMap.of(INBOUND_PORTS, "[23, 81, 9998]"), templateCheckerFor("[23, 81, 9998]"));
+ int[] ports = new int[] {23, 81, 9998};
+ Assert.assertEquals(jcloudsLocation.getTemplate().getOptions().getInboundPorts(), ports);
+ }
+
+ @Test
+ public void testCreateWithMaxConcurrentCallsUnboundedByDefault() throws Exception {
+ final int numCalls = 20;
+ ConcurrencyTracker interceptor = new ConcurrencyTracker();
+ ExecutorService executor = Executors.newCachedThreadPool();
+
+ try {
+ final BailOutJcloudsLocation jcloudsLocation = BailOutJcloudsLocation.newBailOutJcloudsLocation(
+ managementContext, ImmutableMap.<ConfigKey<?>, Object>of(
+ BailOutJcloudsLocation.BUILD_TEMPLATE_INTERCEPTOR, interceptor));
+ for (int i = 0; i < numCalls; i++) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ jcloudsLocation.tryObtain();
+ }
+ });
+ }
+ interceptor.assertCallCountEventually(numCalls);
+ interceptor.unblock();
+ executor.shutdown();
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+ } finally {
+ executor.shutdownNow();
+ }
+ }
+
+ @Test(groups="Integration") // because takes 1 sec
+ public void testCreateWithMaxConcurrentCallsRespectsConfig() throws Exception {
+ final int numCalls = 4;
+ final int maxConcurrentCreations = 2;
+ ConcurrencyTracker interceptor = new ConcurrencyTracker();
+ ExecutorService executor = Executors.newCachedThreadPool();
+
+ try {
+ final BailOutJcloudsLocation jcloudsLocation = BailOutJcloudsLocation.newBailOutJcloudsLocation(
+ managementContext, ImmutableMap.of(
+ BailOutJcloudsLocation.BUILD_TEMPLATE_INTERCEPTOR, interceptor,
+ MAX_CONCURRENT_MACHINE_CREATIONS, maxConcurrentCreations));
+
+ for (int i = 0; i < numCalls; i++) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ jcloudsLocation.tryObtain();
+ }
+ });
+ }
+
+ interceptor.assertCallCountEventually(maxConcurrentCreations);
+ interceptor.assertCallCountContinually(maxConcurrentCreations);
+
+ interceptor.unblock();
+ interceptor.assertCallCountEventually(numCalls);
+ executor.shutdown();
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+
+ } finally {
+ executor.shutdownNow();
+ }
+ }
+
+ @Test(groups="Integration") // because takes 1 sec
+ public void testCreateWithMaxConcurrentCallsAppliesToSubLocations() throws Exception {
+ final int numCalls = 4;
+ final int maxConcurrentCreations = 2;
+ ConcurrencyTracker interceptor = new ConcurrencyTracker();
+ ExecutorService executor = Executors.newCachedThreadPool();
+
+ try {
+ final BailOutJcloudsLocation jcloudsLocation = BailOutJcloudsLocation.newBailOutJcloudsLocation(
+ managementContext, ImmutableMap.of(
+ BailOutJcloudsLocation.BUILD_TEMPLATE_INTERCEPTOR, interceptor,
+ MAX_CONCURRENT_MACHINE_CREATIONS, maxConcurrentCreations));
+
+ for (int i = 0; i < numCalls; i++) {
+ final BailOutJcloudsLocation subLocation = (BailOutJcloudsLocation) jcloudsLocation.newSubLocation(MutableMap.of());
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ subLocation.tryObtain();
+ }
+ });
+ }
+
+ interceptor.assertCallCountEventually(maxConcurrentCreations);
+ interceptor.assertCallCountContinually(maxConcurrentCreations);
+
+ interceptor.unblock();
+ interceptor.assertCallCountEventually(numCalls);
+ executor.shutdown();
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+
+ } finally {
+ executor.shutdownNow();
+ }
+ }
+
+ @Test
+ public void testCreateWithCustomMachineNamer() {
+ final String machineNamerClass = CustomMachineNamer.class.getName();
+ BailOutJcloudsLocation jcloudsLocation = BailOutJcloudsLocation.newBailOutJcloudsLocation(
+ managementContext, ImmutableMap.<ConfigKey<?>, Object>of(
+ LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS, machineNamerClass));
+ jcloudsLocation.tryObtainAndCheck(ImmutableMap.of(CustomMachineNamer.MACHINE_NAME_TEMPLATE, "ignored"), new Predicate<ConfigBag>() {
+ public boolean apply(ConfigBag input) {
+ Assert.assertEquals(input.get(LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS), machineNamerClass);
+ return true;
+ }
+ });
+ }
+
+ @Test
+ public void testCreateWithCustomMachineNamerOnObtain() {
+ final String machineNamerClass = CustomMachineNamer.class.getName();
+ BailOutJcloudsLocation jcloudsLocation = BailOutJcloudsLocation.newBailOutJcloudsLocation(managementContext);
+ ImmutableMap<ConfigKey<String>, String> flags = ImmutableMap.of(
+ CustomMachineNamer.MACHINE_NAME_TEMPLATE, "ignored",
+ LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS, machineNamerClass);
+ jcloudsLocation.tryObtainAndCheck(flags, new Predicate<ConfigBag>() {
+ public boolean apply(ConfigBag input) {
+ Assert.assertEquals(input.get(LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS), machineNamerClass);
+ return true;
+ }
+ });
+ }
+
+ public static class ConcurrencyTracker implements Function<ConfigBag,Void> {
+ final AtomicInteger concurrentCallsCounter = new AtomicInteger();
+ final CountDownLatch continuationLatch = new CountDownLatch(1);
+
+ @Override public Void apply(ConfigBag input) {
+ concurrentCallsCounter.incrementAndGet();
+ try {
+ continuationLatch.await();
+ } catch (InterruptedException e) {
+ throw Exceptions.propagate(e);
+ }
+ return null;
+ }
+
+ public void unblock() {
+ continuationLatch.countDown();
+ }
+
+ public void assertCallCountEventually(final int expected) {
+ Asserts.succeedsEventually(new Runnable() {
+ @Override public void run() {
+ Assert.assertEquals(concurrentCallsCounter.get(), expected);
+ }
+ });
+ }
+
+ public void assertCallCountContinually(final int expected) {
+ Asserts.succeedsContinually(new Runnable() {
+ @Override public void run() {
+ Assert.assertEquals(concurrentCallsCounter.get(), expected);
+ }
+ });
+ }
+ }
+
+
+ @SuppressWarnings("serial")
+ public static class FakeLocalhostWithParentJcloudsLocation extends JcloudsLocation {
+ public static final ConfigKey<Function<ConfigBag,Void>> BUILD_TEMPLATE_INTERCEPTOR = ConfigKeys.newConfigKey(new TypeToken<Function<ConfigBag,Void>>() {}, "buildtemplateinterceptor");
+
+ ConfigBag lastConfigBag;
+
+ public FakeLocalhostWithParentJcloudsLocation() {
+ super();
+ }
+
+ public FakeLocalhostWithParentJcloudsLocation(Map<?, ?> conf) {
+ super(conf);
+ }
+
+ @Override
+ public JcloudsSshMachineLocation obtain(Map<?, ?> flags) throws NoMachinesAvailableException {
+ JcloudsSshMachineLocation result = getManagementContext().getLocationManager().createLocation(LocationSpec.create(JcloudsSshMachineLocation.class)
+ .configure("address", "127.0.0.1")
+ .configure("port", 22)
+ .configure("user", "bob")
+ .configure("jcloudsParent", this));
+ registerJcloudsMachineLocation("bogus", result);
+
+ // explicitly invoke this customizer, to comply with tests
+ for (JcloudsLocationCustomizer customizer : getCustomizers(config().getBag())) {
+ customizer.customize(this, null, (JcloudsMachineLocation)result);
+ }
+ for (MachineLocationCustomizer customizer : getMachineCustomizers(config().getBag())) {
+ customizer.customize((JcloudsMachineLocation)result);
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void releaseNode(String instanceId) {
+ // no-op
+ }
+ }
+
+ @Test
+ public void testInheritsGeo() throws Exception {
+ ConfigBag allConfig = ConfigBag.newInstance()
+ .configure(IMAGE_ID, "bogus")
+ .configure(CLOUD_PROVIDER, "aws-ec2")
+ .configure(CLOUD_REGION_ID, "bogus")
+ .configure(ACCESS_IDENTITY, "bogus")
+ .configure(ACCESS_CREDENTIAL, "bogus")
+ .configure(LocationConfigKeys.LATITUDE, 42d)
+ .configure(LocationConfigKeys.LONGITUDE, -20d)
+ .configure(MACHINE_CREATE_ATTEMPTS, 1);
+ FakeLocalhostWithParentJcloudsLocation ll = managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class).configure(allConfig.getAllConfig()));
+ MachineLocation l = ll.obtain();
+ log.info("loc:" +l);
+ HostGeoInfo geo = HostGeoInfo.fromLocation(l);
+ log.info("geo: "+geo);
+ Assert.assertEquals(geo.latitude, 42d, 0.00001);
+ Assert.assertEquals(geo.longitude, -20d, 0.00001);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testInheritsGeoFromLocationMetadataProperties() throws Exception {
+ // in location-metadata.properties:
+// brooklyn.location.jclouds.softlayer@wdc01.latitude=38.909202
+// brooklyn.location.jclouds.softlayer@wdc01.longitude=-77.47314
+ ConfigBag allConfig = ConfigBag.newInstance()
+ .configure(IMAGE_ID, "bogus")
+ .configure(CLOUD_PROVIDER, "softlayer")
+ .configure(CLOUD_REGION_ID, "wdc01")
+ .configure(ACCESS_IDENTITY, "bogus")
+ .configure(ACCESS_CREDENTIAL, "bogus")
+ .configure(MACHINE_CREATE_ATTEMPTS, 1);
+ FakeLocalhostWithParentJcloudsLocation ll = managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class)
+ .configure(new JcloudsPropertiesFromBrooklynProperties().getJcloudsProperties("softlayer", "wdc01", null, managementContext.getBrooklynProperties()))
+ .configure(allConfig.getAllConfig()));
+ MachineLocation l = ll.obtain();
+ log.info("loc:" +l);
+ HostGeoInfo geo = HostGeoInfo.fromLocation(l);
+ log.info("geo: "+geo);
+ Assert.assertEquals(geo.latitude, 38.909202d, 0.00001);
+ Assert.assertEquals(geo.longitude, -77.47314d, 0.00001);
+ }
+
+ @Test
+ public void testInvokesCustomizerCallbacks() throws Exception {
+ JcloudsLocationCustomizer customizer = Mockito.mock(JcloudsLocationCustomizer.class);
+ MachineLocationCustomizer machineCustomizer = Mockito.mock(MachineLocationCustomizer.class);
+// Mockito.when(customizer.customize(Mockito.any(JcloudsLocation.class), Mockito.any(ComputeService.class), Mockito.any(JcloudsSshMachineLocation.class)));
+ ConfigBag allConfig = ConfigBag.newInstance()
+ .configure(CLOUD_PROVIDER, "aws-ec2")
+ .configure(ACCESS_IDENTITY, "bogus")
+ .configure(ACCESS_CREDENTIAL, "bogus")
+ .configure(JcloudsLocationConfig.JCLOUDS_LOCATION_CUSTOMIZERS, ImmutableList.of(customizer))
+ .configure(JcloudsLocation.MACHINE_LOCATION_CUSTOMIZERS, ImmutableList.of(machineCustomizer))
+ .configure(MACHINE_CREATE_ATTEMPTS, 1);
+ FakeLocalhostWithParentJcloudsLocation ll = managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class).configure(allConfig.getAllConfig()));
+ JcloudsMachineLocation l = (JcloudsMachineLocation)ll.obtain();
+ Mockito.verify(customizer, Mockito.times(1)).customize(ll, null, l);
+ Mockito.verify(customizer, Mockito.never()).preRelease(l);
+ Mockito.verify(customizer, Mockito.never()).postRelease(l);
+ Mockito.verify(machineCustomizer, Mockito.times(1)).customize(l);
+ Mockito.verify(machineCustomizer, Mockito.never()).preRelease(l);
+
+ ll.release(l);
+ Mockito.verify(customizer, Mockito.times(1)).preRelease(l);
+ Mockito.verify(customizer, Mockito.times(1)).postRelease(l);
+ Mockito.verify(machineCustomizer, Mockito.times(1)).preRelease(l);
+ }
+
+ // now test creating users
+
+ protected String getCreateUserStatementsFor(Map<ConfigKey<?>,?> config) {
+ BailOutJcloudsLocation jl = BailOutJcloudsLocation.newBailOutJcloudsLocation(
+ managementContext, MutableMap.<ConfigKey<?>, Object>builder()
+ .put(JcloudsLocationConfig.LOGIN_USER, "root").put(JcloudsLocationConfig.LOGIN_USER_PASSWORD, "m0ck")
+ .put(JcloudsLocationConfig.USER, "bob").put(JcloudsLocationConfig.LOGIN_USER_PASSWORD, "b0b")
+ .putAll(config).build());
+
+ UserCreation creation = jl.createUserStatements(null, jl.config().getBag());
+ return new StatementList(creation.statements).render(OsFamily.UNIX);
+ }
+
+ @Test
+ public void testDisablesRoot() {
+ String statements = getCreateUserStatementsFor(ImmutableMap.<ConfigKey<?>, Object>of());
+ Assert.assertTrue(statements.contains("PermitRootLogin"), "Error:\n"+statements);
+ Assert.assertTrue(statements.matches("(?s).*sudoers.*useradd.*bob.*wheel.*"), "Error:\n"+statements);
+ }
+
+ @Test
+ public void testDisableRootFalse() {
+ String statements = getCreateUserStatementsFor(ImmutableMap.<ConfigKey<?>, Object>of(
+ JcloudsLocationConfig.DISABLE_ROOT_AND_PASSWORD_SSH, false));
+ Assert.assertFalse(statements.contains("PermitRootLogin"), "Error:\n"+statements);
+ Assert.assertTrue(statements.matches("(?s).*sudoers.*useradd.*bob.*wheel.*"), "Error:\n"+statements);
+ }
+
+ @Test
+ public void testDisableRootAndSudoFalse() {
+ String statements = getCreateUserStatementsFor(ImmutableMap.<ConfigKey<?>, Object>of(
+ JcloudsLocationConfig.DISABLE_ROOT_AND_PASSWORD_SSH, false,
+ JcloudsLocationConfig.GRANT_USER_SUDO, false));
+ Assert.assertFalse(statements.contains("PermitRootLogin"), "Error:\n"+statements);
+ Assert.assertFalse(statements.matches("(?s).*sudoers.*useradd.*bob.*wheel.*"), "Error:\n"+statements);
+ }
+
+ // TODO more tests, where flags come in from resolver, named locations, etc
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLoginLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLoginLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLoginLiveTest.java
new file mode 100644
index 0000000..5a17a5a
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLoginLiveTest.java
@@ -0,0 +1,407 @@
+/*
+ * 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 java.io.File;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.location.LocationSpec;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.os.Os;
+import brooklyn.util.stream.Streams;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests different login options for ssh keys, passwords, etc.
+ */
+public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JcloudsLoginLiveTest.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";
+
+ // Image: {id=LON/29fe3e2b-f119-4715-927b-763e99ebe23e, providerId=29fe3e2b-f119-4715-927b-763e99ebe23e, name=Debian 6.06 (Squeeze), location={scope=ZONE, id=LON, description=LON, parent=rackspace-cloudservers-uk, iso3166Codes=[GB-SLG]}, os={family=debian, name=Debian 6.06 (Squeeze), version=6.0, description=Debian 6.06 (Squeeze), is64Bit=true}, description=Debian 6.06 (Squeeze), status=AVAILABLE, loginUser=root, userMetadata={os_distro=debian, 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.debian, com.rackspace__1__release_build_date=2013-08-06_13-05-36, auto_disk_config=True, com.rackspace__1__release_version=4, os_type=linux, com.rackspace__1__visible_rackconnect=1, com.rackspace__1__release_id=300, com.rackspace__1__visible_managed=0, com.rackspace__1__build_core=1, org.openstack__1__os_version=6.06, org.openstack__1_
_architecture=x64, com.rackspace__1__build_managed=0}}
+ public static final String RACKSPACE_DEBIAN_IMAGE_NAME_REGEX = "Debian 6";
+
+ protected JcloudsSshMachineLocation machine;
+
+ private File privateRsaFile = new File(Os.tidyPath("~/.ssh/id_rsa"));
+ private File privateDsaFile = new File(Os.tidyPath("~/.ssh/id_dsa"));
+ private File privateRsaFileTmp = new File(privateRsaFile.getAbsoluteFile()+".tmp");
+ private File privateDsaFileTmp = new File(privateDsaFile.getAbsoluteFile()+".tmp");
+ private File publicRsaFile = new File(Os.tidyPath("~/.ssh/id_rsa.pub"));
+ private File publicDsaFile = new File(Os.tidyPath("~/.ssh/id_dsa.pub"));
+ private File publicRsaFileTmp = new File(publicRsaFile.getAbsoluteFile()+".tmp");
+ private File publicDsaFileTmp = new File(publicDsaFile.getAbsoluteFile()+".tmp");
+ private boolean privateRsaFileMoved;
+ private boolean privateDsaFileMoved;
+ private boolean publicRsaFileMoved;
+ private boolean publicDsaFileMoved;
+
+ @Test(groups = {"Live"})
+ protected void testAwsEc2SpecifyingJustPrivateSshKeyInDeprecatedForm() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.LEGACY_PRIVATE_KEY_FILE.getName(), "~/.ssh/id_rsa");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+
+ machine = createEc2Machine(ImmutableMap.<String,Object>of());
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+ }
+
+ @Test(groups = {"Live"})
+ protected void testAwsEc2SpecifyingPrivateAndPublicSshKeyInDeprecatedForm() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.LEGACY_PRIVATE_KEY_FILE.getName(), "~/.ssh/id_rsa");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.LEGACY_PUBLIC_KEY_FILE.getName(), "~/.ssh/id_rsa.pub");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+
+ machine = createEc2Machine(ImmutableMap.<String,Object>of());
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+ }
+
+ // Uses default key files
+ @Test(groups = {"Live"})
+ protected void testAwsEc2SpecifyingNoKeyFiles() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+
+ machine = createEc2Machine(ImmutableMap.<String,Object>of());
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+ }
+
+ @Test(groups = {"Live"})
+ public void testSpecifyingPasswordAndNoDefaultKeyFilesExist() throws Exception {
+ try {
+ moveSshKeyFiles();
+
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PASSWORD.getName(), "mypassword");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+
+ machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PASSWORD, "mypassword")
+ .build());
+ } finally {
+ restoreSshKeyFiles();
+ }
+ }
+
+ // Generates and uses a random password
+ @Test(groups = {"Live"})
+ protected void testSpecifyingNothingAndNoDefaultKeyFilesExist() throws Exception {
+ try {
+ moveSshKeyFiles();
+
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+
+ machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+ assertSshable(machine);
+ assertEquals(machine.getUser(), "myname");
+ } finally {
+ restoreSshKeyFiles();
+ }
+ }
+
+ @Test(groups = {"Live"})
+ protected void testSpecifyingPasswordAndSshKeysPrefersKeys() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PRIVATE_KEY_FILE.getName(), "~/.ssh/id_rsa");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PUBLIC_KEY_FILE.getName(), "~/.ssh/id_rsa.pub");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PASSWORD.getName(), "mypassword");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+
+ machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PASSWORD, "mypassword")
+ .build());
+ }
+
+ @Test(groups = {"Live"})
+ protected void testSpecifyingPasswordIgnoresDefaultSshKeys() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PASSWORD.getName(), "mypassword");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+
+ machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PASSWORD, "mypassword")
+ .build());
+
+ assertNotSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+ }
+
+ @Test(groups = {"Live"})
+ protected void testSpecifyingPasswordWithPublicKeyAllowsKeyAccess() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PASSWORD.getName(), "mypassword");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PUBLIC_KEY_FILE.getName(), "~/.ssh/id_rsa.pub");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+
+ machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "myname")
+ .put(SshMachineLocation.PASSWORD, "mypassword")
+ .build());
+ }
+
+ // user "root" matches the loginUser=root
+ @Test(groups = {"Live"})
+ protected void testSpecifyingPasswordWhenNoDefaultKeyFilesExistWithRootUser() throws Exception {
+ try {
+ moveSshKeyFiles();
+
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "root");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PASSWORD.getName(), "mypassword");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+
+ machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "root")
+ .put(SshMachineLocation.PASSWORD, "mypassword")
+ .build());
+ } finally {
+ restoreSshKeyFiles();
+ }
+ }
+
+ @Test(groups = {"Live"})
+ protected void testAwsEc2SpecifyingRootUser() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "root");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PRIVATE_KEY_FILE.getName(), "~/.ssh/id_rsa");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PUBLIC_KEY_FILE.getName(), "~/.ssh/id_rsa.pub");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+
+ machine = createEc2Machine(ImmutableMap.<String,Object>of("imageId", AWS_EC2_UBUNTU_10_IMAGE_ID));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "root")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+ }
+
+ @Test(groups = {"Live"})
+ protected void testAwsEc2WhenBlankUserSoUsesRootLoginUser() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PRIVATE_KEY_FILE.getName(), "~/.ssh/id_rsa");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PUBLIC_KEY_FILE.getName(), "~/.ssh/id_rsa.pub");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+
+ machine = createEc2Machine(ImmutableMap.<String,Object>of("imageId", AWS_EC2_UBUNTU_10_IMAGE_ID));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "root")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+ }
+
+ // In JcloudsLocation.NON_ADDABLE_USERS, "ec2-user" was treated special and was not added!
+ // That was very bad for if someone is running brooklyn on a new AWS VM, and just installs brooklyn+runs as the default ec2-user.
+ @Test(groups = {"Live"})
+ protected void testAwsEc2SpecifyingSpecialUser() throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "ec2-user");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PRIVATE_KEY_FILE.getName(), "~/.ssh/id_rsa");
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PUBLIC_KEY_FILE.getName(), "~/.ssh/id_rsa.pub");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+
+ machine = createEc2Machine(ImmutableMap.<String,Object>of("imageId", AWS_EC2_UBUNTU_10_IMAGE_ID));
+ assertSshable(machine);
+
+ assertSshable(ImmutableMap.builder()
+ .put("address", machine.getAddress())
+ .put("user", "ec2-user")
+ .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
+ .build());
+ }
+
+ @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);
+ }
+ }
+
+ protected void assertNotSshable(Map<?,?> machineConfig) {
+ try {
+ assertSshable(machineConfig);
+ Assert.fail("ssh should not have succeeded "+machineConfig);
+ } catch (Exception e) {
+ // expected
+ LOG.debug("Exception as expected when testing sshable "+machineConfig);
+ }
+ }
+
+ private void moveSshKeyFiles() throws Exception {
+ privateRsaFileMoved = false;
+ privateDsaFileMoved = false;
+ publicRsaFileMoved = false;
+ publicDsaFileMoved = false;
+
+ if (privateRsaFile.exists()) {
+ LOG.info("Moving {} to {}", privateRsaFile, privateRsaFileTmp);
+ Runtime.getRuntime().exec("mv "+privateRsaFile.getAbsolutePath()+" "+privateRsaFileTmp.getAbsolutePath());
+ privateRsaFileMoved = true;
+ }
+ if (privateDsaFile.exists()) {
+ LOG.info("Moving {} to {}", privateDsaFile, privateDsaFileTmp);
+ Runtime.getRuntime().exec("mv "+privateDsaFile.getAbsolutePath()+" "+privateDsaFileTmp.getAbsolutePath());
+ privateDsaFileMoved = true;
+ }
+ if (publicRsaFile.exists()) {
+ LOG.info("Moving {} to {}", publicRsaFile, publicRsaFileTmp);
+ Runtime.getRuntime().exec("mv "+publicRsaFile.getAbsolutePath()+" "+publicRsaFileTmp.getAbsolutePath());
+ publicRsaFileMoved = true;
+ }
+ if (publicDsaFile.exists()) {
+ LOG.info("Moving {} to {}", publicDsaFile, publicDsaFileTmp);
+ Runtime.getRuntime().exec("mv "+publicDsaFile.getAbsolutePath()+" "+publicDsaFileTmp.getAbsolutePath());
+ publicDsaFileMoved = true;
+ }
+ }
+
+ private void restoreSshKeyFiles() throws Exception {
+ if (privateRsaFileMoved) {
+ LOG.info("Restoring {} form {}", privateRsaFile, privateRsaFileTmp);
+ Runtime.getRuntime().exec("mv "+privateRsaFileTmp.getAbsolutePath()+" "+privateRsaFile.getAbsolutePath());
+ privateRsaFileMoved = false;
+ }
+ if (privateDsaFileMoved) {
+ LOG.info("Restoring {} form {}", privateDsaFile, privateDsaFileTmp);
+ Runtime.getRuntime().exec("mv "+privateDsaFileTmp.getAbsolutePath()+" "+privateDsaFile.getAbsolutePath());
+ privateDsaFileMoved = false;
+ }
+ if (publicRsaFileMoved) {
+ LOG.info("Restoring {} form {}", publicRsaFile, publicRsaFileTmp);
+ Runtime.getRuntime().exec("mv "+publicRsaFileTmp.getAbsolutePath()+" "+publicRsaFile.getAbsolutePath());
+ publicRsaFileMoved = false;
+ }
+ if (publicDsaFileMoved) {
+ LOG.info("Restoring {} form {}", publicDsaFile, publicDsaFileTmp);
+ Runtime.getRuntime().exec("mv "+publicDsaFileTmp.getAbsolutePath()+" "+publicDsaFile.getAbsolutePath());
+ publicDsaFileMoved = false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java
new file mode 100644
index 0000000..5e25a8c
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.text.Strings;
+
+public class JcloudsMachineNamerTest {
+
+ private static final Logger log = LoggerFactory.getLogger(JcloudsMachineNamerTest.class);
+
+ @Test
+ public void testGenerateGroupIdInVcloud() {
+ ConfigBag cfg = new ConfigBag()
+ .configure(JcloudsLocationConfig.CLOUD_PROVIDER, "vcloud")
+ .configure(JcloudsLocationConfig.CALLER_CONTEXT, "!mycontext!");
+
+ String result = new JcloudsMachineNamer().generateNewGroupId(cfg);
+
+ log.info("test mycontext vcloud group id gives: "+result);
+ // brooklyn-user-!mycontext!-1234
+ // br-<code>-<user>-myco-1234
+ Assert.assertTrue(result.length() <= 24-4-1, "result: "+result);
+
+ String user = Strings.maxlen(System.getProperty("user.name"), 2).toLowerCase();
+ // (length 2 will happen if user is brooklyn, to avoid brooklyn-brooklyn at start!)
+ Assert.assertTrue(result.indexOf(user) >= 0);
+ Assert.assertTrue(result.indexOf("-myc") >= 0);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynPropertiesTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynPropertiesTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynPropertiesTest.java
new file mode 100644
index 0000000..69eda84
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynPropertiesTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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 org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Maps;
+
+public class JcloudsPropertiesFromBrooklynPropertiesTest {
+
+ protected static Map<String, Object> sampleProviderOrApiProps() {
+ Map<String, Object> map = Maps.newHashMap();
+ map.put("brooklyn.location.jclouds.FooServers.identity", "bob");
+ map.put("brooklyn.location.jclouds.FooServers.credential", "s3cr3t");
+ map.put("brooklyn.location.jclouds.FooServers.jclouds.ssh.max-retries", "100");
+ return map;
+ }
+
+ protected static Map<String, Object> sampleNamedProps() {
+ Map<String, Object> map = Maps.newHashMap();
+ map.put("brooklyn.location.named.cloudfirst", "jclouds:openstack-nova");
+ map.put("brooklyn.location.named.cloudfirst.identity", "myId");
+ map.put("brooklyn.location.named.cloudfirst.credential", "password");
+ map.put("brooklyn.location.named.cloudfirst.imageId", "RegionOne/1");
+ map.put("brooklyn.location.named.cloudfirst.securityGroups", "universal");
+ return map;
+ }
+
+ protected static Map<String, Object> unsupportedSampleProviderOrApiProps() {
+ Map<String, Object> map = Maps.newHashMap();
+ map.put("brooklyn.location.jclouds.FooServers.image-id", "invalid-image-id");
+ return map;
+ }
+
+ protected static Map<String, Object> unsupportedNamedProps() {
+ Map<String, Object> map = Maps.newHashMap();
+ map.put("brooklyn.location.named.cloudfirst", "jclouds:openstack-nova");
+ map.put("brooklyn.location.named.cloudfirst.hardware-id", "invalid-hardware-id");
+ return map;
+ }
+
+ private JcloudsPropertiesFromBrooklynProperties parser;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ parser = new JcloudsPropertiesFromBrooklynProperties();
+ }
+
+ @Test
+ public void testProviderOrApiProperties() {
+ Map<String, Object> map = parser.getJcloudsProperties("FooServers", null, null, sampleProviderOrApiProps());
+ Assert.assertEquals(map.get("identity"), "bob");
+ Assert.assertEquals(map.get("credential"), "s3cr3t");
+ Assert.assertEquals(map.get("provider"), "FooServers");
+ }
+
+ @Test
+ public void testNamedProperties() {
+ Map<String, Object> map = parser.getJcloudsProperties("openstack-nova", null, "cloudfirst", sampleNamedProps());
+ Assert.assertEquals(map.get("provider"), "openstack-nova");
+ Assert.assertEquals(map.get("identity"), "myId");
+ Assert.assertEquals(map.get("credential"), "password");
+ Assert.assertEquals(map.get("imageId"), "RegionOne/1");
+ Assert.assertEquals(map.get("securityGroups"), "universal");
+ }
+
+ @Test
+ public void testOrderOfPreference() {
+ Map<String, Object> allProperties = Maps.newHashMap();
+ allProperties.putAll(sampleProviderOrApiProps());
+ allProperties.putAll(sampleNamedProps());
+ Map<String, Object> map = parser.getJcloudsProperties("openstack-nova", null, "cloudfirst", allProperties);
+ Assert.assertEquals(map.get("provider"), "openstack-nova");
+ Assert.assertEquals(map.get("identity"), "myId");
+ Assert.assertEquals(map.get("credential"), "password");
+ Assert.assertEquals(map.get("imageId"), "RegionOne/1");
+ Assert.assertEquals(map.get("securityGroups"), "universal");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsSshingLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsSshingLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsSshingLiveTest.java
new file mode 100644
index 0000000..48ce9cf
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsSshingLiveTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Tests the initial ssh command execution (e.g. user creation), using jclouds TemplateOptions
+ * and using just brooklyn.
+ */
+public class JcloudsSshingLiveTest extends AbstractJcloudsLiveTest {
+
+ public static final String SOFTLAYER_REGION_NAME = SOFTLAYER_AMS01_REGION_NAME;
+ public static final String SOTLAYER_LOCATION_SPEC = "jclouds:" + SOFTLAYER_PROVIDER + (SOFTLAYER_REGION_NAME == null ? "" : ":" + SOFTLAYER_REGION_NAME);
+
+ protected JcloudsSshMachineLocation machine;
+
+ @Test(groups = {"Live"})
+ public void testCreatesUserUsingJcloudsTemplateOptions() throws Exception {
+ runCreatesUser(true);
+ }
+
+ @Test(groups = {"Live"})
+ public void testCreatesUserWithoutUsingJcloudsTemplateOptions() throws Exception {
+ runCreatesUser(false);
+ }
+
+ protected void runCreatesUser(boolean useJcloudsSshInit) throws Exception {
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USE_JCLOUDS_SSH_INIT.getName(), Boolean.toString(useJcloudsSshInit));
+ brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(SOTLAYER_LOCATION_SPEC);
+
+ JcloudsSshMachineLocation machine = obtainMachine(MutableMap.<String,Object>builder()
+ .putIfAbsent("inboundPorts", ImmutableList.of(22))
+ .build());
+ assertSshable(machine);
+ assertEquals(machine.getUser(), "myname");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/LiveTestEntity.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/LiveTestEntity.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/LiveTestEntity.java
new file mode 100644
index 0000000..0ff4474
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/LiveTestEntity.java
@@ -0,0 +1,90 @@
+/*
+ * 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.Collection;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.location.NoMachinesAvailableException;
+import org.apache.brooklyn.test.entity.TestEntity;
+import org.apache.brooklyn.test.entity.TestEntityImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Lifecycle;
+import org.apache.brooklyn.location.MachineProvisioningLocation;
+import org.apache.brooklyn.location.basic.LocationInternal;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+@ImplementedBy(LiveTestEntity.LiveTestEntityImpl.class)
+public interface LiveTestEntity extends TestEntity {
+
+ MachineProvisioningLocation<?> getProvisioningLocation();
+ JcloudsSshMachineLocation getObtainedLocation();
+
+ public static class LiveTestEntityImpl extends TestEntityImpl implements LiveTestEntity {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LiveTestEntityImpl.class);
+ private JcloudsLocation provisioningLocation;
+ private JcloudsSshMachineLocation obtainedLocation;
+
+ @Override
+ public void start(final Collection<? extends Location> locs) {
+ LOG.trace("Starting {}", this);
+ callHistory.add("start");
+ setAttribute(SERVICE_STATE, Lifecycle.STARTING);
+ counter.incrementAndGet();
+ addLocations(locs);
+ provisioningLocation = (JcloudsLocation) Iterables.find(locs, Predicates.instanceOf(JcloudsLocation.class));
+ try {
+ obtainedLocation = (JcloudsSshMachineLocation)provisioningLocation.obtain(((LocationInternal)provisioningLocation).config().getBag().getAllConfig());
+ } catch (NoMachinesAvailableException e) {
+ throw Throwables.propagate(e);
+ }
+ addLocations(ImmutableList.of(obtainedLocation));
+ setAttribute(SERVICE_STATE, Lifecycle.RUNNING);
+ }
+
+ @Override
+ public void stop() {
+ LOG.trace("Stopping {}", this);
+ callHistory.add("stop");
+ setAttribute(SERVICE_STATE, Lifecycle.STOPPING);
+ counter.decrementAndGet();
+ if (provisioningLocation != null && obtainedLocation != null) {
+ provisioningLocation.release(obtainedLocation);
+ }
+ setAttribute(SERVICE_STATE, Lifecycle.STOPPED);
+ }
+
+ public MachineProvisioningLocation<?> getProvisioningLocation() {
+ return provisioningLocation;
+ }
+
+ public JcloudsSshMachineLocation getObtainedLocation() {
+ return obtainedLocation;
+ }
+ }
+
+}