You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/11/17 19:28:45 UTC

[1/7] incubator-brooklyn git commit: Improve SshMachineLocation.toString

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 462e5eadb -> 7c649d73d


Improve SshMachineLocation.toString


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

Branch: refs/heads/master
Commit: af39886a454fbadbfb9d033103a502a0b93530fb
Parents: a8f8c57
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 5 22:21:07 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Nov 5 22:32:59 2015 +0000

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/location/ssh/SshMachineLocation.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/af39886a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
index 27f87f9..f6c823a 100644
--- a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
@@ -866,7 +866,7 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
 
     @Override
     public String toString() {
-        return "SshMachineLocation["+getDisplayName()+":"+address+":"+getPort()+"@"+getId()+"]";
+        return "SshMachineLocation["+getDisplayName()+":"+user+"@"+address+":"+getPort()+"(id="+getId()+")]";
     }
 
     @Override


[5/7] incubator-brooklyn git commit: JcloudsLoginLiveTest: run all tests in AWS

Posted by al...@apache.org.
JcloudsLoginLiveTest: run all tests in AWS

The Rackspace config wasn't working (probably because image ids
have changed).


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

Branch: refs/heads/master
Commit: bf67238bf49536e627a38fb62c749ec749e392c2
Parents: d192ad0
Author: Aled Sage <al...@gmail.com>
Authored: Wed Oct 21 17:53:28 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 17 17:49:27 2015 +0000

----------------------------------------------------------------------
 .../jclouds/AbstractJcloudsLiveTest.java        |  3 +
 .../location/jclouds/JcloudsLoginLiveTest.java  | 85 +++++++++++++-------
 2 files changed, 57 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf67238b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
index 3a475c0..311819d 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
@@ -60,6 +60,9 @@ public class AbstractJcloudsLiveTest {
     public static final String SOFTLAYER_PROVIDER = "softlayer";
     public static final String SOFTLAYER_AMS01_REGION_NAME = "ams01";
     
+    public static final String GCE_PROVIDER = "google-compute-engine";
+    public static final String GCE_USCENTRAL_REGION_NAME = "us-central1-a";
+    
     protected BrooklynProperties brooklynProperties;
     protected LocalManagementContext managementContext;
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bf67238b/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
index aa61487..4e3f567 100644
--- 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
@@ -41,6 +41,15 @@ import com.google.common.collect.ImmutableMap;
  */
 public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
 
+    // TODO Rackspace failed - possibly image no longer exists?
+    // Was using: 
+    //     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";
+
+    // TODO GCE (in GCE_USCENTRAL_REGION_NAME) fails. We get blocked by the VM! e.g. /var/log/auth.log shows:
+    //     Nov  3 14:57:56 ubuntu sshd[1693]: Did not receive identification string from 31.53.199.228
+    //     Nov  3 14:57:56 ubuntu sshguard[971]: Blocking 31.53.199.228:4 for >630secs: 40 danger in 4 attacks over 435 seconds (all: 40d in 1 abuses over 435s).
+
     private static final Logger LOG = LoggerFactory.getLogger(JcloudsLoginLiveTest.class);
 
     public static final String AWS_EC2_REGION_NAME = AWS_EC2_USEAST_REGION_NAME;
@@ -56,14 +65,6 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
     // 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"));
@@ -80,12 +81,13 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
     private boolean publicDsaFileMoved;
 
     @Test(groups = {"Live"})
+    @SuppressWarnings("deprecation")
     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());
+        machine = createEc2Machine();
         assertSshable(machine);
         
         assertSshable(ImmutableMap.builder()
@@ -96,13 +98,14 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
     }
     
     @Test(groups = {"Live"})
+    @SuppressWarnings("deprecation")
     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());
+        machine = createEc2Machine();
         assertSshable(machine);
         
         assertSshable(ImmutableMap.builder()
@@ -118,7 +121,7 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
         brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
         jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
         
-        machine = createEc2Machine(ImmutableMap.<String,Object>of());
+        machine = createEc2Machine();
         assertSshable(machine);
         
         assertSshable(ImmutableMap.builder()
@@ -135,9 +138,9 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
             
             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);
+            jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
             
-            machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+            machine = createEc2Machine();
             assertSshable(machine);
             
             assertSshable(ImmutableMap.builder()
@@ -157,9 +160,9 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
             moveSshKeyFiles();
             
             brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "myname");
-            jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(RACKSPACE_LOCATION_SPEC);
+            jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
             
-            machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+            machine = createEc2Machine();
             assertSshable(machine);
             assertEquals(machine.getUser(), "myname");
         } finally {
@@ -173,9 +176,9 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
         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);
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
         
-        machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+        machine = createEc2Machine();
         assertSshable(machine);
         
         assertSshable(ImmutableMap.builder()
@@ -195,9 +198,32 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
     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);
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
+        
+        machine = createEc2Machine();
+        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 testSpecifyingPasswordIgnoresDefaultSshKeysSkippingJcloudsInit() 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.USE_JCLOUDS_SSH_INIT.getName(), "false");
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
         
-        machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+        machine = createEc2Machine();
         assertSshable(machine);
         
         assertSshable(ImmutableMap.builder()
@@ -218,9 +244,9 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
         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);
+        jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
         
-        machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+        machine = createEc2Machine();
         assertSshable(machine);
         
         assertSshable(ImmutableMap.builder()
@@ -244,9 +270,9 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
             
             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);
+            jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
             
