Repository: brooklyn-server Updated Branches: refs/heads/master 4a65aed0d -> e91b6c5c9
Add shell.env config for SSH sensor and effector Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/e98ab974 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/e98ab974 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/e98ab974 Branch: refs/heads/master Commit: e98ab97400be35a771df07618f4ad26dc98aa8bb Parents: 4a65aed Author: Andrew Donald Kennedy <[email protected]> Authored: Wed Jul 27 15:43:32 2016 +0100 Committer: Andrew Donald Kennedy <[email protected]> Committed: Wed Jul 27 16:14:23 2016 +0100 ---------------------------------------------------------------------- .../core/effector/ssh/SshCommandEffector.java | 77 +++++++++++--------- .../core/sensor/ssh/SshCommandSensor.java | 29 ++++++-- 2 files changed, 66 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e98ab974/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 index ca952fe..6f53c08 100644 --- 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 @@ -19,34 +19,39 @@ package org.apache.brooklyn.core.effector.ssh; import java.util.Map; +import java.util.concurrent.ExecutionException; + +import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; +import com.google.common.collect.Maps; 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.config.MapConfigKey; 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.entity.EntityInternal; 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.core.json.ShellEnvironmentSerializer; -import org.apache.brooklyn.util.text.Strings; - -import com.google.common.base.Preconditions; +import org.apache.brooklyn.util.core.task.Tasks; +import org.apache.brooklyn.util.exceptions.Exceptions; 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 static final MapConfigKey<Object> EFFECTOR_SHELL_ENVIRONMENT = BrooklynConfigKeys.SHELL_ENVIRONMENT; + public SshCommandEffector(ConfigBag params) { super(newEffectorBuilder(params).build()); } - + public SshCommandEffector(Map<String,String> params) { this(ConfigBag.newInstance(params)); } @@ -57,7 +62,6 @@ public final class SshCommandEffector extends AddEffector { return eff; } - protected static class Body extends EffectorBody<String> { private final Effector<?> effector; private final String command; @@ -65,42 +69,47 @@ public final class SshCommandEffector extends AddEffector { 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.command = Preconditions.checkNotNull(params.get(EFFECTOR_COMMAND), "SSH 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)) )); + String sshCommand = SshCommandSensor.makeCommandExecutingInDirectory(command, executionDir, entity()); + + MutableMap<String, Object> env = MutableMap.of(); + + // first set all declared parameters, including default values, + for (ParameterType<?> param : effector.getParameters()) { + env.addIfNotNull(param.getName(), params.get(Effectors.asConfigKey(param))); } - + // then set things from the entities defined shell environment, if applicable - Map<String, Object> shellEnv = entity().getConfig(BrooklynConfigKeys.SHELL_ENVIRONMENT); - ShellEnvironmentSerializer envSerializer = new ShellEnvironmentSerializer(((EntityInternal)entity()).getManagementContext()); - env.putAll(envSerializer.serialize(shellEnv)); - - // 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) + env.putAll(entity().getConfig(BrooklynConfigKeys.SHELL_ENVIRONMENT)); + + // now add the resolved shell environment entries from our configuration + try { + Map<String, Object> effectorEnv = params.get(EFFECTOR_SHELL_ENVIRONMENT); + if (effectorEnv != null && effectorEnv.size() > 0) { + Map<String, Object> effectorEnvResolved = (Map<String, Object>) Tasks.resolveDeepValue(effectorEnv, Object.class, entity().getExecutionContext()); + env.putAll(effectorEnvResolved); + } + } catch (InterruptedException | ExecutionException e) { + Exceptions.propagateIfFatal(e); + } + + // 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.) + // Make sure we do not include the shell.env here again, by filtering it out. + env.putAll(Maps.filterKeys(params.getAllConfig(), Predicates.not(Predicates.equalTo(EFFECTOR_SHELL_ENVIRONMENT.getName())))); + + ShellEnvironmentSerializer serializer = new ShellEnvironmentSerializer(entity().getManagementContext()); + SshEffectorTasks.SshEffectorTaskFactory<String> t = SshEffectorTasks.ssh(sshCommand) .requiringZeroAndReturningStdout() .summary("effector "+effector.getName()) - .environmentVariables(env); + .environmentVariables(serializer.serialize(env)); + return queue(t).get(); } - } - } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e98ab974/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 index 3464281..739bbaf 100644 --- 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 @@ -19,6 +19,7 @@ package org.apache.brooklyn.core.sensor.ssh; import java.util.Map; +import java.util.concurrent.ExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +34,7 @@ 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.config.MapConfigKey; import org.apache.brooklyn.core.effector.AddSensor; import org.apache.brooklyn.core.entity.BrooklynConfigKeys; import org.apache.brooklyn.core.entity.EntityInternal; @@ -44,6 +46,8 @@ 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.core.json.ShellEnvironmentSerializer; +import org.apache.brooklyn.util.core.task.Tasks; +import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.os.Os; import org.apache.brooklyn.util.text.Strings; @@ -63,17 +67,19 @@ public final class SshCommandSensor<T> extends AddSensor<T> { 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"); + public static final MapConfigKey<Object> SENSOR_SHELL_ENVIRONMENT = BrooklynConfigKeys.SHELL_ENVIRONMENT; protected final String command; protected final String executionDir; + protected final Map<String,Object> sensorEnv; 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"); - + command = Preconditions.checkNotNull(params.get(SENSOR_COMMAND), "SSH command must be dupplied when defining this sensor"); executionDir = params.get(SENSOR_EXECUTION_DIR); + sensorEnv = params.get(SENSOR_SHELL_ENVIRONMENT); } @Override @@ -87,9 +93,20 @@ public final class SshCommandSensor<T> extends AddSensor<T> { Supplier<Map<String,String>> envSupplier = new Supplier<Map<String,String>>() { @Override public Map<String, String> get() { - Map<String, Object> env = entity.getConfig(BrooklynConfigKeys.SHELL_ENVIRONMENT); - ShellEnvironmentSerializer envSerializer = new ShellEnvironmentSerializer(((EntityInternal)entity).getManagementContext()); - return envSerializer.serialize(env); + Map<String, Object> env = MutableMap.copyOf(entity.getConfig(BrooklynConfigKeys.SHELL_ENVIRONMENT)); + + // now add the resolved shell environment entries from our configuration + try { + if (sensorEnv != null && sensorEnv.size() > 0) { + Map<String,Object> sensorEnvResolved = (Map<String, Object>) Tasks.resolveDeepValue(sensorEnv, Object.class, ((EntityInternal) entity).getExecutionContext()); + env.putAll(sensorEnvResolved); + } + } catch (InterruptedException | ExecutionException e) { + Exceptions.propagateIfFatal(e); + } + + ShellEnvironmentSerializer serializer = new ShellEnvironmentSerializer(((EntityInternal) entity).getManagementContext()); + return serializer.serialize(env); } }; @@ -109,7 +126,7 @@ public final class SshCommandSensor<T> extends AddSensor<T> { .onSuccess(Functions.compose(new Function<String, T>() { @Override public T apply(String input) { - return TypeCoercions.coerce(Strings.trimEnd(input), getType(entity, type)); + return TypeCoercions.coerce(Strings.trimEnd(input), (Class<T>) sensor.getType()); }}, SshValueFunctions.stdout())); SshFeed.builder()
