You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2019/08/30 15:23:55 UTC

[brooklyn-server] 02/04: set env vars on winrm executions, except for installing

This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git

commit 8efb1c9ebef9f0383e6c8c3c43977afb4dd3660c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Mon Aug 26 21:45:54 2019 +0200

    set env vars on winrm executions, except for installing
---
 .../camp/brooklyn/AbstractWindowsYamlTest.java     |  5 ++
 .../camp/brooklyn/WindowsYamlLiveTest.java         | 58 ++++++++++++++++--
 .../base/AbstractSoftwareProcessSshDriver.java     | 16 ++---
 .../base/AbstractSoftwareProcessWinRmDriver.java   | 68 ++++++++++++----------
 .../base/VanillaWindowsProcessWinRmDriver.java     | 11 +++-
 .../base/lifecycle/WinRmExecuteHelper.java         |  1 +
 .../base/test/location/WindowsTestFixture.java     | 28 ++++++---
 .../util/core/internal/winrm/WinRmTool.java        |  5 +-
 8 files changed, 137 insertions(+), 55 deletions(-)

diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractWindowsYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractWindowsYamlTest.java
index f23bec4..4d9f07c 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractWindowsYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractWindowsYamlTest.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.HasTaskChildren;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
@@ -109,6 +110,10 @@ public abstract class AbstractWindowsYamlTest extends AbstractYamlTest {
         return (stream != null) ? stream.streamContents.get() : null;
     }
 