-            machine = createRackspaceMachine(ImmutableMap.of("imageNameRegex", RACKSPACE_DEBIAN_IMAGE_NAME_REGEX));
+            machine = createEc2Machine();
             assertSshable(machine);
             
             assertSshable(ImmutableMap.builder()
@@ -316,6 +342,10 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
     protected void releaseMachine(JcloudsSshMachineLocation machine) {
         jcloudsLocation.release(machine);
     }
+
+    private JcloudsSshMachineLocation createEc2Machine() throws Exception {
+        return createEc2Machine(ImmutableMap.<String, Object>of());
+    }
     
     private JcloudsSshMachineLocation createEc2Machine(Map<String,? extends Object> conf) throws Exception {
         return obtainMachine(MutableMap.<String,Object>builder()
@@ -325,14 +355,7 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
                 .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));


[2/7] incubator-brooklyn git commit: Fix NetworkingUtilsTest.testIsPortAvailableReportsTrueWhenPortIsFree

Posted by al...@apache.org.
Fix NetworkingUtilsTest.testIsPortAvailableReportsTrueWhenPortIsFree

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

Branch: refs/heads/master
Commit: d192ad04f7903b417d77eb99015eaa9c37a2a1b2
Parents: 3fe1d9d
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 5 22:36:17 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 17 17:49:26 2015 +0000

----------------------------------------------------------------------
 .../org/apache/brooklyn/util/net/NetworkingUtilsTest.java   | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d192ad04/utils/common/src/test/java/org/apache/brooklyn/util/net/NetworkingUtilsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/net/NetworkingUtilsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/net/NetworkingUtilsTest.java
index 788b574..811c712 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/net/NetworkingUtilsTest.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/net/NetworkingUtilsTest.java
@@ -100,14 +100,15 @@ public class NetworkingUtilsTest {
     
     @Test
     public void testIsPortAvailableReportsTrueWhenPortIsFree() throws Exception {
+        final int MIN_FREE = 5;
         int port = 58769;
         int numFree = 0;
-        for (int i = 0; i < 10; i++) {
-            if (Networking.isPortAvailable(port))
+        for (int i = 0; i < 50 && numFree < MIN_FREE; i++) {
+            if (Networking.isPortAvailable(port+i))
                 numFree++;
         }
-        if (numFree<=5)
-            fail("This test requires that at least some ports near 58769+ not be in use.");
+        if (numFree < MIN_FREE)
+            fail("This test requires that at least some ports near "+port+"+ not be in use.");
     }
 
     @Test


[4/7] incubator-brooklyn git commit: Adds TODO question to Networking.isReaachable

Posted by al...@apache.org.
Adds TODO question to Networking.isReaachable

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

Branch: refs/heads/master
Commit: 3fe1d9d758e113fc05a59f7e9fb86f2c14bba5e2
Parents: 4cc09b0
Author: Aled Sage <al...@gmail.com>
Authored: Mon Nov 9 08:28:56 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 17 17:49:26 2015 +0000

----------------------------------------------------------------------
 .../main/java/org/apache/brooklyn/util/net/Networking.java    | 7 +++++++
 1 file changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3fe1d9d7/utils/common/src/main/java/org/apache/brooklyn/util/net/Networking.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/net/Networking.java b/utils/common/src/main/java/org/apache/brooklyn/util/net/Networking.java
index 695e3f8..fb988c7 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/net/Networking.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/net/Networking.java
@@ -26,6 +26,7 @@ import java.net.NetworkInterface;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketException;
+import java.net.URI;
 import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.Enumeration;
@@ -486,6 +487,12 @@ public class Networking {
     }
     
     public static boolean isReachable(HostAndPort endpoint) {
+        // TODO Should we create an unconnected socket, and then use the calls below (see jclouds' InetSocketAddressConnect):
+        //      socket.setReuseAddress(false);
+        //      socket.setSoLinger(false, 1);
+        //      socket.setSoTimeout(timeout);
+        //      socket.connect(socketAddress, timeout);
+        
         try {
             Socket s = new Socket(endpoint.getHostText(), endpoint.getPort());
             closeQuietly(s);


[3/7] incubator-brooklyn git commit: Adds ReachableSocketFinder

Posted by al...@apache.org.
Adds ReachableSocketFinder

Used by JcloudsLocation to determine which IP of the node is reachable.
Previously it used the jclouds’:
    managementContext.utils().sshForNode().apply(node)
but that fails with certain user/login configurations - e.g. when “node”
doesn’t have login-credentials, but the JcloudsLocation.obtain knows
about the credentials through some other configuration.

Code is based on the Jclouds ConcurrentOpenSocketFinder. However, it
is much simplified because we don’t abort-early if the VM’s status
goes to failed (we don’t concurrently poll the cloud-provider to find
out the state, as jclouds was doing).


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

Branch: refs/heads/master
Commit: 4cc09b0ae049d6f0c78ec691993f80fd8e82765c
Parents: af39886
Author: Aled Sage <al...@gmail.com>
Authored: Mon Nov 9 08:13:58 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 17 17:49:26 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/location/jclouds/JcloudsUtil.java  |  50 ++++--
 .../util/net/ReachableSocketFinder.java         | 154 +++++++++++++++++
 .../util/net/ReachableSocketFinderTest.java     | 165 +++++++++++++++++++
 3 files changed, 357 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4cc09b0a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
index 1101b34..685f81d 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
@@ -31,6 +31,7 @@ import java.net.URI;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -41,10 +42,12 @@ import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.net.Protocol;
+import org.apache.brooklyn.util.net.ReachableSocketFinder;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.ssh.IptablesCommands;
 import org.apache.brooklyn.util.ssh.IptablesCommands.Chain;
 import org.apache.brooklyn.util.ssh.IptablesCommands.Policy;
+import org.apache.brooklyn.util.time.Duration;
 import org.jclouds.Constants;
 import org.jclouds.ContextBuilder;
 import org.jclouds.aws.ec2.AWSEC2Api;
@@ -68,7 +71,6 @@ import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
 import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
 import org.jclouds.scriptbuilder.domain.Statement;
 import org.jclouds.scriptbuilder.domain.Statements;
-import org.jclouds.ssh.SshClient;
 import org.jclouds.sshj.config.SshjSshClientModule;
 import org.jclouds.util.Predicates2;
 import org.slf4j.Logger;
@@ -80,11 +82,15 @@ import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.common.io.Files;
+import com.google.common.net.HostAndPort;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import com.google.inject.Module;
 
 public class JcloudsUtil implements JcloudsLocationConfig {
@@ -319,8 +325,11 @@ public class JcloudsUtil implements JcloudsLocationConfig {
                 interpret("chmod 600 /root/.ssh/authorized_keys"));
     }
 
+    /**
+     * @deprecated since 0.9.0; use {@link #getFirstReachableAddress(NodeMetadata, Duration)}
+     */
     public static String getFirstReachableAddress(ComputeServiceContext context, NodeMetadata node) {
-        // To pick the address, it relies on jclouds `sshForNode().apply(Node)` to check all IPs of node (private+public),
+        // Previously this called jclouds `sshForNode().apply(Node)` to check all IPs of node (private+public),
         // to find one that is reachable. It does `openSocketFinder.findOpenSocketOnNode(node, node.getLoginPort(), ...)`.
         // This keeps trying for time org.jclouds.compute.reference.ComputeServiceConstants.Timeouts.portOpen.
         // TODO Want to configure this timeout here.
@@ -333,21 +342,38 @@ public class JcloudsUtil implements JcloudsLocationConfig {
         //     https://issues.apache.org/jira/browse/WHIRR-420
         //     jclouds.ssh.max-retries
         //     jclouds.ssh.retry-auth
-
-        SshClient client;
+        //
+        // With `sshForNode`, we'd seen exceptions:
+        //     java.lang.IllegalStateException: Optional.get() cannot be called on an absent value
+        //     from org.jclouds.crypto.ASN1Codec.createASN1Sequence(ASN1Codec.java:86), if the ssh key has a passphrase, against AWS.
+        // And others reported:
+        //     java.lang.IllegalArgumentException: DER length more than 4 bytes
+        //     when using a key with a passphrase (perhaps from other clouds?); not sure if that's this callpath or a different one.
+
+        return getFirstReachableAddress(node, Duration.FIVE_MINUTES);
+    }
+    
+    public static String getFirstReachableAddress(NodeMetadata node, Duration timeout) {
+        final int port = node.getLoginPort();
+        List<HostAndPort> sockets = FluentIterable
+                .from(Iterables.concat(node.getPublicAddresses(), node.getPrivateAddresses()))
+                .transform(new Function<String, HostAndPort>() {
+                        @Override public HostAndPort apply(String input) {
+                            return HostAndPort.fromParts(input, port);
+                        }})
+                .toList();
+        
+        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
         try {
-            client = context.utils().sshForNode().apply(node);
+            ReachableSocketFinder finder = new ReachableSocketFinder(executor);
+            HostAndPort result = finder.findOpenSocketOnNode(sockets, timeout);
+            return result.getHostText();
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            /* i've seen: java.lang.IllegalStateException: Optional.get() cannot be called on an absent value
-             * from org.jclouds.crypto.ASN1Codec.createASN1Sequence(ASN1Codec.java:86), if the ssh key has a passphrase, against AWS.
-             *
-             * others have reported: java.lang.IllegalArgumentException: DER length more than 4 bytes
-             * when using a key with a passphrase (perhaps from other clouds?); not sure if that's this callpath or a different one.
-             */
             throw new IllegalStateException("Unable to connect SshClient to "+node+"; check that the node is accessible and that the SSH key exists and is correctly configured, including any passphrase defined", e);
+        } finally {
+            executor.shutdownNow();
         }
-        return client.getHostAddress();
     }
 
     // Suggest at least 15 minutes for timeout

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4cc09b0a/utils/common/src/main/java/org/apache/brooklyn/util/net/ReachableSocketFinder.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/net/ReachableSocketFinder.java b/utils/common/src/main/java/org/apache/brooklyn/util/net/ReachableSocketFinder.java
new file mode 100644
index 0000000..716ad72
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/net/ReachableSocketFinder.java
@@ -0,0 +1,154 @@
+/*
+ * 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.util.net;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
+import org.apache.brooklyn.util.repeat.Repeater;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Lists;
+import com.google.common.net.HostAndPort;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+/**
+ * For finding an open/reachable ip:port for a node.
+ */
+public class ReachableSocketFinder {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ReachableSocketFinder.class);
+
+    private final Predicate<HostAndPort> socketTester;
+    private final ListeningExecutorService userExecutor;
+
+    public ReachableSocketFinder(ListeningExecutorService userExecutor) {
+        this(
+                new Predicate<HostAndPort>() {
+                    @Override public boolean apply(HostAndPort input) {
+                        return Networking.isReachable(input);
+                    }}, 
+                userExecutor);
+    }
+
+    public ReachableSocketFinder(Predicate<HostAndPort> socketTester, ListeningExecutorService userExecutor) {
+        this.socketTester = checkNotNull(socketTester, "socketTester");
+        this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+    }
+
+    /**
+     * 
+     * @param sockets The host-and-ports to test
+     * @param timeout Max time to try to connect to the ip:port
+     * 
+     * @return The reachable ip:port
+     * @throws NoSuchElementException If no ports accessible within the given time
+     * @throws NullPointerException  If the sockets or duration is null
+     * @throws IllegalStateException  If the sockets to test is empty
+     */
+    public HostAndPort findOpenSocketOnNode(final Collection<? extends HostAndPort> sockets, Duration timeout) {
+        checkNotNull(sockets, "sockets");
+        checkState(sockets.size() > 0, "No hostAndPort sockets supplied");
+        
+        LOG.debug("blocking on any reachable socket in {} for {}", sockets, timeout);
+
+        final AtomicReference<HostAndPort> result = new AtomicReference<HostAndPort>();
+        boolean passed = Repeater.create("socket-reachable")
+                .limitTimeTo(timeout)
+                .backoffTo(Duration.FIVE_SECONDS)
+                .until(new Callable<Boolean>() {
+                        public Boolean call() {
+                            Optional<HostAndPort> reachableSocket = tryReachable(sockets, Duration.seconds(2));
+                            if (reachableSocket.isPresent()) {
+                                result.compareAndSet(null, reachableSocket.get());
+                                return true;
+                            }
+                            return false;
+                        }})
+                .run();
+
+        if (passed) {
+            LOG.debug("<< socket {} opened", result);
+            assert result.get() != null;
+            return result.get();
+        } else {
+            LOG.warn("No sockets in {} reachable after {}", sockets, timeout);
+            throw new NoSuchElementException("could not connect to any socket in " + sockets);
+        }
+    }
+
+    /**
+     * Checks if any any of the given HostAndPorts are reachable. It checks them all concurrently, and
+     * returns the first that is reachable (or Optional.absent).
+     */
+    private Optional<HostAndPort> tryReachable(Collection<? extends HostAndPort> sockets, Duration timeout) {
+        final AtomicReference<HostAndPort> reachableSocket = new AtomicReference<HostAndPort>();
+        final CountDownLatch latch = new CountDownLatch(1);
+        List<ListenableFuture<?>> futures = Lists.newArrayList();
+        for (final HostAndPort socket : sockets) {
+            futures.add(userExecutor.submit(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            if (socketTester.apply(socket)) {
+                                reachableSocket.compareAndSet(null, socket);
+                                latch.countDown();
+                            }
+                        } catch (RuntimeInterruptedException e) {
+                            throw e;
+                        } catch (RuntimeException e) {
+                            LOG.warn("Error checking reachability of ip:port "+socket, e);
+                        }
+                    }}));
+        }
+        
+        ListenableFuture<List<Object>> compoundFuture = Futures.successfulAsList(futures);
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        try {
+            while (reachableSocket.get() == null && !compoundFuture.isDone() && timeout.isLongerThan(stopwatch)) {
+                latch.await(50, TimeUnit.MILLISECONDS);
+            }            
+            return Optional.fromNullable(reachableSocket.get());
+            
+        } catch (InterruptedException e) {
+            throw Exceptions.propagate(e);
+        } finally {
+            for (Future<?> future : futures) {
+                future.cancel(true);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4cc09b0a/utils/common/src/test/java/org/apache/brooklyn/util/net/ReachableSocketFinderTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/net/ReachableSocketFinderTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/net/ReachableSocketFinderTest.java
new file mode 100644
index 0000000..16228ef
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/net/ReachableSocketFinderTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.util.net;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+import java.net.ServerSocket;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.google.common.net.HostAndPort;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class ReachableSocketFinderTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ReachableSocketFinderTest.class);
+
+    private HostAndPort socket1;
+    private HostAndPort socket2;
+    private Map<HostAndPort, Boolean> reachabilityResults;
+    private ListeningExecutorService executor;
+    private Predicate<HostAndPort> socketTester;
+    private ReachableSocketFinder finder;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        socket1 = HostAndPort.fromParts("1.1.1.1", 1111);
+        socket2 = HostAndPort.fromParts("1.1.1.2", 1112);
+        reachabilityResults = Maps.newConcurrentMap();
+        executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+        socketTester = new Predicate<HostAndPort>() {
+            @Override public boolean apply(HostAndPort input) {
+                return Boolean.TRUE.equals(reachabilityResults.get(input));
+            }
+        };
+        
+        finder = new ReachableSocketFinder(socketTester, executor);
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (executor != null) executor.shutdownNow();
+    }
+    
+    @Test(expectedExceptions=IllegalStateException.class)
+    public void testWhenNoSocketsThrowsIllegalState() throws Exception {
+        finder.findOpenSocketOnNode(ImmutableList.<HostAndPort>of(), Duration.TEN_SECONDS);
+    }
+    
+    @Test
+    public void testReturnsReachableSocket() throws Exception {
+        reachabilityResults.put(socket1, true);
+        reachabilityResults.put(socket2, false);
+        assertEquals(finder.findOpenSocketOnNode(ImmutableList.<HostAndPort>of(socket1, socket2), Duration.TEN_SECONDS), socket1);
+        
+        reachabilityResults.put(socket1, false);
+        reachabilityResults.put(socket2, true);
+        assertEquals(finder.findOpenSocketOnNode(ImmutableList.<HostAndPort>of(socket1, socket2), Duration.TEN_SECONDS), socket2);
+    }
+    
+    @Test
+    public void testPollsUntilPortReachable() throws Exception {
+        reachabilityResults.put(socket1, false);
+        reachabilityResults.put(socket2, false);
+        final ListenableFuture<HostAndPort> future = executor.submit(new Callable<HostAndPort>() {
+                @Override public HostAndPort call() throws Exception {
+                    return finder.findOpenSocketOnNode(ImmutableList.<HostAndPort>of(socket1, socket2), Duration.TEN_SECONDS);
+                }});
+
+        // Should keep trying
+        Asserts.succeedsContinually(new Runnable() {
+            @Override public void run() {
+                assertFalse(future.isDone());
+            }});
+
+        // When port is reached, it completes
+        reachabilityResults.put(socket1, true);
+        assertEquals(future.get(30, TimeUnit.SECONDS), socket1);
+    }
+    
+    // Mark as integration, as can't rely (in Apache infra) for a port to stay unused during test!
+    @Test(groups="Integration")
+    public void testReturnsRealReachableSocket() throws Exception {
+        ReachableSocketFinder realFinder = new ReachableSocketFinder(executor);
+        ServerSocket socket = connectToPort();
+        try {
+            HostAndPort addr = HostAndPort.fromParts(socket.getInetAddress().getHostAddress(), socket.getLocalPort());
+            HostAndPort wrongAddr = HostAndPort.fromParts(socket.getInetAddress().getHostAddress(), findAvailablePort());
+            
+            assertEquals(realFinder.findOpenSocketOnNode(ImmutableList.of(addr, wrongAddr), Duration.ONE_MINUTE), addr);
+        } finally {
+            if (socket != null) {
+                socket.close();
+            }
+        }
+    }
+
+    // Mark as integration, as can't rely (in Apache infra) for a port to stay unused during test!
+    // And slow test - takes 5 seconds.
+    @Test(groups="Integration")
+    public void testFailsIfRealSocketUnreachable() throws Exception {
+        ReachableSocketFinder realFinder = new ReachableSocketFinder(executor);
+        HostAndPort wrongAddr = HostAndPort.fromParts(Networking.getLocalHost().getHostAddress(), findAvailablePort());
+        
+        try {
+            HostAndPort result = realFinder.findOpenSocketOnNode(ImmutableList.of(wrongAddr), Duration.FIVE_SECONDS);
+            fail("Expected failure, but got "+result);
+        } catch (NoSuchElementException e) {
+            // success
+        }
+    }
+
+    private ServerSocket connectToPort() throws Exception {
+        ServerSocket result = new ServerSocket(0);
+        LOG.info("Acquired port "+result+" for test "+JavaClassNames.niceClassAndMethod());
+        return result;
+    }
+    
+    private int findAvailablePort() throws Exception {
+        final int startPort = 58767;
+        final int endPort = 60000;
+        int port = startPort;
+        do {
+            if (Networking.isPortAvailable(port)) {
+                return port;
+            }
+            port++;
+            // repeat until we can get a port
+        } while (port <= endPort);
+        throw new Exception("could not get a port in range "+startPort+"-"+endPort);
+    }
+}


[6/7] incubator-brooklyn git commit: Fix JcloudsLocation login

Posted by al...@apache.org.
Fix JcloudsLocation login

- registerJcloudsSshMachineLocation: use the userCredentials that
  are passed into the method, rather than looking up what we expect
  from the config.
  (Hopefully fixes testSpecifyingPasswordAndSshKeysPrefersKeys).
- Fix waitForSshable to when password supplied on JcloudsLocation
  config, and using useJcloudsSshInit=false.
- Fix use of DISABLE_ROOT_AND_PASSWORD_SSH: if for root user with
  password-based login, then explicitly set PasswordAuthentication=yes.
  If root user, then explicitly set PermitRootLogin=true
- Fix getPublicHostnameAws so pass in the credentials (some code-paths
  will not have configured the credentials in the generic config).
  Same for getPrivateHostnameAws.
- Tidy up the createTemporarySshMachineLocaton
- Logging of timing: include how long to get semaphore
- Logging of failure: include how long for each stage

Previously hit a problem when the jclouds location was configured with
a password + a blank ssh key, and using useJcloudsSshInit=false.
It failed to ssh to the newly provisioned AWS VM in waitForSshable. It
got the node.getCredentials, which gives us the ssh-key from the AWS
key-pair. But then we instantiate an SshMachineLocation to check if we
can connection (before continuing with the user-setup). That
machineLocation inherits the password (which has not been set on the
machine), so it fails to ssh - the password takes precedence over the
ssh-key.


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

Branch: refs/heads/master
Commit: f34e7e69839d4b1898fb55348d9aaf6743fed6c4
Parents: bf67238
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 5 22:28:35 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 17 17:49:27 2015 +0000

----------------------------------------------------------------------
 .../location/jclouds/JcloudsLocation.java       | 226 +++++++++++--------
 .../jclouds/AbstractJcloudsLiveTest.java        |   1 +
 .../location/jclouds/JcloudsLoginLiveTest.java  |  51 ++++-
 3 files changed, 168 insertions(+), 110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f34e7e69/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
index 4e322bd..642aafb 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
@@ -645,6 +645,12 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         String groupId = elvis(setup.get(GROUP_ID), cloudMachineNamer.generateNewGroupId(setup));
         NodeMetadata node = null;
         JcloudsMachineLocation machineLocation = null;
+        Duration semaphoreTimestamp = null;
+        Duration templateTimestamp = null;
+        Duration provisionTimestamp = null;
+        Duration usableTimestamp = null;
+        Duration customizedTimestamp = null;
+        Stopwatch provisioningStopwatch = Stopwatch.createStarted();
         
         try {
             LOG.info("Creating VM "+setup.getDescription()+" in "+this);
@@ -659,9 +665,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             } else {
                 LOG.debug("Acquired in {} machine-creation permit immediately", this);
             }
-
-            Stopwatch provisioningStopwatch = Stopwatch.createStarted();
-            Duration templateTimestamp, provisionTimestamp, usableTimestamp, customizedTimestamp;
+            semaphoreTimestamp = Duration.of(provisioningStopwatch);
 
             LoginCredentials userCredentials = null;
             Set<? extends NodeMetadata> nodes;
@@ -770,6 +774,11 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                 if (customCredentials.getOptionalPassword().isPresent()) setup.put(PASSWORD, customCredentials.getOptionalPassword().get());
                 if (customCredentials.getOptionalPrivateKey().isPresent()) setup.put(PRIVATE_KEY_DATA, customCredentials.getOptionalPrivateKey().get());
             }
+            if (userCredentials == null || (!userCredentials.getOptionalPassword().isPresent() && !userCredentials.getOptionalPrivateKey().isPresent())) {
+                // We either don't have any userCredentials, or it is missing both a password/key.
+                // TODO See waitForSshable, which now handles if the node.getLoginCredentials has both a password+key
+                userCredentials = extractVmCredentials(setup, node, initialCredentials);
+            }
             if (userCredentials == null) {
                 // TODO See waitForSshable, which now handles if the node.getLoginCredentials has both a password+key
                 userCredentials = extractVmCredentials(setup, node, initialCredentials);
@@ -984,7 +993,9 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                                 + " && key=" + userCredentials.getOptionalPrivateKey().or("<absent>")
                                 : "")
                         + " ready after "+Duration.of(provisioningStopwatch).toStringRounded()
-                        + " ("+template+" template built in "+Duration.of(templateTimestamp).toStringRounded()+";"
+                        + " ("
+                        + "semaphore obtained in "+Duration.of(semaphoreTimestamp).toStringRounded()+";"
+                        + template+" template built in "+Duration.of(templateTimestamp).subtract(semaphoreTimestamp).toStringRounded()+";"
                         + " "+node+" provisioned in "+Duration.of(provisionTimestamp).subtract(templateTimestamp).toStringRounded()+";"
                         + " "+machineLocation+" connection usable in "+Duration.of(usableTimestamp).subtract(provisionTimestamp).toStringRounded()+";"
                         + " and os customized in "+Duration.of(customizedTimestamp).subtract(usableTimestamp).toStringRounded()+" - "+Joiner.on(", ").join(customisationForLogging)+")";
@@ -1014,16 +1025,29 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                     + "For more information on VPC vs classic see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-vpc.html.");
             }
             
