Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,23 @@
@Beta
public class AddSensor<T> implements EntityInitializer {

public static final ConfigKey<String> SENSOR_NAME = ConfigKeys.newStringConfigKey("name", "The name of the sensor to create");
public static final ConfigKey<Duration> SENSOR_PERIOD = ConfigKeys.newConfigKey(Duration.class, "period", "Period, including units e.g. 1m or 5s or 200ms; default 5 minutes", Duration.FIVE_MINUTES);
public static final ConfigKey<String> SENSOR_TYPE = ConfigKeys.newStringConfigKey("targetType", "Target type for the value; default String", "java.lang.String");
public static final ConfigKey<String> SENSOR_NAME = ConfigKeys.newStringConfigKey(
"name", "The name of the sensor to create");

public static final ConfigKey<Duration> SENSOR_PERIOD = ConfigKeys.newDurationConfigKey(
"period",
"Period in which the sensor should be updated, including units e.g. 1m, 5s or 200ms; default 5 minutes",
Duration.FIVE_MINUTES);

public static final ConfigKey<String> SENSOR_TYPE = ConfigKeys.newStringConfigKey(
"targetType", "Target type for the value; default String",
"java.lang.String");

protected final String name;
protected final Duration period;
protected final String type;
protected final AttributeSensor<T> sensor;
protected final ConfigBag params;

public AddSensor(Map<String, String> params) {
this(ConfigBag.newInstance(params));
Expand All @@ -65,6 +74,7 @@ public AddSensor(final ConfigBag params) {
this.period = params.get(SENSOR_PERIOD);
this.type = params.get(SENSOR_TYPE);
this.sensor = newSensor();
this.params = params;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
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.EntityInitializers;
import org.apache.brooklyn.core.sensor.ssh.SshCommandSensor;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.config.ConfigBag;
Expand Down Expand Up @@ -58,45 +59,47 @@ public static EffectorBuilder<String> newEffectorBuilder(ConfigBag params) {

protected static class Body extends EffectorBody<String> {
private final Effector<?> effector;
private final String command;
private final String executionDir;
private final ConfigBag params;

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);
Preconditions.checkNotNull(params.getAllConfigRaw().get(EFFECTOR_COMMAND.getName()), "command must be supplied when defining this effector");
this.params = params;
// TODO could take a custom "env" aka effectorShellEnv
}

@Override
public String call(ConfigBag params) {
String command = this.command;

ConfigBag allConfig = ConfigBag.newInstanceCopying(this.params).putAll(params);
String command = EntityInitializers.resolve(allConfig, EFFECTOR_COMMAND);
String executionDir = EntityInitializers.resolve(allConfig, EFFECTOR_EXECUTION_DIR);

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)) ));
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);
.requiringZeroAndReturningStdout()
.summary("effector " + effector.getName())
.environmentVariables(env);
return queue(t).get();
}

}



}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

import org.apache.brooklyn.api.entity.EntityInitializer;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.mgmt.ExecutionContext;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.internal.ConfigKeySelfExtracting;
import org.apache.brooklyn.util.core.task.BasicExecutionContext;

import com.google.common.collect.ImmutableList;

