You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by gr...@apache.org on 2014/06/23 16:59:48 UTC
[5/6] git commit: Addresses server pool review comments
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 <sa...@cloudsoftcorp.com>
Authored: Fri Jun 20 14:37:24 2014 +0100
Committer: Andrew Kennedy <gr...@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;
+ }
+
+}