-            LOG.error("Failed to start VM for {}{}: {}",
-                    new Object[] {setup.getDescription(), (destroyNode ? " (destroying "+node+")" : ""), e.getMessage()});
+            LOG.error("Failed to start VM for "+setup.getDescription() + (destroyNode ? " (destroying)" : "")
+                    + (node != null ? "; node "+node : "")
+                    + " after "+Duration.of(provisioningStopwatch).toStringRounded()
+                    + (semaphoreTimestamp != null ? " ("
+                            + "semaphore obtained in "+Duration.of(semaphoreTimestamp).toStringRounded()+";"
+                            + (templateTimestamp != null && semaphoreTimestamp != null ? " template built in "+Duration.of(templateTimestamp).subtract(semaphoreTimestamp).toStringRounded()+";" : "")
+                            + (provisionTimestamp != null && templateTimestamp != null ? " node provisioned in "+Duration.of(provisionTimestamp).subtract(templateTimestamp).toStringRounded()+";" : "")
+                            + (usableTimestamp != null && provisioningStopwatch != null ? " connection usable in "+Duration.of(usableTimestamp).subtract(provisionTimestamp).toStringRounded()+";" : "")
+                            + (customizedTimestamp != null && usableTimestamp != null ? " and OS customized in "+Duration.of(customizedTimestamp).subtract(usableTimestamp).toStringRounded() : "")
+                            + ")"
+                            : "")
+                    + ": "+e.getMessage());
             LOG.debug(Throwables.getStackTraceAsString(e));