+    protected Optional<Task<?>> findTaskOrSubTask(Entity entity, Predicate<? super Task<?>> matcher) {
+        return findTaskOrSubTask(BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), entity), matcher);
+    }
+    
     protected Optional<Task<?>> findTaskOrSubTask(Iterable<? extends Task<?>> tasks, Predicate<? super Task<?>> matcher) {
         List<String> taskNames = Lists.newArrayList();
         Optional<Task<?>> result = findTaskOrSubTaskImpl(tasks, matcher, taskNames);
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java
index 7c38647..6e1a0a1 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java
@@ -25,14 +25,20 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Dumper;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.VanillaWindowsProcess;
 import org.apache.brooklyn.entity.software.base.test.location.WindowsTestFixture;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.core.task.TaskPredicates;
+import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import org.apache.brooklyn.util.text.StringPredicates;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
@@ -44,8 +50,12 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
 /**
@@ -54,6 +64,8 @@ import com.google.common.collect.Lists;
 @Test
 public class WindowsYamlLiveTest extends AbstractWindowsYamlTest {
     
+    // set EXISTING_WINDOWS_TEST_USER_PASS_HOST_ENV_VAR as per WindowsTestFixture to re-use existing machines
+    
     // TODO Remove duplication of assertStreams and VanillaWindowsProcessWinrmStreamsLiveTest.assertStreams
     
     private static final Logger log = LoggerFactory.getLogger(WindowsYamlLiveTest.class);
@@ -88,16 +100,16 @@ public class WindowsYamlLiveTest extends AbstractWindowsYamlTest {
         
         location = WindowsTestFixture.setUpWindowsLocation(mgmt());
         machine = location.obtain(ImmutableMap.of());
-        String ip = machine.getAddress().getHostAddress();
-        String password = machine.config().get(WinRmMachineLocation.PASSWORD);
 
         yamlLocation = ImmutableList.of(
                 "location:",
                 "  byon:",
                 "    hosts:",
-                "    - winrm: "+ip+":5985",
-                "      password: \""+password.replace("\"", "\\\"") + "\"",
-                "      user: Administrator",
+                "    - winrm: "+machine.getAddress().getHostAddress() 
+                        // this is the default, probably not necessary but kept for posterity 
+                        +":5985",
+                "      password: "+JavaStringEscapes.wrapJavaString(machine.config().get(WinRmMachineLocation.PASSWORD)),
+                "      user: "+machine.config().get(WinRmMachineLocation.USER),
                 "      osFamily: windows");
     }
 
@@ -318,6 +330,42 @@ public class WindowsYamlLiveTest extends AbstractWindowsYamlTest {
         }
     }
 
+    @Test(groups="Live")
+    public void testEnvVarResolution() throws Exception {
+        List<String> yaml = Lists.newArrayList();
+        yaml.addAll(yamlLocation);
+        String in = "%KEY1%: %ADDR_RESOLVED%";
+        yaml.addAll(ImmutableList.of(
+            "services:",
+            "  - type: org.apache.brooklyn.entity.software.base.VanillaWindowsProcess", 
+            "    brooklyn.config:", 
+            "      install.command: "+JavaStringEscapes.wrapJavaString("echo "+in), 
+            "      customize.command: "+JavaStringEscapes.wrapJavaString("echo "+in), 
+            "      launch.command: "+JavaStringEscapes.wrapJavaString("echo "+in), 
+            "      stop.command: echo true", 
+            "      checkRunning.command: echo true", 
+            "      shell.env:", 
+            "        KEY1: Address", 
+            "        ADDR_RESOLVED: $brooklyn:attributeWhenReady(\"host.address\")"));
+
+        app = createAndStartApplication(Joiner.on("\n").join(yaml));
+        waitForApplicationTasks(app);
+        log.info("App started:");
+        Dumper.dumpInfo(app);
+        
+        
+        Entity win = Iterables.getOnlyElement(app.getChildren());
+        String out = "Address: "+win.sensors().get(SoftwareProcess.ADDRESS);
+        assertPhaseStreamEquals(win, "install", "stdout", Predicates.equalTo(in));
+        assertPhaseStreamEquals(win, "customize", "stdout", Predicates.equalTo(out));
+        assertPhaseStreamEquals(win, "launch", "stdout", Predicates.equalTo(out));
+    }
+    
+    private void assertPhaseStreamEquals(Entity entity, String phase, String stream, Predicate<String> check) {
+        Optional<Task<?>> t = findTaskOrSubTask(entity, TaskPredicates.displayNameSatisfies(StringPredicates.startsWith("winrm: "+phase)));
+        Asserts.assertThat(BrooklynTaskTags.stream(t.get(), stream).getStreamContentsAbbreviated().trim(), check);
+    }
+
     @Override
     protected Logger getLogger() {
         return log;
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
index d1118ad..9ff370c 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
@@ -493,6 +493,8 @@ public abstract class AbstractSoftwareProcessSshDriver extends AbstractSoftwareP
     public static final String RESTARTING = "restarting";
 
     public static final String PID_FILENAME = "pid.txt";
+    static final String INSTALL_DIR_ENV_VAR = "INSTALL_DIR";
+    static final String RUN_DIR_ENV_VAR = "RUN_DIR";
 
     /* Flags */
 
@@ -578,9 +580,9 @@ public abstract class AbstractSoftwareProcessSshDriver extends AbstractSoftwareP
                 final String mutexId = "installation lock at host";
                 s.useMutex(getLocation().mutexes(), mutexId, "installing "+elvis(entity,this));
                 s.header.append(
-                        "export INSTALL_DIR=\""+getInstallDir()+"\"",
-                        "mkdir -p $INSTALL_DIR",
-                        "cd $INSTALL_DIR",
+                        "export "+INSTALL_DIR_ENV_VAR+"=\""+getInstallDir()+"\"",
+                        "mkdir -p $"+INSTALL_DIR_ENV_VAR,
+                        "cd $"+INSTALL_DIR_ENV_VAR,
                         "test -f BROOKLYN && exit 0"
                         );
 
@@ -592,10 +594,10 @@ public abstract class AbstractSoftwareProcessSshDriver extends AbstractSoftwareP
             }
             if (ImmutableSet.of(CUSTOMIZING, LAUNCHING, CHECK_RUNNING, STOPPING, KILLING, RESTARTING).contains(phase)) {
                 s.header.append(
-                        "export INSTALL_DIR=\""+getInstallDir()+"\"",
-                        "export RUN_DIR=\""+getRunDir()+"\"",
-                        "mkdir -p $RUN_DIR",
-                        "cd $RUN_DIR"
+                        "export "+INSTALL_DIR_ENV_VAR+"=\""+getInstallDir()+"\"",
+                        "export "+RUN_DIR_ENV_VAR+"=\""+getRunDir()+"\"",
+                        "mkdir -p $"+RUN_DIR_ENV_VAR,
+                        "cd $"+RUN_DIR_ENV_VAR
                         );
             }
         }
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java
index e125918..0303313 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java
@@ -29,10 +29,8 @@ import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
-import javax.annotation.Nullable;
 import javax.xml.ws.WebServiceException;
 
