brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From grk...@apache.org
Subject [5/6] git commit: Addresses server pool review comments
Date Mon, 23 Jun 2014 14:59:48 GMT
Addresses server pool review comments


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

Branch: refs/heads/master
Commit: 63bebd5a6e0863dbc47b0e032bfcb2ef06181205
Parents: 28c03c7
Author: Sam Corbett <sam.corbett@cloudsoftcorp.com>
Authored: Fri Jun 20 14:37:24 2014 +0100
Committer: Andrew Kennedy <grkvlt@apache.org>
Committed: Mon Jun 23 15:31:20 2014 +0100

----------------------------------------------------------------------
 .../location/access/PortForwardManager.java     |   2 +-
 .../basic/ByonLocationResolverTest.java         |   2 +-
 .../entity/machine/MachineAttributes.java       |  83 ++++++++++
 .../brooklyn/entity/machine/MachineEntity.java  |  39 +++++
 .../entity/machine/MachineEntityImpl.java       | 155 +++++++++++++++++++
 .../brooklyn/entity/pool/MachineAttributes.java |  83 ----------
 .../brooklyn/entity/pool/MachineEntity.java     |  39 -----
 .../brooklyn/entity/pool/MachineEntityImpl.java | 155 -------------------
 .../java/brooklyn/entity/pool/ServerPool.java   |  17 +-
 .../brooklyn/entity/pool/ServerPoolImpl.java    |  44 +++---
 .../entity/pool/ServerPoolLocation.java         |   4 +-
 .../entity/pool/ServerPoolLocationResolver.java |   6 +-
 .../entity/pool/AbstractServerPoolTest.java     |   5 +-
 .../pool/ServerPoolLocationResolverTest.java    |  70 +++++++++
 14 files changed, 396 insertions(+), 308 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/core/src/main/java/brooklyn/location/access/PortForwardManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/access/PortForwardManager.java b/core/src/main/java/brooklyn/location/access/PortForwardManager.java
index 71edc4b..f13f400 100644
--- a/core/src/main/java/brooklyn/location/access/PortForwardManager.java
+++ b/core/src/main/java/brooklyn/location/access/PortForwardManager.java
@@ -18,7 +18,7 @@ import com.google.common.net.HostAndPort;
  * an unused port on a firewall / public IP address. It may then go on actually to talk to
that firewall/IP to
  * provision the forwarding rule.
  * <p>