-            
+
             if (destroyNode) {
+                Stopwatch destroyingStopwatch = Stopwatch.createStarted();
                 if (machineLocation != null) {
                     releaseSafely(machineLocation);
                 } else {
                     releaseNodeSafely(node);
                 }
+                LOG.info("Destroyed " + (machineLocation != null ? "machine " + machineLocation : "node " + node)
+                        + " in " + Duration.of(destroyingStopwatch).toStringRounded());
             }
 
             throw Exceptions.propagate(e);
@@ -1552,19 +1576,27 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         }
     }
 
+    /**
+     * Creates a temporary ssh machine location (i.e. will not be persisted), which uses the given credentials.
+     * It ignores any credentials (e.g. password, key-phrase, etc) that are supplied in the config.
+     */
     protected SshMachineLocation createTemporarySshMachineLocation(HostAndPort hostAndPort, LoginCredentials creds, ConfigBag config) {
+        String initialUser = creds.getUser();
         Optional<String> initialPassword = creds.getOptionalPassword();
         Optional<String> initialPrivateKey = creds.getOptionalPrivateKey();
-        String initialUser = creds.getUser();
 
         Map<String,Object> sshProps = Maps.newLinkedHashMap(config.getAllConfig());
         sshProps.put("user", initialUser);
         sshProps.put("address", hostAndPort.getHostText());
         sshProps.put("port", hostAndPort.getPort());
         sshProps.put(AbstractLocation.TEMPORARY_LOCATION.getName(), true);
+        sshProps.remove("password");
+        sshProps.remove("privateKeyData");
+        sshProps.remove("privateKeyFile");
+        sshProps.remove("privateKeyPassphrase");
+
         if (initialPassword.isPresent()) sshProps.put("password", initialPassword.get());
         if (initialPrivateKey.isPresent()) sshProps.put("privateKeyData", initialPrivateKey.get());
-        if (initialPrivateKey.isPresent()) sshProps.put("privateKeyData", initialPrivateKey.get());
 
         if (isManaged()) {
             return getManagementContext().getLocationManager().createLocation(sshProps, SshMachineLocation.class);
@@ -1602,48 +1634,25 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                     commands.add(statement.render(scriptOsFamily));
                 }
 
-                Optional<String> initialPassword = initialCredentials.getOptionalPassword();
-                Optional<String> initialPrivateKey = initialCredentials.getOptionalPrivateKey();
                 String initialUser = initialCredentials.getUser();
                 String address = hostAndPortOverride.isPresent() ? hostAndPortOverride.get().getHostText() : JcloudsUtil.getFirstReachableAddress(computeService.getContext(), node);
                 int port = hostAndPortOverride.isPresent() ? hostAndPortOverride.get().getPort() : node.getLoginPort();
                 
-                Map<String,Object> sshProps = Maps.newLinkedHashMap(config.getAllConfig());
-                sshProps.put("user", initialUser);
-                sshProps.put("address", address);
-                sshProps.put("port", port);
-                if (initialPassword.isPresent()) {
-                    sshProps.put("password", initialPassword.get());
-                } else {
-                    sshProps.remove("password");
-                }
-                if (initialPrivateKey.isPresent()) {
-                    sshProps.put("privateKeyData", initialPrivateKey.get());
-                } else {
-                    sshProps.remove("privateKeyData");
-                }
-    
                 // TODO Retrying lots of times as workaround for vcloud-director. There the guest customizations
                 // can cause the VM to reboot shortly after it was ssh'able.
                 Map<String,Object> execProps = Maps.newLinkedHashMap();
                 execProps.put(ShellTool.PROP_RUN_AS_ROOT.getName(), true);
                 execProps.put(SshTool.PROP_SSH_TRIES.getName(), 50);
                 execProps.put(SshTool.PROP_SSH_TRIES_TIMEOUT.getName(), 10*60*1000);
-    
+
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("VM {}: executing user creation/setup via {}@{}:{}; commands: {}", new Object[] {
                             config.getDescription(), initialUser, address, port, commands});
                 }
