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/07/02 18:22:44 UTC

[1/7] incubator-brooklyn git commit: Adds PRIVATE_ADDRESSES config to SshMachineLocation

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 5d60b2c81 -> da6d887f9


Adds PRIVATE_ADDRESSES config to SshMachineLocation

- and same to WinRmMachineLocation


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

Branch: refs/heads/master
Commit: 7b866a9ecf5aa87798c9130ade2e865a35545d88
Parents: 32960be
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jun 26 14:36:18 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Jun 26 15:33:07 2015 +0100

----------------------------------------------------------------------
 .../location/basic/SshMachineLocation.java      | 11 ++++-
 .../location/basic/WinRmMachineLocation.java    | 11 ++++-
 .../location/basic/SshMachineLocationTest.java  | 10 +++++
 .../basic/WinRmMachineLocationTest.java         | 44 ++++++++++++++++++++
 4 files changed, 73 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7b866a9e/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
index a249305..68f224d 100644
--- a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
@@ -21,6 +21,7 @@ package brooklyn.location.basic;
 import static brooklyn.util.GroovyJavaMethods.truth;
 
 import com.google.common.annotations.Beta;
+
 import groovy.lang.Closure;
 
 import java.io.Closeable;
@@ -114,6 +115,7 @@ import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.net.HostAndPort;
+import com.google.common.reflect.TypeToken;
 
 /**
  * Operations on a machine that is accessible via ssh.
@@ -145,6 +147,12 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
     public static final ConfigKey<Boolean> DETECT_MACHINE_DETAILS = ConfigKeys.newBooleanConfigKey("detectMachineDetails",
             "Attempt to detect machine details automatically. Works with SSH-accessible Linux instances.", true);
 
+    public static final ConfigKey<Iterable<String>> PRIVATE_ADDRESSES = ConfigKeys.newConfigKey(
+            new TypeToken<Iterable<String>>() {},
+            "privateAddresses",
+            "Private addresses of this machine, e.g. those within the private network", 
+            null);
+
     @SetFromFlag
     protected String user;
 
@@ -460,7 +468,8 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
     
     @Override
     public Set<String> getPrivateAddresses() {
-        return ImmutableSet.of();
+        Iterable<String> result = getConfig(PRIVATE_ADDRESSES);
+        return (result == null) ? ImmutableSet.<String>of() : ImmutableSet.copyOf(result);
     }
 
     public HostAndPort getSshHostAndPort() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7b866a9e/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java b/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
index 36c0360..54ee63a 100644
--- a/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
@@ -53,7 +53,7 @@ import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
-import com.google.common.net.HostAndPort;
+import com.google.common.reflect.TypeToken;
 
 public class WinRmMachineLocation extends AbstractLocation implements MachineLocation {
 
@@ -92,6 +92,12 @@ public class WinRmMachineLocation extends AbstractLocation implements MachineLoc
             "Max number of times to attempt WinRM operations", 
             10);
 
+    public static final ConfigKey<Iterable<String>> PRIVATE_ADDRESSES = ConfigKeys.newConfigKey(
+            new TypeToken<Iterable<String>>() {},
+            "privateAddresses",
+            "Private addresses of this machine, e.g. those within the private network", 
+            null);
+
     @Override
     public InetAddress getAddress() {
         return getConfig(ADDRESS);
@@ -128,7 +134,8 @@ public class WinRmMachineLocation extends AbstractLocation implements MachineLoc
     
     @Override
     public Set<String> getPrivateAddresses() {
-        return ImmutableSet.of();
+        Iterable<String> result = getConfig(PRIVATE_ADDRESSES);
+        return (result == null) ? ImmutableSet.<String>of() : ImmutableSet.copyOf(result);
     }
 
     public WinRmToolResponse executeScript(String script) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7b866a9e/core/src/test/java/brooklyn/location/basic/SshMachineLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/location/basic/SshMachineLocationTest.java b/core/src/test/java/brooklyn/location/basic/SshMachineLocationTest.java
index 31d48f2..61dc65e 100644
--- a/core/src/test/java/brooklyn/location/basic/SshMachineLocationTest.java
+++ b/core/src/test/java/brooklyn/location/basic/SshMachineLocationTest.java
@@ -122,6 +122,16 @@ public class SshMachineLocationTest {
         assertSame(host2.getMachineDetails(), machineDetails);
     }
     
+    @Test
+    public void testConfigurePrivateAddresses() throws Exception {
+        SshMachineLocation host2 = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
+                .configure("address", Networking.getLocalHost())
+                .configure(SshMachineLocation.PRIVATE_ADDRESSES, ImmutableList.of("1.2.3.4"))
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true));
+
+        assertEquals(host2.getPrivateAddresses(), ImmutableSet.of("1.2.3.4"));
+    }
+    
     // Wow, this is hard to test (until I accepted creating the entity + effector)! Code smell?
     // Need to call getMachineDetails in a DynamicSequentialTask so that the "innessential" takes effect,
     // to not fail its caller. But to get one of those outside of an effector is non-obvious.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7b866a9e/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationTest.java b/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationTest.java
new file mode 100644
index 0000000..de9db6c
--- /dev/null
+++ b/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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 brooklyn.location.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.entity.basic.BrooklynConfigKeys;
+import brooklyn.location.LocationSpec;
+import brooklyn.util.net.Networking;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class WinRmMachineLocationTest extends BrooklynAppUnitTestSupport {
+
+    @Test
+    public void testConfigurePrivateAddresses() throws Exception {
+        WinRmMachineLocation host = mgmt.getLocationManager().createLocation(LocationSpec.create(WinRmMachineLocation.class)
+                .configure("address", Networking.getLocalHost())
+                .configure(WinRmMachineLocation.PRIVATE_ADDRESSES, ImmutableList.of("1.2.3.4"))
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true));
+
+        assertEquals(host.getPrivateAddresses(), ImmutableSet.of("1.2.3.4"));
+    }
+}


[2/7] incubator-brooklyn git commit: Adds MACHINE_CHOOSER to FixedListMachineProvisioningLocation

Posted by al...@apache.org.
Adds MACHINE_CHOOSER to FixedListMachineProvisioningLocation
    
Allows a function to be supplied, to choose from the set of available
machines when obtain() is called.


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

Branch: refs/heads/master
Commit: 64adbb7f3b5198f2f79a13890597f0561ec0637e
Parents: 09f3cc8
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jun 26 14:45:54 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Jun 26 15:33:08 2015 +0100

----------------------------------------------------------------------
 .../FixedListMachineProvisioningLocation.java   |  26 ++-
 ...ixedListMachineProvisioningLocationTest.java | 165 +++++++++++++++++++
 .../util/collections/CollectionFunctionals.java |  17 ++
 .../collections/CollectionFunctionalsTest.java  |   6 +
 4 files changed, 213 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64adbb7f/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
index 411d12a..d8aad46 100644
--- a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
@@ -31,12 +31,15 @@ import java.util.Set;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
 import brooklyn.location.MachineLocation;
 import brooklyn.location.MachineProvisioningLocation;
 import brooklyn.location.NoMachinesAvailableException;
 import brooklyn.management.LocationManager;
+import brooklyn.util.collections.CollectionFunctionals;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.flags.SetFromFlag;
@@ -44,12 +47,14 @@ import brooklyn.util.stream.Streams;
 import brooklyn.util.text.WildcardGlobs;
 import brooklyn.util.text.WildcardGlobs.PhraseTreatment;
 
+import com.google.common.base.Function;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
 
 /**
  * A provisioner of {@link MachineLocation}s which takes a list of machines it can connect to.
@@ -69,6 +74,13 @@ implements MachineProvisioningLocation<T>, Closeable {
     
     private static final Logger log = LoggerFactory.getLogger(FixedListMachineProvisioningLocation.class);
     
+    public static final ConfigKey<Function<Iterable<? extends MachineLocation>, MachineLocation>> MACHINE_CHOOSER =
+            ConfigKeys.newConfigKey(
+                    new TypeToken<Function<Iterable<? extends MachineLocation>, MachineLocation>>() {}, 
+                    "byon.machineChooser",
+                    "For choosing which of the possible machines is chosen and returned by obtain()",
+                    CollectionFunctionals.<MachineLocation>firstElement());
+    
     private final Object lock = new Object();
     
     @SetFromFlag
@@ -226,6 +238,7 @@ implements MachineProvisioningLocation<T>, Closeable {
     public T obtain(Map<?,?> flags) throws NoMachinesAvailableException {
         T machine;
         T desiredMachine = (T) flags.get("desiredMachine");
+        Function<Iterable<? extends MachineLocation>, MachineLocation> chooser = getConfigPreferringOverridden(MACHINE_CHOOSER, flags);
         
         synchronized (lock) {
             Set<T> a = getAvailable();
@@ -245,7 +258,10 @@ implements MachineProvisioningLocation<T>, Closeable {
                             (inUse.contains(desiredMachine) ? "machine in use" : "machine unknown"));
                 }
             } else {
-                machine = a.iterator().next();
+                machine = (T) chooser.apply(a);
+                if (!a.contains(machine)) {
+                    throw new IllegalStateException("Machine chooser attempted to choose '"+machine+"' from outside the available set, in "+this);
+                }
             }
             inUse.add(machine);
         }
@@ -270,6 +286,14 @@ implements MachineProvisioningLocation<T>, Closeable {
         return Maps.<String,Object>newLinkedHashMap();
     }
     
+    @SuppressWarnings("unchecked")
+    private <K> K getConfigPreferringOverridden(ConfigKey<K> key, Map<?,?> overrides) {
+        K result = (K) overrides.get(key);
+        if (result == null) result = (K) overrides.get(key.getName());
+        if (result == null) result = getConfig(key);
+        return result;
+    }
+
     /**
      * Facilitates fluent/programmatic style for constructing a fixed pool of machines.
      * <pre>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64adbb7f/core/src/test/java/brooklyn/location/basic/FixedListMachineProvisioningLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/location/basic/FixedListMachineProvisioningLocationTest.java b/core/src/test/java/brooklyn/location/basic/FixedListMachineProvisioningLocationTest.java
index 72ec433..b0edf8c 100644
--- a/core/src/test/java/brooklyn/location/basic/FixedListMachineProvisioningLocationTest.java
+++ b/core/src/test/java/brooklyn/location/basic/FixedListMachineProvisioningLocationTest.java
@@ -24,7 +24,11 @@ import static org.testng.Assert.fail;
 import java.net.Inet4Address;
 import java.net.UnknownHostException;
 import java.util.List;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
@@ -32,6 +36,7 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.location.LocationSpec;
+import brooklyn.location.MachineLocation;
 import brooklyn.location.NoMachinesAvailableException;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.test.entity.LocalManagementContextForTests;
@@ -40,13 +45,20 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.net.Networking;
 import brooklyn.util.stream.Streams;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 
 /**
  * Provisions {@link SshMachineLocation}s in a specific location from a list of known machines
  */
 public class FixedListMachineProvisioningLocationTest {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(FixedListMachineProvisioningLocationTest.class);
+
     SshMachineLocation machine;
     LocalManagementContext mgmt;
     FixedListMachineProvisioningLocation<SshMachineLocation> provisioner;
@@ -318,6 +330,159 @@ public class FixedListMachineProvisioningLocationTest {
         }
     }
     
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testMachineChooser() throws Exception {
+        List<SshMachineLocation> machines = Lists.newArrayList();
+        for (int i = 0; i < 10; i++) {
+            machines.add(mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class).configure("address", Networking.getInetAddressWithFixedName("1.1.1."+i))));
+        }
+        final List<SshMachineLocation> desiredOrder = randomized(machines);
+        
+        Function<Iterable<? extends MachineLocation>, MachineLocation> chooser = new Function<Iterable<? extends MachineLocation>, MachineLocation>() {
+            @Override public MachineLocation apply(Iterable<? extends MachineLocation> input) {
+                for (SshMachineLocation contender : desiredOrder) {
+                    if (Iterables.contains(input, contender)) {
+                        return contender;
+                    }
+                }
+                Assert.fail("No intersection of input="+input+" and desiredOrder="+desiredOrder);
+                return null; // unreachable code
+            }
+        };
+        provisioner2 = mgmt.getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class)
+                .configure("machines", machines)
+                .configure(FixedListMachineProvisioningLocation.MACHINE_CHOOSER, chooser));
+
+        List<SshMachineLocation> result = Lists.newArrayList();
+        for (int i = 0; i < machines.size(); i++) {
+            result.add(provisioner2.obtain());
+        }
+        assertEquals(result, desiredOrder, "result="+result+"; desired="+desiredOrder);
+        LOG.debug("chooser's desiredOrder="+desiredOrder);
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testMachineChooserPassedToObtain() throws Exception {
+        List<SshMachineLocation> machines = Lists.newArrayList();
+        for (int i = 0; i < 10; i++) {
+            machines.add(mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class).configure("address", Networking.getInetAddressWithFixedName("1.1.1."+i))));
+        }
+        final List<SshMachineLocation> desiredOrder = randomized(machines);
+        
+        Function<Iterable<? extends MachineLocation>, MachineLocation> chooser = new Function<Iterable<? extends MachineLocation>, MachineLocation>() {
+            @Override public MachineLocation apply(Iterable<? extends MachineLocation> input) {
+                for (SshMachineLocation contender : desiredOrder) {
+                    if (Iterables.contains(input, contender)) {
+                        return contender;
+                    }
+                }
+                Assert.fail("No intersection of input="+input+" and desiredOrder="+desiredOrder);
+                return null; // unreachable code
+            }
+        };
+        provisioner2 = mgmt.getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class)
+                .configure("machines", machines));
+
+        List<SshMachineLocation> result = Lists.newArrayList();
+        for (int i = 0; i < machines.size(); i++) {
+            result.add(provisioner2.obtain(ImmutableMap.of(FixedListMachineProvisioningLocation.MACHINE_CHOOSER, chooser)));
+        }
+        assertEquals(result, desiredOrder, "result="+result+"; desired="+desiredOrder);
+        LOG.debug("chooser's desiredOrder="+desiredOrder);
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testMachineChooserNotCalledWhenNoMachines() throws Exception {
+        List<SshMachineLocation> machines = ImmutableList.of(
+                mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class).configure("address", Networking.getInetAddressWithFixedName("1.1.1.1"))));
+        final AtomicInteger callCount = new AtomicInteger();
+        
+        Function<Iterable<? extends MachineLocation>, MachineLocation> chooser = new Function<Iterable<? extends MachineLocation>, MachineLocation>() {
+            @Override public MachineLocation apply(Iterable<? extends MachineLocation> input) {
+                callCount.incrementAndGet();
+                return Iterables.get(input, 0);
+            }
+        };
+        provisioner2 = mgmt.getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class)
+                .configure("machines", machines)
+                .configure(FixedListMachineProvisioningLocation.MACHINE_CHOOSER, chooser));
+        provisioner2.obtain();
+
+        // When no machines available should fail gracefully, without asking the "chooser"
+        try {
+            provisioner2.obtain();
+            fail("Expected "+NoMachinesAvailableException.class.getSimpleName());
+        } catch (NoMachinesAvailableException e) {
+            // Pass; sensible exception
+        }
+        assertEquals(callCount.get(), 1);
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testFailsWhenMachineChooserReturnsAlreadyAllocatedMachine() throws Exception {
+        final SshMachineLocation machine1 = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class).configure("address", Networking.getInetAddressWithFixedName("1.1.1.1")));
+        final SshMachineLocation machine2 = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class).configure("address", Networking.getInetAddressWithFixedName("1.1.1.2")));
+        List<SshMachineLocation> machines = ImmutableList.of(machine1, machine2);
+        
+        Function<Iterable<? extends MachineLocation>, MachineLocation> chooser = new Function<Iterable<? extends MachineLocation>, MachineLocation>() {
+            @Override public MachineLocation apply(Iterable<? extends MachineLocation> input) {
+                return machine1;
+            }
+        };
+        provisioner2 = mgmt.getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class)
+                .configure("machines", machines)
+                .configure(FixedListMachineProvisioningLocation.MACHINE_CHOOSER, chooser));
+        provisioner2.obtain();
+
+        // Should fail when tries to return same machine for a second time
+        try {
+            provisioner2.obtain();
+            fail("Expected "+IllegalStateException.class.getSimpleName());
+        } catch (IllegalStateException e) {
+            if (!e.toString().contains("Machine chooser attempted to choose ")) throw e;
+        }
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testFailsWhenMachineChooserReturnsInvalidMachine() throws Exception {
+        final SshMachineLocation machine1 = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class).configure("address", Networking.getInetAddressWithFixedName("1.1.1.1")));
+        final SshMachineLocation machineOther = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class).configure("address", Networking.getInetAddressWithFixedName("2.2.2.1")));
+        List<SshMachineLocation> machines = ImmutableList.of(machine1);
+        
+        Function<Iterable<? extends MachineLocation>, MachineLocation> chooser = new Function<Iterable<? extends MachineLocation>, MachineLocation>() {
+            @Override public MachineLocation apply(Iterable<? extends MachineLocation> input) {
+                return machineOther;
+            }
+        };
+        provisioner2 = mgmt.getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class)
+                .configure("machines", machines)
+                .configure(FixedListMachineProvisioningLocation.MACHINE_CHOOSER, chooser));
+
+        // Call when no machines available should fail gracefully, without asking the "chooser"
+        try {
+            provisioner2.obtain();
+            fail("Expected "+IllegalStateException.class.getSimpleName());
+        } catch (IllegalStateException e) {
+            if (!e.toString().contains("Machine chooser attempted to choose ")) throw e;
+        }
+    }
+
+    private static <T> List<T> randomized(Iterable<T> list) {
+        // TODO inefficient implementation, but don't care for small tests
+        Random random = new Random();
+        List<T> result = Lists.newLinkedList();
+        for (T element : list) {
+            int index = (result.isEmpty() ? 0 : random.nextInt(result.size()));
+            result.add(index, element);
+        }
+        return result;
+    }
+    
     private static void assertUserAndHost(SshMachineLocation l, String user, String host) {
         assertEquals(l.getUser(), user);
         assertEquals(l.getAddress().getHostAddress(), host);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64adbb7f/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java b/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
index 9ac7202..4208fe3 100644
--- a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
+++ b/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
@@ -106,6 +106,23 @@ public class CollectionFunctionals {
         return new SizeFunction(valueIfInputNull);
     }
 
+    public static final class FirstElementFunction<T> implements Function<Iterable<? extends T>, T> {
+        private FirstElementFunction() {
+        }
+
+        @Override
+        public T apply(Iterable<? extends T> input) {
+            if (input==null) return null;
+            return Iterables.get(input, 0);
+        }
+
+        @Override public String toString() { return "firstElementFunction"; }
+    }
+
+    public static <T> Function<Iterable<? extends T>, T> firstElement() {
+        return new FirstElementFunction<T>();
+    }
+    
     public static <K> Function<Map<K,?>,Set<K>> keys() {
         return new KeysOfMapFunction<K>();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64adbb7f/utils/common/src/test/java/brooklyn/util/collections/CollectionFunctionalsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/brooklyn/util/collections/CollectionFunctionalsTest.java b/utils/common/src/test/java/brooklyn/util/collections/CollectionFunctionalsTest.java
index 6611d9b..059fa5f 100644
--- a/utils/common/src/test/java/brooklyn/util/collections/CollectionFunctionalsTest.java
+++ b/utils/common/src/test/java/brooklyn/util/collections/CollectionFunctionalsTest.java
@@ -48,4 +48,10 @@ public class CollectionFunctionalsTest {
         Assert.assertEquals(CollectionFunctionals.mapSize(-1).apply(null), (Integer)(-1));
     }
 
+    @Test
+    public void testFirstElement() {
+        Assert.assertEquals(CollectionFunctionals.firstElement().apply(null), null);
+        Assert.assertEquals(CollectionFunctionals.firstElement().apply(ImmutableList.of("a")), "a");
+        Assert.assertEquals(CollectionFunctionals.firstElement().apply(ImmutableList.of("a", "b", "c")), "a");
+    }
 }


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

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


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

Branch: refs/heads/master
Commit: da6d887f9dac79b54001ee044841ac519e713bc5
Parents: 5d60b2c 43beb54
Author: Aled Sage <al...@gmail.com>
Authored: Thu Jul 2 17:22:29 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Jul 2 17:22:29 2015 +0100

----------------------------------------------------------------------
 .../location/basic/ByonLocationResolver.java    | 124 ++++++++++--
 .../FixedListMachineProvisioningLocation.java   |  26 ++-
 .../location/basic/SshMachineLocation.java      |  11 +-
 .../location/basic/WinRmMachineLocation.java    |  11 +-
 .../basic/ByonLocationResolverTest.java         |  68 +++----
 ...ixedListMachineProvisioningLocationTest.java | 165 ++++++++++++++++
 .../location/basic/SshMachineLocationTest.java  |  10 +
 docs/guide/ops/locations/index.md               |  25 +++
 .../entity/basic/SoftwareProcessEntityTest.java |   3 +
 .../basic/WinRmMachineLocationTest.java         |  44 +++++
 .../creation/BrooklynYamlLocationResolver.java  |   4 +-
 .../camp/brooklyn/ByonLocationsYamlTest.java    | 193 +++++++++++++++++++
 .../util/collections/CollectionFunctionals.java |  17 ++
 .../brooklyn/util/net/UserAndHostAndPort.java   |   4 +
 .../collections/CollectionFunctionalsTest.java  |   6 +
 15 files changed, 650 insertions(+), 61 deletions(-)
----------------------------------------------------------------------



[5/7] incubator-brooklyn git commit: Fix SoftwareProcessEntityTest.MyService

Posted by al...@apache.org.
Fix SoftwareProcessEntityTest.MyService

- Set the SERVICE_STATE_ACTUAL, rather than leaving the attribute
  always saying Lifecycle.CREATED


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

Branch: refs/heads/master
Commit: 7fd92be51e3cd1e791d4a7060610399d77ac1713
Parents: 4e625b9
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jun 26 14:47:02 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Jul 2 17:20:19 2015 +0100

----------------------------------------------------------------------
 .../java/brooklyn/entity/basic/SoftwareProcessEntityTest.java     | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7fd92be5/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
index 55deb4e..70bc416 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
@@ -507,6 +507,7 @@ public class SoftwareProcessEntityTest extends BrooklynAppUnitTestSupport {
             events.add("stop");
             launched = false;
             entity.setAttribute(Startable.SERVICE_UP, false);
+            entity.setAttribute(SoftwareProcess.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED);
         }
     
         @Override
@@ -519,6 +520,7 @@ public class SoftwareProcessEntityTest extends BrooklynAppUnitTestSupport {
         @Override
         public void install() {
             events.add("install");
+            entity.setAttribute(SoftwareProcess.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
         }
     
         @Override
@@ -531,6 +533,7 @@ public class SoftwareProcessEntityTest extends BrooklynAppUnitTestSupport {
             events.add("launch");
             launched = true;
             entity.setAttribute(Startable.SERVICE_UP, true);
+            entity.setAttribute(SoftwareProcess.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
         }
 
         @Override


[6/7] incubator-brooklyn git commit: BrooklynYamlLocationResolver: don’t swallow exception

Posted by al...@apache.org.
BrooklynYamlLocationResolver: don’t swallow exception

Previously inresolveLocation() we were just getting the “collapseText”
of the exception in the thrown toString, rather than having the
cause set. This meant that the underlying cause (e.g. of an NPE etc)
was never being logged.

Instead, set the cause when throwing the the IllegalStateException,
as well as having the nice 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/43beb54c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/43beb54c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/43beb54c

Branch: refs/heads/master
Commit: 43beb54c29a093e0c96268c1a9fd6ca16101a231
Parents: 7fd92be
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jun 26 14:49:02 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Jul 2 17:20:19 2015 +0100

----------------------------------------------------------------------
 .../camp/brooklyn/spi/creation/BrooklynYamlLocationResolver.java | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/43beb54c/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlLocationResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlLocationResolver.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlLocationResolver.java
index d9f7a65..3495687 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlLocationResolver.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlLocationResolver.java
@@ -134,7 +134,9 @@ public class BrooklynYamlLocationResolver {
         
         Maybe<Location> l = mgmt.getLocationRegistry().resolve(spec, null, flags);
         if (l.isPresent()) return l.get();
+        
+        RuntimeException exception = ((Absent<?>)l).getException();
         throw new IllegalStateException("Illegal parameter for 'location' ("+spec+"); not resolvable: "+
-            Exceptions.collapseText( ((Absent<?>)l).getException() ));
+            Exceptions.collapseText( exception ), exception);
     }
 }


[4/7] incubator-brooklyn git commit: ByonLocationResolver: support complex machine config

Posted by al...@apache.org.
ByonLocationResolver: support complex machine config

Adds support for each machine in BYON having more complex config,
such as each having its own set of config options (where each machine
has a map of config values).


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

Branch: refs/heads/master
Commit: 4e625b9bf4ca6d1f847944b338be0032abf5646c
Parents: 64adbb7
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jun 26 14:46:31 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Jul 2 17:20:18 2015 +0100

----------------------------------------------------------------------
 .../location/basic/ByonLocationResolver.java    | 124 ++++++++++--
 docs/guide/ops/locations/index.md               |  25 +++
 .../camp/brooklyn/ByonLocationsYamlTest.java    | 193 +++++++++++++++++++
 .../brooklyn/util/net/UserAndHostAndPort.java   |   4 +
 4 files changed, 326 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4e625b9b/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java b/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java
index 2ce37d2..067af47 100644
--- a/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java
+++ b/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.location.basic;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
 import java.net.InetAddress;
 import java.util.List;
 import java.util.Map;
@@ -27,18 +29,23 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Sanitizer;
 import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
 import brooklyn.location.MachineLocation;
 import brooklyn.management.internal.LocalLocationManager;
-import brooklyn.util.JavaGroovyEquivalents;
+import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
+import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.net.UserAndHostAndPort;
 import brooklyn.util.text.WildcardGlobs;
 import brooklyn.util.text.WildcardGlobs.PhraseTreatment;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.net.HostAndPort;
 
 /**
  * Examples of valid specs:
@@ -86,7 +93,8 @@ public class ByonLocationResolver extends AbstractLocationResolver {
 
         Object hosts = config.getStringKey("hosts");
         config.remove("hosts");
-        String user = (String)config.getStringKey("user");
+        String user = (String) config.getStringKey("user");
+        Integer port = (Integer) TypeCoercions.coerce(config.getStringKey("port"), Integer.class);
         Class<? extends MachineLocation> locationClass = OS_TO_MACHINE_LOCATION_TYPE.get(config.get(OS_FAMILY));
         
         List<String> hostAddresses;
@@ -108,25 +116,17 @@ public class ByonLocationResolver extends AbstractLocationResolver {
         }
         
         List<MachineLocation> machines = Lists.newArrayList();
-        for (String host : hostAddresses) {
-            String userHere = user;
-            String hostHere = host;
-            if (host.contains("@")) {
-                userHere = host.substring(0, host.indexOf("@"));
-                hostHere = host.substring(host.indexOf("@")+1);
-            }
-            try {
-                InetAddress.getByName(hostHere.trim());
-            } catch (Exception e) {
-                throw new IllegalArgumentException("Invalid host '"+hostHere+"' specified in '"+spec+"': "+e);
-            }
-            LocationSpec<? extends MachineLocation> locationSpec = LocationSpec.create(locationClass)
-                    .configure("address", hostHere.trim())
-                    .configureIfNotNull(LocalLocationManager.CREATE_UNMANAGED, config.get(LocalLocationManager.CREATE_UNMANAGED));
-            if (JavaGroovyEquivalents.groovyTruth(userHere)) {
-                locationSpec.configure("user", userHere.trim());
+        for (Object host : hostAddresses) {
+            LocationSpec<? extends MachineLocation> machineSpec;
+            if (host instanceof String) {
+                machineSpec = parseMachine((String)host, locationClass, MutableMap.of("user", user, "port", port), spec);
+            } else if (host instanceof Map) {
+                machineSpec = parseMachine((Map<String, ?>)host, locationClass, MutableMap.of("user", user, "port", port), spec);
+            } else {
+                throw new IllegalArgumentException("Expected machine to be String or Map, but was "+host.getClass().getName()+" ("+host+")");
             }
-            MachineLocation machine = managementContext.getLocationManager().createLocation(locationSpec);
+            machineSpec.configureIfNotNull(LocalLocationManager.CREATE_UNMANAGED, config.get(LocalLocationManager.CREATE_UNMANAGED));
+            MachineLocation machine = managementContext.getLocationManager().createLocation(machineSpec);
             machines.add(machine);
         }
         
@@ -134,4 +134,88 @@ public class ByonLocationResolver extends AbstractLocationResolver {
 
         return config;
     }
+    
+    protected LocationSpec<? extends MachineLocation> parseMachine(Map<String, ?> vals, Class<? extends MachineLocation> locationClass, Map<String, ?> defaults, String specForErrMsg) {
+        Map<String, Object> valSanitized = Sanitizer.sanitize(vals);
+        Map<String, Object> machineConfig = MutableMap.copyOf(vals);
+        
+        String osfamily = (String) machineConfig.remove(OS_FAMILY.getName());
+        String ssh = (String) machineConfig.remove("ssh");
+        String winrm = (String) machineConfig.remove("winrm");
+        checkArgument(ssh != null ^ winrm != null, "Must specify exactly one of 'ssh' or 'winrm' for machine: %s", valSanitized);
+        
+        UserAndHostAndPort userAndHostAndPort;
+        if (ssh != null) {
+            userAndHostAndPort = parseUserAndHostAndPort((String)ssh);
+        } else {
+            userAndHostAndPort = parseUserAndHostAndPort((String)winrm);
+        }
+        
+        String host = userAndHostAndPort.getHostAndPort().getHostText().trim();
+        machineConfig.put("address", host);
+        try {
+            InetAddress.getByName(host);
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Invalid host '"+host+"' specified in '"+specForErrMsg+"': "+e);
+        }
+
+        if (userAndHostAndPort.getUser() != null) {
+            checkArgument(!vals.containsKey("user"), "Must not specify user twice for machine: %s", valSanitized);
+            machineConfig.put("user", userAndHostAndPort.getUser());
+        }
+        if (userAndHostAndPort.getHostAndPort().hasPort()) {
+            checkArgument(!vals.containsKey("port"), "Must not specify port twice for machine: %s", valSanitized);
+            machineConfig.put("port", userAndHostAndPort.getHostAndPort().getPort());
+        }
+        for (Map.Entry<String, ?> entry : defaults.entrySet()) {
+            if (!machineConfig.containsKey(entry.getKey())) {
+                machineConfig.put(entry.getKey(), entry.getValue());
+            }
+        }
+        
+        Class<? extends MachineLocation> locationClassHere = locationClass;
+        if (osfamily != null) {
+            locationClassHere = OS_TO_MACHINE_LOCATION_TYPE.get(osfamily);
+        }
+
+        return LocationSpec.create(locationClassHere).configure(machineConfig);
+    }
+
+    protected LocationSpec<? extends MachineLocation> parseMachine(String val, Class<? extends MachineLocation> locationClass, Map<String, ?> defaults, String specForErrMsg) {
+        Map<String, Object> machineConfig = Maps.newLinkedHashMap();
+
+        UserAndHostAndPort userAndHostAndPort = parseUserAndHostAndPort(val);
+        
+        String host = userAndHostAndPort.getHostAndPort().getHostText().trim();
+        machineConfig.put("address", host);
+        try {
+            InetAddress.getByName(host.trim());
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Invalid host '"+host+"' specified in '"+specForErrMsg+"': "+e);
+        }
+        
+        if (userAndHostAndPort.getUser() != null) {
+            machineConfig.put("user", userAndHostAndPort.getUser());
+        }
+        if (userAndHostAndPort.getHostAndPort().hasPort()) {
+            machineConfig.put("port", userAndHostAndPort.getHostAndPort().getPort());
+        }
+        for (Map.Entry<String, ?> entry : defaults.entrySet()) {
+            if (!machineConfig.containsKey(entry.getKey())) {
+                machineConfig.put(entry.getKey(), entry.getValue());
+            }
+        }
+
+        return LocationSpec.create(locationClass).configure(machineConfig);
+    }
+    
+    private UserAndHostAndPort parseUserAndHostAndPort(String val) {
+        String userPart = null;
+        String hostPart = val;
+        if (val.contains("@")) {
+            userPart = val.substring(0, val.indexOf("@"));
+            hostPart = val.substring(val.indexOf("@")+1);
+        }
+        return UserAndHostAndPort.fromParts(userPart, HostAndPort.fromString(hostPart));
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4e625b9b/docs/guide/ops/locations/index.md
----------------------------------------------------------------------
diff --git a/docs/guide/ops/locations/index.md b/docs/guide/ops/locations/index.md
index 6fc5b4b..28a238a 100644
--- a/docs/guide/ops/locations/index.md
+++ b/docs/guide/ops/locations/index.md
@@ -401,6 +401,31 @@ brooklyn.location.named.On-Prem\ Iron\ Example.privateKeyFile=~/.ssh/produser_id
 brooklyn.location.named.On-Prem\ Iron\ Example.privateKeyPassphrase=s3cr3tpassphrase
 {% endhighlight %}
 
+For more complex host configuration, one can define custom config values per machine. In the example 
+below, there will be two machines. The first will be a machine reachable on
+`ssh -i ~/.ssh/brooklyn.pem -p 8022 myuser@50.51.52.53`. The second is a windows machine, reachable 
+over WinRM. Each machine has also has a private address (e.g. for within a private network).
+
+{% highlight yaml %}
+location:
+  byon:
+    hosts:
+    - ssh: 50.51.52.53:8022
+      privateAddresses: [10.0.0.1]
+      privateKeyFile: ~/.ssh/brooklyn.pem
+      user: myuser
+    - winrm: 50.51.52.54:8985
+      privateAddresses: [10.0.0.2]
+      password: mypassword
+      user: myuser
+      osfamily: windows
+{% endhighlight %}
+
+The BYON location also supports a machine chooser, using the config key `byon.machineChooser`. 
+This allows one to plugin logic to choose from the set of available machines in the pool. For
+example, additional config could be supplied for each machine. This could be used (during the call
+to `location.obtain()`) to find the config that matches the requirements of the entity being
+provisioned. See `brooklyn.location.basic.FixedListMachineProvisioningLocation.MACHINE_CHOOSER`.
 
 
 ### Other Location Topics

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4e625b9b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java
new file mode 100644
index 0000000..5ce0dac
--- /dev/null
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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 io.brooklyn.camp.brooklyn;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.StringReader;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.location.MachineLocation;
+import brooklyn.location.basic.FixedListMachineProvisioningLocation;
+import brooklyn.location.basic.LocationPredicates;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.location.basic.WinRmMachineLocation;
+import brooklyn.util.net.UserAndHostAndPort;
+
+import com.google.api.client.repackaged.com.google.common.base.Joiner;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+public class ByonLocationsYamlTest extends AbstractYamlTest {
+    private static final Logger log = LoggerFactory.getLogger(ByonLocationsYamlTest.class);
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testByonSpec() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                "location: byon(user=myuser,mykey=myval,hosts=\"1.1.1.1\")",
+                "services:",
+                "- serviceType: brooklyn.entity.basic.BasicApplication");
+        
+        Entity app = createStartWaitAndLogApplication(new StringReader(yaml));
+        FixedListMachineProvisioningLocation<SshMachineLocation> loc = (FixedListMachineProvisioningLocation<SshMachineLocation>) Iterables.get(app.getLocations(), 0);
+        
+        Set<SshMachineLocation> machines = loc.getAvailable();
+        SshMachineLocation machine = Iterables.getOnlyElement(machines);
+        assertMachine(machine, UserAndHostAndPort.fromParts("myuser", "1.1.1.1",  22), ImmutableMap.of("mykey", "myval"));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testByonMachine() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                "location:",
+                "  byon:",
+                "    hosts:",
+                "    - ssh: 1.1.1.1:8022",
+                "      privateAddresses: [10.0.0.1]",
+                "      password: mypassword",
+                "      user: myuser",
+                "      mykey: myval",
+                "services:",
+                "- serviceType: brooklyn.entity.basic.BasicApplication");
+        
+        Entity app = createStartWaitAndLogApplication(new StringReader(yaml));
+        FixedListMachineProvisioningLocation<SshMachineLocation> loc = (FixedListMachineProvisioningLocation<SshMachineLocation>) Iterables.get(app.getLocations(), 0);
+        
+        Set<SshMachineLocation> machines = loc.getAvailable();
+        SshMachineLocation machine = Iterables.getOnlyElement(machines);
+        assertMachine(machine, UserAndHostAndPort.fromParts("myuser", "1.1.1.1",  8022), ImmutableMap.of(
+                SshMachineLocation.PASSWORD.getName(), "mypassword",
+                "mykey", "myval"));
+        assertEquals(machine.getPrivateAddresses(), ImmutableSet.of("10.0.0.1"));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testByonWindowsMachine() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                "location:",
+                "  byon:",
+                "    hosts:",
+                "    - winrm: 1.1.1.1:8985",
+                "      privateAddresses: [10.0.0.1]",
+                "      password: mypassword",
+                "      user: myuser",
+                "      mykey: myval",
+                "      osfamily: windows",
+                "services:",
+                "- serviceType: brooklyn.entity.basic.BasicApplication");
+        
+        Entity app = createStartWaitAndLogApplication(new StringReader(yaml));
+        FixedListMachineProvisioningLocation<WinRmMachineLocation> loc = (FixedListMachineProvisioningLocation<WinRmMachineLocation>) Iterables.get(app.getLocations(), 0);
+        
+        Set<WinRmMachineLocation> machines = loc.getAvailable();
+        WinRmMachineLocation machine = Iterables.getOnlyElement(machines);
+        assertMachine(machine, UserAndHostAndPort.fromParts("myuser", "1.1.1.1",  8985), ImmutableMap.of(
+                SshMachineLocation.PASSWORD.getName(), "mypassword",
+                "mykey", "myval"));
+        assertEquals(machine.getPrivateAddresses(), ImmutableSet.of("10.0.0.1"));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testByonMultiMachine() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                "location:",
+                "  byon:",
+                "    hosts:",
+                "    - ssh: 1.1.1.1:8022",
+                "      privateAddresses: [10.0.0.1]",
+                "      password: mypassword",
+                "      user: myuser",
+                "      mykey: myval1",
+                "    - ssh: 1.1.1.2:8022",
+                "      privateAddresses: [10.0.0.2]",
+                "      password: mypassword",
+                "      user: myuser",
+                "      mykey: myval2",
+                "    - winrm: 1.1.1.3:8985",
+                "      privateAddresses: [10.0.0.3]",
+                "      password: mypassword",
+                "      user: myuser",
+                "      mykey: myval3",
+                "      osfamily: windows",
+                "services:",
+                "- serviceType: brooklyn.entity.basic.BasicApplication");
+        
+        Entity app = createStartWaitAndLogApplication(new StringReader(yaml));
+        FixedListMachineProvisioningLocation<MachineLocation> loc = (FixedListMachineProvisioningLocation<MachineLocation>) Iterables.get(app.getLocations(), 0);
+        
+        Set<MachineLocation> machines = loc.getAvailable();
+        assertEquals(machines.size(), 3, "machines="+machines);
+        SshMachineLocation machine1 = (SshMachineLocation) Iterables.find(machines, LocationPredicates.configEqualTo(ConfigKeys.newStringConfigKey("mykey"), "myval1"));
+        SshMachineLocation machine2 = (SshMachineLocation) Iterables.find(machines, LocationPredicates.configEqualTo(ConfigKeys.newStringConfigKey("mykey"), "myval2"));
+        WinRmMachineLocation machine3 = (WinRmMachineLocation) Iterables.find(machines, Predicates.instanceOf(WinRmMachineLocation.class));
+
+        assertMachine(machine1, UserAndHostAndPort.fromParts("myuser", "1.1.1.1",  8022), ImmutableMap.of(
+                SshMachineLocation.PASSWORD.getName(), "mypassword",
+                "mykey", "myval1"));
+        assertEquals(machine1.getPrivateAddresses(), ImmutableSet.of("10.0.0.1"));
+
+        assertMachine(machine2, UserAndHostAndPort.fromParts("myuser", "1.1.1.2",  8022), ImmutableMap.of(
+                SshMachineLocation.PASSWORD.getName(), "mypassword",
+                "mykey", "myval2"));
+        assertEquals(machine2.getPrivateAddresses(), ImmutableSet.of("10.0.0.2"));
+
+        assertMachine(machine3, UserAndHostAndPort.fromParts("myuser", "1.1.1.3",  8985), ImmutableMap.of(
+                SshMachineLocation.PASSWORD.getName(), "mypassword",
+                "mykey", "myval3"));
+        assertEquals(machine3.getPrivateAddresses(), ImmutableSet.of("10.0.0.3"));
+    }
+    
+    private void assertMachine(SshMachineLocation machine, UserAndHostAndPort conn, Map<String, ?> config) {
+        assertEquals(machine.getAddress().getHostAddress(), conn.getHostAndPort().getHostText());
+        assertEquals(machine.getPort(), conn.getHostAndPort().getPort());
+        assertEquals(machine.getUser(), conn.getUser());
+        for (Map.Entry<String, ?> entry : config.entrySet()) {
+            Object actualVal = machine.getConfig(ConfigKeys.newConfigKey(Object.class, entry.getKey()));
+            assertEquals(actualVal, entry.getValue());
+        }
+    }
+    
+    private void assertMachine(WinRmMachineLocation machine, UserAndHostAndPort conn, Map<String, ?> config) {
+        assertEquals(machine.getAddress().getHostAddress(), conn.getHostAndPort().getHostText());
+        assertEquals(machine.getConfig(WinRmMachineLocation.WINRM_PORT), (Integer) conn.getHostAndPort().getPort());
+        assertEquals(machine.getUser(), conn.getUser());
+        for (Map.Entry<String, ?> entry : config.entrySet()) {
+            Object actualVal = machine.getConfig(ConfigKeys.newConfigKey(Object.class, entry.getKey()));
+            assertEquals(actualVal, entry.getValue());
+        }
+    }
+    
+    @Override
+    protected Logger getLogger() {
+        return log;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4e625b9b/utils/common/src/main/java/brooklyn/util/net/UserAndHostAndPort.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/net/UserAndHostAndPort.java b/utils/common/src/main/java/brooklyn/util/net/UserAndHostAndPort.java
index 49780b4..b2b67e7 100644
--- a/utils/common/src/main/java/brooklyn/util/net/UserAndHostAndPort.java
+++ b/utils/common/src/main/java/brooklyn/util/net/UserAndHostAndPort.java
@@ -31,6 +31,10 @@ public class UserAndHostAndPort implements Serializable {
         return new UserAndHostAndPort(user, HostAndPort.fromParts(host, port));
     }
 
+    public static UserAndHostAndPort fromParts(String user, HostAndPort hostAndPort) {
+        return new UserAndHostAndPort(user, hostAndPort);
+    }
+
     /**
      * Split a string of the form myuser@myhost:1234 into a user, host and port.
      *  


[3/7] incubator-brooklyn git commit: Cleanup ByonLocationResolverTest

Posted by al...@apache.org.
Cleanup ByonLocationResolverTest


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

Branch: refs/heads/master
Commit: 09f3cc87afcf99772bf6597dc4bb2f77ed10660d
Parents: 7b866a9
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jun 26 14:44:57 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Jun 26 15:33:08 2015 +0100

----------------------------------------------------------------------
 .../basic/ByonLocationResolverTest.java         | 68 +++++++++-----------
 1 file changed, 32 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/09f3cc87/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java b/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java
index c83d2f0..307fc6a 100644
--- a/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java
+++ b/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java
@@ -38,6 +38,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.location.MachineLocation;
 import brooklyn.location.MachineProvisioningLocation;
@@ -47,12 +48,12 @@ import brooklyn.test.Asserts;
 import brooklyn.test.entity.LocalManagementContextForTests;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.net.Networking;
+import brooklyn.util.net.UserAndHostAndPort;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.StringPredicates;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -209,16 +210,20 @@ public class ByonLocationResolverTest {
 
     @Test
     public void testResolvesUsernameAtHost() throws Exception {
-        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1\")"), ImmutableSet.of(new UserHostTuple("myuser", "1.1.1.1")));
-        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1,myuser2@1.1.1.1\")"), ImmutableSet.of(new UserHostTuple("myuser", "1.1.1.1"), new UserHostTuple("myuser2", "1.1.1.1")));
-        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1,myuser2@1.1.1.2\")"), ImmutableSet.of(new UserHostTuple("myuser", "1.1.1.1"), new UserHostTuple("myuser2", "1.1.1.2")));
+        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1\")"), 
+                ImmutableSet.of(UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22)));
+        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1,myuser2@1.1.1.1\")"), ImmutableSet.of(
+                UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22), UserAndHostAndPort.fromParts("myuser2", "1.1.1.1", 22)));
+        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1,myuser2@1.1.1.2\")"), ImmutableSet.of(
+                UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22), UserAndHostAndPort.fromParts("myuser2", "1.1.1.2", 22)));
     }
 
     @Test
     public void testResolvesUserArg() throws Exception {
-        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"1.1.1.1\",user=bob)"), ImmutableSet.of(new UserHostTuple("bob", "1.1.1.1")));
+        assertByonClusterWithUsersEquals(resolve("byon(hosts=\"1.1.1.1\",user=bob)"), 
+                ImmutableSet.of(UserAndHostAndPort.fromParts("bob", "1.1.1.1", 22)));
         assertByonClusterWithUsersEquals(resolve("byon(user=\"bob\",hosts=\"myuser@1.1.1.1,1.1.1.1\")"), 
-                ImmutableSet.of(new UserHostTuple("myuser", "1.1.1.1"), new UserHostTuple("bob", "1.1.1.1")));
+                ImmutableSet.of(UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22), UserAndHostAndPort.fromParts("bob", "1.1.1.1", 22)));
     }
 
     @Test
@@ -244,6 +249,14 @@ public class ByonLocationResolverTest {
         Assert.assertEquals("bob", l.getUser());
     }
 
+    @Test
+    public void testResolvesPortArg() throws Exception {
+        assertByonClusterWithUsersEquals(resolve("byon(user=bob,port=8022,hosts=\"1.1.1.1\")"), 
+                ImmutableSet.of(UserAndHostAndPort.fromParts("bob", "1.1.1.1", 8022)));
+        assertByonClusterWithUsersEquals(resolve("byon(user=bob,port=8022,hosts=\"myuser@1.1.1.1,1.1.1.2:8901\")"), 
+                ImmutableSet.of(UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 8022), UserAndHostAndPort.fromParts("bob", "1.1.1.2", 8901)));
+    }
+
     @SuppressWarnings("unchecked")
     @Test
     /** private key should be inherited, so confirm that happens correctly */
@@ -342,6 +355,13 @@ public class ByonLocationResolverTest {
         assertTrue(location instanceof SshMachineLocation, "Expected location to be SshMachineLocation, found " + location);
     }
 
+    @Test
+    public void testAdditionalConfig() throws Exception {
+        FixedListMachineProvisioningLocation<MachineLocation> loc = resolve("byon(mykey=myval,hosts=\"1.1.1.1\")");
+        MachineLocation machine = loc.obtain(ImmutableMap.of());
+        assertEquals(machine.getConfig(ConfigKeys.newConfigKey(String.class, "mykey")), "myval");
+    }
+
     private void assertByonClusterEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<String> expectedHosts) {
         assertByonClusterEquals(cluster, expectedHosts, defaultNamePredicate);
     }
@@ -359,14 +379,15 @@ public class ByonLocationResolverTest {
         assertTrue(expectedName.apply(cluster.getDisplayName()), "name="+cluster.getDisplayName());
     }
 
-    private void assertByonClusterWithUsersEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<UserHostTuple> expectedHosts) {
+    private void assertByonClusterWithUsersEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<UserAndHostAndPort> expectedHosts) {
         assertByonClusterWithUsersEquals(cluster, expectedHosts, defaultNamePredicate);
     }
     
-    private void assertByonClusterWithUsersEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<UserHostTuple> expectedHosts, Predicate<? super String> expectedName) {
-        Set<UserHostTuple> actualHosts = ImmutableSet.copyOf(Iterables.transform(cluster.getMachines(), new Function<MachineLocation, UserHostTuple>() {
-            @Override public UserHostTuple apply(MachineLocation input) {
-                return new UserHostTuple(((SshMachineLocation)input).getUser(), input.getAddress().getHostName());
+    private void assertByonClusterWithUsersEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<UserAndHostAndPort> expectedHosts, Predicate<? super String> expectedName) {
+        Set<UserAndHostAndPort> actualHosts = ImmutableSet.copyOf(Iterables.transform(cluster.getMachines(), new Function<MachineLocation, UserAndHostAndPort>() {
+            @Override public UserAndHostAndPort apply(MachineLocation input) {
+                SshMachineLocation machine = (SshMachineLocation) input;
+                return UserAndHostAndPort.fromParts(machine.getUser(), machine.getAddress().getHostName(), machine.getPort());
             }}));
         assertEquals(actualHosts, expectedHosts);
         assertTrue(expectedName.apply(cluster.getDisplayName()), "name="+cluster.getDisplayName());
@@ -399,29 +420,4 @@ public class ByonLocationResolverTest {
     private FixedListMachineProvisioningLocation<MachineLocation> resolve(String val, Map<?, ?> locationFlags) {
         return (FixedListMachineProvisioningLocation<MachineLocation>) managementContext.getLocationRegistry().resolve(val, locationFlags);
     }
-
-    private static class UserHostTuple {
-        final String username;
-        final String hostname;
-        
-        UserHostTuple(String username, String hostname) {
-            this.username = username;
-            this.hostname = hostname;
-        }
-        
-        @Override
-        public boolean equals(Object o) {
-            return o instanceof UserHostTuple && Objects.equal(username, ((UserHostTuple)o).username)
-                    && Objects.equal(hostname, ((UserHostTuple)o).hostname);
-        }
-        
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(username, hostname);
-        }
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(UserHostTuple.class).add("user", username).add("host", hostname).toString();
-        }
-    }
 }