You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/01/15 11:11:59 UTC
[1/7] incubator-brooklyn git commit: Avoid NPE in
PortForwardManager.rebindSupport
Repository: incubator-brooklyn
Updated Branches:
refs/heads/master 6455a9da2 -> e4ecb3871
Avoid NPE in PortForwardManager.rebindSupport
- caused by publicIpIdToHostname containing a null key or null value
(not sure what; it’s deprecated so not worrying about it!).
- Instead of ImmutableMap for copying it, use MutableMap.copyOf
so will not fail on null.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/c61a3093
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/c61a3093
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/c61a3093
Branch: refs/heads/master
Commit: c61a309302240c6108243ef25341802a12031d56
Parents: d89062b
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jan 9 12:12:12 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Jan 14 22:38:08 2015 +0000
----------------------------------------------------------------------
.../java/brooklyn/location/access/PortForwardManagerImpl.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c61a3093/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java b/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java
index 7d30a69..c9a596b 100644
--- a/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java
+++ b/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java
@@ -117,8 +117,8 @@ public class PortForwardManagerImpl extends AbstractLocation implements PortForw
Map<String, PortMapping> mappingsCopy;
Map<String,String> publicIpIdToHostnameCopy;
synchronized (mutex) {
- mappingsCopy = ImmutableMap.copyOf(mappings);
- publicIpIdToHostnameCopy = ImmutableMap.copyOf(publicIpIdToHostname);
+ mappingsCopy = MutableMap.copyOf(mappings);
+ publicIpIdToHostnameCopy = MutableMap.copyOf(publicIpIdToHostname);
}
return getMementoWithProperties(MutableMap.<String,Object>of(
"mappings", mappingsCopy,
[2/7] incubator-brooklyn git commit: BROOKLYN-106: Fix sshj’s async-exec
Posted by al...@apache.org.
BROOKLYN-106: Fix sshj’s async-exec
- on repeated timeouts of longPoll, then keep
going.
- On long-poll, reduce the sshTriesTimeout.
- On timeout/error, don’t wait forever for
stdout/stderr streams to close.
- Potential improvement to disconnect/reconnect.
- Adds Duration.isShorterThan(Stopwatch)
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/c06a2297
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/c06a2297
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/c06a2297
Branch: refs/heads/master
Commit: c06a2297eadfd5b6322bde303a65cbc0e477c7d1
Parents: 0673146
Author: Aled Sage <al...@gmail.com>
Authored: Thu Jan 8 21:12:58 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Jan 14 22:38:08 2015 +0000
----------------------------------------------------------------------
.../util/internal/ssh/ShellAbstractTool.java | 34 +++--
.../internal/ssh/sshj/SshjClientConnection.java | 2 +-
.../util/internal/ssh/sshj/SshjTool.java | 150 ++++++++++++++++---
.../sshj/SshjToolAsyncStubIntegrationTest.java | 14 +-
.../ssh/sshj/SshjToolIntegrationTest.java | 80 ++++++----
.../main/java/brooklyn/util/time/Duration.java | 9 +-
6 files changed, 219 insertions(+), 70 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c06a2297/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java b/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java
index 82624d7..e677399 100644
--- a/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java
+++ b/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java
@@ -247,7 +247,7 @@ public abstract class ShellAbstractTool implements ShellTool {
}
this.scriptNameWithoutExtension = "brooklyn-"+
Time.makeDateStampString()+"-"+Identifiers.makeRandomId(4)+
- (summary==null ? "" : "-"+summary);
+ (Strings.isBlank(summary) ? "" : "-"+summary);
this.scriptPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension+".sh");
}
@@ -367,14 +367,13 @@ public abstract class ShellAbstractTool implements ShellTool {
* An offset can be given, to only retrieve data starting at a particular character (indexed from 0).
*/
protected List<String> buildLongPollCommand(int stdoutPosition, int stderrPosition, Duration timeout) {
- // Note that `tail -c +1` means start at the *first* character (i.e. start counting from 1, not 0)
- // TODO Relies on commands terminating when ssh connection dropped (because not run with `nohup`)
- String catStdoutCmd = "tail -c +"+(stdoutPosition+1)+" -f "+stdoutPath+" &";
- String catStderrCmd = "tail -c +"+(stderrPosition+1)+" -f "+stderrPath+" 1>&2 &";
long maxTime = Math.max(1, timeout.toSeconds());
+ // Note that `tail -c +1` means start at the *first* character (i.e. start counting from 1, not 0)
List<String> waitForExitStatusParts = ImmutableList.of(
"# Long poll", // comment is to aid testing - see SshjToolAsyncStubIntegrationTest
+ "tail -c +"+(stdoutPosition+1)+" -f "+stdoutPath+" & export TAIL_STDOUT_PID=$!",
+ "tail -c +"+(stderrPosition+1)+" -f "+stderrPath+" 1>&2 & export TAIL_STDERR_PID=$!",
"EXIT_STATUS_PATH="+exitStatusPath,
"PID_PATH="+pidPath,
"MAX_TIME="+maxTime,
@@ -390,9 +389,11 @@ public abstract class ShellAbstractTool implements ShellTool {
" sleep 3",
" if test -s $EXIT_STATUS_PATH; then",
" EXIT_STATUS=`cat $EXIT_STATUS_PATH`",
+ " kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID}",
" exit $EXIT_STATUS",
" else",
" echo \"No exit status in $EXIT_STATUS_PATH, and pid in $PID_PATH ($PID) not executing\"",
+ " kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID}",
" exit 126",
" fi",
" fi",
@@ -401,25 +402,32 @@ public abstract class ShellAbstractTool implements ShellTool {
" sleep 1",
" COUNTER+=1",
"done",
+ "kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID}",
"exit 125"+"\n");
String waitForExitStatus = Joiner.on("\n").join(waitForExitStatusParts);
- MutableList.Builder<String> cmds = MutableList.<String>builder()
- .add(runAsRoot ? BashCommands.sudo(catStdoutCmd) : catStdoutCmd)
- .add(runAsRoot ? BashCommands.sudo(catStderrCmd) : catStderrCmd)
- .add(runAsRoot ? BashCommands.sudo(waitForExitStatus) : waitForExitStatus);
- return cmds.build();
+ return ImmutableList.of(runAsRoot ? BashCommands.sudo(waitForExitStatus) : waitForExitStatus);
}
protected List<String> deleteTemporaryFilesCommand() {
+ ImmutableList.Builder<String> cmdParts = ImmutableList.builder();
+
if (!Boolean.TRUE.equals(noDeleteAfterExec)) {
// use "-f" because some systems have "rm" aliased to "rm -i"
// use "< /dev/null" to guarantee doesn't hang
- return ImmutableList.of(
+ cmdParts.add(
"rm -f "+scriptPath+" "+stdoutPath+" "+stderrPath+" "+exitStatusPath+" "+pidPath+" < /dev/null");
- } else {
- return ImmutableList.<String>of();
}
+
+ // If the buildLongPollCommand didn't complete properly then it might have left tail command running;
+ // ensure they are killed.
+ cmdParts.add(
+ "ps aux | grep \"tail -c\" | grep \""+stdoutPath+"\" | grep -v grep | awk '{ printf $2 }' | xargs kill",
+ "ps aux | grep \"tail -c\" | grep \""+stderrPath+"\" | grep -v grep | awk '{ printf $2 }' | xargs kill");
+
+ String cmd = Joiner.on("\n").join(cmdParts.build());
+
+ return ImmutableList.of(runAsRoot ? BashCommands.sudo(cmd) : cmd);
}
public abstract int run();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c06a2297/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java b/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java
index 52347d2..982022a 100644
--- a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java
+++ b/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java
@@ -169,8 +169,8 @@ public class SshjClientConnection implements SshAction<SSHClient> {
} catch (IOException e) {
if (LOG.isDebugEnabled()) LOG.debug("<< exception disconnecting from {}: {}", e, e.getMessage());
}
- ssh = null;
}
+ ssh = null;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c06a2297/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java b/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java
index e7ecd0c..8fa38ad 100644
--- a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java
+++ b/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java
@@ -55,7 +55,9 @@ import org.slf4j.LoggerFactory;
import brooklyn.internal.BrooklynFeatureEnablement;
import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.RuntimeTimeoutException;
import brooklyn.util.internal.ssh.BackoffLimitedRetryHandler;
+import brooklyn.util.internal.ssh.ShellTool;
import brooklyn.util.internal.ssh.SshAbstractTool;
import brooklyn.util.internal.ssh.SshTool;
import brooklyn.util.io.FileUtil;
@@ -333,6 +335,24 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
}
+ /**
+ * Executes the script in the background (`nohup ... &`), and then executes other ssh commands to poll for the
+ * stdout, stderr and exit code of that original process (which will each have been written to separate files).
+ *
+ * The polling is a "long poll". That is, it executes a long-running ssh command to retrieve the stdout, etc.
+ * If that long-poll command fails, then we just execute another one to pick up from where it left off.
+ * This means we do not need to execute many ssh commands (which are expensive), but can still return promptly
+ * when the command completes.
+ *
+ * Much of this was motivated by https://issues.apache.org/jira/browse/BROOKLYN-106, which is no longer
+ * an issue. The retries (e.g. in the upload-script) are arguably overkill given that {@link #acquire(SshAction)}
+ * will already retry. However, leaving this in place as it could prove useful when working with flakey
+ * networks in the future.
+ *
+ * TODO There are (probably) issues with this method when using {@link ShellTool#PROP_RUN_AS_ROOT}.
+ * I (Aled) saw the .pid file having an owner of root:root, and a failure message in stderr of:
+ * -bash: line 3: /tmp/brooklyn-20150113-161203056-XMEo-move_install_dir_from_user_to_.pid: Permission denied
+ */
protected int execScriptAsyncAndPoll(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
return new ToolAbstractAsyncExecScript(props) {
private int maxConsecutiveSshFailures = 3;
@@ -346,9 +366,37 @@ public class SshjTool extends SshAbstractTool implements SshTool {
public int run() {
timer = Stopwatch.createStarted();
- String scriptContents = toScript(props, commands, env);
+ final String scriptContents = toScript(props, commands, env);
if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as async script: {}", host, scriptContents);
- copyToServer(ImmutableMap.of("permissions", "0700"), scriptContents.getBytes(), scriptPath);
+
+ // Upload script; try repeatedly because have seen timeout intermittently on vcloud-director (BROOKLYN-106 related).
+ boolean uploadSuccess = Repeater.create("async script upload on "+SshjTool.this.toString()+" (for "+getSummary()+")")
+ .backoffTo(maxDelayBetweenPolls)
+ .limitIterationsTo(3)
+ .rethrowException()
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ iteration++;
+ if (LOG.isDebugEnabled()) {
+ String msg = "Uploading (iteration="+iteration+") for async script on "+SshjTool.this.toString()+" (for "+getSummary()+")";
+ if (iteration == 1) {
+ LOG.trace(msg);
+ } else {
+ LOG.debug(msg);
+ }
+ }
+ copyToServer(ImmutableMap.of("permissions", "0700"), scriptContents.getBytes(), scriptPath);
+ return true;
+ }})
+ .run();
+
+ if (!uploadSuccess) {
+ // Unexpected! Should have either returned true or have rethrown the exception; should never get false.
+ String msg = "Unexpected state: repeated failure for async script upload on "+SshjTool.this.toString()+" ("+getSummary()+")";
+ LOG.warn(msg+"; rethrowing");
+ throw new IllegalStateException(msg);
+ }
// Execute script asynchronously
int execResult = asInt(acquire(new ShellAction(buildRunScriptCommand(), out, err, execTimeout)), -1);
@@ -357,7 +405,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
// Long polling to get the status
try {
final AtomicReference<Integer> result = new AtomicReference<Integer>();
- boolean success = Repeater.create("async script on "+SshjTool.this.toString()+" (for "+getSummary()+")")
+ boolean success = Repeater.create("async script long-poll on "+SshjTool.this.toString()+" (for "+getSummary()+")")
.backoffTo(maxDelayBetweenPolls)
.limitTimeTo(execTimeout)
.until(new Callable<Boolean>() {
@@ -377,13 +425,28 @@ public class SshjTool extends SshAbstractTool implements SshTool {
LOG.warn(msg+"; rethrowing");
throw new TimeoutException(msg);
}
-
+
return result.get();
} catch (Exception e) {
+ LOG.debug("Problem polling for async script on "+SshjTool.this.toString()+" (for "+getSummary()+"); rethrowing after deleting temporary files", e);
throw Exceptions.propagate(e);
+ } finally {
+ // Delete the temporary files created (and the `tail -c` commands that might have been left behind by long-polls).
+ // Using pollTimeout so doesn't wait forever, but waits for a reasonable (configurable) length of time.
+ // TODO also execute this if the `buildRunScriptCommand` fails, as that might have left files behind?
+ try {
+ int execDeleteResult = asInt(acquire(new ShellAction(deleteTemporaryFilesCommand(), out, err, pollTimeout)), -1);
+ if (execDeleteResult != 0) {
+ LOG.debug("Problem deleting temporary files of async script on "+SshjTool.this.toString()+" (for "+getSummary()+"): exit status "+execDeleteResult);
+ }
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ LOG.debug("Problem deleting temporary files of async script on "+SshjTool.this.toString()+" (for "+getSummary()+"); continuing", e);
+ }
}
}
+
Integer longPoll() throws IOException {
// Long-polling to get stdout, stderr + exit status of async task.
// If our long-poll disconnects, we will just re-execute.
@@ -391,11 +454,20 @@ public class SshjTool extends SshAbstractTool implements SshTool {
// If we disconnect, we will pick up from that char of the stream.
// TODO Additional stdout/stderr written by buildLongPollCommand() could interfere,
// causing us to miss some characters.
- // TODO Want to include timeout for long-polling
Duration nextPollTimeout = Duration.min(pollTimeout, Duration.millis(execTimeout.toMilliseconds()-timer.elapsed(TimeUnit.MILLISECONDS)));
CountingOutputStream countingOut = (out == null) ? null : new CountingOutputStream(out);
CountingOutputStream countingErr = (err == null) ? null : new CountingOutputStream(err);
- int longPollResult = asInt(acquire(new ShellAction(buildLongPollCommand(stdoutCount, stderrCount, nextPollTimeout), countingOut, countingErr, nextPollTimeout)), -1);
+ List<String> pollCommand = buildLongPollCommand(stdoutCount, stderrCount, nextPollTimeout);
+ Duration sshJoinTimeout = nextPollTimeout.add(Duration.TEN_SECONDS);
+ ShellAction action = new ShellAction(pollCommand, countingOut, countingErr, sshJoinTimeout);
+
+ int longPollResult;
+ try {
+ longPollResult = asInt(acquire(action, 3, nextPollTimeout), -1);
+ } catch (RuntimeTimeoutException e) {
+ if (LOG.isDebugEnabled()) LOG.debug("Long-poll timed out on "+SshjTool.this.toString()+" (for "+getSummary()+"): "+e);
+ return null;
+ }
stdoutCount += (countingOut == null) ? 0 : countingOut.getCount();
stderrCount += (countingErr == null) ? 0 : countingErr.getCount();
@@ -407,7 +479,14 @@ public class SshjTool extends SshAbstractTool implements SshTool {
// probably a connection failure; try again
if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status -1; will retry on "+SshjTool.this.toString()+" (for "+getSummary()+")");
return null;
-
+
+ } else if (longPollResult == 125) {
+ // 125 is the special code for timeout in long-poll (see buildLongPollCommand).
+ // However, there is a tiny chance that the underlying command might have returned that exact exit code!
+ // Don't treat a timeout as a "consecutiveSshFailure".
+ if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status "+longPollResult+"; most likely timeout; retrieving actual status on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+ return retrieveStatusCommand();
+
} else {
// want to double-check whether this is the exit-code from the async process, or
// some unexpected failure in our long-poll command.
@@ -427,6 +506,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
return null;
}
}
+
Integer retrieveStatusCommand() throws IOException {
// want to double-check whether this is the exit-code from the async process, or
// some unexpected failure in our long-poll command.
@@ -469,6 +549,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
}.run();
}
+
public int execShellDirect(Map<String,?> props, List<String> commands, Map<String,?> env) {
OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
@@ -493,6 +574,13 @@ public class SshjTool extends SshAbstractTool implements SshTool {
if (Boolean.FALSE.equals(props.get("blocks"))) {
throw new IllegalArgumentException("Cannot exec non-blocking: command="+commands);
}
+
+ // If async is set, then do it as execScript
+ Boolean execAsync = getOptionalVal(props, PROP_EXEC_ASYNC);
+ if (Boolean.TRUE.equals(execAsync) && BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC)) {
+ return execScriptAsyncAndPoll(props, commands, env);
+ }
+
OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
String separator = getOptionalVal(props, PROP_SEPARATOR);
@@ -526,6 +614,10 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
protected <T, C extends SshAction<T>> T acquire(C action) {
+ return acquire(action, sshTries, sshTriesTimeout == 0 ? Duration.PRACTICALLY_FOREVER : Duration.millis(sshTriesTimeout));
+ }
+
+ protected <T, C extends SshAction<T>> T acquire(C action, int sshTries, Duration sshTriesTimeout) {
Stopwatch stopwatch = Stopwatch.createStarted();
for (int i = 0; i < sshTries; i++) {
@@ -561,7 +653,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
String errorMessage = String.format("(%s) error acquiring %s", toString(), action);
String fullMessage = String.format("%s (attempt %s/%s, in time %s/%s)",
errorMessage, (i+1), sshTries, Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)),
- (sshTriesTimeout > 0 ? Time.makeTimeStringRounded(sshTriesTimeout) : "unlimited"));
+ (sshTriesTimeout.equals(Duration.PRACTICALLY_FOREVER) ? "unlimited" : Time.makeTimeStringRounded(sshTriesTimeout)));
try {
disconnect();
} catch (Exception e2) {
@@ -570,9 +662,9 @@ public class SshjTool extends SshAbstractTool implements SshTool {
if (i + 1 == sshTries) {
LOG.debug("<< {} (rethrowing, out of retries): {}", fullMessage, e.getMessage());
throw propagate(e, fullMessage + "; out of retries");
- } else if (sshTriesTimeout > 0 && stopwatch.elapsed(TimeUnit.MILLISECONDS) > sshTriesTimeout) {
- LOG.debug("<< {} (rethrowing, out of time - max {}): {}", new Object[] { fullMessage, Time.makeTimeString(sshTriesTimeout, true), e.getMessage() });
- throw propagate(e, fullMessage + "; out of time");
+ } else if (sshTriesTimeout.isShorterThan(stopwatch)) {
+ LOG.debug("<< {} (rethrowing, out of time - max {}): {}", new Object[] { fullMessage, Time.makeTimeStringRounded(sshTriesTimeout), e.getMessage() });
+ throw new RuntimeTimeoutException(fullMessage + "; out of time", e);
} else {
if (LOG.isDebugEnabled()) LOG.debug("<< {}: {}", fullMessage, e.getMessage());
backoffForAttempt(i + 1, errorMessage + ": " + e.getMessage());
@@ -804,15 +896,16 @@ public class SshjTool extends SshAbstractTool implements SshTool {
errgobbler.start();
}
try {
-
output.join((int)Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE), TimeUnit.MILLISECONDS);
return output;
} finally {
// wait for all stdout/stderr to have been re-directed
try {
- if (outgobbler != null) outgobbler.join();
- if (errgobbler != null) errgobbler.join();
+ // Don't use forever (i.e. 0) because BROOKLYN-106: ssh hangs
+ long joinTimeout = 10*1000;
+ if (outgobbler != null) outgobbler.join(joinTimeout);
+ if (errgobbler != null) errgobbler.join(joinTimeout);
} catch (InterruptedException e) {
LOG.warn("Interrupted gobbling streams from ssh: "+command, e);
Thread.currentThread().interrupt();
@@ -904,6 +997,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
closeWhispering(output, this);
+ boolean timedOut = false;
try {
long timeoutMillis = Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE);
long timeoutEnd = System.currentTimeMillis() + timeoutMillis;
@@ -917,19 +1011,25 @@ public class SshjTool extends SshAbstractTool implements SshTool {
(!shell.isOpen() || ((SessionChannel)session).getExitStatus()!=null);
try {
shell.join(1000, TimeUnit.MILLISECONDS);
- } catch (ConnectionException e) { last = e; }
- if (endBecauseReturned)
+ } catch (ConnectionException e) {
+ last = e;
+ }
+ if (endBecauseReturned) {
// shell is still open, ie some process is running
// but we have a result code, so main shell is finished
// we waited one second extra to allow any background process
// which is nohupped to really be in the background (#162)
// now let's bail out
break;
+ }
} while (System.currentTimeMillis() < timeoutEnd);
if (shell.isOpen() && ((SessionChannel)session).getExitStatus()==null) {
- LOG.debug("Timeout ({}) in SSH shell to {}", sshClientConnection.getSessionTimeout(), this);
- // we timed out, or other problem -- reproduce the error
- throw last;
+ LOG.debug("Timeout ({}) in SSH shell to {}", timeout, this);
+ // we timed out, or other problem -- reproduce the error.
+ // The shell.join should always have thrown ConnectionExceptoin (looking at code of
+ // AbstractChannel), but javadoc of Channel doesn't explicity say that so play it safe.
+ timedOut = true;
+ throw (last != null) ? last : new TimeoutException("Timeout after "+timeout+" executing "+this);
}
return ((SessionChannel)session).getExitStatus();
} finally {
@@ -937,8 +1037,16 @@ public class SshjTool extends SshAbstractTool implements SshTool {
closeWhispering(shell, this);
shell = null;
try {
- if (outgobbler != null) outgobbler.join();
- if (errgobbler != null) errgobbler.join();
+ // Don't use forever (i.e. 0) because BROOKLYN-106: ssh hangs
+ long joinTimeout = (timedOut) ? 1000 : 10*1000;
+ if (outgobbler != null) {
+ outgobbler.join(joinTimeout);
+ outgobbler.close();
+ }
+ if (errgobbler != null) {
+ errgobbler.join(joinTimeout);
+ errgobbler.close();
+ }
} catch (InterruptedException e) {
LOG.warn("Interrupted gobbling streams from ssh: "+commands, e);
Thread.currentThread().interrupt();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c06a2297/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java b/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
index 2acb200..caebac1 100644
--- a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
+++ b/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
@@ -29,7 +29,9 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import brooklyn.internal.BrooklynFeatureEnablement;
import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.internal.ssh.SshAbstractTool.SshAction;
import brooklyn.util.internal.ssh.sshj.SshjTool.ShellAction;
import brooklyn.util.time.Duration;
@@ -58,15 +60,17 @@ public class SshjToolAsyncStubIntegrationTest {
private SshjTool tool;
private List<InjectedResult> sequence;
int counter = 0;
+ private boolean origFeatureEnablement;
@BeforeMethod(alwaysRun=true)
public void setUp() throws Exception {
+ origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
sequence = Lists.newArrayList();
counter = 0;
tool = new SshjTool(ImmutableMap.<String,Object>of("host", "localhost")) {
@SuppressWarnings("unchecked")
- protected <T, C extends SshAction<T>> T acquire(C action) {
+ protected <T, C extends SshAction<T>> T acquire(C action, int sshTries, Duration sshTriesTimeout) {
if (action instanceof SshjTool.ShellAction) {
SshjTool.ShellAction shellAction = (SshjTool.ShellAction) action;
InjectedResult injectedResult = sequence.get(counter);
@@ -74,14 +78,18 @@ public class SshjToolAsyncStubIntegrationTest {
counter++;
return (T) injectedResult.result.apply(shellAction);
}
- return super.acquire(action);
+ return super.acquire(action, sshTries, sshTriesTimeout);
}
};
}
@AfterMethod(alwaysRun=true)
public void tearDown() throws Exception {
- if (tool != null) tool.disconnect();
+ try {
+ if (tool != null) tool.disconnect();
+ } finally {
+ BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+ }
}
private Predicate<SshjTool.ShellAction> containsCmd(final String cmd) {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c06a2297/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java b/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java
index b81712d..c809ad1 100644
--- a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java
+++ b/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java
@@ -37,8 +37,10 @@ import net.schmizz.sshj.connection.channel.direct.Session;
import org.testng.annotations.Test;
+import brooklyn.internal.BrooklynFeatureEnablement;
import brooklyn.test.Asserts;
import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.RuntimeTimeoutException;
import brooklyn.util.internal.ssh.SshException;
import brooklyn.util.internal.ssh.SshTool;
import brooklyn.util.internal.ssh.SshToolAbstractIntegrationTest;
@@ -129,7 +131,7 @@ public class SshjToolIntegrationTest extends SshToolAbstractIntegrationTest {
try {
localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("true"));
fail();
- } catch (SshException e) {
+ } catch (RuntimeTimeoutException e) {
if (!e.toString().contains("out of time")) throw e;
assertEquals(callCount.get(), 2);
}
@@ -165,45 +167,56 @@ public class SshjToolIntegrationTest extends SshToolAbstractIntegrationTest {
@Test(groups = {"Integration"})
public void testAsyncExecStdoutAndStderr() throws Exception {
- // Include a sleep, to ensure that the contents retrieved in first poll and subsequent polls are appended
- List<String> cmds = ImmutableList.of(
- "echo mystringToStdout",
- "echo mystringToStderr 1>&2",
- "sleep 3",
- "echo mystringPostSleepToStdout",
- "echo mystringPostSleepToStderr 1>&2");
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ByteArrayOutputStream err = new ByteArrayOutputStream();
- int exitCode = tool.execScript(
- ImmutableMap.of(
- "out", out,
- "err", err,
- SshjTool.PROP_EXEC_ASYNC.getName(), true,
- SshjTool.PROP_NO_EXTRA_OUTPUT.getName(), true,
- SshjTool.PROP_EXEC_ASYNC_POLLING_TIMEOUT.getName(), Duration.ONE_SECOND),
- cmds,
- ImmutableMap.<String,String>of());
- String outStr = new String(out.toByteArray());
- String errStr = new String(err.toByteArray());
-
- assertEquals(exitCode, 0);
- assertEquals(outStr.trim(), "mystringToStdout\nmystringPostSleepToStdout");
- assertEquals(errStr.trim(), "mystringToStderr\nmystringPostSleepToStderr");
+ boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
+ try {
+ // Include a sleep, to ensure that the contents retrieved in first poll and subsequent polls are appended
+ List<String> cmds = ImmutableList.of(
+ "echo mystringToStdout",
+ "echo mystringToStderr 1>&2",
+ "sleep 5",
+ "echo mystringPostSleepToStdout",
+ "echo mystringPostSleepToStderr 1>&2");
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ int exitCode = tool.execScript(
+ ImmutableMap.of(
+ "out", out,
+ "err", err,
+ SshjTool.PROP_EXEC_ASYNC.getName(), true,
+ SshjTool.PROP_NO_EXTRA_OUTPUT.getName(), true,
+ SshjTool.PROP_EXEC_ASYNC_POLLING_TIMEOUT.getName(), Duration.ONE_SECOND),
+ cmds,
+ ImmutableMap.<String,String>of());
+ String outStr = new String(out.toByteArray());
+ String errStr = new String(err.toByteArray());
+
+ assertEquals(exitCode, 0);
+ assertEquals(outStr.trim(), "mystringToStdout\nmystringPostSleepToStdout");
+ assertEquals(errStr.trim(), "mystringToStderr\nmystringPostSleepToStderr");
+ } finally {
+ BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+ }
}
@Test(groups = {"Integration"})
public void testAsyncExecReturnsExitCode() throws Exception {
- int exitCode = tool.execScript(
- ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true),
- ImmutableList.of("exit 123"),
- ImmutableMap.<String,String>of());
- assertEquals(exitCode, 123);
+ boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
+ try {
+ int exitCode = tool.execScript(
+ ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true),
+ ImmutableList.of("exit 123"),
+ ImmutableMap.<String,String>of());
+ assertEquals(exitCode, 123);
+ } finally {
+ BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+ }
}
@Test(groups = {"Integration"})
public void testAsyncExecTimesOut() throws Exception {
Stopwatch stopwatch = Stopwatch.createStarted();
+ boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
try {
tool.execScript(
ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true, SshjTool.PROP_EXEC_TIMEOUT.getName(), Duration.millis(1)),
@@ -213,6 +226,8 @@ public class SshjToolIntegrationTest extends SshToolAbstractIntegrationTest {
} catch (Exception e) {
TimeoutException te = Exceptions.getFirstThrowableOfType(e, TimeoutException.class);
if (te == null) throw e;
+ } finally {
+ BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
}
long seconds = stopwatch.elapsed(TimeUnit.SECONDS);
@@ -234,6 +249,8 @@ public class SshjToolIntegrationTest extends SshToolAbstractIntegrationTest {
long seconds = stopwatch.elapsed(TimeUnit.SECONDS);
assertTrue(seconds < 30, "exec took "+seconds+" seconds");
}});
+
+ boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
try {
thread.start();
@@ -249,6 +266,7 @@ public class SshjToolIntegrationTest extends SshToolAbstractIntegrationTest {
assertFalse(thread.isAlive());
} finally {
thread.interrupt();
+ BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c06a2297/utils/common/src/main/java/brooklyn/util/time/Duration.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/time/Duration.java b/utils/common/src/main/java/brooklyn/util/time/Duration.java
index 3950bc7..0f73ef8 100644
--- a/utils/common/src/main/java/brooklyn/util/time/Duration.java
+++ b/utils/common/src/main/java/brooklyn/util/time/Duration.java
@@ -277,10 +277,18 @@ public class Duration implements Comparable<Duration>, Serializable {
return compareTo(x) > 0;
}
+ public boolean isLongerThan(Stopwatch stopwatch) {
+ return isLongerThan(Duration.millis(stopwatch.elapsed(TimeUnit.MILLISECONDS)));
+ }
+
public boolean isShorterThan(Duration x) {
return compareTo(x) < 0;
}
+ public boolean isShorterThan(Stopwatch stopwatch) {
+ return isShorterThan(Duration.millis(stopwatch.elapsed(TimeUnit.MILLISECONDS)));
+ }
+
/** returns the larger of this value or the argument */
public Duration lowerBound(Duration alternateMinimumValue) {
if (isShorterThan(alternateMinimumValue)) return alternateMinimumValue;
@@ -303,5 +311,4 @@ public class Duration implements Comparable<Duration>, Serializable {
public Duration maximum(Duration alternateMaximumValue) {
return upperBound(alternateMaximumValue);
}
-
}
[6/7] incubator-brooklyn git commit: BROOKLYN-113: curl retries and
times out sooner
Posted by al...@apache.org.
BROOKLYN-113: curl retries and times out sooner
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/6fe7994e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/6fe7994e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/6fe7994e
Branch: refs/heads/master
Commit: 6fe7994ef585f04fa8bcdf143cfb2f174e84cb9b
Parents: c61a309
Author: Aled Sage <al...@gmail.com>
Authored: Tue Jan 13 13:54:00 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Jan 15 10:10:09 2015 +0000
----------------------------------------------------------------------
utils/common/src/main/java/brooklyn/util/ssh/BashCommands.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6fe7994e/utils/common/src/main/java/brooklyn/util/ssh/BashCommands.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/ssh/BashCommands.java b/utils/common/src/main/java/brooklyn/util/ssh/BashCommands.java
index 457a60a..e60b332 100644
--- a/utils/common/src/main/java/brooklyn/util/ssh/BashCommands.java
+++ b/utils/common/src/main/java/brooklyn/util/ssh/BashCommands.java
@@ -505,7 +505,7 @@ public class BashCommands {
List<String> commands = new ArrayList<String>();
for (String url : urls) {
- String command = "curl -f -L -k ";
+ String command = "curl -f -L -k --retry 10 --keepalive-time 30 --speed-time 30 ";
if (user!=null && password!=null) {
command = command + format("-u %s:%s ", user, password);
}
[7/7] incubator-brooklyn git commit: This closes #448
Posted by al...@apache.org.
This closes #448
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/e4ecb387
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/e4ecb387
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/e4ecb387
Branch: refs/heads/master
Commit: e4ecb38710abe55308dac90895c9ace0f854f073
Parents: 6455a9d 6fe7994
Author: Aled Sage <al...@gmail.com>
Authored: Thu Jan 15 10:11:17 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Jan 15 10:11:17 2015 +0000
----------------------------------------------------------------------
.../internal/BrooklynFeatureEnablement.java | 47 +++++-
.../location/access/PortForwardManagerImpl.java | 4 +-
.../location/basic/SshMachineLocation.java | 5 +-
.../internal/LocalManagementContext.java | 10 +-
.../util/internal/ssh/ShellAbstractTool.java | 34 +++--
.../internal/ssh/sshj/SshjClientConnection.java | 2 +-
.../util/internal/ssh/sshj/SshjTool.java | 150 ++++++++++++++++---
.../internal/BrooklynFeatureEnablementTest.java | 27 ++++
.../sshj/SshjToolAsyncStubIntegrationTest.java | 14 +-
.../ssh/sshj/SshjToolIntegrationTest.java | 80 ++++++----
.../java/brooklyn/util/ssh/BashCommands.java | 2 +-
.../main/java/brooklyn/util/time/Duration.java | 9 +-
.../brooklyn/util/stream/StreamGobblerTest.java | 88 +++++++++++
13 files changed, 386 insertions(+), 86 deletions(-)
----------------------------------------------------------------------
[4/7] incubator-brooklyn git commit: Adds StreamGobblerTest
Posted by al...@apache.org.
Adds StreamGobblerTest
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/d89062b8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/d89062b8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/d89062b8
Branch: refs/heads/master
Commit: d89062b86f99d2cfae0d1558c4697b23ab7d3c7c
Parents: ce16828
Author: Aled Sage <al...@gmail.com>
Authored: Thu Jan 8 22:19:47 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Jan 14 22:38:08 2015 +0000
----------------------------------------------------------------------
.../brooklyn/util/stream/StreamGobblerTest.java | 88 ++++++++++++++++++++
1 file changed, 88 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d89062b8/utils/common/src/test/java/brooklyn/util/stream/StreamGobblerTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/brooklyn/util/stream/StreamGobblerTest.java b/utils/common/src/test/java/brooklyn/util/stream/StreamGobblerTest.java
new file mode 100644
index 0000000..4722829
--- /dev/null
+++ b/utils/common/src/test/java/brooklyn/util/stream/StreamGobblerTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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 brooklyn.util.stream;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+
+import org.testng.annotations.Test;
+
+import brooklyn.test.Asserts;
+
+public class StreamGobblerTest {
+
+ @Test
+ public void testGobbleStream() throws Exception {
+ byte[] bytes = new byte[] {'a','b','c'};
+ InputStream stream = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ StreamGobbler gobbler = new StreamGobbler(stream, out, null);
+ gobbler.start();
+ try {
+ gobbler.join(10*1000);
+ assertFalse(gobbler.isAlive());
+ assertEquals(new String(out.toByteArray()), "abc\n");
+ } finally {
+ gobbler.close();
+ gobbler.interrupt();
+ }
+ }
+
+ @Test
+ public void testGobbleMultiLineBlockingStream() throws Exception {
+ PipedOutputStream pipedOutputStream = new PipedOutputStream();
+ PipedInputStream stream = new PipedInputStream(pipedOutputStream);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ StreamGobbler gobbler = new StreamGobbler(stream, out, null);
+ gobbler.start();
+ try {
+ pipedOutputStream.write("line1\n".getBytes());
+ assertEqualsEventually(out, "line1\n");
+
+ pipedOutputStream.write("line2\n".getBytes());
+ assertEqualsEventually(out, "line1\nline2\n");
+
+ pipedOutputStream.write("line".getBytes());
+ pipedOutputStream.write("3\n".getBytes());
+ assertEqualsEventually(out, "line1\nline2\nline3\n");
+
+ pipedOutputStream.close();
+
+ gobbler.join(10*1000);
+ assertFalse(gobbler.isAlive());
+ assertEquals(new String(out.toByteArray()), "line1\nline2\nline3\n");
+ } finally {
+ gobbler.close();
+ gobbler.interrupt();
+ }
+ }
+
+ private void assertEqualsEventually(final ByteArrayOutputStream out, final String expected) {
+ Asserts.succeedsEventually(new Runnable() {
+ public void run() {
+ assertEquals(new String(out.toByteArray()), expected);
+ }});
+ }
+}
[5/7] incubator-brooklyn git commit: Feature-enablement: init from
brooklyn properties
Posted by al...@apache.org.
Feature-enablement: init from brooklyn properties
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/ce168285
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/ce168285
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/ce168285
Branch: refs/heads/master
Commit: ce168285ff8c71f460701e5d818c58c343dae64a
Parents: c06a229
Author: Aled Sage <al...@gmail.com>
Authored: Thu Jan 8 21:19:31 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Jan 14 22:38:08 2015 +0000
----------------------------------------------------------------------
.../internal/BrooklynFeatureEnablement.java | 47 ++++++++++++++++----
.../internal/LocalManagementContext.java | 10 ++++-
.../internal/BrooklynFeatureEnablementTest.java | 27 +++++++++++
3 files changed, 74 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ce168285/core/src/main/java/brooklyn/internal/BrooklynFeatureEnablement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/internal/BrooklynFeatureEnablement.java b/core/src/main/java/brooklyn/internal/BrooklynFeatureEnablement.java
index 9946ac7..7ecd7cd 100644
--- a/core/src/main/java/brooklyn/internal/BrooklynFeatureEnablement.java
+++ b/core/src/main/java/brooklyn/internal/BrooklynFeatureEnablement.java
@@ -23,6 +23,7 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import brooklyn.config.BrooklynProperties;
import brooklyn.internal.storage.BrooklynStorage;
import brooklyn.management.ha.HighAvailabilityMode;
import brooklyn.util.internal.ssh.ShellTool;
@@ -43,27 +44,29 @@ public class BrooklynFeatureEnablement {
private static final Logger LOG = LoggerFactory.getLogger(BrooklynFeatureEnablement.class);
- public static final String FEATURE_POLICY_PERSISTENCE_PROPERTY = "brooklyn.experimental.feature.policyPersistence";
+ public static final String FEATURE_PROPERTY_PREFIX = "brooklyn.experimental.feature";
- public static final String FEATURE_ENRICHER_PERSISTENCE_PROPERTY = "brooklyn.experimental.feature.enricherPersistence";
+ public static final String FEATURE_POLICY_PERSISTENCE_PROPERTY = FEATURE_PROPERTY_PREFIX+".policyPersistence";
+
+ public static final String FEATURE_ENRICHER_PERSISTENCE_PROPERTY = FEATURE_PROPERTY_PREFIX+".enricherPersistence";
- public static final String FEATURE_FEED_PERSISTENCE_PROPERTY = "brooklyn.experimental.feature.feedPersistence";
+ public static final String FEATURE_FEED_PERSISTENCE_PROPERTY = FEATURE_PROPERTY_PREFIX+".feedPersistence";
/** whether feeds are automatically registered when set on entities, so that they are persisted */
- public static final String FEATURE_FEED_REGISTRATION_PROPERTY = "brooklyn.experimental.feature.feedRegistration";
+ public static final String FEATURE_FEED_REGISTRATION_PROPERTY = FEATURE_PROPERTY_PREFIX+".feedRegistration";
- public static final String FEATURE_CATALOG_PERSISTENCE_PROPERTY = "brooklyn.experimental.feature.catalogPersistence";
+ public static final String FEATURE_CATALOG_PERSISTENCE_PROPERTY = FEATURE_PROPERTY_PREFIX+".catalogPersistence";
/** whether the default standby mode is {@link HighAvailabilityMode#HOT_STANDBY} or falling back to the traditional
* {@link HighAvailabilityMode#STANDBY} */
- public static final String FEATURE_DEFAULT_STANDBY_IS_HOT_PROPERTY = "brooklyn.experimental.feature.defaultStandbyIsHot";
+ public static final String FEATURE_DEFAULT_STANDBY_IS_HOT_PROPERTY = FEATURE_PROPERTY_PREFIX+".defaultStandbyIsHot";
/** whether to attempt to use {@link BrooklynStorage} (datagrid) as a backing store for data;
* note this is <b>not</b> compatible with {@link #FEATURE_DEFAULT_STANDBY_IS_HOT_PROPERTY}
* which uses a blob/file store and a larger-granularity rebind process than was intended with the datagrid */
/* not sure if we still even need this? now the rebind/read-only feature reloads on demand from the persistence store;
* the data-grid backing */
- public static final String FEATURE_USE_BROOKLYN_LIVE_OBJECTS_DATAGRID_STORAGE = "brooklyn.experimental.feature.useBrooklynLiveObjectsDatagridStorage";
+ public static final String FEATURE_USE_BROOKLYN_LIVE_OBJECTS_DATAGRID_STORAGE = FEATURE_PROPERTY_PREFIX+".useBrooklynLiveObjectsDatagridStorage";
/**
* Renaming threads can really helps with debugging etc; however it's a massive performance hit (2x)
@@ -91,7 +94,7 @@ public class BrooklynFeatureEnablement {
* If this feature is disabled, then even if the {@link ShellTool#PROP_EXEC_ASYNC} is configured it
* will still use the classic ssh approach.
*/
- public static final String FEATURE_SSH_ASYNC_EXEC = "brooklyn.experimental.feature.ssh.asyncExec";
+ public static final String FEATURE_SSH_ASYNC_EXEC = FEATURE_PROPERTY_PREFIX+".ssh.asyncExec";
private static final Map<String, Boolean> FEATURE_ENABLEMENTS = Maps.newLinkedHashMap();
@@ -118,6 +121,34 @@ public class BrooklynFeatureEnablement {
setDefaults();
}
+ /**
+ * Initialises the feature-enablement from brooklyn properties. For each
+ * property, prefer a system-property if present; otherwise use the value
+ * from brooklyn properties.
+ */
+ public static void init(BrooklynProperties props) {
+ boolean changed = false;
+ for (Map.Entry<String, Object> entry : props.asMapWithStringKeys().entrySet()) {
+ String property = entry.getKey();
+ if (property.startsWith(FEATURE_PROPERTY_PREFIX)) {
+ if (!FEATURE_ENABLEMENTS.containsKey(property)) {
+ Object rawVal = System.getProperty(property);
+ if (rawVal == null) {
+ rawVal = entry.getValue();
+ }
+ boolean val = Boolean.parseBoolean(""+rawVal);
+ FEATURE_ENABLEMENTS.put(property, val);
+
+ changed = true;
+ LOG.debug("Init feature enablement of "+property+" set to "+val);
+ }
+ }
+ }
+ if (!changed) {
+ LOG.debug("Init feature enablement did nothing, as no settings in brooklyn properties");
+ }
+ }
+
public static boolean isEnabled(String property) {
synchronized (MUTEX) {
if (!FEATURE_ENABLEMENTS.containsKey(property)) {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ce168285/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
index 257e1f6..202e4a6 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
@@ -44,6 +44,7 @@ import brooklyn.entity.effector.Effectors;
import brooklyn.entity.proxying.InternalEntityFactory;
import brooklyn.entity.proxying.InternalLocationFactory;
import brooklyn.entity.proxying.InternalPolicyFactory;
+import brooklyn.internal.BrooklynFeatureEnablement;
import brooklyn.internal.storage.DataGridFactory;
import brooklyn.location.Location;
import brooklyn.management.AccessController;
@@ -171,16 +172,19 @@ public class LocalManagementContext extends AbstractManagementContext {
public LocalManagementContext(Builder builder, Map<String, Object> brooklynAdditionalProperties, DataGridFactory datagridFactory) {
super(builder.build(), datagridFactory);
+
+ checkNotNull(configMap, "brooklynProperties");
+
// TODO in a persisted world the planeId may be injected
this.managementPlaneId = Strings.makeRandomId(8);
-
this.managementNodeId = Strings.makeRandomId(8);
- checkNotNull(configMap, "brooklynProperties");
this.builder = builder;
this.brooklynAdditionalProperties = brooklynAdditionalProperties;
if (brooklynAdditionalProperties != null)
configMap.addFromMap(brooklynAdditionalProperties);
+ BrooklynFeatureEnablement.init(configMap);
+
this.locationManager = new LocalLocationManager(this);
this.accessManager = new LocalAccessManager();
this.usageManager = new LocalUsageManager(this);
@@ -385,6 +389,8 @@ public class LocalManagementContext extends AbstractManagementContext {
clearLocationRegistry();
+ BrooklynFeatureEnablement.init(configMap);
+
// Notify listeners that properties have been reloaded
for (PropertiesReloadListener listener : reloadListeners) {
listener.reloaded();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ce168285/core/src/test/java/brooklyn/internal/BrooklynFeatureEnablementTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/internal/BrooklynFeatureEnablementTest.java b/core/src/test/java/brooklyn/internal/BrooklynFeatureEnablementTest.java
index 38b9ee5..ea0fed6 100644
--- a/core/src/test/java/brooklyn/internal/BrooklynFeatureEnablementTest.java
+++ b/core/src/test/java/brooklyn/internal/BrooklynFeatureEnablementTest.java
@@ -25,6 +25,8 @@ import static org.testng.Assert.assertTrue;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import brooklyn.config.BrooklynProperties;
+
public class BrooklynFeatureEnablementTest {
@BeforeMethod(alwaysRun=true)
@@ -88,4 +90,29 @@ public class BrooklynFeatureEnablementTest {
System.clearProperty(featureProperty);
}
}
+
+ @Test
+ public void testCanSetDefaultWhichIsIgnoredIfBrooklynProps() throws Exception {
+ String featureProperty = "brooklyn.experimental.feature.testCanSetDefaultWhichIsIgnoredIfBrooklynProps";
+ BrooklynProperties props = BrooklynProperties.Factory.newEmpty();
+ props.put(featureProperty, false);
+ BrooklynFeatureEnablement.init(props);
+ BrooklynFeatureEnablement.setDefault(featureProperty, true);
+ assertFalse(BrooklynFeatureEnablement.isEnabled(featureProperty));
+ }
+
+ @Test
+ public void testPrefersSysPropOverBrooklynProps() throws Exception {
+ String featureProperty = "brooklyn.experimental.feature.testPrefersSysPropOverBrooklynProps";
+ BrooklynProperties props = BrooklynProperties.Factory.newEmpty();
+ props.put(featureProperty, false);
+ System.setProperty(featureProperty, "true");
+ try {
+ BrooklynFeatureEnablement.init(props);
+ BrooklynFeatureEnablement.setDefault(featureProperty, true);
+ assertTrue(BrooklynFeatureEnablement.isEnabled(featureProperty));
+ } finally {
+ System.clearProperty(featureProperty);
+ }
+ }
}
[3/7] incubator-brooklyn git commit: Fix SshMachineLocation pool’s displayName
Posted by al...@apache.org.
Fix SshMachineLocation pool’s displayName
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/06731468
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/06731468
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/06731468
Branch: refs/heads/master
Commit: 0673146862730a07b6469981979b2bb2ea20c0b8
Parents: 6455a9d
Author: Aled Sage <al...@gmail.com>
Authored: Thu Jan 8 21:09:07 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Jan 14 22:38:08 2015 +0000
----------------------------------------------------------------------
.../main/java/brooklyn/location/basic/SshMachineLocation.java | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/06731468/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
index 59a273e..c7b202a 100644
--- a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java
@@ -304,10 +304,9 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
private BasicPool<SshTool> buildPool(final Map<String, ?> properties) {
return BasicPool.<SshTool>builder()
- .name(getDisplayName()+"@"+address+
+ .name(getDisplayName()+"@"+address+":"+getPort()+
(hasConfig(SSH_HOST, true) ? "("+getConfig(SSH_HOST)+":"+getConfig(SSH_PORT)+")" : "")+
- ":"+
- System.identityHashCode(this))
+ ":hash"+System.identityHashCode(this))
.supplier(new Supplier<SshTool>() {
@Override public SshTool get() {
return connectSsh(properties);