-    
-                SshMachineLocation sshLoc = null;
+
+                HostAndPort hostAndPort = hostAndPortOverride.isPresent() ? hostAndPortOverride.get() : HostAndPort.fromParts(address, port);
+                SshMachineLocation sshLoc = createTemporarySshMachineLocation(hostAndPort, initialCredentials, config);
                 try {
-                    if (isManaged()) {
-                        sshProps.put(AbstractLocation.TEMPORARY_LOCATION.getName(), true);
-                        sshLoc = getManagementContext().getLocationManager().createLocation(sshProps, SshMachineLocation.class);
-                    } else {
-                        sshLoc = new SshMachineLocation(sshProps);
-                    }
-    
                     // BROOKLYN-188: for SUSE, need to specify the path (for groupadd, useradd, etc)
                     Map<String, ?> env = ImmutableMap.of("PATH", sbinPath());
                     
@@ -1766,6 +1775,9 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
 
                 if (credential.isUsingPassword()) {
                     createdUserCreds = LoginCredentials.builder().user(user).password(credential.getPassword()).build();
+                    if (Boolean.FALSE.equals(config.get(DISABLE_ROOT_AND_PASSWORD_SSH))) {
+                        statements.add(org.jclouds.scriptbuilder.statements.ssh.SshStatements.sshdConfig(ImmutableMap.of("PasswordAuthentication", "yes")));
+                    }
                 } else if (credential.hasKey()) {
                     createdUserCreds = LoginCredentials.builder().user(user).privateKey(credential.getPrivateKeyData()).build();
                 }
@@ -1788,6 +1800,8 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             if (config.get(PUBLIC_KEY_FILE) != null) config.put(PUBLIC_KEY_FILE, "");
 
         } else if (Strings.isBlank(user) || user.equals(loginUser) || user.equals(ROOT_USERNAME)) {
+            boolean useKey = Strings.isNonBlank(credential.getPublicKeyData());
+            
             // For subsequent ssh'ing, we'll be using the loginUser
             if (Strings.isBlank(user)) {
                 user = loginUser;
@@ -1800,12 +1814,20 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             statements.add(new ReplaceShadowPasswordEntry(Sha512Crypt.function(), user, passwordToSet));
             createdUserCreds = LoginCredentials.builder().user(user).password(passwordToSet).build();
 
-            if (Strings.isNonBlank(credential.getPublicKeyData())) {
+            if (useKey) {
                 statements.add(new AuthorizeRSAPublicKeys("~"+user+"/.ssh", ImmutableList.of(credential.getPublicKeyData())));
-                if (!credential.isUsingPassword() && Strings.isNonBlank(credential.getPrivateKeyData())) {
+                if (Strings.isNonBlank(credential.getPrivateKeyData())) {
                     createdUserCreds = LoginCredentials.builder().user(user).privateKey(credential.getPrivateKeyData()).build();
                 }
             }
+            
+            if (!useKey || Boolean.FALSE.equals(config.get(DISABLE_ROOT_AND_PASSWORD_SSH))) {
+                // ensure password is permitted for ssh
+                statements.add(org.jclouds.scriptbuilder.statements.ssh.SshStatements.sshdConfig(ImmutableMap.of("PasswordAuthentication", "yes")));
+                if (user.equals(ROOT_USERNAME)) {
+                    statements.add(org.jclouds.scriptbuilder.statements.ssh.SshStatements.sshdConfig(ImmutableMap.of("PermitRootLogin", "yes")));
+                }
+            }
 
         } else {
             String pubKey = credential.getPublicKeyData();
@@ -1883,8 +1905,10 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                 createdUserCreds = LoginCredentials.builder().user(user).privateKey(privKey).build();
             } else if (passwordToSet!=null) {
                 createdUserCreds = LoginCredentials.builder().user(user).password(passwordToSet).build();
-                
-                // if setting a password also ensure password is permitted for ssh
+            }
+            
+            if (!useKey || Boolean.FALSE.equals(config.get(DISABLE_ROOT_AND_PASSWORD_SSH))) {
+                // ensure password is permitted for ssh
                 statements.add(org.jclouds.scriptbuilder.statements.ssh.SshStatements.sshdConfig(ImmutableMap.of("PasswordAuthentication", "yes")));
             }
         }
@@ -2096,13 +2120,13 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         return registerJcloudsSshMachineLocation(null, node, null, sshHostAndPort, setup);
     }
 
-    protected JcloudsSshMachineLocation registerJcloudsSshMachineLocation(ComputeService computeService, NodeMetadata node, LoginCredentials initialCredentials, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) throws IOException {
-        if (initialCredentials==null)
-            initialCredentials = node.getCredentials();
+    protected JcloudsSshMachineLocation registerJcloudsSshMachineLocation(ComputeService computeService, NodeMetadata node, LoginCredentials userCredentials, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) throws IOException {
+        if (userCredentials == null)
+            userCredentials = node.getCredentials();
 
         String vmHostname = getPublicHostname(node, sshHostAndPort, setup);
 
-        JcloudsSshMachineLocation machine = createJcloudsSshMachineLocation(computeService, node, vmHostname, sshHostAndPort, setup);
+        JcloudsSshMachineLocation machine = createJcloudsSshMachineLocation(computeService, node, vmHostname, sshHostAndPort, userCredentials, setup);
         registerJcloudsMachineLocation(node.getId(), machine);
         return machine;
     }
@@ -2113,13 +2137,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         vmInstanceIds.put(machine, nodeId);
     }
     
-    /** @deprecated since 0.7.0 use variant which takes compute service; no longer called internally,
-     * so marked final to force any overrides to switch to new syntax */
-    @Deprecated
-    protected final JcloudsSshMachineLocation createJcloudsSshMachineLocation(NodeMetadata node, String vmHostname, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) throws IOException {
-        return createJcloudsSshMachineLocation(null, node, vmHostname, sshHostAndPort, setup);
-    }
-    protected JcloudsSshMachineLocation createJcloudsSshMachineLocation(ComputeService computeService, NodeMetadata node, String vmHostname, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) throws IOException {
+    protected JcloudsSshMachineLocation createJcloudsSshMachineLocation(ComputeService computeService, NodeMetadata node, String vmHostname, Optional<HostAndPort> sshHostAndPort, LoginCredentials userCredentials, ConfigBag setup) throws IOException {
         Map<?,?> sshConfig = extractSshConfig(setup, node);
         String nodeAvailabilityZone = extractAvailabilityZone(setup, node);
         String nodeRegion = extractRegion(setup, node);
@@ -2159,11 +2177,13 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                     .configure("displayName", vmHostname)
                     .configure("address", address)
                     .configure(JcloudsSshMachineLocation.SSH_PORT, sshHostAndPort.isPresent() ? sshHostAndPort.get().getPort() : node.getLoginPort())
-                    .configure("user", getUser(setup))
                     // don't think "config" does anything
                     .configure(sshConfig)
                     // FIXME remove "config" -- inserted directly, above
                     .configure("config", sshConfig)
+                    .configure("user", userCredentials.getUser())
+                    .configure(SshMachineLocation.PASSWORD, userCredentials.getOptionalPassword().orNull())
+                    .configure(SshMachineLocation.PRIVATE_KEY_DATA, userCredentials.getOptionalPrivateKey().orNull())
                     .configure("jcloudsParent", this)
                     .configure("node", node)
                     .configureIfNotNull(CLOUD_AVAILABILITY_ZONE_ID, nodeAvailabilityZone)
@@ -2180,11 +2200,13 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                     .put("displayName", vmHostname)
                     .put("address", address)
                     .put("port", sshHostAndPort.isPresent() ? sshHostAndPort.get().getPort() : node.getLoginPort())
-                    .put("user", getUser(setup))
                     // don't think "config" does anything
                     .putAll(sshConfig)
                     // FIXME remove "config" -- inserted directly, above
                     .put("config", sshConfig)
+                    .put("user", userCredentials.getUser())
+                    .putIfNotNull(SshMachineLocation.PASSWORD.getName(), userCredentials.getOptionalPassword().orNull())
+                    .putIfNotNull(SshMachineLocation.PRIVATE_KEY_DATA.getName(), userCredentials.getOptionalPrivateKey().orNull())
                     .put("callerContext", setup.get(CALLER_CONTEXT))
                     .putIfNotNull(CLOUD_AVAILABILITY_ZONE_ID.getName(), nodeAvailabilityZone)
                     .putIfNotNull(CLOUD_REGION_ID.getName(), nodeRegion)
@@ -2575,31 +2597,47 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         String connectionDetails = user + "@" + vmIp + ":" + vmPort;
         final HostAndPort hostAndPort = hostAndPortOverride.isPresent() ? hostAndPortOverride.get() : HostAndPort.fromParts(vmIp, vmPort);
         final AtomicReference<LoginCredentials> credsSuccessful = new AtomicReference<LoginCredentials>();
-        
+
+        // Don't use config that relates to the final user credentials (those have nothing to do 
+        // with the initial credentials of the VM returned by the cloud provider).
+        ConfigBag sshProps = ConfigBag.newInstanceCopying(setup);
+        sshProps.remove("password");
+        sshProps.remove("privateKeyData");
+        sshProps.remove("privateKeyFile");
+        sshProps.remove("privateKeyPassphrase");
+
         final Map<SshMachineLocation, LoginCredentials> machinesToTry = Maps.newLinkedHashMap();
         for (LoginCredentials creds : credentialsToTry) {
-            machinesToTry.put(createTemporarySshMachineLocation(hostAndPort, creds, setup), creds);
+            machinesToTry.put(createTemporarySshMachineLocation(hostAndPort, creds, sshProps), creds);
         }
-        Callable<Boolean> checker = new Callable<Boolean>() {
-            public Boolean call() {
-                for (Map.Entry<SshMachineLocation, LoginCredentials> entry : machinesToTry.entrySet()) {
-                    SshMachineLocation machine = entry.getKey();
-                    int exitstatus = machine.execScript(
-                            ImmutableMap.of(
-                                    SshTool.PROP_SSH_TRIES_TIMEOUT.getName(), Duration.THIRTY_SECONDS.toMilliseconds(),
-                                    SshTool.PROP_SSH_TRIES.getName(), 1), 
-                            "check-connectivity", 
-                            ImmutableList.of("true"));
-                    boolean success = (exitstatus == 0);
-                    if (success) {
-                        credsSuccessful.set(entry.getValue());
-                        return true;
+        try {
+            Callable<Boolean> checker = new Callable<Boolean>() {
+                public Boolean call() {
+                    for (Map.Entry<SshMachineLocation, LoginCredentials> entry : machinesToTry.entrySet()) {
+                        SshMachineLocation machine = entry.getKey();
+                        int exitstatus = machine.execScript(
+                                ImmutableMap.of(
+                                        SshTool.PROP_SSH_TRIES_TIMEOUT.getName(), Duration.THIRTY_SECONDS.toMilliseconds(),
+                                        SshTool.PROP_SSH_TRIES.getName(), 1), 
+                                "check-connectivity", 
+                                ImmutableList.of("true"));
+                        boolean success = (exitstatus == 0);
+                        if (success) {
+                            credsSuccessful.set(entry.getValue());
+                            return true;
+                        }
                     }
-                }
-                return false;
-            }};
-
-        waitForReachable(checker, connectionDetails, credentialsToTry, setup, timeout);
+                    return false;
+                }};
+    
+            waitForReachable(checker, connectionDetails, credentialsToTry, setup, timeout);
+        } finally {
+            for (SshMachineLocation machine : machinesToTry.keySet()) {
+                getManagementContext().getLocationManager().unmanage(machine);
+                Streams.closeQuietly(machine);
+            }
+        }
+        
         return credsSuccessful.get();
     }
 
@@ -2702,12 +2740,16 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         }
     }
 
+    protected String getPublicHostname(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) {
+        return getPublicHostname(node, sshHostAndPort, node.getCredentials(), setup);
+    }
+    
     /**
      * Attempts to obtain the hostname or IP of the node, as advertised by the cloud provider.
      * Prefers public, reachable IPs.
      * For some clouds (e.g. aws-ec2), it will attempt to find the public hostname.
      */
-    protected String getPublicHostname(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) {
+    protected String getPublicHostname(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, LoginCredentials userCredentials, ConfigBag setup) {
         String provider = (setup != null) ? setup.get(CLOUD_PROVIDER) : null;
         if (provider == null) provider= getProvider();
 
@@ -2731,7 +2773,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                 } else {
                     HostAndPort hostAndPortToUse = sshHostAndPort.isPresent() ? sshHostAndPort.get() : inferredHostAndPort;
                     try {
-                        return getPublicHostnameAws(hostAndPortToUse, setup);
+                        return getPublicHostnameAws(hostAndPortToUse, userCredentials, setup);
                     } catch (Exception e) {
                         if (inferredHostAndPort != null) { 
                             LOG.warn("Error querying aws-ec2 instance "+node.getId()+"@"+node.getLocation()+" over ssh for its hostname; falling back to first reachable IP", e);
@@ -2768,27 +2810,11 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         }
     }
 
-    private String getPublicHostnameAws(HostAndPort sshHostAndPort, ConfigBag setup) {
+    private String getPublicHostnameAws(HostAndPort hostAndPort, LoginCredentials userCredentials, ConfigBag setup) {
         SshMachineLocation sshLocByIp = null;
         try {
-            ConfigBag sshConfig = extractSshConfig(setup, new ConfigBag());
-
             // TODO messy way to get an SSH session
-            if (isManaged()) {
-                sshLocByIp = getManagementContext().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
-                        .configure("address", sshHostAndPort.getHostText())
-                        .configure("port", sshHostAndPort.getPort())
-                        .configure("user", getUser(setup))
-                        .configure(sshConfig.getAllConfig()));
-            } else {
-                MutableMap<Object, Object> locationProps = MutableMap.builder()
-                        .put("address", sshHostAndPort.getHostText())
-                        .put("port", sshHostAndPort.getPort())
-                        .put("user", getUser(setup))
-                        .putAll(sshConfig.getAllConfig())
-                        .build();
-                sshLocByIp = new SshMachineLocation(locationProps);
-            }
+            sshLocByIp = createTemporarySshMachineLocation(hostAndPort, userCredentials, setup);
 
             ByteArrayOutputStream outStream = new ByteArrayOutputStream();
             ByteArrayOutputStream errStream = new ByteArrayOutputStream();
@@ -2803,7 +2829,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             for (String line : outLines) {
                 if (line.startsWith("ec2-")) return line.trim();
             }
-            throw new IllegalStateException("Could not obtain aws-ec2 hostname for vm "+sshHostAndPort+"; exitcode="+exitcode+"; stdout="+outString+"; stderr="+new String(errStream.toByteArray()));
+            throw new IllegalStateException("Could not obtain aws-ec2 hostname for vm "+hostAndPort+"; exitcode="+exitcode+"; stdout="+outString+"; stderr="+new String(errStream.toByteArray()));
         } finally {
             Streams.closeQuietly(sshLocByIp);
         }
@@ -2815,6 +2841,10 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
      * For some clouds (e.g. aws-ec2), it will attempt to find the fully qualified hostname (as that works in public+private).
      */
     protected String getPrivateHostname(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) {
+        return getPrivateHostname(node, sshHostAndPort, node.getCredentials(), setup);
+    }
+    
+    protected String getPrivateHostname(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, LoginCredentials userCredentials, ConfigBag setup) {
         String provider = (setup != null) ? setup.get(CLOUD_PROVIDER) : null;
         if (provider == null) provider= getProvider();
 
@@ -2822,14 +2852,14 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         // exceptional situation rather than a pattern to follow. We need a better way to
         // do cloud-specific things.
         if ("aws-ec2".equals(provider)) {
-            Maybe<String> result = getPrivateHostnameAws(node, sshHostAndPort, setup);
+            Maybe<String> result = getPrivateHostnameAws(node, sshHostAndPort, userCredentials, setup);
             if (result.isPresent()) return result.get();
         }
 
         return getPrivateHostnameGeneric(node, setup);
     }
 
-    private Maybe<String> getPrivateHostnameAws(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, ConfigBag setup) {
+    private Maybe<String> getPrivateHostnameAws(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, LoginCredentials userCredentials, ConfigBag setup) {
         // TODO Remove duplication from getPublicHostname.
         // TODO Don't like 
         HostAndPort inferredHostAndPort = null;
@@ -2845,7 +2875,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         if (sshHostAndPort.isPresent() || inferredHostAndPort != null) {
             HostAndPort hostAndPortToUse = sshHostAndPort.isPresent() ? sshHostAndPort.get() : inferredHostAndPort;
             try {
-                return Maybe.of(getPublicHostnameAws(hostAndPortToUse, setup));
+                return Maybe.of(getPublicHostnameAws(hostAndPortToUse, userCredentials, setup));
             } catch (Exception e) {
                 LOG.warn("Error querying aws-ec2 instance instance "+node.getId()+"@"+node.getLocation()+" over ssh for its hostname; falling back to jclouds metadata for address", e);
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f34e7e69/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
index 311819d..7723a01 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
@@ -52,6 +52,7 @@ public class AbstractJcloudsLiveTest {
     public static final String AWS_EC2_PROVIDER = "aws-ec2";
     public static final String AWS_EC2_MICRO_HARDWARE_ID = "t1.micro";
     public static final String AWS_EC2_SMALL_HARDWARE_ID = "m1.small";
+    public static final String AWS_EC2_MEDIUM_HARDWARE_ID = "m3.medium";
     public static final String AWS_EC2_EUWEST_REGION_NAME = "eu-west-1";
     public static final String AWS_EC2_USEAST_REGION_NAME = "us-east-1";
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f34e7e69/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
index 4e3f567..d8c38fa 100644
--- 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
@@ -19,19 +19,21 @@
 package org.apache.brooklyn.location.jclouds;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
 
 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.api.location.LocationSpec;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.stream.Streams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -171,27 +173,50 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
     }
 
     @Test(groups = {"Live"})
-    protected void testSpecifyingPasswordAndSshKeysPrefersKeys() throws Exception {
+    public void testSpecifyingPasswordAndSshKeysPrefersKeysAndDisablesPassword() throws Exception {
+        runSpecifyingPasswordAndSshKeysPrefersKeys(false);
+    }
+
+    @Test(groups = {"Live"})
+    public void testSpecifyingPasswordAndSshKeysPrefersKeysAndAllowsPassword() throws Exception {
+        runSpecifyingPasswordAndSshKeysPrefersKeys(true);
+    }
+
+    protected void runSpecifyingPasswordAndSshKeysPrefersKeys(boolean leavePasswordSsh) 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");
+        if (leavePasswordSsh) {
+            brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.DISABLE_ROOT_AND_PASSWORD_SSH.getName(), false);
+        }
         jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
         
         machine = createEc2Machine();
         assertSshable(machine);
         
-        assertSshable(ImmutableMap.builder()
-                .put("address", machine.getAddress())
-                .put("user", "myname")
-                .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
-                .build());
+        assertNull(machine.config().get(SshMachineLocation.PASSWORD));
+        assertNotNull(machine.config().get(SshMachineLocation.PRIVATE_KEY_DATA));
         
         assertSshable(ImmutableMap.builder()
                 .put("address", machine.getAddress())
                 .put("user", "myname")
-                .put(SshMachineLocation.PASSWORD, "mypassword")
+                .put(SshMachineLocation.PRIVATE_KEY_FILE, Os.tidyPath("~/.ssh/id_rsa"))
                 .build());
+
+        if (leavePasswordSsh) {
+            assertSshable(ImmutableMap.builder()
+                    .put("address", machine.getAddress())
+                    .put("user", "myname")
+                    .put(SshMachineLocation.PASSWORD, "mypassword")
+                    .build());
+        } else {
+            assertNotSshable(ImmutableMap.builder()
+                    .put("address", machine.getAddress())
+                    .put("user", "myname")
+                    .put(SshMachineLocation.PASSWORD, "mypassword")
+                    .build());
+        }
     }
 
     @Test(groups = {"Live"})
@@ -244,6 +269,7 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
         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");
+        brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.DISABLE_ROOT_AND_PASSWORD_SSH.getName(), false);
         jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
         
         machine = createEc2Machine();
@@ -270,6 +296,7 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
             
             brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.USER.getName(), "root");
             brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.PASSWORD.getName(), "mypassword");
+            brooklynProperties.put(BROOKLYN_PROPERTIES_PREFIX+JcloudsLocationConfig.DISABLE_ROOT_AND_PASSWORD_SSH.getName(), false);
             jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC);
             
             machine = createEc2Machine();
@@ -351,7 +378,7 @@ public class JcloudsLoginLiveTest extends AbstractJcloudsLiveTest {
         return obtainMachine(MutableMap.<String,Object>builder()
                 .putAll(conf)
                 .putIfAbsent("imageId", AWS_EC2_CENTOS_IMAGE_ID)
-                .putIfAbsent("hardwareId", AWS_EC2_SMALL_HARDWARE_ID)
+                .putIfAbsent("hardwareId", AWS_EC2_MEDIUM_HARDWARE_ID)
                 .putIfAbsent("inboundPorts", ImmutableList.of(22))
                 .build());
     }



[7/7] incubator-brooklyn git commit: This closes #1034

Posted by al...@apache.org.
This closes #1034


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

Branch: refs/heads/master
Commit: 7c649d73d3fbc671b98b6f0314dabb8a04b64c97
Parents: 462e5ea f34e7e6
Author: Aled Sage <al...@gmail.com>
Authored: Tue Nov 17 18:28:25 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 17 18:28:25 2015 +0000

----------------------------------------------------------------------
 .../location/ssh/SshMachineLocation.java        |   2 +-
 .../location/jclouds/JcloudsLocation.java       | 226 +++++++++++--------
 .../brooklyn/location/jclouds/JcloudsUtil.java  |  50 +++-
 .../jclouds/AbstractJcloudsLiveTest.java        |   4 +
 .../location/jclouds/JcloudsLoginLiveTest.java  | 126 +++++++----
 .../apache/brooklyn/util/net/Networking.java    |   7 +
 .../util/net/ReachableSocketFinder.java         | 154 +++++++++++++
 .../brooklyn/util/net/NetworkingUtilsTest.java  |   9 +-
 .../util/net/ReachableSocketFinderTest.java     | 165 ++++++++++++++
 9 files changed, 590 insertions(+), 153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7c649d73/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
----------------------------------------------------------------------