Expand All @@ -45,5 +50,30 @@ public void apply(EntityLocal entity) {
public static EntityInitializer addingTags(Object... tags) {
return new AddTags(tags);
}


/**
* Resolves key in the
* {@link BasicExecutionContext#getCurrentExecutionContext current execution context}.
* @see #resolve(ConfigBag, ConfigKey, ExecutionContext)
*/
public static <T> T resolve(ConfigBag configBag, ConfigKey<T> key) {
return resolve(configBag, key, BasicExecutionContext.getCurrentExecutionContext());
}

/**
* Gets the value for key from configBag.
* <p>
* If key is an instance of {@link ConfigKeySelfExtracting} and executionContext is
* not null then its value will be retrieved per the key's implementation of
* {@link ConfigKeySelfExtracting#extractValue extractValue}. Otherwise, the value
* will be retrieved from configBag directly.
*/
public static <T> T resolve(ConfigBag configBag, ConfigKey<T> key, ExecutionContext executionContext) {
if (key instanceof ConfigKeySelfExtracting && executionContext != null) {
ConfigKeySelfExtracting<T> ckse = ((ConfigKeySelfExtracting<T>) key);
return ckse.extractValue(configBag.getAllConfigAsConfigKeyMap(), executionContext);
}
return configBag.get(key);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@

import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.api.mgmt.TaskAdaptable;
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.Entities;
import org.apache.brooklyn.enricher.stock.Propagator;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.core.task.ValueResolver;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.time.Duration;
import org.slf4j.Logger;
Expand All @@ -47,7 +45,8 @@
* This supports a {@link StaticSensor#SENSOR_PERIOD}
* which can be useful if the supplied value is such a function.
* However when the source is another sensor,
* consider using {@link Propagator} which listens for changes instead. */
* consider using {@link Propagator} which listens for changes instead.
*/
public class StaticSensor<T> extends AddSensor<T> {

private static final Logger log = LoggerFactory.getLogger(StaticSensor.class);
Expand All @@ -65,18 +64,24 @@ public StaticSensor(ConfigBag params) {
timeout = params.get(TIMEOUT);
}

@SuppressWarnings("unchecked")
@Override
public void apply(final EntityLocal entity) {
super.apply(entity);

class ResolveValue implements Callable<Maybe<T>> {
@SuppressWarnings("unchecked")
@Override
public Maybe<T> call() throws Exception {
return Tasks.resolving(value).as((Class<T>)sensor.getType()).timeout(timeout).getMaybe();
return Tasks.resolving(value)
.as((Class<T>)sensor.getType())
.timeout(timeout)
.getMaybe();
}
}
final Task<Maybe<T>> resolveValue = Tasks.<Maybe<T>>builder().displayName("resolving " + value).body(new ResolveValue()).build();
final Task<Maybe<T>> resolveValue = Tasks.<Maybe<T>>builder()
.displayName("resolving " + value)
.body(new ResolveValue())
.build();

class SetValue implements Callable<T> {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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.EntityInitializers;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.text.Identifiers;

Expand All @@ -33,23 +34,21 @@ public class CreatePasswordSensor extends AddSensor<String> {

public static final ConfigKey<String> ACCEPTABLE_CHARS = ConfigKeys.newStringConfigKey("password.chars", "The characters allowed in password");

private Integer passwordLength;
private String acceptableChars;

public CreatePasswordSensor(Map<String, String> params) {
this(ConfigBag.newInstance(params));
}

public CreatePasswordSensor(ConfigBag params) {
super(params);
passwordLength = params.get(PASSWORD_LENGTH);
acceptableChars = params.get(ACCEPTABLE_CHARS);
}

@Override
public void apply(EntityLocal entity) {
super.apply(entity);

Integer passwordLength = EntityInitializers.resolve(params, PASSWORD_LENGTH);
String acceptableChars = EntityInitializers.resolve(params, ACCEPTABLE_CHARS);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply is called before managing any of the entities in the spec hierarchy (i.e. a camp plan) so this can't be resolved at this point. It would just block app creation. Could you add some tests to prove me wrong :).
StaticSensor does the right thing by pushing all of it in tasks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, this was lazy of me.


String password = acceptableChars == null
? Identifiers.makeRandomPassword(passwordLength)
: Identifiers.makeRandomPassword(passwordLength, acceptableChars);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
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.entity.EntityInitializers;
import org.apache.brooklyn.core.sensor.http.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.core.task.Tasks;
import org.apache.brooklyn.util.os.Os;
import org.apache.brooklyn.util.text.Strings;
import org.slf4j.Logger;
Expand Down Expand Up @@ -61,16 +63,9 @@ public final class SshCommandSensor<T> extends AddSensor<T> {
+ "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);
Preconditions.checkNotNull(params.getAllConfigRaw().get(SENSOR_COMMAND.getName()), "command");
}

@Override
Expand All @@ -91,6 +86,8 @@ public Map<String, String> get() {
Supplier<String> commandSupplier = new Supplier<String>() {
@Override
public String get() {
String command = EntityInitializers.resolve(params, SENSOR_COMMAND);
String executionDir = EntityInitializers.resolve(params, SENSOR_EXECUTION_DIR);
return makeCommandExecutingInDirectory(command, executionDir, entity);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
* A class that supplies objects of a single type. When used as a ConfigKey value,
* the evaluation is deferred until getConfig() is called. The returned value will then
* be coerced to the correct type.
*
* <p>
* Subsequent calls to getConfig will result in further calls to deferredProvider.get(),
* rather than reusing the result. If you want to reuse the result, consider instead
* using a Future.
*
* Note that this functionality replaces the ues of Closure in brooklyn 0.4.0, which
* <p>
* Note that this functionality replaces the ues of Closure in brooklyn 0.4.0, which
* served the same purpose.
*/
public interface DeferredSupplier<T> extends Supplier<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

/**
* Resolves a given object, as follows:
* <li> If it is a {@link Tasks} or a {@link DeferredSupplier} then get its contents
* <li> If it is a {@link Task} or a {@link DeferredSupplier} then get its contents
* <li> If it's a map and {@link #deep(boolean)} is requested, it applies resolution to contents
* <li> It applies coercion
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
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.EntityInitializers;
import org.apache.brooklyn.core.sensor.DependentConfiguration;
import org.apache.brooklyn.core.sensor.http.HttpRequestSensor;
import org.apache.brooklyn.core.sensor.ssh.SshCommandSensor;
Expand Down Expand Up @@ -61,22 +62,8 @@ public final class JmxAttributeSensor<T> extends AddSensor<T> {
public static final ConfigKey<String> ATTRIBUTE = ConfigKeys.newStringConfigKey("attribute", "JMX attribute to poll in object");
public static final ConfigKey<Object> DEFAULT_VALUE = ConfigKeys.newConfigKey(Object.class, "defaultValue", "Default value for sensor; normally null");

protected final String objectName;
protected final String attribute;
protected final Object defaultValue;

public JmxAttributeSensor(final ConfigBag params) {
super(params);

objectName = Preconditions.checkNotNull(params.get(OBJECT_NAME), "objectName");
attribute = Preconditions.checkNotNull(params.get(ATTRIBUTE), "attribute");
defaultValue = params.get(DEFAULT_VALUE);

try {
ObjectName.getInstance(objectName);
} catch (MalformedObjectNameException mone) {
throw new IllegalArgumentException("Malformed JMX object name: " + objectName, mone);
}
}

@Override
Expand All @@ -88,6 +75,16 @@ public void apply(final EntityLocal entity) {
LOG.debug("Submitting task to add JMX sensor {} to {}", name, entity);
}

final String objectName = Preconditions.checkNotNull(EntityInitializers.resolve(params, OBJECT_NAME), "objectName");
final String attribute = Preconditions.checkNotNull(EntityInitializers.resolve(params, ATTRIBUTE), "attribute");
final Object defaultValue = EntityInitializers.resolve(params, DEFAULT_VALUE);

try {
ObjectName.getInstance(objectName);
} catch (MalformedObjectNameException mone) {
throw new IllegalArgumentException("Malformed JMX object name: " + objectName, mone);
}

Task<Integer> jmxPortTask = DependentConfiguration.attributeWhenReady(entity, UsesJmx.JMX_PORT);
Task<JmxFeed> jmxFeedTask = Tasks.<JmxFeed>builder()
.description("Add JMX feed")
Expand All @@ -100,10 +97,10 @@ public JmxFeed call() throws Exception {
.entity(entity)
.period(period)
.helper(helper)
.pollAttribute(new JmxAttributePollConfig<T>(sensor)
.pollAttribute(new JmxAttributePollConfig<>(sensor)
.objectName(objectName)
.attributeName(attribute)
.onFailureOrException(Functions.<T>constant((T) defaultValue)))
.onFailureOrException(Functions.constant((T) defaultValue)))
.build();
entity.addFeed(feed);
return feed;
Expand Down