- * Subseequently the other side can use this class {@link #lookup(Location, int)} if it knows
the
+ * Subsequently the other side can use this class {@link #lookup(Location, int)} if it knows
the
  * location and private port it wishes to talk to.
  * <p>
  * Implementations typically will not know anything about what the firewall/IP actually is,
they just handle a

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/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 6d64331..5862e26 100644
--- a/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java
+++ b/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java
@@ -86,7 +86,7 @@ public class ByonLocationResolverTest {
     }
 
     @Test
-    public void testPropertyScopePrescedence() throws Exception {
+    public void testPropertyScopePrecedence() throws Exception {
         brooklynProperties.put("brooklyn.location.named.mynamed", "byon:(hosts=\"1.1.1.1\")");
         
         // prefer those in "named" over everything else

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/machine/MachineAttributes.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/machine/MachineAttributes.java b/software/base/src/main/java/brooklyn/entity/machine/MachineAttributes.java
new file mode 100644
index 0000000..028a554
--- /dev/null
+++ b/software/base/src/main/java/brooklyn/entity/machine/MachineAttributes.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 by Cloudsoft Corporation Limited
+ *
+ * Licensed 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.entity.machine;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.annotation.Nullable;
+
+import brooklyn.config.render.RendererHints;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.Sensors;
+import brooklyn.util.guava.Functionals;
+import brooklyn.util.math.MathFunctions;
+import brooklyn.util.text.ByteSizeStrings;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Function;
+
+public class MachineAttributes {
+
+    /** Do not instantiate. */
+    private MachineAttributes() { }
+
+    /*
+     * Sensor attributes for machines.
+     */
+
+    public static final AttributeSensor<Duration> UPTIME = Sensors.newSensor(Duration.class,
"machine.uptime", "Current uptime");
+    public static final AttributeSensor<Double> LOAD_AVERAGE = Sensors.newDoubleSensor("machine.loadAverage",
"Current load average");
+
+    public static final AttributeSensor<Double> CPU_USAGE = Sensors.newDoubleSensor("machine.cpu",
"Current CPU usage");
+    public static final AttributeSensor<Double> AVERAGE_CPU_USAGE = Sensors.newDoubleSensor("cpu.average",
"Average CPU usage across the cluster");
+
+    public static final AttributeSensor<Long> FREE_MEMORY = Sensors.newLongSensor("machine.memory.free",
"Current free memory");
+    public static final AttributeSensor<Long> TOTAL_MEMORY = Sensors.newLongSensor("machine.memory.total",
"Total memory");
+    public static final AttributeSensor<Long> USED_MEMORY = Sensors.newLongSensor("machine.memory.used",
"Current memory usage");
+    public static final AttributeSensor<Double> USED_MEMORY_DELTA_PER_SECOND_LAST =
Sensors.newDoubleSensor("memory.used.delta", "Change in memory usage per second");
+    public static final AttributeSensor<Double> USED_MEMORY_DELTA_PER_SECOND_IN_WINDOW
= Sensors.newDoubleSensor("memory.used.windowed", "Average change in memory usage over 30s");
+
+    private static AtomicBoolean initialized = new AtomicBoolean(false);
+
+    /** Setup renderer hints. */
+    public static void init() {
+        if (initialized.getAndSet(true)) return;
+
+        final Function<Double, Long> longValue = new Function<Double, Long>()
{
+            @Override
+            public Long apply(@Nullable Double input) {
+                if (input == null) return null;
+                return input.longValue();
+            }
+        };
+
+        RendererHints.register(UPTIME, RendererHints.displayValue(Time.toTimeStringRounded()));
+
+        RendererHints.register(CPU_USAGE, RendererHints.displayValue(MathFunctions.percent(2)));
+        RendererHints.register(AVERAGE_CPU_USAGE, RendererHints.displayValue(MathFunctions.percent(2)));
+
+        RendererHints.register(FREE_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
+        RendererHints.register(TOTAL_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
+        RendererHints.register(USED_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
+        RendererHints.register(USED_MEMORY_DELTA_PER_SECOND_LAST, RendererHints.displayValue(Functionals.chain(longValue,
ByteSizeStrings.metric())));
+        RendererHints.register(USED_MEMORY_DELTA_PER_SECOND_IN_WINDOW, RendererHints.displayValue(Functionals.chain(longValue,
ByteSizeStrings.metric())));
+    }
+
+    static {
+        init();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/machine/MachineEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/machine/MachineEntity.java b/software/base/src/main/java/brooklyn/entity/machine/MachineEntity.java
new file mode 100644
index 0000000..d1649db
--- /dev/null
+++ b/software/base/src/main/java/brooklyn/entity/machine/MachineEntity.java
@@ -0,0 +1,39 @@
+package brooklyn.entity.machine;
+
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.MethodEffector;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.ImplementedBy;
+import brooklyn.event.AttributeSensor;
+import brooklyn.util.time.Duration;
+
+@ImplementedBy(MachineEntityImpl.class)
+public interface MachineEntity extends SoftwareProcess {
+
+    AttributeSensor<Duration> UPTIME = MachineAttributes.UPTIME;
+    AttributeSensor<Double> LOAD_AVERAGE = MachineAttributes.LOAD_AVERAGE;
+    AttributeSensor<Double> CPU_USAGE = MachineAttributes.CPU_USAGE;
+    AttributeSensor<Long> FREE_MEMORY = MachineAttributes.FREE_MEMORY;
+    AttributeSensor<Long> TOTAL_MEMORY = MachineAttributes.TOTAL_MEMORY;
+    AttributeSensor<Long> USED_MEMORY = MachineAttributes.USED_MEMORY;
+
+    MethodEffector<String> EXEC_COMMAND = new MethodEffector<String>(MachineEntity.class,
"execCommand");
+    MethodEffector<String> EXEC_COMMAND_TIMEOUT = new MethodEffector<String>(MachineEntity.class,
"execCommandTimeout");
+
+    /**
+     * Execute a command and return the output.
+     */
+    @Effector(description="Execute a command and return the output")
+    String execCommand(
+            @EffectorParam(name="command", description="Command") String command);
+
+    /**
+     * Execute a command and return the output, or throw an exception after a timeout.
+     */
+    @Effector(description="Execute a command and return the output")
+    String execCommandTimeout(
+            @EffectorParam(name="command", description="Command") String command,
+            @EffectorParam(name="timeout", description="Timeout") Duration timeout);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java b/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java
new file mode 100644
index 0000000..4631df3
--- /dev/null
+++ b/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java
@@ -0,0 +1,155 @@
+package brooklyn.entity.machine;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.EmptySoftwareProcessDriver;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.software.SshEffectorTasks;
+import brooklyn.event.feed.ssh.SshFeed;
+import brooklyn.event.feed.ssh.SshPollConfig;
+import brooklyn.event.feed.ssh.SshPollValue;
+import brooklyn.location.basic.Machines;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.system.ProcessTaskWrapper;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Splitter;
+
+public class MachineEntityImpl extends SoftwareProcessImpl implements MachineEntity {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MachineEntityImpl.class);
+
+    static {
+    	MachineAttributes.init();
+    }
+
+    private transient SshFeed sensorFeed;
+
+    @Override
+    public void init() {
+        LOG.info("Starting server pool machine with id {}", getId());
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        connectServiceUpIsRunning();
+
+        // Sensors linux-specific
+        if (!getMachine().getMachineDetails().getOsDetails().isLinux()) return;
+
+        sensorFeed = SshFeed.builder()
+                .entity(this)
+                .period(Duration.THIRTY_SECONDS)
+                .poll(new SshPollConfig<Double>(LOAD_AVERAGE)
+                		.command("uptime")
+                        .onFailureOrException(Functions.constant(-1d))
+                        .onSuccess(new Function<SshPollValue, Double>() {
+                            @Override
+                            public Double apply(SshPollValue input) {
+                                String loadAverage = Strings.getFirstWordAfter(input.getStdout(),
"load average:").replace(",", "");
+                                return Double.valueOf(loadAverage);
+                            }
+                        }))
+                .poll(new SshPollConfig<Double>(CPU_USAGE)
+                        .command("cat /proc/stat")
+                        .onFailureOrException(Functions.constant(0d))
+                        .onSuccess(new Function<SshPollValue, Double>() {
+                            @Override
+                            public Double apply(SshPollValue input) {
+                                List<String> cpuData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
+                                Integer system = Integer.parseInt(cpuData.get(1));
+                                Integer user = Integer.parseInt(cpuData.get(3));
+                                Integer idle = Integer.parseInt(cpuData.get(4));
+                                return (double) (system + user) / (double) (system + user
+ idle);
+                            }
+                        }))
+                .poll(new SshPollConfig<Long>(USED_MEMORY)
+                		.command("free | grep Mem:")
+                        .onFailureOrException(Functions.constant(-1L))
+                        .onSuccess(new Function<SshPollValue, Long>() {
+                            @Override
+                            public Long apply(SshPollValue input) {
+                                List<String> memoryData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
+                                return Long.parseLong(memoryData.get(2));
+                            }
+                        }))
+                .poll(new SshPollConfig<Long>(FREE_MEMORY)
+                		.command("free | grep Mem:")
+                        .onFailureOrException(Functions.constant(-1L))
+                        .onSuccess(new Function<SshPollValue, Long>() {
+                            @Override
+                            public Long apply(SshPollValue input) {
+                                List<String> memoryData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
+                                return Long.parseLong(memoryData.get(3));
+                            }
+                        }))
+                .poll(new SshPollConfig<Long>(TOTAL_MEMORY)
+                		.command("free | grep Mem:")
+                        .onFailureOrException(Functions.constant(-1L))
+                        .onSuccess(new Function<SshPollValue, Long>() {
+                            @Override
+                            public Long apply(SshPollValue input) {
+                                List<String> memoryData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
+                                return Long.parseLong(memoryData.get(1));
+                            }
+                        }))
+                .build();
+
+    }
+
+    @Override
+    public void disconnectSensors() {
+        disconnectServiceUpIsRunning();
+        if (sensorFeed != null) sensorFeed.stop();
+        super.disconnectSensors();
+    }
+
+	@Override
+	public Class<?> getDriverInterface() {
+		return EmptySoftwareProcessDriver.class;
+	}
+
+    public SshMachineLocation getMachine() {
+    	return Machines.findUniqueSshMachineLocation(getLocations()).get();
+    }
+
+    @Override
+    public String execCommand(String command) {
+        return execCommandTimeout(command, Duration.ONE_MINUTE);
+    }
+
+    @Override
+    public String execCommandTimeout(String command, Duration timeout) {
+        try {
+            ProcessTaskWrapper<Integer> task = SshEffectorTasks.ssh(command)
+                    .machine(getMachine())
+                    .summary(Strings.getFirstWord(command))
+                    .newTask();
+            Integer result = DynamicTasks.queueIfPossible(task)
+                    .executionContext(this)
+                    .orSubmitAsync()
+                    .asTask()
+                    .get(timeout);
+            if (result != 0) {
+                LOG.warn("Command failed: {}", task.getStderr());
+                throw new IllegalStateException("Command failed, return code " + result);
+            }
+            return task.getStdout();
+        } catch (TimeoutException te) {
+            throw new IllegalStateException("Timed out running command: " + command);
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/pool/MachineAttributes.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/MachineAttributes.java b/software/base/src/main/java/brooklyn/entity/pool/MachineAttributes.java
deleted file mode 100644
index d7a661a..0000000
--- a/software/base/src/main/java/brooklyn/entity/pool/MachineAttributes.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2014 by Cloudsoft Corporation Limited
- *
- * Licensed 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.entity.pool;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.annotation.Nullable;
-
-import brooklyn.config.render.RendererHints;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.Sensors;
-import brooklyn.util.guava.Functionals;
-import brooklyn.util.math.MathFunctions;
-import brooklyn.util.text.ByteSizeStrings;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Function;
-
-public class MachineAttributes {
-
-    /** Do not instantiate. */
-    private MachineAttributes() { }
-
-    /*
-     * Sensor attributes for machines.
-     */
-
-    public static final AttributeSensor<Duration> UPTIME = Sensors.newSensor(Duration.class,
"machine.uptime", "Current uptime");
-    public static final AttributeSensor<Double> LOAD_AVERAGE = Sensors.newDoubleSensor("machine.loadAverage",
"Current load average");
-
-    public static final AttributeSensor<Double> CPU_USAGE = Sensors.newDoubleSensor("machine.cpu",
"Current CPU usage");
-    public static final AttributeSensor<Double> AVERAGE_CPU_USAGE = Sensors.newDoubleSensor("cpu.average",
"Average CPU usage across the cluster");
-
-    public static final AttributeSensor<Long> FREE_MEMORY = Sensors.newLongSensor("machine.memory.free",
"Current free memory");
-    public static final AttributeSensor<Long> TOTAL_MEMORY = Sensors.newLongSensor("machine.memory.total",
"Total memory");
-    public static final AttributeSensor<Long> USED_MEMORY = Sensors.newLongSensor("machine.memory.used",
"Current memory usage");
-    public static final AttributeSensor<Double> USED_MEMORY_DELTA_PER_SECOND_LAST =
Sensors.newDoubleSensor("memory.used.delta", "Change in memory usage per second");
-    public static final AttributeSensor<Double> USED_MEMORY_DELTA_PER_SECOND_IN_WINDOW
= Sensors.newDoubleSensor("memory.used.windowed", "Average change in memory usage over 30s");
-
-    private static AtomicBoolean initialized = new AtomicBoolean(false);
-
-    /** Setup renderer hints. */
-    public static void init() {
-        if (initialized.getAndSet(true)) return;
-
-        final Function<Double, Long> longValue = new Function<Double, Long>()
{
-            @Override
-            public Long apply(@Nullable Double input) {
-                if (input == null) return null;
-                return input.longValue();
-            }
-        };
-
-        RendererHints.register(UPTIME, RendererHints.displayValue(Time.toTimeStringRounded()));
-
-        RendererHints.register(CPU_USAGE, RendererHints.displayValue(MathFunctions.percent(2)));
-        RendererHints.register(AVERAGE_CPU_USAGE, RendererHints.displayValue(MathFunctions.percent(2)));
-
-        RendererHints.register(FREE_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
-        RendererHints.register(TOTAL_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
-        RendererHints.register(USED_MEMORY, RendererHints.displayValue(ByteSizeStrings.metric()));
-        RendererHints.register(USED_MEMORY_DELTA_PER_SECOND_LAST, RendererHints.displayValue(Functionals.chain(longValue,
ByteSizeStrings.metric())));
-        RendererHints.register(USED_MEMORY_DELTA_PER_SECOND_IN_WINDOW, RendererHints.displayValue(Functionals.chain(longValue,
ByteSizeStrings.metric())));
-    }
-
-    static {
-        init();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/pool/MachineEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/MachineEntity.java b/software/base/src/main/java/brooklyn/entity/pool/MachineEntity.java
deleted file mode 100644
index 219c9cd..0000000
--- a/software/base/src/main/java/brooklyn/entity/pool/MachineEntity.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package brooklyn.entity.pool;
-
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.MethodEffector;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.event.AttributeSensor;
-import brooklyn.util.time.Duration;
-
-@ImplementedBy(MachineEntityImpl.class)
-public interface MachineEntity extends SoftwareProcess {
-
-    AttributeSensor<Duration> UPTIME = MachineAttributes.UPTIME;
-    AttributeSensor<Double> LOAD_AVERAGE = MachineAttributes.LOAD_AVERAGE;
-    AttributeSensor<Double> CPU_USAGE = MachineAttributes.CPU_USAGE;
-    AttributeSensor<Long> FREE_MEMORY = MachineAttributes.FREE_MEMORY;
-    AttributeSensor<Long> TOTAL_MEMORY = MachineAttributes.TOTAL_MEMORY;
-    AttributeSensor<Long> USED_MEMORY = MachineAttributes.USED_MEMORY;
-
-    MethodEffector<String> EXEC_COMMAND = new MethodEffector<String>(MachineEntity.class,
"execCommand");
-    MethodEffector<String> EXEC_COMMAND_TIMEOUT = new MethodEffector<String>(MachineEntity.class,
"execCommandTimeout");
-
-    /**
-     * Execute a command and return the output.
-     */
-    @Effector(description="Execute a command and return the output")
-    String execCommand(
-            @EffectorParam(name="command", description="Command") String command);
-
-    /**
-     * Execute a command and return the output, or throw an exception after a timeout.
-     */
-    @Effector(description="Execute a command and return the output")
-    String execCommandTimeout(
-            @EffectorParam(name="command", description="Command") String command,
-            @EffectorParam(name="timeout", description="Timeout") Duration timeout);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/pool/MachineEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/MachineEntityImpl.java b/software/base/src/main/java/brooklyn/entity/pool/MachineEntityImpl.java
deleted file mode 100644
index 4fc87dc..0000000
--- a/software/base/src/main/java/brooklyn/entity/pool/MachineEntityImpl.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package brooklyn.entity.pool;
-
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.EmptySoftwareProcessDriver;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.software.SshEffectorTasks;
-import brooklyn.event.feed.ssh.SshFeed;
-import brooklyn.event.feed.ssh.SshPollConfig;
-import brooklyn.event.feed.ssh.SshPollValue;
-import brooklyn.location.basic.Machines;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Splitter;
-
-public class MachineEntityImpl extends SoftwareProcessImpl implements MachineEntity {
-
-    private static final Logger LOG = LoggerFactory.getLogger(MachineEntityImpl.class);
-
-    static {
-    	MachineAttributes.init();
-    }
-
-    private transient SshFeed sensorFeed;
-
-    @Override
-    public void init() {
-        LOG.info("Starting server pool machine with id {}", getId());
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        connectServiceUpIsRunning();
-
-        // Sensors linux-specific
-        if (!getMachine().getMachineDetails().getOsDetails().isLinux()) return;
-
-        sensorFeed = SshFeed.builder()
-                .entity(this)
-                .period(Duration.THIRTY_SECONDS)
-                .poll(new SshPollConfig<Double>(LOAD_AVERAGE)
-                		.command("uptime")
-                        .onFailureOrException(Functions.constant(-1d))
-                        .onSuccess(new Function<SshPollValue, Double>() {
-                            @Override
-                            public Double apply(SshPollValue input) {
-                                String loadAverage = Strings.getFirstWordAfter(input.getStdout(),
"load average:").replace(",", "");
-                                return Double.valueOf(loadAverage);
-                            }
-                        }))
-                .poll(new SshPollConfig<Double>(CPU_USAGE)
-                        .command("cat /proc/stat")
-                        .onFailureOrException(Functions.constant(0d))
-                        .onSuccess(new Function<SshPollValue, Double>() {
-                            @Override
-                            public Double apply(SshPollValue input) {
-                                List<String> cpuData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
-                                Integer system = Integer.parseInt(cpuData.get(1));
-                                Integer user = Integer.parseInt(cpuData.get(3));
-                                Integer idle = Integer.parseInt(cpuData.get(4));
-                                return (double) (system + user) / (double) (system + user
+ idle);
-                            }
-                        }))
-                .poll(new SshPollConfig<Long>(USED_MEMORY)
-                		.command("free | grep Mem:")
-                        .onFailureOrException(Functions.constant(-1L))
-                        .onSuccess(new Function<SshPollValue, Long>() {
-                            @Override
-                            public Long apply(SshPollValue input) {
-                                List<String> memoryData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
-                                return Long.parseLong(memoryData.get(2));
-                            }
-                        }))
-                .poll(new SshPollConfig<Long>(FREE_MEMORY)
-                		.command("free | grep Mem:")
-                        .onFailureOrException(Functions.constant(-1L))
-                        .onSuccess(new Function<SshPollValue, Long>() {
-                            @Override
-                            public Long apply(SshPollValue input) {
-                                List<String> memoryData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
-                                return Long.parseLong(memoryData.get(3));
-                            }
-                        }))
-                .poll(new SshPollConfig<Long>(TOTAL_MEMORY)
-                		.command("free | grep Mem:")
-                        .onFailureOrException(Functions.constant(-1L))
-                        .onSuccess(new Function<SshPollValue, Long>() {
-                            @Override
-                            public Long apply(SshPollValue input) {
-                                List<String> memoryData = Splitter.on(" ").omitEmptyStrings().splitToList(Strings.getFirstLine(input.getStdout()));
-                                return Long.parseLong(memoryData.get(1));
-                            }
-                        }))
-                .build();
-
-    }
-
-    @Override
-    public void disconnectSensors() {
-        disconnectServiceUpIsRunning();
-        if (sensorFeed != null) sensorFeed.stop();
-        super.disconnectSensors();
-    }
-
-	@Override
-	public Class<?> getDriverInterface() {
-		return EmptySoftwareProcessDriver.class;
-	}
-
-    public SshMachineLocation getMachine() {
-    	return Machines.findUniqueSshMachineLocation(getLocations()).get();
-    }
-
-    @Override
-    public String execCommand(String command) {
-        return execCommandTimeout(command, Duration.ONE_MINUTE);
-    }
-
-    @Override
-    public String execCommandTimeout(String command, Duration timeout) {
-        try {
-            ProcessTaskWrapper<Integer> task = SshEffectorTasks.ssh(command)
-                    .machine(getMachine())
-                    .summary(Strings.getFirstWord(command))
-                    .newTask();
-            Integer result = DynamicTasks.queueIfPossible(task)
-                    .executionContext(this)
-                    .orSubmitAsync()
-                    .asTask()
-                    .get(timeout);
-            if (result != 0) {
-                LOG.warn("Command failed: {}", task.getStderr());
-                throw new IllegalStateException("Command failed, return code " + result);
-            }
-            return task.getStdout();
-        } catch (TimeoutException te) {
-            throw new IllegalStateException("Timed out running command: " + command);
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/pool/ServerPool.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/ServerPool.java b/software/base/src/main/java/brooklyn/entity/pool/ServerPool.java
index 53a7185..b1db826 100644
--- a/software/base/src/main/java/brooklyn/entity/pool/ServerPool.java
+++ b/software/base/src/main/java/brooklyn/entity/pool/ServerPool.java
@@ -4,6 +4,7 @@ import java.util.Map;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.machine.MachineEntity;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.entity.proxying.ImplementedBy;
@@ -22,9 +23,19 @@ import brooklyn.location.dynamic.LocationOwner;
  *     <li>
  *         The pool does not configure ports appropriately for applications subsequently
  *         deployed. If an entity that is to be run in the pool requires any ports open
- *         other than port 22 then that port should be configured on the {@link #MEMBER_SPEC}
- *         of the pool. This is a limitation of Brooklyn that will be addressed in a
- *         future release.
+ *         other than port 22 then thoses port should be configured with the
+ *         {@link brooklyn.location.cloud.CloudLocationConfig#INBOUND_PORTS INBOUND_PORTS}
+ *         config key as part of the pool's
+ *         {@link brooklyn.entity.basic.SoftwareProcess#PROVISIONING_PROPERTIES PROVISIONING_PROPERTIES}.
+ *         For example, in YAML:
+ *         <pre>
+ *     - type: brooklyn.entity.pool.ServerPool
+ *       brooklyn.config:
+ *         # Suitable for TomcatServers
+ *         provisioning.properties:
+ *         inboundPorts: [22, 31880, 8443, 8080, 31001, 1099]
+ *         </pre>
+ *         This is a limitation of Brooklyn that will be addressed in a future release.
  *     </li>
  * </ul>
  */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
index 51619ad..7ac7034 100644
--- a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
@@ -21,6 +21,7 @@ import com.google.common.reflect.TypeToken;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import brooklyn.entity.group.DynamicClusterImpl;
@@ -32,6 +33,7 @@ import brooklyn.location.MachineLocation;
 import brooklyn.location.NoMachinesAvailableException;
 import brooklyn.location.basic.BasicLocationDefinition;
 import brooklyn.location.basic.Machines;
+import brooklyn.location.dynamic.DynamicLocation;
 import brooklyn.management.LocationManager;
 import brooklyn.policy.PolicySpec;
 import brooklyn.util.collections.MutableMap;
@@ -68,13 +70,10 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool
{
     @Override
     public void init() {
         super.init();
-
         setAttribute(AVAILABLE_COUNT, 0);
         setAttribute(CLAIMED_COUNT, 0);
         setAttribute(ENTITY_MACHINE, Maps.<Entity, MachineLocation>newHashMap());
         setAttribute(MACHINE_ENTITY, Maps.<MachineLocation, Entity>newHashMap());
-
-        // addPolicy(new AutoScalerPolicy(...));
     }
 
     @Override
@@ -115,7 +114,7 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool
{
     protected ServerPoolLocation createLocation() {
         return createLocation(MutableMap.<String, Object>builder()
                 .putAll(getConfig(LOCATION_FLAGS))
-                .put("owner", this)
+                .put(DynamicLocation.OWNER.getName(), this)
                 .build());
     }
 
@@ -187,14 +186,25 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool
{
     public void releaseMachine(MachineLocation machine) {
         synchronized (mutex) {
             Entity entity = getMachineEntityMap().get(machine);
-            setEntityStatus(entity, MachinePoolMemberStatus.AVAILABLE);
-            updateCountSensors();
-            LOG.debug("{} has been released in {}", machine, this);
+            if (entity == null) {
+                LOG.warn("{} releasing machine {} but its owning entity is not known!", this,
machine);
+            } else {
+                setEntityStatus(entity, MachinePoolMemberStatus.AVAILABLE);
+                updateCountSensors();
+                LOG.debug("{} has been released in {}", machine, this);
+            }
         }
     }
 
-    /** Overrides to modify the delta to the maximum of the argument and the sum of
-     * the sizes of the immediateRemovals and availableMachines collections. */
+    /**
+     * Overrides to restrict delta to the number of machines that can be <em>safely</em>
+     * removed (i.e. those that are {@link MachinePoolMemberStatus#UNUSABLE unusable} or
+     * {@link MachinePoolMemberStatus#AVAILABLE available}).
+     * <p/>
+     * Does not modify delta if the pool is stopping.
+     * @param delta Requested number of members to remove
+     * @return The entities that were removed
+     */
     @Override
     protected Collection<Entity> shrink(int delta) {
         synchronized (mutex) {
@@ -230,7 +240,7 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool
{
     }
 
     private final Function<Collection<Entity>, Entity> UNCLAIMED_REMOVAL_STRATEGY
= new Function<Collection<Entity>, Entity>() {
-        // Semantics of superclass mean that mutex should already be held when appy is called
+        // Semantics of superclass mean that mutex should already be held when apply is called
         @Override
         public Entity apply(Collection<Entity> input) {
             synchronized (mutex) {
@@ -277,23 +287,17 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool
{
     }
 
     private void setEntityStatus(Entity entity, MachinePoolMemberStatus status) {
-        checkNotNull(entity, "What?");
         ((EntityInternal) entity).setAttribute(SERVER_STATUS, status);
     }
 
-    private Predicate<Entity> statusPredicate(final MachinePoolMemberStatus status)
{
-        return new Predicate<Entity>() {
-                @Override public boolean apply(Entity input) {
-                    return status.equals(input.getAttribute(SERVER_STATUS));
-                }};
-    }
-
     private Optional<Entity> getMemberWithStatus(MachinePoolMemberStatus status) {
-        return Iterables.tryFind(getMembers(), statusPredicate(status));
+        return Iterables.tryFind(getMembers(),
+                EntityPredicates.attributeEqualTo(SERVER_STATUS, status));
     }
 
     private Iterable<Entity> getMembersWithStatus(MachinePoolMemberStatus status) {
-        return Iterables.filter(getMembers(), statusPredicate(status));
+        return Iterables.filter(getMembers(),
+                EntityPredicates.attributeEqualTo(SERVER_STATUS, status));
     }
 
     private void updateCountSensors() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
index 133fa50..8191b45 100644
--- a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
+++ b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
@@ -1,5 +1,7 @@
 package brooklyn.entity.pool;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.Collection;
 import java.util.Map;
 
@@ -28,7 +30,7 @@ public class ServerPoolLocation extends AbstractLocation implements MachineProvi
 
     @Override
     public void init() {
-        LOG.debug("Initialising. Owner is: {}", getConfig(OWNER));
+        LOG.debug("Initialising. Owner is: {}", checkNotNull(getConfig(OWNER), OWNER.getName()));
         super.init();
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocationResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocationResolver.java
b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocationResolver.java
index c9f06b0..e5ae2eb 100644
--- a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocationResolver.java
+++ b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocationResolver.java
@@ -15,6 +15,7 @@ import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 
+import brooklyn.entity.Entity;
 import brooklyn.location.Location;
 import brooklyn.location.LocationRegistry;
 import brooklyn.location.LocationResolver.EnableableLocationResolver;
@@ -70,7 +71,7 @@ public class ServerPoolLocationResolver implements EnableableLocationResolver
{
 
         Matcher matcher = PATTERN.matcher(spec);
         if (!matcher.matches()) {
-            String m = String.format("Invalid location '%s'; must specify either %s:entityId
or %s:entityId:(name=abc)",
+            String m = String.format("Invalid location '%s'; must specify either %s:entityId
or %s:entityId:(key=argument)",
                     spec, PREFIX, PREFIX);
             throw new IllegalArgumentException(m);
         }
@@ -80,7 +81,6 @@ public class ServerPoolLocationResolver implements EnableableLocationResolver
{
         String displayNamePart = argsMap.get("displayName");
         String namePart = argsMap.get("name");
 
-        // TODO: Could include existing servers here?
         if (!ACCEPTABLE_ARGS.containsAll(argsMap.keySet())) {
             Set<String> illegalArgs = Sets.difference(argsMap.keySet(), ACCEPTABLE_ARGS);
             throw new IllegalArgumentException("Invalid location '"+spec+"'; illegal args
"+illegalArgs+"; acceptable args are "+ACCEPTABLE_ARGS);
@@ -107,7 +107,7 @@ public class ServerPoolLocationResolver implements EnableableLocationResolver
{
         final String displayName = displayNamePart != null ? displayNamePart : "Server Pool
" + poolId;
         final String locationName = namePart != null ? namePart : "serverpool-" + poolId;
 
-        ServerPool pool = (ServerPool) managementContext.getEntityManager().getEntity(poolId);
+        Entity pool = managementContext.getEntityManager().getEntity(poolId);
         LocationSpec<ServerPoolLocation> locationSpec = LocationSpec.create(ServerPoolLocation.class)
                 .configure(flags)
                 .configure(DynamicLocation.OWNER, pool)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/test/java/brooklyn/entity/pool/AbstractServerPoolTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/pool/AbstractServerPoolTest.java
b/software/base/src/test/java/brooklyn/entity/pool/AbstractServerPoolTest.java
index 70159a1..3b984af 100644
--- a/software/base/src/test/java/brooklyn/entity/pool/AbstractServerPoolTest.java
+++ b/software/base/src/test/java/brooklyn/entity/pool/AbstractServerPoolTest.java
@@ -80,8 +80,9 @@ public abstract class AbstractServerPoolTest {
             fail("Expected exception when starting app with too many entities for pool");
         } catch (Exception e) {
             Throwable t = Exceptions.getFirstThrowableOfType(e, NoMachinesAvailableException.class);
-            assertTrue(t != null,
-                    "expected " + NoMachinesAvailableException.class.getName() + " to be
thrown, not found in " + e);
+            if (t == null) {
+                throw new RuntimeException(e);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63bebd5a/software/base/src/test/java/brooklyn/entity/pool/ServerPoolLocationResolverTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/pool/ServerPoolLocationResolverTest.java
b/software/base/src/test/java/brooklyn/entity/pool/ServerPoolLocationResolverTest.java
new file mode 100644
index 0000000..6b5f623
--- /dev/null
+++ b/software/base/src/test/java/brooklyn/entity/pool/ServerPoolLocationResolverTest.java
@@ -0,0 +1,70 @@
+package brooklyn.entity.pool;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.EmptySoftwareProcess;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+import brooklyn.location.LocationSpec;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.location.dynamic.DynamicLocation;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.test.entity.LocalManagementContextForTests;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.util.collections.MutableMap;
+
+public class ServerPoolLocationResolverTest {
+
+    private LocalManagementContext managementContext;
+    private Entity locationOwner;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        managementContext = new LocalManagementContextForTests(BrooklynProperties.Factory.newEmpty());
+        TestApplication t = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+        locationOwner = t.createAndManageChild(EntitySpec.create(ServerPool.class)
+                .configure(ServerPool.INITIAL_SIZE, 0)
+                .configure(ServerPool.MEMBER_SPEC, EntitySpec.create(EmptySoftwareProcess.class)));
+        Location poolLocation = managementContext.getLocationManager()
+                .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
+        t.start(ImmutableList.of(poolLocation));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (managementContext != null) Entities.destroyAll(managementContext);
+    }
+
+    @Test
+    public void testResolve() {
+        ServerPoolLocation location = resolve("pool:" + locationOwner.getId());
+        assertEquals(location.getOwner().getId(), locationOwner.getId());
+    }
+
+    @Test
+    public void testSetsDisplayName() {
+        ServerPoolLocation location = resolve("pool:" + locationOwner.getId() + ":(displayName=xyz)");
+        assertEquals(location.getDisplayName(), "xyz");
+    }
+
+    private ServerPoolLocation resolve(String val) {
+        Map<String, Object> flags = MutableMap.<String, Object>of(DynamicLocation.OWNER.getName(),
locationOwner);
+        Location l = managementContext.getLocationRegistry().resolve(val, flags);
+        Assert.assertNotNull(l);
+        return (ServerPoolLocation) l;
+    }
+
+}


Mime
View raw message