-import com.google.common.base.Function;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
@@ -43,6 +41,7 @@ import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.software.base.lifecycle.NativeWindowsScriptRunner;
 import org.apache.brooklyn.entity.software.base.lifecycle.WinRmExecuteHelper;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.internal.winrm.WinRmTool;
 import org.apache.brooklyn.util.core.internal.winrm.WinRmToolResponse;
 import org.apache.brooklyn.util.core.mutex.WithMutexes;
@@ -75,37 +74,37 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
         entity.sensors().set(WINDOWS_PASSWORD, location.config().get(WinRmMachineLocation.PASSWORD));
     }
 
-    /** @see #newScript(Map, String) */
-    protected WinRmExecuteHelper newScript(String phase) {
-        return newScript(Maps.<String, Object>newLinkedHashMap(), phase);
+    protected WinRmExecuteHelper newScript(String command, String psCommand, String phase, String taskNamePrefix) {
+        return newScript(command, psCommand, phase, taskNamePrefix, null);
     }
 
-    protected WinRmExecuteHelper newScript(String command, String psCommand, String phase) {
-        return newScript(command, psCommand, phase, null);
-    }
-
-    protected WinRmExecuteHelper newScript(String command, String psCommand, String phase, String ntDomain) {
-        Map<String, String> environment = (Map)getEntity().getConfig(WinRmTool.SHELL_ENVIRONMENT);
-    
-        if (environment == null) {
-            // Important only to call getShellEnvironment() if env was not supplied; otherwise it
-            // could cause us to resolve config (e.g. block for attributeWhenReady) too early.
-            environment = getShellEnvironment();
-        }
-        return newScript(phase)
-                .setNtDomain(ntDomain)
+    protected WinRmExecuteHelper newScript(String command, String psCommand, String phase, String taskNamePrefix, String ntDomain) {
+        WinRmExecuteHelper result = newEmptyScript(taskNamePrefix);
+        result.setNtDomain(ntDomain)
                 .setCommand(command)
                 .setPsCommand(psCommand)
-                .setEnv(environment)
                 .failOnNonZeroResultCode()
                 .gatherOutput();
+        
+        Map<String, String> env = MutableMap.of();
+        env.put("INSTALL_DIR", getInstallDir());
+        if (AbstractSoftwareProcessSshDriver.INSTALLING.equals(phase)) {
+            // don't set shell env during this phase; otherwise it could cause us 
+            // to resolve config (e.g. block for attributeWhenReady) too early; instead just give install dir
+        } else {
+            env.put("RUN_DIR", getRunDir());
+            env.putAll(getShellEnvironment());
+        }
+        result.setEnv(env);
+        
+        return result;
     }
 
-    protected WinRmExecuteHelper newScript(Map<String, ?> flags, String phase) {
+    protected WinRmExecuteHelper newEmptyScript(String taskNamePrefix) {
         if (!Entities.isManaged(getEntity()))
-            throw new IllegalStateException(getEntity() + " is no longer managed; cannot create script to run here (" + phase + ")");
+            throw new IllegalStateException(getEntity() + " is no longer managed; cannot create script to run here (" + taskNamePrefix + ")");
 
-        WinRmExecuteHelper s = new WinRmExecuteHelper(this, phase + " " + elvis(entity, this));
+        WinRmExecuteHelper s = new WinRmExecuteHelper(this, taskNamePrefix + " " + elvis(entity, this));
         return s;
     }
 
@@ -115,6 +114,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
             newScript(
                     getEntity().getConfig(BrooklynConfigKeys.PRE_INSTALL_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.PRE_INSTALL_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.INSTALLING,
                     "pre-install-command")
                 .useMutex(getLocation().mutexes(), "installation lock at host", "installing "+elvis(entity,this))
                 .execute();
@@ -135,6 +135,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
             newScript(
                     getEntity().getConfig(BrooklynConfigKeys.POST_INSTALL_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.POST_INSTALL_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.INSTALLING,
                     "post-install-command")
             .useMutex(getLocation().mutexes(), "installation lock at host", "installing "+elvis(entity,this))
             .execute();
@@ -147,6 +148,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
             executeCommandInTask(
                     getEntity().getConfig(BrooklynConfigKeys.PRE_CUSTOMIZE_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.PRE_CUSTOMIZE_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.CUSTOMIZING,
                     "pre-customize-command");
         }
     }
@@ -157,6 +159,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
             executeCommandInTask(
                     getEntity().getConfig(BrooklynConfigKeys.POST_CUSTOMIZE_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.POST_CUSTOMIZE_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.CUSTOMIZING,
                     "post-customize-command");
         }
     }
@@ -167,6 +170,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
             executeCommandInTask(
                     getEntity().getConfig(BrooklynConfigKeys.PRE_LAUNCH_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.PRE_LAUNCH_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.LAUNCHING,
                     "pre-launch-command");
         }
     }
@@ -177,6 +181,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
             executeCommandInTask(
                     getEntity().getConfig(BrooklynConfigKeys.POST_LAUNCH_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.POST_LAUNCH_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.LAUNCHING,
                     "post-launch-command");
         }
     }
@@ -235,12 +240,12 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
         return getLocation();
     }
 
