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:36 UTC
[07/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/RebindJcloudsLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java
new file mode 100644
index 0000000..535b6a8
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.rebind.RebindTestUtils;
+import org.apache.brooklyn.location.OsDetails;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.util.config.ConfigBag;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+public class RebindJcloudsLocationLiveTest extends AbstractJcloudsLiveTest {
+
+ 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;
+
+ private ClassLoader classLoader = getClass().getClassLoader();
+ private TestApplication origApp;
+ private LiveTestEntity origEntity;
+ private File mementoDir;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ origApp = ApplicationBuilder.newManagedApp(EntitySpec.create(TestApplication.class), managementContext);
+ origEntity = origApp.createAndManageChild(EntitySpec.create(LiveTestEntity.class));
+
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+ jcloudsLocation.setConfig(JcloudsLocation.HARDWARE_ID, AWS_EC2_SMALL_HARDWARE_ID);
+ }
+
+ @AfterMethod(alwaysRun = true)
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (origApp != null) Entities.destroyAll(origApp.getManagementContext());
+ if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
+ }
+
+ @Override
+ protected LocalManagementContext newManagementContext() {
+ mementoDir = Files.createTempDir();
+ return RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader, 1);
+ }
+
+ @Test(groups="Live")
+ public void testRebindsToJcloudsMachine() throws Exception {
+ origApp.start(ImmutableList.of(jcloudsLocation));
+ JcloudsLocation origJcloudsLocation = jcloudsLocation;
+ System.out.println("orig locations: " + origEntity.getLocations());
+ JcloudsSshMachineLocation origMachine = (JcloudsSshMachineLocation) Iterables.find(origEntity.getLocations(), Predicates.instanceOf(JcloudsSshMachineLocation.class));
+
+ TestApplication newApp = rebind();
+ LiveTestEntity newEntity = (LiveTestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(LiveTestEntity.class));
+ JcloudsSshMachineLocation newMachine = (JcloudsSshMachineLocation) Iterables.find(newEntity.getLocations(), Predicates.instanceOf(JcloudsSshMachineLocation.class));
+
+ assertMachineEquals(newMachine, origMachine);
+ assertTrue(newMachine.isSshable());
+
+ JcloudsLocation newJcloudsLoction = newMachine.getParent();
+ assertJcloudsLocationEquals(newJcloudsLoction, origJcloudsLocation);
+ }
+
+ private void assertMachineEquals(JcloudsSshMachineLocation actual, JcloudsSshMachineLocation expected) {
+ String errmsg = "actual="+actual.toVerboseString()+"; expected="+expected.toVerboseString();
+ assertEquals(actual.getId(), expected.getId(), errmsg);
+ assertEquals(actual.getJcloudsId(), expected.getJcloudsId(), errmsg);
+ assertOsDetailEquals(actual.getOsDetails(), expected.getOsDetails());
+ assertEquals(actual.getSshHostAndPort(), expected.getSshHostAndPort());
+ assertEquals(actual.getPrivateAddress(), expected.getPrivateAddress());
+ assertConfigBagEquals(actual.config().getBag(), expected.config().getBag(), errmsg);
+ }
+
+ private void assertOsDetailEquals(OsDetails actual, OsDetails expected) {
+ String errmsg = "actual="+actual+"; expected="+expected;
+ if (actual == null) assertNull(expected, errmsg);
+ assertEquals(actual.isWindows(), expected.isWindows());
+ assertEquals(actual.isLinux(), expected.isLinux());
+ assertEquals(actual.isMac(), expected.isMac());
+ assertEquals(actual.getName(), expected.getName());
+ assertEquals(actual.getArch(), expected.getArch());
+ assertEquals(actual.getVersion(), expected.getVersion());
+ assertEquals(actual.is64bit(), expected.is64bit());
+ }
+
+ private void assertJcloudsLocationEquals(JcloudsLocation actual, JcloudsLocation expected) {
+ String errmsg = "actual="+actual.toVerboseString()+"; expected="+expected.toVerboseString();
+ assertEquals(actual.getId(), expected.getId(), errmsg);
+ assertEquals(actual.getProvider(), expected.getProvider(), errmsg);
+ assertEquals(actual.getRegion(), expected.getRegion(), errmsg);
+ assertEquals(actual.getIdentity(), expected.getIdentity(), errmsg);
+ assertEquals(actual.getCredential(), expected.getCredential(), errmsg);
+ assertEquals(actual.getHostGeoInfo(), expected.getHostGeoInfo(), errmsg);
+ assertConfigBagEquals(actual.config().getBag(), expected.config().getBag(), errmsg);
+ }
+
+ private void assertConfigBagEquals(ConfigBag actual, ConfigBag expected, String errmsg) {
+ // TODO revisit the strong assertion that configBags are equal
+
+// // TODO Can we include all of these things (e.g. when locations are entities, so flagged fields not treated special)?
+// List<String> configToIgnore = ImmutableList.of("id", "template", "usedPorts", "machineCreationSemaphore", "config");
+// MutableMap<Object, Object> actualMap = MutableMap.builder().putAll(actual.getAllConfig())
+// .removeAll(configToIgnore)
+// .build();
+// MutableMap<Object, Object> expectedMap = MutableMap.builder().putAll(expected.getAllConfig())
+// .removeAll(configToIgnore)
+// .build();
+//
+// assertEquals(actualMap, expectedMap, errmsg+"; actualBag="+actualMap+"; expectedBag="+expectedMap);
+ }
+
+ private TestApplication rebind() throws Exception {
+ RebindTestUtils.waitForPersisted(origApp);
+ return (TestApplication) RebindTestUtils.rebind(mementoDir, getClass().getClassLoader());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
new file mode 100644
index 0000000..cc52ef2
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.assertNotEquals;
+import static org.testng.Assert.assertNull;
+
+import org.jclouds.domain.LoginCredentials;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.config.ConfigBag;
+
+import com.google.common.net.HostAndPort;
+
+public class RebindJcloudsLocationTest extends RebindTestFixtureWithApp {
+
+ public static final String LOC_SPEC = "jclouds:aws-ec2:us-east-1";
+
+ private JcloudsLocation origLoc;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ origLoc = (JcloudsLocation) origManagementContext.getLocationRegistry().resolve(LOC_SPEC);
+ }
+
+ // Previously, the rebound config contained "id" which was then passed to createTemporarySshMachineLocation, causing
+ // that to fail (because the LocationSpec should not have had "id" in its config)
+ @Test
+ public void testReboundConfigDoesNotContainId() throws Exception {
+ rebind();
+
+ JcloudsLocation newLoc = (JcloudsLocation) newManagementContext.getLocationManager().getLocation(origLoc.getId());
+
+ ConfigBag newLocConfig = newLoc.config().getBag();
+ ConfigBag config = ConfigBag.newInstanceCopying(newLocConfig);
+
+ assertNull(newLocConfig.getStringKey(("id")));
+
+ SshMachineLocation tempMachine = newLoc.createTemporarySshMachineLocation(
+ HostAndPort.fromParts("localhost", 1234),
+ LoginCredentials.builder().identity("myuser").password("mypass").noPrivateKey().build(),
+ config);
+ assertNotEquals(tempMachine.getId(), newLoc.getId());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/SimpleJcloudsLocationUserLoginAndConfigLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/SimpleJcloudsLocationUserLoginAndConfigLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/SimpleJcloudsLocationUserLoginAndConfigLiveTest.java
new file mode 100644
index 0000000..3e33ce8
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/SimpleJcloudsLocationUserLoginAndConfigLiveTest.java
@@ -0,0 +1,249 @@
+/*
+ * 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.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.location.NoMachinesAvailableException;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+public class SimpleJcloudsLocationUserLoginAndConfigLiveTest extends AbstractJcloudsLiveTest {
+
+ // FIXME And tidy up this one
+
+ private static final String LOCATION_SPEC = AWS_EC2_PROVIDER + ":" + AWS_EC2_USEAST_REGION_NAME;
+
+ private static final Logger log = LoggerFactory.getLogger(SimpleJcloudsLocationUserLoginAndConfigLiveTest.class);
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ jcloudsLocation = resolve(LOCATION_SPEC);
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test(groups="Live")
+ public void testJcloudsCreateBogStandard() throws Exception {
+ log.info("TEST testJcloudsCreateBogStandard");
+ JcloudsSshMachineLocation m1 = obtainMachine(ImmutableMap.of());
+
+ Map details = MutableMap.of("id", m1.getJcloudsId(), "hostname", m1.getAddress().getHostAddress(), "user", m1.getUser());
+ log.info("got machine "+m1+" at "+jcloudsLocation+": "+details+"; now trying to rebind");
+ String result;
+ // echo conflates spaces of arguments
+ result = execWithOutput(m1, Arrays.asList("echo trying m1", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m1"));
+
+ log.info("now trying rebind "+m1);
+ JcloudsSshMachineLocation m2 = jcloudsLocation.rebindMachine(details);
+ result = execWithOutput(m2, Arrays.asList("echo trying m2", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m2"));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test(groups="Live")
+ public void testJcloudsCreateBogStandardWithUserBrooklyn() throws Exception {
+ log.info("TEST testJcloudsCreateBogStandardWithUserBrooklyn");
+ JcloudsSshMachineLocation m1 = obtainMachine(MutableMap.of("user", "brooklyn"));
+
+ Map details = MutableMap.of("id", m1.getJcloudsId(), "hostname", m1.getAddress().getHostAddress(), "user", m1.getUser());
+ log.info("got machine "+m1+" at "+jcloudsLocation+": "+details+"; now trying to rebind");
+ String result;
+ // echo conflates spaces of arguments
+ result = execWithOutput(m1, Arrays.asList("echo trying m1", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m1"));
+
+ log.info("now trying rebind "+m1);
+ JcloudsSshMachineLocation m2 = jcloudsLocation.rebindMachine(details);
+ result = execWithOutput(m2, Arrays.asList("echo trying m2", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m2"));
+
+ Assert.assertEquals(m2.getUser(), "brooklyn");
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test(groups="Live")
+ public void testJcloudsCreateUserMetadata() throws Exception {
+ log.info("TEST testJcloudsCreateBogStandard");
+ String key = "brooklyn-test-user-data";
+ String value = "test-"+Identifiers.makeRandomId(4);
+ JcloudsSshMachineLocation m1 = obtainMachine(MutableMap.of("userMetadata", key+"="+value));
+
+ Map details = MutableMap.of("id", m1.getJcloudsId(), "hostname", m1.getAddress().getHostAddress(), "user", m1.getUser(),
+ "userMetadata", key+"="+value);
+ Assert.assertEquals(m1.node.getUserMetadata().get(key), value);
+
+ log.info("got machine "+m1+" at "+jcloudsLocation+": "+details+"; now trying to rebind");
+ String result;
+ // echo conflates spaces of arguments
+ result = execWithOutput(m1, Arrays.asList("echo trying m1", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m1"));
+
+ log.info("now trying rebind "+m1);
+ JcloudsSshMachineLocation m2 = jcloudsLocation.rebindMachine(details);
+ result = execWithOutput(m2, Arrays.asList("echo trying m2", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m2"));
+ Assert.assertEquals(m2.node.getUserMetadata().get(key), value);
+ }
+
+ // a curious image, centos, but user is ec2-user, and handily not correctly auto-detected
+ // test we can specify a loginUser different from user, and that user is created etc...
+ // imageId=us-east-1/ami-f95cf390
+ public static final String EC2_CENTOS_IMAGE = "us-east-1/ami-f95cf390";
+
+ @Test(groups="Live")
+ public void testJcloudsMissingUser() throws Exception {
+ log.info("TEST testJcloudsMissingUser");
+ try {
+ // wait up to 30s for login (override default of 5m so test runs faster)
+ obtainMachine(MutableMap.of("imageId", EC2_CENTOS_IMAGE, "waitForSshable", 30*1000));
+ log.info("whoops we logged in");
+ } catch (NoMachinesAvailableException e) {
+ log.info("got error as expected, for missing user: "+e); // success
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test(groups="Live")
+ public void testJcloudsWithSpecificLoginUserAndSameUser() throws Exception {
+ log.info("TEST testJcloudsWithSpecificLoginUserAndSameUser");
+ JcloudsSshMachineLocation m1 = obtainMachine(MutableMap.of(
+ "imageId", EC2_CENTOS_IMAGE,
+ "loginUser", "ec2-user",
+ "user", "ec2-user",
+ "waitForSshable", 30*1000));
+
+ Map details = MutableMap.of("id", m1.getJcloudsId(), "hostname", m1.getAddress().getHostAddress(), "user", m1.getUser());
+ log.info("got machine "+m1+" at "+jcloudsLocation+": "+details+"; now trying to rebind");
+ String result;
+ // echo conflates spaces of arguments
+ result = execWithOutput(m1, Arrays.asList("echo trying m1", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m1"));
+
+ log.info("now trying rebind "+m1);
+ JcloudsSshMachineLocation m2 = jcloudsLocation.rebindMachine(details);
+ result = execWithOutput(m2, Arrays.asList("echo trying m2", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m2"));
+
+ Assert.assertEquals(m2.getUser(), "ec2-user");
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test(groups="Live")
+ public void testJcloudsWithSpecificLoginUserAndNewUser() throws Exception {
+ log.info("TEST testJcloudsWithSpecificLoginUserAndNewUser");
+ JcloudsSshMachineLocation m1 = obtainMachine(MutableMap.of(
+ "imageId", EC2_CENTOS_IMAGE,
+ "loginUser", "ec2-user",
+ "user", "newbob",
+ "waitForSshable", 30*1000));
+
+ Map details = MutableMap.of("id", m1.getJcloudsId(), "hostname", m1.getAddress().getHostAddress(), "user", m1.getUser());
+ log.info("got machine "+m1+" at "+jcloudsLocation+": "+details+"; now trying to rebind");
+ String result;
+ // echo conflates spaces of arguments
+ result = execWithOutput(m1, Arrays.asList("echo trying m1", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m1"));
+
+ log.info("now trying rebind "+m1);
+ JcloudsSshMachineLocation m2 = jcloudsLocation.rebindMachine(details);
+ result = execWithOutput(m2, Arrays.asList("echo trying m2", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m2"));
+
+ Assert.assertEquals(m2.getUser(), "newbob");
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test(groups="Live")
+ public void testJcloudsWithSpecificLoginUserAndDefaultUser() throws Exception {
+ log.info("TEST testJcloudsWithSpecificLoginUserAndDefaultUser");
+ JcloudsSshMachineLocation m1 = obtainMachine(MutableMap.of(
+ "imageId", EC2_CENTOS_IMAGE,
+ "loginUser", "ec2-user",
+ "waitForSshable", 30*1000));
+
+ Map details = MutableMap.of("id", m1.getJcloudsId(), "hostname", m1.getAddress().getHostAddress(), "user", m1.getUser());
+ log.info("got machine "+m1+" at "+jcloudsLocation+": "+details+"; now trying to rebind");
+ String result;
+ // echo conflates spaces of arguments
+ result = execWithOutput(m1, Arrays.asList("echo trying m1", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m1"));
+
+ log.info("now trying rebind "+m1);
+ JcloudsSshMachineLocation m2 = jcloudsLocation.rebindMachine(details);
+ result = execWithOutput(m2, Arrays.asList("echo trying m2", "hostname", "date"));
+ Assert.assertTrue(result.contains("trying m2"));
+ }
+
+ @Test(groups="Live")
+ public void testJcloudsCreateWithNoSudoGranted() throws Exception {
+ log.info("TEST testJcloudsCreateWithNoSudoGranted");
+ JcloudsSshMachineLocation m = obtainMachine(MutableMap.of(
+ "grantUserSudo", false,
+ "waitForSshable", 30*1000));
+
+ int exitCode = execWithExitCode(m, ImmutableList.of(BashCommands.sudo("echo yes")));
+ Assert.assertFalse(exitCode == 0, "exit code for sudo command should not have been 0");
+ }
+
+ private String execWithOutput(SshMachineLocation m, List<String> commands) {
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+ exec(m, commands, stdout, stderr);
+ return new String(stdout.toByteArray());
+ }
+
+ private int execWithExitCode(SshMachineLocation m, List<String> commands) {
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+ return exec(m, commands, stdout, stderr);
+ }
+
+ private int exec(SshMachineLocation m, List<String> commands, ByteArrayOutputStream stdout, ByteArrayOutputStream stderr) {
+ Map<String, Object> flags = Maps.newLinkedHashMap();
+ flags.put("out", stdout);
+ flags.put("err", stderr);
+ int exitCode = m.execCommands(flags, "test", commands);
+ log.info("stdout from "+commands+":\n"+new String(stdout.toByteArray()));
+ log.info("stderr from "+commands+":\n"+new String(stderr.toByteArray()));
+ log.info("exit code: " + exitCode);
+ return exitCode;
+ }
+
+ 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/SingleMachineProvisioningLocationJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/SingleMachineProvisioningLocationJcloudsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/SingleMachineProvisioningLocationJcloudsLiveTest.java
new file mode 100644
index 0000000..e9b9dd8
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/SingleMachineProvisioningLocationJcloudsLiveTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.ConfigKeys;
+import org.apache.brooklyn.location.MachineLocation;
+import org.apache.brooklyn.location.basic.SingleMachineProvisioningLocation;
+
+public class SingleMachineProvisioningLocationJcloudsLiveTest extends AbstractJcloudsLiveTest {
+private static final Logger log = LoggerFactory.getLogger(SingleMachineProvisioningLocation.class);
+
+ private SingleMachineProvisioningLocation<JcloudsSshMachineLocation> location;
+
+ private static final String JCLOUDS_LOCATION_SPEC = "jclouds:" + AWS_EC2_PROVIDER + ":" + AWS_EC2_USEAST_REGION_NAME;
+
+ @Test(groups="Live")
+ public void testJcloudsSingle() throws Exception {
+ location = resolve("single:(target='"+JCLOUDS_LOCATION_SPEC+"')");
+
+ MachineLocation m1 = obtainMachine();
+ assertNotNull(m1);
+
+ log.info("GOT "+m1);
+ }
+
+ @Test(groups="Live")
+ public void testJcloudsSingleRelease() throws Exception {
+ location = resolve("single:(target='"+JCLOUDS_LOCATION_SPEC+"')");
+
+ JcloudsSshMachineLocation m1 = obtainMachine();
+ log.info("GOT " + m1);
+ JcloudsSshMachineLocation m2 = obtainMachine();
+ log.info("GOT " + m2);
+ assertSame(m1, m2);
+
+ location.release(m1);
+ assertTrue(m2.isSshable());
+
+ location.release(m2);
+ assertFalse(m2.isSshable());
+ }
+
+ @Test(groups="Live")
+ public void testJcloudsSingleObtainReleaseObtain() throws Exception {
+ location = resolve("single:(target='"+JCLOUDS_LOCATION_SPEC+"')");
+
+ JcloudsSshMachineLocation m1 = obtainMachine();
+ log.info("GOT " + m1);
+
+ location.release(m1);
+ assertFalse(m1.isSshable());
+
+ JcloudsSshMachineLocation m2 = obtainMachine();
+ assertTrue(m2.isSshable());
+ assertNotEquals(m1, m2);
+
+ location.release(m2);
+ assertFalse(m2.isSshable());
+ }
+
+ @Test(groups="Live")
+ public void testJCloudsNamedSingle() throws Exception {
+ brooklynProperties.put(ConfigKeys.newStringConfigKey("brooklyn.location.named.FooServers"), JCLOUDS_LOCATION_SPEC);
+ location = resolve("single:(target='named:FooServers')");
+
+ JcloudsSshMachineLocation m1 = obtainMachine();
+ assertTrue(m1.isSshable());
+
+ location.release(m1);
+ assertFalse(m1.isSshable());
+ }
+
+ @Override
+ protected JcloudsSshMachineLocation obtainMachine(Map<?, ?> conf) throws Exception {
+ JcloudsSshMachineLocation result = location.obtain(conf);
+ machines.add(result);
+ return result;
+ }
+
+ @Override
+ protected void releaseMachine(JcloudsSshMachineLocation machine) {
+ if (location.getChildren().contains(machine)) {
+ machines.remove(machine);
+ location.release(machine);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private SingleMachineProvisioningLocation<JcloudsSshMachineLocation> resolve(String spec) {
+ SingleMachineProvisioningLocation<JcloudsSshMachineLocation> result = (SingleMachineProvisioningLocation<JcloudsSshMachineLocation>)
+ managementContext.getLocationRegistry().resolve(spec);
+ // FIXME Do we really need to setManagementContext?!
+ //result.setManagementContext(managementContext);
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StandaloneJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StandaloneJcloudsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StandaloneJcloudsLiveTest.java
new file mode 100644
index 0000000..b08a087
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StandaloneJcloudsLiveTest.java
@@ -0,0 +1,254 @@
+/*
+ * 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.assertNotNull;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.Set;
+import java.util.UUID;
+
+import org.jclouds.Constants;
+import org.jclouds.ContextBuilder;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.RunNodesException;
+import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.options.RunScriptOptions;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Credentials;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.Statements;
+import org.jclouds.scriptbuilder.statements.login.AdminAccess;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+public class StandaloneJcloudsLiveTest {
+
+ // FIXME Why do this?
+ // Were we seeing bugs in jclouds for which this was easier to debug and report
+ // Is it because testProvisioningVmWithCustomUsername is disabled and not working?
+
+ public static final Logger LOG = LoggerFactory.getLogger(StandaloneJcloudsLiveTest.class);
+
+ private static final String PROVIDER = AbstractJcloudsLiveTest.AWS_EC2_PROVIDER;
+ private static final String REGION = AbstractJcloudsLiveTest.AWS_EC2_USEAST_REGION_NAME;
+ private static final String PRIVATE_IMAGE_ID = "us-east-1/ami-f95cf390";
+
+ static BrooklynProperties globals = BrooklynProperties.Factory.newDefault();
+
+ String identity = globals.getFirst("brooklyn.location.jclouds.aws-ec2.identity");
+ String credential = globals.getFirst("brooklyn.location.jclouds.aws-ec2.credential");
+
+ @Test(enabled=false, groups={"WIP","Live"})
+ public void createVm() {
+ String groupId = "mygroup-"+System.getProperty("user.name")+"-"+UUID.randomUUID().toString();
+
+ Properties properties = new Properties();
+ properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, Boolean.toString(true));
+ properties.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, Boolean.toString(true));
+ // handy to list all images... but very slow!
+// properties.setProperty(AWSEC2Constants.PROPERTY_EC2_AMI_QUERY, "state=available;image-type=machine");
+
+ ComputeServiceContext computeServiceContext = ContextBuilder.newBuilder(PROVIDER).
+ modules(Arrays.asList(new SshjSshClientModule(), new SLF4JLoggingModule())).
+ credentials(identity, credential).
+ overrides(properties).
+ build(ComputeServiceContext.class);
+
+ final ComputeService computeService = computeServiceContext.getComputeService();
+
+ NodeMetadata node = null;
+ try {
+ LOG.info("Creating VM for "+identity);
+
+ TemplateBuilder templateBuilder = computeService.templateBuilder();
+ templateBuilder.locationId(REGION);
+
+ Template template = templateBuilder.build();
+ Set<? extends NodeMetadata> nodes = computeService.createNodesInGroup(groupId, 1, template);
+ node = Iterables.getOnlyElement(nodes, null);
+ if (node == null) throw new IllegalStateException("No nodes returned");
+
+ assertNotNull(node.getOperatingSystem());
+
+ Credentials nodeCredentials = node.getCredentials();
+ final LoginCredentials expectedCredentials = LoginCredentials.fromCredentials(nodeCredentials);
+
+ LOG.info("Started VM, waiting for it to be sshable");
+ boolean reachable = false;
+ for (int i=0; i<120; i++) {
+ try {
+ Statement statement = Statements.newStatementList(Statements.exec("date"));
+ ExecResponse response = computeService.runScriptOnNode(node.getId(), statement,
+ RunScriptOptions.Builder.overrideLoginCredentials(expectedCredentials));
+ if (response.getExitStatus() == 0) {
+ LOG.info("ssh 'date' succeeded");
+ reachable = true;
+ break;
+ }
+ LOG.info("ssh 'date' failed, exit "+response.getExitStatus()+", but still in retry loop");
+ } catch (Exception e) {
+ if (i<120)
+ LOG.info("ssh 'date' failed, but still in retry loop: "+e);
+ else {
+ LOG.error("ssh 'date' failed after timeout: "+e, e);
+ Throwables.propagate(e);
+ }
+ }
+ Thread.sleep(1000);
+ }
+
+ if (!reachable) {
+ throw new IllegalStateException("SSH failed, never reachable");
+ }
+
+ } catch (RunNodesException e) {
+ if (e.getNodeErrors().size() > 0) {
+ node = Iterables.get(e.getNodeErrors().keySet(), 0);
+ }
+ LOG.error("Failed to start VM: "+e, e);
+ throw Throwables.propagate(e);
+ } catch (Exception e) {
+ LOG.error("Failed to start VM: "+e, e);
+ throw Throwables.propagate(e);
+ } finally {
+ LOG.info("Now destroying VM: "+node);
+ computeService.destroyNode( node.getId() );
+
+ computeService.getContext().close();
+ }
+
+ }
+
+ @Test(enabled=false, groups={"WIP","Live"})
+ public void createVmWithAdminUser() {
+ String groupId = "mygroup-"+System.getProperty("user.name")+"-"+UUID.randomUUID().toString();
+
+ Properties properties = new Properties();
+ properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, Boolean.toString(true));
+ properties.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, Boolean.toString(true));
+
+ ComputeServiceContext computeServiceContext = ContextBuilder.newBuilder(PROVIDER).
+ modules(Arrays.asList(new SshjSshClientModule(), new SLF4JLoggingModule())).
+ credentials(identity, credential).
+ overrides(properties).
+ build(ComputeServiceContext.class);
+
+ final ComputeService computeService = computeServiceContext.getComputeService();
+
+ NodeMetadata node = null;
+ try {
+ LOG.info("Creating VM for "+identity);
+ String myPubKey = Files.toString(new File(System.getProperty("user.home")+"/.ssh/aws-id_rsa.pub"), Charset.defaultCharset());
+ String myPrivKey = Files.toString(new File(System.getProperty("user.home")+"/.ssh/aws-id_rsa"), Charset.defaultCharset());
+
+ TemplateBuilder templateBuilder = computeService.templateBuilder();
+ templateBuilder.locationId(REGION);
+ TemplateOptions opts = new TemplateOptions();
+
+// templateBuilder.imageId("us-east-1/ami-2342a94a"); //rightscale
+ // either use above, or below
+ templateBuilder.imageId(PRIVATE_IMAGE_ID); //private one (to test when user isn't autodetected)
+ opts.overrideLoginUser("ec2-user");
+
+ AdminAccess.Builder adminBuilder = AdminAccess.builder().
+ adminUsername("bob").
+ grantSudoToAdminUser(true).
+ authorizeAdminPublicKey(true).adminPublicKey(myPubKey).
+ // items below aren't wanted but values for some are required otherwise AdminAccess uses all defaults
+ lockSsh(true).adminPassword(Identifiers.makeRandomId(12)).
+ resetLoginPassword(false).loginPassword(Identifiers.makeRandomId(12)).
+ installAdminPrivateKey(false).adminPrivateKey("ignored");
+ opts.runScript(adminBuilder.build());
+
+ templateBuilder.options(opts);
+
+ Template template = templateBuilder.build();
+ Set<? extends NodeMetadata> nodes = computeService.createNodesInGroup(groupId, 1, template);
+ node = Iterables.getOnlyElement(nodes, null);
+ if (node == null) throw new IllegalStateException("No nodes returned");
+
+ LOG.info("Started VM, waiting for it to be sshable on "+node.getPublicAddresses());
+ final LoginCredentials crds =
+// node.getCredentials();
+ LoginCredentials.builder().user("bob").privateKey(myPrivKey).build();
+ boolean reachable = false;
+ for (int i=0; i<120; i++) {
+ try {
+ Statement statement = Statements.newStatementList(Statements.exec("date"));
+ ExecResponse response = computeService.runScriptOnNode(node.getId(), statement,
+ RunScriptOptions.Builder.overrideLoginCredentials(crds));
+ if (response.getExitStatus() == 0) {
+ LOG.info("ssh 'date' succeeded");
+ reachable = true;
+ break;
+ }
+ LOG.info("ssh 'date' failed, exit "+response.getExitStatus()+", but still in retry loop");
+ } catch (Exception e) {
+ if (i<120)
+ LOG.info("ssh 'date' failed, but still in retry loop: "+e);
+ else {
+ LOG.error("ssh 'date' failed after timeout: "+e, e);
+ Throwables.propagate(e);
+ }
+ }
+ Thread.sleep(1000);
+ }
+
+ if (!reachable) {
+ throw new IllegalStateException("SSH failed, never reachable");
+ }
+
+ } catch (RunNodesException e) {
+ if (e.getNodeErrors().size() > 0) {
+ node = Iterables.get(e.getNodeErrors().keySet(), 0);
+ }
+ LOG.error("Failed to start VM: "+e, e);
+ throw Throwables.propagate(e);
+ } catch (Exception e) {
+ LOG.error("Failed to start VM: "+e, e);
+ throw Throwables.propagate(e);
+ } finally {
+ LOG.info("Now destroying VM: "+node);
+ computeService.destroyNode( node.getId() );
+
+ computeService.getContext().close();
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizerTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizerTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizerTest.java
new file mode 100644
index 0000000..c6025ba
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizerTest.java
@@ -0,0 +1,311 @@
+/*
+ * 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.networking;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.Collections;
+
+import org.jclouds.aws.AWSResponseException;
+import org.jclouds.aws.domain.AWSError;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.SecurityGroup;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.extensions.SecurityGroupExtension;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Location;
+import org.jclouds.net.domain.IpPermission;
+import org.jclouds.net.domain.IpProtocol;
+import org.mockito.Answers;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Cidr;
+
+public class JcloudsLocationSecurityGroupCustomizerTest {
+
+ JcloudsLocationSecurityGroupCustomizer customizer;
+ ComputeService computeService;
+ Location location;
+ SecurityGroupExtension securityApi;
+
+ /** Used to skip external checks in unit tests. */
+ private static class TestCidrSupplier implements Supplier<Cidr> {
+ @Override public Cidr get() {
+ return new Cidr("192.168.10.10/32");
+ }
+ }
+
+ @BeforeMethod
+ public void setUp() {
+ customizer = new JcloudsLocationSecurityGroupCustomizer("testapp", new TestCidrSupplier());
+ location = mock(Location.class);
+ securityApi = mock(SecurityGroupExtension.class);
+ computeService = mock(ComputeService.class, Answers.RETURNS_DEEP_STUBS.get());
+ when(computeService.getSecurityGroupExtension()).thenReturn(Optional.of(securityApi));
+ }
+
+ @Test
+ public void testSameInstanceReturnedForSameApplication() {
+ assertEquals(JcloudsLocationSecurityGroupCustomizer.getInstance("a"),
+ JcloudsLocationSecurityGroupCustomizer.getInstance("a"));
+ assertNotEquals(JcloudsLocationSecurityGroupCustomizer.getInstance("a"),
+ JcloudsLocationSecurityGroupCustomizer.getInstance("b"));
+ }
+
+ @Test
+ public void testSecurityGroupAddedWhenJcloudsLocationCustomised() {
+ Template template = mock(Template.class);
+ TemplateOptions templateOptions = mock(TemplateOptions.class);
+ when(template.getLocation()).thenReturn(location);
+ when(template.getOptions()).thenReturn(templateOptions);
+ SecurityGroup group = newGroup("id");
+ when(securityApi.createSecurityGroup(anyString(), eq(location))).thenReturn(group);
+
+ // Two Brooklyn.JcloudsLocations added to same Jclouds.Location
+ JcloudsLocation jcloudsLocationA = new JcloudsLocation(MutableMap.of("deferConstruction", true));
+ JcloudsLocation jcloudsLocationB = new JcloudsLocation(MutableMap.of("deferConstruction", true));
+ customizer.customize(jcloudsLocationA, computeService, template);
+ customizer.customize(jcloudsLocationB, computeService, template);
+
+ // One group with three permissions shared by both locations.
+ // Expect TCP, UDP and ICMP between members of group and SSH to Brooklyn
+ verify(securityApi).createSecurityGroup(anyString(), eq(location));
+ verify(securityApi, times(4)).addIpPermission(any(IpPermission.class), eq(group));
+ // New groups set on options
+ verify(templateOptions, times(2)).securityGroups(anyString());
+ }
+
+ @Test
+ public void testSharedGroupLoadedWhenItExistsButIsNotCached() {
+ Template template = mock(Template.class);
+ TemplateOptions templateOptions = mock(TemplateOptions.class);
+ when(template.getLocation()).thenReturn(location);
+ when(template.getOptions()).thenReturn(templateOptions);
+ JcloudsLocation jcloudsLocation = new JcloudsLocation(MutableMap.of("deferConstruction", true));
+ SecurityGroup shared = newGroup(customizer.getNameForSharedSecurityGroup());
+ SecurityGroup irrelevant = newGroup("irrelevant");
+ when(securityApi.listSecurityGroupsInLocation(location)).thenReturn(ImmutableSet.of(irrelevant, shared));
+
+ customizer.customize(jcloudsLocation, computeService, template);
+
+ verify(securityApi).listSecurityGroupsInLocation(location);
+ verify(securityApi, never()).createSecurityGroup(anyString(), any(Location.class));
+ }
+
+ @Test
+ public void testAddPermissionsToNode() {
+ IpPermission ssh = newPermission(22);
+ IpPermission jmx = newPermission(31001);
+ String nodeId = "node";
+ SecurityGroup sharedGroup = newGroup(customizer.getNameForSharedSecurityGroup());
+ SecurityGroup group = newGroup("id");
+ when(securityApi.listSecurityGroupsForNode(nodeId)).thenReturn(ImmutableSet.of(sharedGroup, group));
+ when(computeService.getContext().unwrap().getId()).thenReturn("aws-ec2");
+
+ customizer.addPermissionsToLocation(ImmutableList.of(ssh, jmx), nodeId, computeService);
+
+ verify(securityApi, never()).createSecurityGroup(anyString(), any(Location.class));
+ verify(securityApi, times(1)).addIpPermission(ssh, group);
+ verify(securityApi, times(1)).addIpPermission(jmx, group);
+ }
+
+ @Test
+ public void testAddPermissionsToNodeUsesUncachedSecurityGroup() {
+ JcloudsLocation jcloudsLocation = new JcloudsLocation(MutableMap.of("deferConstruction", true));
+ IpPermission ssh = newPermission(22);
+ String nodeId = "nodeId";
+ SecurityGroup sharedGroup = newGroup(customizer.getNameForSharedSecurityGroup());
+ SecurityGroup uniqueGroup = newGroup("unique");
+
+ Template template = mock(Template.class);
+ TemplateOptions templateOptions = mock(TemplateOptions.class);
+ when(template.getLocation()).thenReturn(location);
+ when(template.getOptions()).thenReturn(templateOptions);
+ when(securityApi.createSecurityGroup(anyString(), eq(location))).thenReturn(sharedGroup);
+ when(computeService.getContext().unwrap().getId()).thenReturn("aws-ec2");
+
+ // Call customize to cache the shared group
+ customizer.customize(jcloudsLocation, computeService, template);
+ reset(securityApi);
+ when(securityApi.listSecurityGroupsForNode(nodeId)).thenReturn(ImmutableSet.of(uniqueGroup, sharedGroup));
+ customizer.addPermissionsToLocation(ImmutableSet.of(ssh), nodeId, computeService);
+
+ // Expect the per-machine group to have been altered, not the shared group
+ verify(securityApi).addIpPermission(ssh, uniqueGroup);
+ verify(securityApi, never()).addIpPermission(any(IpPermission.class), eq(sharedGroup));
+ }
+
+ @Test
+ public void testSecurityGroupsLoadedWhenAddingPermissionsToUncachedNode() {
+ IpPermission ssh = newPermission(22);
+ String nodeId = "nodeId";
+ SecurityGroup sharedGroup = newGroup(customizer.getNameForSharedSecurityGroup());
+ SecurityGroup uniqueGroup = newGroup("unique");
+
+ when(securityApi.listSecurityGroupsForNode(nodeId)).thenReturn(ImmutableSet.of(sharedGroup, uniqueGroup));
+ when(computeService.getContext().unwrap().getId()).thenReturn("aws-ec2");
+
+ // Expect first call to list security groups on nodeId, second to use cached version
+ customizer.addPermissionsToLocation(ImmutableSet.of(ssh), nodeId, computeService);
+ customizer.addPermissionsToLocation(ImmutableSet.of(ssh), nodeId, computeService);
+
+ verify(securityApi, times(1)).listSecurityGroupsForNode(nodeId);
+ verify(securityApi, times(2)).addIpPermission(ssh, uniqueGroup);
+ verify(securityApi, never()).addIpPermission(any(IpPermission.class), eq(sharedGroup));
+ }
+
+ @Test
+ public void testAddRuleNotRetriedByDefault() {
+ IpPermission ssh = newPermission(22);
+ String nodeId = "node";
+ SecurityGroup sharedGroup = newGroup(customizer.getNameForSharedSecurityGroup());
+ SecurityGroup uniqueGroup = newGroup("unique");
+ when(securityApi.listSecurityGroupsForNode(nodeId)).thenReturn(ImmutableSet.of(sharedGroup, uniqueGroup));
+ when(securityApi.addIpPermission(eq(ssh), eq(uniqueGroup)))
+ .thenThrow(new RuntimeException("exception creating " + ssh));
+ when(computeService.getContext().unwrap().getId()).thenReturn("aws-ec2");
+
+ try {
+ customizer.addPermissionsToLocation(ImmutableList.of(ssh), nodeId, computeService);
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("repeated errors from provider"), "message=" + e.getMessage());
+ }
+ verify(securityApi, never()).createSecurityGroup(anyString(), any(Location.class));
+ verify(securityApi, times(1)).addIpPermission(ssh, uniqueGroup);
+ }
+
+ @Test
+ public void testCustomExceptionRetryablePredicate() {
+ final String message = "testCustomExceptionRetryablePredicate";
+ Predicate<Exception> messageChecker = new Predicate<Exception>() {
+ @Override
+ public boolean apply(Exception input) {
+ Throwable t = input;
+ while (t != null) {
+ if (t.getMessage().contains(message)) {
+ return true;
+ } else {
+ t = t.getCause();
+ }
+ }
+ return false;
+ }
+ };
+ customizer.setRetryExceptionPredicate(messageChecker);
+ when(computeService.getContext().unwrap().getId()).thenReturn("aws-ec2");
+
+ IpPermission ssh = newPermission(22);
+ String nodeId = "node";
+ SecurityGroup sharedGroup = newGroup(customizer.getNameForSharedSecurityGroup());
+ SecurityGroup uniqueGroup = newGroup("unique");
+ when(securityApi.listSecurityGroupsForNode(nodeId)).thenReturn(ImmutableSet.of(sharedGroup, uniqueGroup));
+ when(securityApi.addIpPermission(eq(ssh), eq(uniqueGroup)))
+ .thenThrow(new RuntimeException(new Exception(message)))
+ .thenThrow(new RuntimeException(new Exception(message)))
+ .thenReturn(sharedGroup);
+
+ customizer.addPermissionsToLocation(ImmutableList.of(ssh), nodeId, computeService);
+
+ verify(securityApi, never()).createSecurityGroup(anyString(), any(Location.class));
+ verify(securityApi, times(3)).addIpPermission(ssh, uniqueGroup);
+ }
+
+ @Test
+ public void testAddRuleRetriedOnAwsFailure() {
+ IpPermission ssh = newPermission(22);
+ String nodeId = "nodeId";
+ SecurityGroup sharedGroup = newGroup(customizer.getNameForSharedSecurityGroup());
+ SecurityGroup uniqueGroup = newGroup("unique");
+ customizer.setRetryExceptionPredicate(JcloudsLocationSecurityGroupCustomizer.newAwsExceptionRetryPredicate());
+ when(securityApi.listSecurityGroupsForNode(nodeId)).thenReturn(ImmutableSet.of(sharedGroup, uniqueGroup));
+ when(securityApi.addIpPermission(any(IpPermission.class), eq(uniqueGroup)))
+ .thenThrow(newAwsResponseExceptionWithCode("InvalidGroup.InUse"))
+ .thenThrow(newAwsResponseExceptionWithCode("DependencyViolation"))
+ .thenThrow(newAwsResponseExceptionWithCode("RequestLimitExceeded"))
+ .thenThrow(newAwsResponseExceptionWithCode("Blocked"))
+ .thenReturn(sharedGroup);
+ when(computeService.getContext().unwrap().getId()).thenReturn("aws-ec2");
+
+ try {
+ customizer.addPermissionsToLocation(ImmutableList.of(ssh), nodeId, computeService);
+ } catch (Exception e) {
+ String expected = "repeated errors from provider";
+ assertTrue(e.getMessage().contains(expected), "expected exception message to contain " + expected + ", was: " + e.getMessage());
+ }
+
+ verify(securityApi, never()).createSecurityGroup(anyString(), any(Location.class));
+ verify(securityApi, times(4)).addIpPermission(ssh, uniqueGroup);
+ }
+
+ private SecurityGroup newGroup(String id) {
+ URI uri = null;
+ String ownerId = null;
+ return new SecurityGroup(
+ "providerId",
+ id,
+ id,
+ location,
+ uri,
+ Collections.<String, String>emptyMap(),
+ ImmutableSet.<String>of(),
+ ImmutableSet.<IpPermission>of(),
+ ownerId);
+ }
+
+ private IpPermission newPermission(int port) {
+ return IpPermission.builder()
+ .ipProtocol(IpProtocol.TCP)
+ .fromPort(port)
+ .toPort(port)
+ .cidrBlock("0.0.0.0/0")
+ .build();
+ }
+
+ private AWSError newAwsErrorWithCode(String code) {
+ AWSError e = new AWSError();
+ e.setCode(code);
+ return e;
+ }
+
+ private Exception newAwsResponseExceptionWithCode(String code) {
+ AWSResponseException e = new AWSResponseException("irrelevant message", null, null, newAwsErrorWithCode(code));
+ return new RuntimeException(e);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java
new file mode 100644
index 0000000..860a8e3
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.networking;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.util.List;
+
+import org.apache.brooklyn.location.jclouds.AbstractJcloudsStubbedLiveTest;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+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.config.ConfigKey;
+import org.apache.brooklyn.location.access.PortForwardManager;
+import org.apache.brooklyn.location.access.PortForwardManagerImpl;
+import org.apache.brooklyn.location.jclouds.JcloudsSshMachineLocation;
+import brooklyn.util.net.Cidr;
+import brooklyn.util.net.Protocol;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.net.HostAndPort;
+
+/**
+ * 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 class JcloudsPortForwardingStubbedLiveTest extends AbstractJcloudsStubbedLiveTest {
+
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(JcloudsPortForwardingStubbedLiveTest.class);
+
+ static class RecordingJcloudsPortForwarderExtension implements JcloudsPortForwarderExtension {
+ final PortForwardManager pfm;
+ final List<List<Object>> opens = Lists.newCopyOnWriteArrayList();
+ final List<List<Object>> closes = Lists.newCopyOnWriteArrayList();
+ int nextPublicPort = 12345;
+
+ RecordingJcloudsPortForwarderExtension(PortForwardManager pfm) {
+ this.pfm = pfm;
+ }
+ @Override public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) {
+ opens.add(ImmutableList.of(node, targetPort, optionalPublicPort, protocol, accessingCidr));
+ HostAndPort result = HostAndPort.fromParts("1.2.3.4", nextPublicPort++);
+ pfm.associate(node.getId(), result, targetPort);
+ return result;
+ }
+ @Override public void closePortForwarding(NodeMetadata node, int targetPort, HostAndPort publicHostAndPort, Protocol protocol) {
+ closes.add(ImmutableList.of(node, targetPort, publicHostAndPort, protocol));
+ pfm.forgetPortMapping(node.getId(), publicHostAndPort.getPort());
+ }
+ }
+
+ @Override
+ protected NodeCreator newNodeCreator() {
+ return new NodeCreator() {
+ int nextIpSuffix = 2;
+ @Override
+ protected NodeMetadata newNode(String group, Template template) {
+ int ipSuffix = nextIpSuffix++;
+ NodeMetadata result = new NodeMetadataBuilder()
+ .id("myid-"+ipSuffix)
+ .credentials(LoginCredentials.builder().identity("myuser").credential("mypassword").build())
+ .loginPort(22)
+ .status(Status.RUNNING)
+ .publicAddresses(ImmutableList.of("173.194.32."+ipSuffix))
+ .privateAddresses(ImmutableList.of("172.168.10."+ipSuffix))
+ .build();
+ return result;
+ }
+ };
+ }
+
+ @Test(groups = {"Live", "Live-sanity"})
+ protected void testPortForwardingCallsForwarder() throws Exception {
+ PortForwardManager pfm = new PortForwardManagerImpl();
+ RecordingJcloudsPortForwarderExtension portForwarder = new RecordingJcloudsPortForwarderExtension(pfm);
+
+ JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.<ConfigKey<?>,Object>of(
+ JcloudsLocation.USE_PORT_FORWARDING, true,
+ JcloudsLocation.PORT_FORWARDER, portForwarder));
+
+ NodeMetadata created = nodeCreator.created.get(0);
+ assertEquals(nodeCreator.created.size(), 1, "created="+nodeCreator.created+"; machine="+machine);
+ assertEquals(machine.getNode(), created);
+ assertEquals(portForwarder.opens.size(), 1, "opens="+portForwarder.opens+"; machine="+machine);
+ assertEquals(portForwarder.opens.get(0).get(0), created);
+ assertEquals(portForwarder.opens.get(0).get(1), 22);
+ assertEquals(portForwarder.opens.get(0).get(3), Protocol.TCP);
+ assertEquals(portForwarder.opens.get(0).get(4), Cidr.UNIVERSAL);
+ assertEquals(machine.getSshHostAndPort(), HostAndPort.fromParts("1.2.3.4", 12345));
+
+ releaseMachine(machine);
+ String destroyed = nodeCreator.destroyed.get(0);
+ assertEquals(nodeCreator.destroyed.size(), 1, "destroyed="+nodeCreator.destroyed+"; machine="+machine);
+ assertEquals(destroyed, created.getId());
+ assertEquals(portForwarder.closes.size(), 1, "closes="+portForwarder.closes+"; machine="+machine);
+ assertEquals(portForwarder.closes.get(0).get(0), created);
+ assertEquals(portForwarder.closes.get(0).get(1), 22);
+ assertEquals(portForwarder.closes.get(0).get(2), HostAndPort.fromParts("1.2.3.4", 12345));
+ assertEquals(portForwarder.closes.get(0).get(3), Protocol.TCP);
+ }
+
+ @Test(groups = {"Live", "Live-sanity"})
+ protected void testDeregistersWithPortForwardManagerOnRelease() throws Exception {
+ PortForwardManager pfm = new PortForwardManagerImpl();
+ RecordingJcloudsPortForwarderExtension portForwarder = new RecordingJcloudsPortForwarderExtension(pfm);
+
+ JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.<ConfigKey<?>,Object>of(
+ JcloudsLocation.PORT_FORWARDER, portForwarder,
+ JcloudsLocation.PORT_FORWARDING_MANAGER, pfm));
+
+ // Add an association for this machine - expect that to be deleted when the machine is released.
+ HostAndPort publicHostAndPort = HostAndPort.fromParts("1.2.3.4", 1234);
+ pfm.associate("mypublicip", publicHostAndPort, machine, 80);
+ assertEquals(pfm.lookup(machine, 80), publicHostAndPort);
+ assertEquals(pfm.lookup("mypublicip", 80), publicHostAndPort);
+
+ // Release
+ releaseMachine(machine);
+
+ // Expect to have been cleared from PortForwardManager's records
+ assertNull(pfm.lookup(machine, 80));
+ assertNull(pfm.lookup("mypublicip", 80));
+
+ // And for port-forwarding to have been closed
+ assertEquals(portForwarder.closes.size(), 1, "closes="+portForwarder.closes+"; machine="+machine);
+ assertEquals(portForwarder.closes.get(0).get(1), 80);
+ assertEquals(portForwarder.closes.get(0).get(2), HostAndPort.fromParts("1.2.3.4", 1234));
+ assertEquals(portForwarder.closes.get(0).get(3), Protocol.TCP);
+ }
+
+ @Test(groups = {"Live", "Live-sanity"})
+ protected void testReleaseVmDoesNotImpactOtherVms() throws Exception {
+ PortForwardManager pfm = new PortForwardManagerImpl();
+ RecordingJcloudsPortForwarderExtension portForwarder = new RecordingJcloudsPortForwarderExtension(pfm);
+
+ JcloudsSshMachineLocation machine1 = obtainMachine(ImmutableMap.<ConfigKey<?>,Object>of(
+ JcloudsLocation.USE_PORT_FORWARDING, true,
+ JcloudsLocation.PORT_FORWARDER, portForwarder,
+ JcloudsLocation.PORT_FORWARDING_MANAGER, pfm));
+
+ JcloudsSshMachineLocation machine2 = obtainMachine(ImmutableMap.<ConfigKey<?>,Object>of(
+ JcloudsLocation.USE_PORT_FORWARDING, true,
+ JcloudsLocation.PORT_FORWARDER, portForwarder,
+ JcloudsLocation.PORT_FORWARDING_MANAGER, pfm));
+
+ NodeMetadata node1 = nodeCreator.created.get(0);
+
+ // Add an association for machine2 - expect that not to be touched when machine1 is released.
+ HostAndPort publicHostAndPort = HostAndPort.fromParts("1.2.3.4", 1234);
+ pfm.associate("mypublicip", publicHostAndPort, machine2, 80);
+
+ // Release machine1
+ releaseMachine(machine1);
+
+ // Expect machine2 to still be registered
+ assertEquals(pfm.lookup(machine2, 80), publicHostAndPort);
+ assertEquals(pfm.lookup("mypublicip", 80), publicHostAndPort);
+
+ // And no calls to "close" for machine2; just for machine1's port 22
+ assertEquals(portForwarder.closes.size(), 1, "closes="+portForwarder.closes+"; machine1="+machine1);
+ assertEquals(portForwarder.closes.get(0).get(0), node1);
+ assertEquals(portForwarder.closes.get(0).get(1), 22);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SecurityGroupLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SecurityGroupLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SecurityGroupLiveTest.java
new file mode 100644
index 0000000..0eed616
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SecurityGroupLiveTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.networking;
+
+import org.testng.annotations.Test;
+
+@Test(groups = {"Live", "WIP"})
+public class SecurityGroupLiveTest {
+
+ public void testCreateEc2WithSecurityGroup() {
+ SecurityGroupDefinition sgDef = new SecurityGroupDefinition()
+ .allowingInternalPorts(8097, 8098).allowingInternalPortRange(6000, 7999)
+ .allowingPublicPort(8099);
+ // TODO create machine and test
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/pool/JcloudsMachinePoolLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/pool/JcloudsMachinePoolLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/pool/JcloudsMachinePoolLiveTest.java
new file mode 100644
index 0000000..4d30c80
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/pool/JcloudsMachinePoolLiveTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.pool;
+
+import java.util.Arrays;
+
+import org.apache.brooklyn.location.jclouds.AbstractJcloudsLiveTest;
+import org.jclouds.ContextBuilder;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.sshj.config.SshjSshClientModule;
+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.jclouds.JcloudsLocation;
+
+public class JcloudsMachinePoolLiveTest extends AbstractJcloudsLiveTest {
+
+ public static final Logger log = LoggerFactory.getLogger(JcloudsMachinePoolLiveTest.class);
+
+ private static final String PROVIDER = AWS_EC2_PROVIDER;
+ private static final String LOCATION_SPEC = PROVIDER + ":" + AWS_EC2_EUWEST_REGION_NAME;
+
+ public static class SamplePool extends MachinePool {
+ public SamplePool(ComputeService svc) {
+ super(svc);
+ }
+
+ 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 ComputeServiceContext context;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(LOCATION_SPEC);
+
+ context = ContextBuilder.newBuilder(PROVIDER)
+ .modules(Arrays.asList(new SshjSshClientModule(), new SLF4JLoggingModule()))
+ .credentials(jcloudsLocation.getIdentity(), jcloudsLocation.getCredential())
+ .build(ComputeServiceContext.class);
+ }
+
+ @AfterMethod(alwaysRun=true)
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ super.tearDown();
+ } finally {
+ if (context != null) context.close();
+ }
+ }
+
+ @Test(groups={"Live","WIP"})
+ public void buildClaimAndDestroy() {
+ ComputeService svc = context.getComputeService();
+ SamplePool p = new SamplePool(svc);
+ log.info("buildClaimAndDestroy: created pool");
+ p.refresh();
+ log.info("buildClaimAndDestroy: refreshed pool");
+ p.ensureExists(2, SamplePool.USUAL_VM);
+ log.info("buildClaimAndDestroy: ensure have 2");
+ MachineSet l = p.claim(1, SamplePool.USUAL_VM);
+ Assert.assertEquals(l.size(), 1);
+ log.info("buildClaimAndDestroy: claimed 1");
+ MachineSet unclaimedUsual = p.unclaimed(MachinePoolPredicates.matching(SamplePool.USUAL_VM));
+ log.info("buildClaimAndDestroy: unclaimed now "+unclaimedUsual);
+ Assert.assertTrue(!unclaimedUsual.isEmpty());
+ p.destroy(unclaimedUsual);
+ unclaimedUsual = p.unclaimed(MachinePoolPredicates.matching(SamplePool.USUAL_VM));
+ log.info("buildClaimAndDestroy: destroyed, unclaimed now "+unclaimedUsual);
+ log.info("end");
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
new file mode 100644
index 0000000..fd93a7a
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.provider;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.location.NoMachinesAvailableException;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+public abstract class AbstractJcloudsLocationTest {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractJcloudsLocationTest.class);
+
+ private final String provider;
+
+ protected JcloudsLocation loc;
+ protected List<SshMachineLocation> machines = MutableList.of();
+ protected ManagementContext ctx;
+
+ protected AbstractJcloudsLocationTest(String provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * The location and image id tuplets to test.
+ */
+ @DataProvider(name = "fromImageId")
+ public abstract Object[][] cloudAndImageIds();
+
+ /**
+ * A single location and image id tuplet to test.
+ */
+ @DataProvider(name = "fromFirstImageId")
+ public Object[][] cloudAndImageFirstId() {
+ Object[][] all = cloudAndImageIds();
+ return (all != null) ? new Object[][] { all[0] } : new Object[][] { };
+ }
+
+ /**
+ * The location and image name pattern tuplets to test.
+ */
+ @DataProvider(name = "fromImageNamePattern")
+ public abstract Object[][] cloudAndImageNamePatterns();
+
+ /**
+ * The location, image pattern and image owner tuplets to test.
+ */
+ @DataProvider(name = "fromImageDescriptionPattern")
+ public abstract Object[][] cloudAndImageDescriptionPatterns();
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() {
+ BrooklynProperties props = BrooklynProperties.Factory.newDefault().addFromMap(ImmutableMap.of("provider", provider));
+ ctx = Entities.newManagementContext(props.asMapWithStringKeys());
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() {
+ List<Exception> exceptions = Lists.newArrayList();
+ for (SshMachineLocation machine : machines) {
+ try {
+ loc.release(machine);
+ } catch (Exception e) {
+ LOG.warn("Error releasing {}: {}; continuing...", machine, e.getMessage());
+ exceptions.add(e);
+ }
+ }
+ if (!exceptions.isEmpty()) {
+ LOG.info("Exception during tearDown: {}", Exceptions.collapseText(exceptions.get(0)));
+ }
+ machines.clear();
+
+ if (ctx != null) Entities.destroyAllCatching(ctx);
+ }
+
+ @Test(dataProvider="fromImageId")
+ public void testTagMapping(String regionName, String imageId, String imageOwner) {
+ Map<String, Object> dummy = ImmutableMap.<String, Object>of("identity", "DUMMY", "credential", "DUMMY");
+ loc = (JcloudsLocation) ctx.getLocationRegistry().resolve(provider + (regionName == null ? "" : ":" + regionName), dummy);
+ ImmutableMap.Builder<String, Object> builder = ImmutableMap.<String, Object>builder().put("imageId", imageId);
+ if (imageOwner != null) builder.put("imageOwner", imageOwner);
+ Map<String, Object> tagMapping = builder.build();
+ loc.setTagMapping(ImmutableMap.<String, Map<String, ? extends Object>>of("MyEntityType", tagMapping));
+
+ Map<String, Object> flags = loc.getProvisioningFlags(ImmutableList.of("MyEntityType"));
+ assertTrue(Maps.<String, Object>difference(flags, tagMapping).entriesOnlyOnRight().isEmpty(), "flags="+flags);
+ }
+
+ @Test(groups = "Live", dataProvider="fromImageId")
+ public void testProvisionVmUsingImageId(String regionName, String imageId, String imageOwner) {
+ loc = (JcloudsLocation) ctx.getLocationRegistry().resolve(provider + (regionName == null ? "" : ":" + regionName));
+ SshMachineLocation machine = obtainMachine(MutableMap.of("imageId", imageId, "imageOwner", imageOwner, JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 2));
+
+ LOG.info("Provisioned {} vm {}; checking if ssh'able", provider, machine);
+ assertTrue(machine.isSshable());
+ }
+
+ @Test(groups = "Live", dataProvider="fromImageNamePattern")
+ public void testProvisionVmUsingImageNamePattern(String regionName, String imageNamePattern, String imageOwner) {
+ loc = (JcloudsLocation) ctx.getLocationRegistry().resolve(provider + (regionName == null ? "" : ":" + regionName));
+ SshMachineLocation machine = obtainMachine(MutableMap.of("imageNameRegex", imageNamePattern, "imageOwner", imageOwner, JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 2));
+
+ LOG.info("Provisioned {} vm {}; checking if ssh'able", provider, machine);
+ assertTrue(machine.isSshable());
+ }
+
+ @Test(groups = "Live", dataProvider="fromImageDescriptionPattern")
+ public void testProvisionVmUsingImageDescriptionPattern(String regionName, String imageDescriptionPattern, String imageOwner) {
+ loc = (JcloudsLocation) ctx.getLocationRegistry().resolve(provider + (regionName == null ? "" : ":" + regionName));
+ SshMachineLocation machine = obtainMachine(MutableMap.of("imageDescriptionRegex", imageDescriptionPattern, "imageOwner", imageOwner, JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 2));
+
+ LOG.info("Provisioned {} vm {}; checking if ssh'able", provider, machine);
+ assertTrue(machine.isSshable());
+ }
+
+ // Use this utility method to ensure machines are released on tearDown
+ protected SshMachineLocation obtainMachine(Map flags) {
+ try {
+ SshMachineLocation result = (SshMachineLocation)loc.obtain(flags);
+ machines.add(result);
+ return result;
+ } catch (NoMachinesAvailableException nmae) {
+ LOG.warn("No machines available", nmae);
+ throw Exceptions.propagate(nmae);
+ }
+ }
+
+ protected SshMachineLocation release(SshMachineLocation machine) {
+ machines.remove(machine);
+ loc.release(machine);
+ return machine;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationLiveTest.java
new file mode 100644
index 0000000..6644645
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationLiveTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.provider;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class AwsEc2LocationLiveTest extends AbstractJcloudsLocationTest {
+
+ private static final String PROVIDER = "aws-ec2";
+ private static final String EUWEST_REGION_NAME = "eu-west-1";
+ private static final String USEAST_REGION_NAME = "us-east-1";
+ private static final String EUWEST_IMAGE_ID = EUWEST_REGION_NAME+"/"+"ami-89def4fd"; // RightImage_CentOS_5.4_i386_v5.5.9_EBS
+ private static final String USEAST_IMAGE_ID = USEAST_REGION_NAME+"/"+"ami-2342a94a"; // RightImage_CentOS_5.4_i386_v5.5.9_EBS
+ private static final String IMAGE_OWNER = "411009282317";
+ private static final String IMAGE_PATTERN = "RightImage_CentOS_5.4_i386_v5.5.9_EBS";
+
+ public AwsEc2LocationLiveTest() {
+ super(PROVIDER);
+ }
+
+ @Override
+ @DataProvider(name = "fromImageId")
+ public Object[][] cloudAndImageIds() {
+ return new Object[][] {
+ new Object[] { EUWEST_REGION_NAME, EUWEST_IMAGE_ID, IMAGE_OWNER },
+ new Object[] { USEAST_REGION_NAME, USEAST_IMAGE_ID, IMAGE_OWNER }
+ };
+ }
+
+ @Override
+ @DataProvider(name = "fromImageDescriptionPattern")
+ public Object[][] cloudAndImageDescriptionPatterns() {
+ return new Object[][] {
+ new Object[] { EUWEST_REGION_NAME, IMAGE_PATTERN, IMAGE_OWNER },
+ new Object[] { USEAST_REGION_NAME, IMAGE_PATTERN, IMAGE_OWNER }
+ };
+ }
+
+ @Override
+ @DataProvider(name = "fromImageNamePattern")
+ public Object[][] cloudAndImageNamePatterns() {
+ return new Object[][] {
+ new Object[] { USEAST_REGION_NAME, IMAGE_PATTERN, IMAGE_OWNER }
+ };
+ }
+
+ @Test(enabled = false)
+ public void noop() { } /* just exists to let testNG IDE run the test */
+}