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:45 UTC
[2/7] incubator-brooklyn git commit: Adds MACHINE_CHOOSER to
FixedListMachineProvisioningLocation
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");
+ }
}