-    protected int executeCommandInTask(String command, String psCommand, String phase) {
-        return executeCommandInTask(command, psCommand, phase, null);
+    protected int executeCommandInTask(String command, String psCommand, String phase, String taskNamePrefix) {
+        return executeCommandInTask(command, psCommand, phase, taskNamePrefix, null);
     }
 
-    protected int executeCommandInTask(String command, String psCommand, String phase, String ntDomain) {
-        WinRmExecuteHelper helper = newScript(command, psCommand, phase, ntDomain);
+    protected int executeCommandInTask(String command, String psCommand, String phase, String taskNamePrefix, String ntDomain) {
+        WinRmExecuteHelper helper = newScript(command, psCommand, phase, taskNamePrefix, ntDomain);
         return helper.execute();
     }
 
@@ -324,15 +329,15 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
     }
 
     @Override
-    public Integer executeNativeOrPsCommand(Map flags, String regularCommand, String powerShellCommand, String phase, Boolean allowNoOp) {
+    public Integer executeNativeOrPsCommand(Map flags, String regularCommand, String powerShellCommand, String summary, Boolean allowNoOp) {
         if (Strings.isBlank(regularCommand) && Strings.isBlank(powerShellCommand)) {
             if (allowNoOp) {
                 return new WinRmToolResponse("", "", 0).getStatusCode();
             } else {
-                throw new IllegalStateException(String.format("Exactly one of cmd or psCmd must be set for %s of %s", phase, entity));
+                throw new IllegalStateException(String.format("Exactly one of cmd or psCmd must be set for %s of %s", summary, entity));
             }
         } else if (!Strings.isBlank(regularCommand) && !Strings.isBlank(powerShellCommand)) {
-            throw new IllegalStateException(String.format("%s and %s cannot both be set for %s of %s", regularCommand, powerShellCommand, phase, entity));
+            throw new IllegalStateException(String.format("%s and %s cannot both be set for %s of %s", regularCommand, powerShellCommand, summary, entity));
         }
 
         ByteArrayOutputStream stdIn = new ByteArrayOutputStream();
@@ -360,6 +365,9 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar
         if (flags.get(WinRmTool.COMPUTER_NAME) != null) {
             winrmProps.put(WinRmTool.COMPUTER_NAME, flags.get(WinRmTool.COMPUTER_NAME));
         }
+        if (flags.get(WinRmTool.ENVIRONMENT)!=null) {
+            winrmProps.put(WinRmTool.ENVIRONMENT, flags.get(WinRmTool.ENVIRONMENT));
+        }
 
         if (Strings.isBlank(regularCommand)) {
             response = getLocation().executePsScript(winrmProps.build(), ImmutableList.of(powerShellCommand));
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinRmDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinRmDriver.java
index d901242..5058ddd 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinRmDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinRmDriver.java
@@ -50,7 +50,7 @@ public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWin
         // TODO: At some point in the future, this should probably be refactored to get the name of the machine in WinRmMachineLocation and set it as the hostname sensor
         String hostname = null;
         if (entity.getConfig(VanillaWindowsProcess.INSTALL_REBOOT_REQUIRED)) {
-            WinRmExecuteHelper checkHostnameTask = newScript("Checking hostname")
+            WinRmExecuteHelper checkHostnameTask = newEmptyScript("Checking hostname")
                     .setCommand("hostname")
                     .failOnNonZeroResultCode()
                     .gatherOutput();
@@ -62,7 +62,7 @@ public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWin
         if(Strings.isNonBlank(getEntity().getConfig(VanillaWindowsProcess.INSTALL_COMMAND)) || Strings.isNonBlank(getEntity().getConfig(VanillaWindowsProcess.INSTALL_POWERSHELL_COMMAND))) {
             String cmd = getEntity().getConfig(VanillaWindowsProcess.INSTALL_COMMAND);
             String psCmd = getEntity().getConfig(VanillaWindowsProcess.INSTALL_POWERSHELL_COMMAND);
-            newScript(cmd, psCmd, "install-command", hostname)
+            newScript(cmd, psCmd, AbstractSoftwareProcessSshDriver.INSTALLING, "installing-command", hostname)
                     .useMutex(getLocation().mutexes(), "installation lock at host", "installing "+elvis(entity,this))
                     .execute();
         }
@@ -77,6 +77,7 @@ public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWin
             executeCommandInTask(
                     getEntity().getConfig(VanillaWindowsProcess.CUSTOMIZE_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.CUSTOMIZE_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.CUSTOMIZING,
                     "customize-command");
         }
         if (entity.getConfig(VanillaWindowsProcess.CUSTOMIZE_REBOOT_REQUIRED)) {
@@ -91,6 +92,7 @@ public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWin
             executeCommandInTask(
                     getEntity().getConfig(VanillaWindowsProcess.LAUNCH_COMMAND),
                     getEntity().getConfig(VanillaWindowsProcess.LAUNCH_POWERSHELL_COMMAND),
+                    AbstractSoftwareProcessSshDriver.LAUNCHING,
                     "launch-command");
         }
     }
@@ -101,7 +103,9 @@ public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWin
         try {
             exitCode = executeCommandInTask(
                     getEntity().getConfig(VanillaWindowsProcess.CHECK_RUNNING_COMMAND),
-                    getEntity().getConfig(VanillaWindowsProcess.CHECK_RUNNING_POWERSHELL_COMMAND), "is-running-command");
+                    getEntity().getConfig(VanillaWindowsProcess.CHECK_RUNNING_POWERSHELL_COMMAND), 
+                    AbstractSoftwareProcessSshDriver.CHECK_RUNNING,
+                    "is-running-command");
         } catch (Exception e) {
             Throwable interestingCause = findExceptionCausedByWindowsRestart(e);
             if (interestingCause != null) {
@@ -122,6 +126,7 @@ public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWin
         executeCommandInTask(
                 getEntity().getConfig(VanillaWindowsProcess.STOP_COMMAND),
                 getEntity().getConfig(VanillaWindowsProcess.STOP_POWERSHELL_COMMAND),
+                AbstractSoftwareProcessSshDriver.STOPPING,
                 "stop-command");
     }
 
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/WinRmExecuteHelper.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/WinRmExecuteHelper.java
index ecfa3bd..c7f9285 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/WinRmExecuteHelper.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/WinRmExecuteHelper.java
@@ -196,6 +196,7 @@ public class WinRmExecuteHelper {
                 flags.put("err", stderr);
             }
             flags.put(WinRmTool.COMPUTER_NAME, domain);
+            if (env!=null) flags.put(WinRmTool.ENVIRONMENT, env);
             result = runner.executeNativeOrPsCommand(flags, command, psCommand, summary, false);
             if (!resultCodeCheck.apply(result)) {
                 throw logWithDetailsAndThrow(format("Execution failed, invalid result %s for %s", result, summary), null);
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java
index 07ccdef..1a744c0 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java
@@ -27,12 +27,17 @@ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.location.jclouds.JcloudsLocation;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.text.Strings;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
 public class WindowsTestFixture {
 
+    /** Can be configured as `user:pass@host` to allow use of a pre-existing fixed winrm target;
+     * if not, will provision in AWS */
+    public static final String EXISTING_WINDOWS_TEST_USER_PASS_HOST_ENV_VAR = "EXISTING_WINDOWS_TEST_USER_PASS_HOST_ENV_VAR";
+    
     public static MachineProvisioningLocation<WinRmMachineLocation> setUpWindowsLocation(ManagementContext mgmt) throws Exception {
         return setUpWindowsLocation(mgmt, ImmutableMap.<String, Object>of());
     }
@@ -41,8 +46,17 @@ public class WindowsTestFixture {
     public static MachineProvisioningLocation<WinRmMachineLocation> setUpWindowsLocation(ManagementContext mgmt, Map<String, ?> props) throws Exception {
         // Commented out / unused code included here to make it easy to supply a 
         // pre-existing Windows VM for use in a bunch of different tests.
-//        return (MachineProvisioningLocation<WinRmMachineLocation>) newByonLocation((ManagementContextInternal) mgmt);
-        return (MachineProvisioningLocation<WinRmMachineLocation>) newJcloudsLocation((ManagementContextInternal) mgmt, props);
+        String userPassAtHost = System.getenv(EXISTING_WINDOWS_TEST_USER_PASS_HOST_ENV_VAR);
+        if (Strings.isBlank(userPassAtHost)) {
+            return (MachineProvisioningLocation<WinRmMachineLocation>) newJcloudsLocation((ManagementContextInternal) mgmt, props);
+        } else {
+            return (MachineProvisioningLocation<WinRmMachineLocation>) newByonLocation((ManagementContextInternal) mgmt,
+                MutableMap.of(
+                        "winrm", userPassAtHost.split("@")[1],
+                        "password", userPassAtHost.split(":")[1].split("@")[0],
+                        "user", userPassAtHost.split(":")[0]
+                    ));
+        }
     }
     
     private static MachineProvisioningLocation<?> newJcloudsLocation(ManagementContextInternal mgmt, Map<String, ?> props) {
@@ -62,17 +76,17 @@ public class WindowsTestFixture {
                 .build());
     }
     
-    @SuppressWarnings("unused")
     private static MachineProvisioningLocation<?> newByonLocation(ManagementContextInternal mgmt, Map<String, ?> props) {
         Map<String, Object> config = new LinkedHashMap<>();
-        config.put("hosts", "52.12.211.123:5985");
+        config.put("useJcloudsSshInit", "false");
+        config.put("byonIdentity", "123");
         config.put("osFamily", "windows");
+        // these are overwritten by the map
         config.put("winrm", "52.12.211.123:5985");
         config.put("user", "Administrator");
         config.put("password", "pa55w0rd");
-        config.put("useJcloudsSshInit", "false");
-        config.put("byonIdentity", "123");
         config.putAll(props);
-        return (MachineProvisioningLocation<?>) mgmt.getLocationRegistry().getLocationManaged("byon", config);
+        
+        return (MachineProvisioningLocation<?>) mgmt.getLocationRegistry().getLocationManaged("byon", ImmutableMap.of("hosts", ImmutableList.of(config)));
     }
 }
diff --git a/software/winrm/src/main/java/org/apache/brooklyn/util/core/internal/winrm/WinRmTool.java b/software/winrm/src/main/java/org/apache/brooklyn/util/core/internal/winrm/WinRmTool.java
index dff6e07..1d9d2b9 100644
--- a/software/winrm/src/main/java/org/apache/brooklyn/util/core/internal/winrm/WinRmTool.java
+++ b/software/winrm/src/main/java/org/apache/brooklyn/util/core/internal/winrm/WinRmTool.java
@@ -49,6 +49,8 @@ public interface WinRmTool {
     ConfigKey<Integer> PROP_PORT = ConfigKeys.newIntegerConfigKey("port", "WinRM port to use when connecting to the remote machine");
     ConfigKey<Boolean> USE_HTTPS_WINRM = ConfigKeys.newBooleanConfigKey("winrm.useHttps", "The parameter tells the machine sensors whether the winrm port is over https. If the parameter is true then 5986 will be used as a winrm port.", false);
     ConfigKey<Integer> RETRIES_OF_NETWORK_FAILURES = ConfigKeys.newIntegerConfigKey("retriesOfNetworkFailures", "The parameter sets the number of retries for connection failures. If you use high value, consider taking care for the machine's network.", 4);
+    
+    @SetFromFlag("env")
     ConfigKey<Map<String,String>> ENVIRONMENT = MapConfigKey.builder(new TypeToken<Map<String,String>>() {})
             .name("winrm.environment")
             .description("WinRM Environment variables").build();
@@ -91,9 +93,6 @@ public interface WinRmTool {
             "Can be used to pass additional custom data to the WinrmTool, which is especially useful " +
                     "if writing a bespoke tool implementation");
 
-    @SetFromFlag("env")
-    MapConfigKey<Object> SHELL_ENVIRONMENT = BrooklynConfigKeys.SHELL_ENVIRONMENT;
-
     /**
      * @deprecated since 0.9.0; use {@link #executeCommand(List)} to avoid ambiguity between native command and power shell.
      */