Move o.a.b.sensor.ssh contents to core
- Moved SshCommandEffector (which strangely was in .sensor.ssh) to
o.a.b.core.effector.ssh
- Moved SshCommandSensor (which strangely was in .sensor.ssh) to
o.a.b.core.sensor.ssh
- Changed these classes to reference config in BrooklynConfigKeys,
rather than in SoftwareProcess.*
- Added BrooklynConfigKeys.SHELL_ENVIRONMENT, which SoftwareProcess
now uses.
- Made SshCommandSensor.makeCommandExecutingInDirectory public and
marked as @Beta (was previously static package-private, for use
by SshCommandEffector as well).
- Split SshCommandIntegrationTest into two:
- SshCommandEffectorIntegrationTest (and removed unnecessary tempFile
creation)
- SshCommandSensorIntegrationTest (and moved tempFile creation/deletion
into setUp/tearDown)
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit:
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/080d2de0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/080d2de0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/080d2de0
Branch: refs/heads/master
Commit: 080d2de0806f5524886b4d6d8bfea7c71a45dbc7
Parents: 8e439bd
Author: Aled Sage <[email protected]>
Authored: Thu Aug 20 11:24:20 2015 +0100
Committer: Aled Sage <[email protected]>
Committed: Thu Aug 20 11:24:20 2015 +0100
----------------------------------------------------------------------
.../core/effector/ssh/SshCommandEffector.java | 102 +++++++++++++
.../core/entity/BrooklynConfigKeys.java | 9 ++
.../core/sensor/ssh/SshCommandSensor.java | 141 ++++++++++++++++++
.../ssh/SshCommandEffectorIntegrationTest.java | 94 ++++++++++++
.../ssh/SshCommandSensorIntegrationTest.java | 89 ++++++++++++
.../entity/java/JmxAttributeSensor.java | 2 +-
.../entity/software/base/SoftwareProcess.java | 7 +-
.../brooklyn/sensor/ssh/SshCommandEffector.java | 103 --------------
.../brooklyn/sensor/ssh/SshCommandSensor.java | 142 -------------------
.../test/ssh/SshCommandIntegrationTest.java | 126 ----------------
10 files changed, 439 insertions(+), 376 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffector.java
----------------------------------------------------------------------
diff --git
a/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffector.java
b/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffector.java
new file mode 100644
index 0000000..b22f717
--- /dev/null
+++
b/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffector.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.effector.ssh;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.AddEffector;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.sensor.ssh.SshCommandSensor;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.base.Preconditions;
+
+public final class SshCommandEffector extends AddEffector {
+
+ public static final ConfigKey<String> EFFECTOR_COMMAND =
ConfigKeys.newStringConfigKey("command");
+ public static final ConfigKey<String> EFFECTOR_EXECUTION_DIR =
SshCommandSensor.SENSOR_EXECUTION_DIR;
+
+ public SshCommandEffector(ConfigBag params) {
+ super(newEffectorBuilder(params).build());
+ }
+
+ public SshCommandEffector(Map<String,String> params) {
+ this(ConfigBag.newInstance(params));
+ }
+
+ public static EffectorBuilder<String> newEffectorBuilder(ConfigBag params)
{
+ EffectorBuilder<String> eff =
AddEffector.newEffectorBuilder(String.class, params);
+ eff.impl(new Body(eff.buildAbstract(), params));
+ return eff;
+ }
+
+
+ protected static class Body extends EffectorBody<String> {
+ private final Effector<?> effector;
+ private final String command;
+ private final String executionDir;
+
+ public Body(Effector<?> eff, ConfigBag params) {
+ this.effector = eff;
+ this.command =
Preconditions.checkNotNull(params.get(EFFECTOR_COMMAND), "command must be
supplied when defining this effector");
+ this.executionDir = params.get(EFFECTOR_EXECUTION_DIR);
+ // TODO could take a custom "env" aka effectorShellEnv
+ }
+
+ @Override
+ public String call(ConfigBag params) {
+ String command = this.command;
+
+ command =
SshCommandSensor.makeCommandExecutingInDirectory(command, executionDir,
entity());
+
+ MutableMap<String, String> env = MutableMap.of();
+ // first set all declared parameters, including default values
+ for (ParameterType<?> param: effector.getParameters()) {
+ env.addIfNotNull(param.getName(), Strings.toString(
params.get(Effectors.asConfigKey(param)) ));
+ }
+
+ // then set things from the entities defined shell environment, if
applicable
+
env.putAll(Strings.toStringMap(entity().getConfig(BrooklynConfigKeys.SHELL_ENVIRONMENT),
""));
+
+ // if we wanted to resolve the surrounding environment in real
time -- see above
+// Map<String,Object> paramsResolved = (Map<String, Object>)
Tasks.resolveDeepValue(effectorShellEnv, Map.class,
entity().getExecutionContext());
+
+ // finally set the parameters we've been passed; this will repeat
declared parameters but to no harm,
+ // it may pick up additional values (could be a flag defining
whether this is permitted or not)
+ env.putAll(Strings.toStringMap(params.getAllConfig()));
+
+ SshEffectorTasks.SshEffectorTaskFactory<String> t =
SshEffectorTasks.ssh(command)
+ .requiringZeroAndReturningStdout()
+ .summary("effector "+effector.getName())
+ .environmentVariables(env);
+ return queue(t).get();
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
----------------------------------------------------------------------
diff --git
a/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
b/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
index cedccb8..c1ad143 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
@@ -26,15 +26,18 @@ import static
org.apache.brooklyn.core.config.ConfigKeys.newStringConfigKey;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.config.MapConfigKey;
import org.apache.brooklyn.core.entity.trait.Startable;
import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
import
org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
import org.apache.brooklyn.core.server.BrooklynServerConfig;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.util.core.internal.ssh.ShellTool;
import org.apache.brooklyn.util.core.internal.ssh.SshTool;
import org.apache.brooklyn.util.time.Duration;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
/** Commonly used config keys, for use in entities. Similar to {@link
Attributes}.
* See also {@link BrooklynServerConfig} for config keys for controlling the
server. */
@@ -103,6 +106,12 @@ public class BrooklynConfigKeys {
public static final ConfigKey<String> POST_LAUNCH_COMMAND =
ConfigKeys.newStringConfigKey("post.launch.command",
"Command to be run after the launch method being called on the
driver");
+ public static final MapConfigKey<Object> SHELL_ENVIRONMENT = new
MapConfigKey<Object>(
+ Object.class,
+ "shell.env",
+ "Map of environment variables to pass to the runtime shell",
+ ImmutableMap.<String,Object>of());
+
public static final AttributeSensorAndConfigKey<String, String>
INSTALL_DIR = new TemplatedStringAttributeSensorAndConfigKey("install.dir",
"Directory for this software to be installed in",
"${" +
"config['"+ONBOX_BASE_DIR.getName()+"']!" +
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git
a/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
new file mode 100644
index 0000000..c418f93
--- /dev/null
+++
b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.sensor.ssh;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntityInitializer;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.AddSensor;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.sensor.HttpRequestSensor;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshValueFunctions;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+
+/**
+ * Configurable {@link EntityInitializer} which adds an SSH sensor feed
running the <code>command</code> supplied
+ * in order to populate the sensor with the indicated <code>name</code>. Note
that the <code>targetType</code> is ignored,
+ * and always set to {@link String}.
+ *
+ * @see HttpRequestSensor
+ */
+@Beta
+public final class SshCommandSensor<T> extends AddSensor<T> {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(SshCommandSensor.class);
+
+ public static final ConfigKey<String> SENSOR_COMMAND =
ConfigKeys.newStringConfigKey("command", "SSH command to execute for sensor");
+ public static final ConfigKey<String> SENSOR_EXECUTION_DIR =
ConfigKeys.newStringConfigKey("executionDir", "Directory where the command
should run; "
+ + "if not supplied, executes in the entity's run dir (or home dir if
no run dir is defined); "
+ + "use '~' to always execute in the home dir, or 'custom-feed/' to
execute in a custom-feed dir relative to the run dir");
+
+ protected final String command;
+ protected final String executionDir;
+
+ public SshCommandSensor(final ConfigBag params) {
+ super(params);
+
+ // TODO create a supplier for the command string to support attribute
embedding
+ command = Preconditions.checkNotNull(params.get(SENSOR_COMMAND),
"command");
+
+ executionDir = params.get(SENSOR_EXECUTION_DIR);
+ }
+
+ @Override
+ public void apply(final EntityLocal entity) {
+ super.apply(entity);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Adding SSH sensor {} to {}", name, entity);
+ }
+
+ Supplier<Map<String,String>> envSupplier = new
Supplier<Map<String,String>>() {
+ @Override
+ public Map<String, String> get() {
+ return
MutableMap.copyOf(Strings.toStringMap(entity.getConfig(BrooklynConfigKeys.SHELL_ENVIRONMENT),
""));
+ }
+ };
+
+ Supplier<String> commandSupplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return makeCommandExecutingInDirectory(command, executionDir,
entity);
+ }
+ };
+
+ SshPollConfig<T> pollConfig = new SshPollConfig<T>(sensor)
+ .period(period)
+ .env(envSupplier)
+ .command(commandSupplier)
+ .checkSuccess(SshValueFunctions.exitStatusEquals(0))
+ .onFailureOrException(Functions.constant((T) null))
+ .onSuccess(Functions.compose(new Function<String, T>() {
+ @Override
+ public T apply(String input) {
+ return TypeCoercions.coerce(input, getType(type));
+ }}, SshValueFunctions.stdout()));
+
+ SshFeed.builder()
+ .entity(entity)
+ .onlyIfServiceUp()
+ .poll(pollConfig)
+ .build();
+ }
+
+ @Beta
+ public static String makeCommandExecutingInDirectory(String command,
String executionDir, EntityLocal entity) {
+ String finalCommand = command;
+ String execDir = executionDir;
+ if (Strings.isBlank(execDir)) {
+ // default to run dir
+ execDir = entity.getAttribute(BrooklynConfigKeys.RUN_DIR);
+ // if no run dir, default to home
+ if (Strings.isBlank(execDir)) {
+ execDir = "~";
+ }
+ } else if (!Os.isAbsolutish(execDir)) {
+ // relative paths taken wrt run dir
+ String runDir = entity.getAttribute(BrooklynConfigKeys.RUN_DIR);
+ if (!Strings.isBlank(runDir)) {
+ execDir = Os.mergePaths(runDir, execDir);
+ }
+ }
+ if (!"~".equals(execDir)) {
+ finalCommand = "mkdir -p '"+execDir+"' && cd '"+execDir+"' &&
"+finalCommand;
+ }
+ return finalCommand;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffectorIntegrationTest.java
----------------------------------------------------------------------
diff --git
a/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffectorIntegrationTest.java
b/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffectorIntegrationTest.java
new file mode 100644
index 0000000..7b5dd9a
--- /dev/null
+++
b/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshCommandEffectorIntegrationTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.effector.ssh;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+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;
+
+public class SshCommandEffectorIntegrationTest {
+
+ final static AttributeSensor<String> SENSOR_STRING =
Sensors.newStringSensor("aString", "");
+ final static AttributeSensor<Integer> SENSOR_INT =
Sensors.newIntegerSensor("aLong", "");
+ final static Effector<String> EFFECTOR_SAY_HI =
Effectors.effector(String.class, "sayHi").buildAbstract();
+
+ private TestApplication app;
+ private SshMachineLocation machine;
+ private EntityLocal entity;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ app = TestApplication.Factory.newManagedInstanceForTests();
+ machine = app.newLocalhostProvisioningLocation().obtain();
+ entity =
app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
+ app.start(ImmutableList.<Location>of());
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+ }
+
+ @Test(groups="Integration")
+ public void testSshEffector() throws Exception {
+ new SshCommandEffector(ConfigBag.newInstance()
+ .configure(SshCommandEffector.EFFECTOR_NAME, "sayHi")
+ .configure(SshCommandEffector.EFFECTOR_COMMAND, "echo hi"))
+ .apply(entity);
+
+ String val = entity.invoke(EFFECTOR_SAY_HI,
MutableMap.<String,String>of()).get();
+ Assert.assertEquals(val.trim(), "hi", "val="+val);
+ }
+
+ @Test(groups="Integration")
+ public void testSshEffectorWithParameters() throws Exception {
+ new SshCommandEffector(ConfigBag.newInstance()
+ .configure(SshCommandEffector.EFFECTOR_NAME, "sayHi")
+ .configure(SshCommandEffector.EFFECTOR_COMMAND, "echo $foo")
+ .configure(SshCommandEffector.EFFECTOR_PARAMETER_DEFS,
+ MutableMap.<String,Object>of("foo",
MutableMap.of("defaultValue", "hi"))))
+ .apply(entity);
+
+ String val;
+ // explicit value
+ val = entity.invoke(EFFECTOR_SAY_HI,
MutableMap.<String,String>of("foo", "bar")).get();
+ Assert.assertEquals(val.trim(), "bar", "val="+val);
+
+ // default value
+ val = entity.invoke(EFFECTOR_SAY_HI,
MutableMap.<String,String>of()).get();
+ Assert.assertEquals(val.trim(), "hi", "val="+val);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/core/src/test/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensorIntegrationTest.java
----------------------------------------------------------------------
diff --git
a/core/src/test/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensorIntegrationTest.java
b/core/src/test/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensorIntegrationTest.java
new file mode 100644
index 0000000..bdb4a81
--- /dev/null
+++
b/core/src/test/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensorIntegrationTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.sensor.ssh;
+
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.time.Duration;
+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;
+
+public class SshCommandSensorIntegrationTest {
+
+ final static AttributeSensor<String> SENSOR_STRING =
Sensors.newStringSensor("aString", "");
+ final static AttributeSensor<Integer> SENSOR_INT =
Sensors.newIntegerSensor("aLong", "");
+ final static Effector<String> EFFECTOR_SAY_HI =
Effectors.effector(String.class, "sayHi").buildAbstract();
+
+ private TestApplication app;
+ private SshMachineLocation machine;
+ private EntityLocal entity;
+ private File tempFile;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ app = TestApplication.Factory.newManagedInstanceForTests();
+ machine = app.newLocalhostProvisioningLocation().obtain();
+ entity =
app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
+ app.start(ImmutableList.<Location>of());
+ tempFile = File.createTempFile("testSshCommand", ".txt");
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+ if (tempFile != null) tempFile.delete();
+ }
+
+ @Test(groups="Integration")
+ public void testSshSensor() throws Exception {
+ new SshCommandSensor<String>(ConfigBag.newInstance()
+ .configure(SshCommandSensor.SENSOR_PERIOD,
Duration.millis(100))
+ .configure(SshCommandSensor.SENSOR_NAME,
SENSOR_STRING.getName())
+ .configure(SshCommandSensor.SENSOR_COMMAND, "echo foo >
"+tempFile.getAbsolutePath()+"\n"
+ + "wc "+tempFile.getAbsolutePath()))
+ .apply(entity);
+ entity.setAttribute(Attributes.SERVICE_UP, true);
+
+ String val = EntityTestUtils.assertAttributeEventuallyNonNull(entity,
SENSOR_STRING);
+ assertTrue(val.contains("1"), "val="+val);
+ String[] counts = val.trim().split("\\s+");
+ Assert.assertEquals(counts.length, 4, "val="+val);
+ Assert.assertEquals(counts[0], "1", "val="+val);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
----------------------------------------------------------------------
diff --git
a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
index ae80754..595547e 100644
---
a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
+++
b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
@@ -30,10 +30,10 @@ import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.effector.AddSensor;
import org.apache.brooklyn.core.sensor.DependentConfiguration;
import org.apache.brooklyn.core.sensor.HttpRequestSensor;
+import org.apache.brooklyn.core.sensor.ssh.SshCommandSensor;
import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
import org.apache.brooklyn.feed.jmx.JmxFeed;
import org.apache.brooklyn.feed.jmx.JmxHelper;
-import org.apache.brooklyn.sensor.ssh.SshCommandSensor;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.task.DynamicTasks;
import org.apache.brooklyn.util.core.task.Tasks;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
----------------------------------------------------------------------
diff --git
a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
index cee2d40..b14d6d8 100644
---
a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
+++
b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
@@ -102,6 +102,9 @@ public interface SoftwareProcess extends Entity, Startable {
@SetFromFlag("postLaunchCommand")
ConfigKey<String> POST_LAUNCH_COMMAND =
BrooklynConfigKeys.POST_LAUNCH_COMMAND;
+ @SetFromFlag("env")
+ MapConfigKey<Object> SHELL_ENVIRONMENT =
BrooklynConfigKeys.SHELL_ENVIRONMENT;
+
@SetFromFlag("version")
ConfigKey<String> SUGGESTED_VERSION = BrooklynConfigKeys.SUGGESTED_VERSION;
@@ -218,10 +221,6 @@ public interface SoftwareProcess extends Entity, Startable
{
ConfigKey<Map<String, String>> RUNTIME_TEMPLATES =
ConfigKeys.newConfigKey(new TypeToken<Map<String, String>>() { },
"templates.runtime", "Mapping of templates, to be filled in and
copied before customisation, to destination name relative to runDir");
- @SetFromFlag("env")
- MapConfigKey<Object> SHELL_ENVIRONMENT = new
MapConfigKey<Object>(Object.class,
- "shell.env", "Map of environment variables to pass to the runtime
shell", MutableMap.<String,Object>of());
-
@SetFromFlag("provisioningProperties")
MapConfigKey<Object> PROVISIONING_PROPERTIES = new
MapConfigKey<Object>(Object.class,
"provisioning.properties", "Custom properties to be passed in when
provisioning a new machine", MutableMap.<String,Object>of());
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
----------------------------------------------------------------------
diff --git
a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
deleted file mode 100644
index 9e3d885..0000000
---
a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.ssh;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.effector.AddEffector;
-import org.apache.brooklyn.core.effector.EffectorBody;
-import org.apache.brooklyn.core.effector.Effectors;
-import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
-import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
-import
org.apache.brooklyn.core.effector.ssh.SshEffectorTasks.SshEffectorTaskFactory;
-import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.text.Strings;
-
-import com.google.common.base.Preconditions;
-
-public final class SshCommandEffector extends AddEffector {
-
- public static final ConfigKey<String> EFFECTOR_COMMAND =
ConfigKeys.newStringConfigKey("command");
- public static final ConfigKey<String> EFFECTOR_EXECUTION_DIR =
SshCommandSensor.SENSOR_EXECUTION_DIR;
-
- public SshCommandEffector(ConfigBag params) {
- super(newEffectorBuilder(params).build());
- }
-
- public SshCommandEffector(Map<String,String> params) {
- this(ConfigBag.newInstance(params));
- }
-
- public static EffectorBuilder<String> newEffectorBuilder(ConfigBag params)
{
- EffectorBuilder<String> eff =
AddEffector.newEffectorBuilder(String.class, params);
- eff.impl(new Body(eff.buildAbstract(), params));
- return eff;
- }
-
-
- protected static class Body extends EffectorBody<String> {
- private final Effector<?> effector;
- private final String command;
- private final String executionDir;
-
- public Body(Effector<?> eff, ConfigBag params) {
- this.effector = eff;
- this.command =
Preconditions.checkNotNull(params.get(EFFECTOR_COMMAND), "command must be
supplied when defining this effector");
- this.executionDir = params.get(EFFECTOR_EXECUTION_DIR);
- // TODO could take a custom "env" aka effectorShellEnv
- }
-
- @Override
- public String call(ConfigBag params) {
- String command = this.command;
-
- command =
SshCommandSensor.makeCommandExecutingInDirectory(command, executionDir,
entity());
-
- MutableMap<String, String> env = MutableMap.of();
- // first set all declared parameters, including default values
- for (ParameterType<?> param: effector.getParameters()) {
- env.addIfNotNull(param.getName(), Strings.toString(
params.get(Effectors.asConfigKey(param)) ));
- }
-
- // then set things from the entities defined shell environment, if
applicable
-
env.putAll(Strings.toStringMap(entity().getConfig(SoftwareProcess.SHELL_ENVIRONMENT),
""));
-
- // if we wanted to resolve the surrounding environment in real
time -- see above
-// Map<String,Object> paramsResolved = (Map<String, Object>)
Tasks.resolveDeepValue(effectorShellEnv, Map.class,
entity().getExecutionContext());
-
- // finally set the parameters we've been passed; this will repeat
declared parameters but to no harm,
- // it may pick up additional values (could be a flag defining
whether this is permitted or not)
- env.putAll(Strings.toStringMap(params.getAllConfig()));
-
- SshEffectorTaskFactory<String> t = SshEffectorTasks.ssh(command)
- .requiringZeroAndReturningStdout()
- .summary("effector "+effector.getName())
- .environmentVariables(env);
- return queue(t).get();
- }
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git
a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
deleted file mode 100644
index 31c116f..0000000
---
a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.ssh;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.EntityInitializer;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.effector.AddSensor;
-import org.apache.brooklyn.core.sensor.HttpRequestSensor;
-import org.apache.brooklyn.entity.java.JmxAttributeSensor;
-import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.feed.ssh.SshFeed;
-import org.apache.brooklyn.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.feed.ssh.SshValueFunctions;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.os.Os;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
-
-/**
- * Configurable {@link EntityInitializer} which adds an SSH sensor feed
running the <code>command</code> supplied
- * in order to populate the sensor with the indicated <code>name</code>. Note
that the <code>targetType</code> is ignored,
- * and always set to {@link String}.
- *
- * @see HttpRequestSensor
- * @see JmxAttributeSensor
- */
-@Beta
-public final class SshCommandSensor<T> extends AddSensor<T> {
-
- private static final Logger LOG =
LoggerFactory.getLogger(SshCommandSensor.class);
-
- public static final ConfigKey<String> SENSOR_COMMAND =
ConfigKeys.newStringConfigKey("command", "SSH command to execute for sensor");
- public static final ConfigKey<String> SENSOR_EXECUTION_DIR =
ConfigKeys.newStringConfigKey("executionDir", "Directory where the command
should run; "
- + "if not supplied, executes in the entity's run dir (or home dir if
no run dir is defined); "
- + "use '~' to always execute in the home dir, or 'custom-feed/' to
execute in a custom-feed dir relative to the run dir");
-
- protected final String command;
- protected final String executionDir;
-
- public SshCommandSensor(final ConfigBag params) {
- super(params);
-
- // TODO create a supplier for the command string to support attribute
embedding
- command = Preconditions.checkNotNull(params.get(SENSOR_COMMAND),
"command");
-
- executionDir = params.get(SENSOR_EXECUTION_DIR);
- }
-
- @Override
- public void apply(final EntityLocal entity) {
- super.apply(entity);
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Adding SSH sensor {} to {}", name, entity);
- }
-
- Supplier<Map<String,String>> envSupplier = new
Supplier<Map<String,String>>() {
- @Override
- public Map<String, String> get() {
- return
MutableMap.copyOf(Strings.toStringMap(entity.getConfig(SoftwareProcess.SHELL_ENVIRONMENT),
""));
- }
- };
-
- Supplier<String> commandSupplier = new Supplier<String>() {
- @Override
- public String get() {
- return makeCommandExecutingInDirectory(command, executionDir,
entity);
- }
- };
-
- SshPollConfig<T> pollConfig = new SshPollConfig<T>(sensor)
- .period(period)
- .env(envSupplier)
- .command(commandSupplier)
- .checkSuccess(SshValueFunctions.exitStatusEquals(0))
- .onFailureOrException(Functions.constant((T) null))
- .onSuccess(Functions.compose(new Function<String, T>() {
- @Override
- public T apply(String input) {
- return TypeCoercions.coerce(input, getType(type));
- }}, SshValueFunctions.stdout()));
-
- SshFeed.builder()
- .entity(entity)
- .onlyIfServiceUp()
- .poll(pollConfig)
- .build();
- }
-
- static String makeCommandExecutingInDirectory(String command, String
executionDir, EntityLocal entity) {
- String finalCommand = command;
- String execDir = executionDir;
- if (Strings.isBlank(execDir)) {
- // default to run dir
- execDir = entity.getAttribute(SoftwareProcess.RUN_DIR);
- // if no run dir, default to home
- if (Strings.isBlank(execDir)) {
- execDir = "~";
- }
- } else if (!Os.isAbsolutish(execDir)) {
- // relative paths taken wrt run dir
- String runDir = entity.getAttribute(SoftwareProcess.RUN_DIR);
- if (!Strings.isBlank(runDir)) {
- execDir = Os.mergePaths(runDir, execDir);
- }
- }
- if (!"~".equals(execDir)) {
- finalCommand = "mkdir -p '"+execDir+"' && cd '"+execDir+"' &&
"+finalCommand;
- }
- return finalCommand;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/080d2de0/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
----------------------------------------------------------------------
diff --git
a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
deleted file mode 100644
index c57711f..0000000
---
a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.entity.software.base.test.ssh;
-
-import static org.testng.Assert.assertTrue;
-
-import java.io.File;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.effector.Effectors;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.ssh.SshCommandEffector;
-import org.apache.brooklyn.sensor.ssh.SshCommandSensor;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.time.Duration;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-
-import com.google.common.collect.ImmutableList;
-
-public class SshCommandIntegrationTest {
-
- final static AttributeSensor<String> SENSOR_STRING =
Sensors.newStringSensor("aString", "");
- final static AttributeSensor<Integer> SENSOR_INT =
Sensors.newIntegerSensor("aLong", "");
- final static Effector<String> EFFECTOR_SAY_HI =
Effectors.effector(String.class, "sayHi").buildAbstract();
-
- private TestApplication app;
- private SshMachineLocation machine;
- private EntityLocal entity;
-
- @BeforeMethod(alwaysRun=true)
- public void setUp() throws Exception {
- app = TestApplication.Factory.newManagedInstanceForTests();
- machine = app.newLocalhostProvisioningLocation().obtain();
- entity =
app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
- app.start(ImmutableList.<Location>of());
- }
-
- @AfterMethod(alwaysRun=true)
- public void tearDown() throws Exception {
- if (app != null) Entities.destroyAll(app.getManagementContext());
- }
-
- @Test(groups="Integration")
- public void testSshSensor() throws Exception {
- File tempFile = File.createTempFile("testSshCommand", "txt");
- tempFile.deleteOnExit();
- new SshCommandSensor<String>(ConfigBag.newInstance()
- .configure(SshCommandSensor.SENSOR_PERIOD,
Duration.millis(100))
- .configure(SshCommandSensor.SENSOR_NAME,
SENSOR_STRING.getName())
- .configure(SshCommandSensor.SENSOR_COMMAND, "echo foo >
"+tempFile.getAbsolutePath()+"\n"
- + "wc "+tempFile.getAbsolutePath()))
- .apply(entity);
- entity.setAttribute(Attributes.SERVICE_UP, true);
-
- String val = EntityTestUtils.assertAttributeEventuallyNonNull(entity,
SENSOR_STRING);
- assertTrue(val.contains("1"), "val="+val);
- String[] counts = val.trim().split("\\s+");
- Assert.assertEquals(counts.length, 4, "val="+val);
- Assert.assertEquals(counts[0], "1", "val="+val);
- }
-
- @Test(groups="Integration")
- public void testSshEffector() throws Exception {
- File tempFile = File.createTempFile("testSshCommand", "txt");
- tempFile.deleteOnExit();
- new SshCommandEffector(ConfigBag.newInstance()
- .configure(SshCommandEffector.EFFECTOR_NAME, "sayHi")
- .configure(SshCommandEffector.EFFECTOR_COMMAND, "echo hi"))
- .apply(entity);
-
- String val = entity.invoke(EFFECTOR_SAY_HI,
MutableMap.<String,String>of()).get();
- Assert.assertEquals(val.trim(), "hi", "val="+val);
- }
-
- @Test(groups="Integration")
- public void testSshEffectorWithParameters() throws Exception {
- File tempFile = File.createTempFile("testSshCommand", "txt");
- tempFile.deleteOnExit();
- new SshCommandEffector(ConfigBag.newInstance()
- .configure(SshCommandEffector.EFFECTOR_NAME, "sayHi")
- .configure(SshCommandEffector.EFFECTOR_COMMAND, "echo $foo")
- .configure(SshCommandEffector.EFFECTOR_PARAMETER_DEFS,
- MutableMap.<String,Object>of("foo",
MutableMap.of("defaultValue", "hi"))))
- .apply(entity);
-
- String val;
- // explicit value
- val = entity.invoke(EFFECTOR_SAY_HI,
MutableMap.<String,String>of("foo", "bar")).get();
- Assert.assertEquals(val.trim(), "bar", "val="+val);
-
- // default value
- val = entity.invoke(EFFECTOR_SAY_HI,
MutableMap.<String,String>of()).get();
- Assert.assertEquals(val.trim(), "hi", "val="+val);
- }
-
-}