http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java
new file mode 100644
index 0000000..accda93
--- /dev/null
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java
@@ -0,0 +1,45 @@
+/*
+ * 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.location.jclouds;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+
+import brooklyn.location.MachineLocation;
+import brooklyn.location.basic.HasSubnetHostname;
+
+public interface JcloudsMachineLocation extends MachineLocation, 
HasSubnetHostname {
+    
+    @Override
+    public JcloudsLocation getParent();
+    
+    public NodeMetadata getNode();
+    
+    public Template getTemplate();
+
+    public String getJcloudsId();
+
+    /** In most clouds, the public hostname is the only way to ensure VMs in 
different zones can access each other. */
+    @Override
+    public String getSubnetHostname();
+
+    String getUser();
+
+    int getPort();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
index c715ad5..6e98e3a 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
@@ -68,7 +68,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.net.HostAndPort;
 import com.google.common.util.concurrent.ListenableFuture;
 
-public class JcloudsSshMachineLocation extends SshMachineLocation implements 
HasSubnetHostname {
+public class JcloudsSshMachineLocation extends SshMachineLocation implements 
JcloudsMachineLocation {
     
     private static final Logger LOG = 
LoggerFactory.getLogger(JcloudsSshMachineLocation.class);
     private static final long serialVersionUID = -443866395634771659L;
@@ -133,14 +133,17 @@ public class JcloudsSshMachineLocation extends 
SshMachineLocation implements Has
                 .toString();
     }
 
+    @Override
     public NodeMetadata getNode() {
         return node;
     }
     
+    @Override
     public Template getTemplate() {
         return template;
     }
     
+    @Override
     public JcloudsLocation getParent() {
         return jcloudsParent;
     }
@@ -199,6 +202,7 @@ public class JcloudsSshMachineLocation extends 
SshMachineLocation implements Has
         return Optional.absent();
     }
     
+    @Override
     public String getJcloudsId() {
         return node.getId();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
index 02a46a5..150d5ff 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
@@ -18,8 +18,133 @@
  */
 package brooklyn.location.jclouds;
 
+import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.location.basic.WinRmMachineLocation;
+import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.net.Networking;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.net.HostAndPort;
+
+public class JcloudsWinRmMachineLocation extends WinRmMachineLocation 
implements JcloudsMachineLocation {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(JcloudsWinRmMachineLocation.class);
+
+    @SetFromFlag
+    JcloudsLocation jcloudsParent;
+    
+    @SetFromFlag
+    NodeMetadata node;
+    
+    @SetFromFlag
+    Template template;
+
+    public JcloudsWinRmMachineLocation() {
+    }
+
+    @Override
+    public String toVerboseString() {
+        return Objects.toStringHelper(this).omitNullValues()
+                .add("id", getId()).add("name", getDisplayName())
+                .add("user", getUser())
+                .add("address", getAddress())
+                .add("port", getPort())
+                .add("node", getNode())
+                .add("jcloudsId", getJcloudsId())
+                .add("privateAddresses", node.getPrivateAddresses())
+                .add("publicAddresses", node.getPublicAddresses())
+                .add("parentLocation", getParent())
+                .add("osDetails", getOsDetails())
+                .toString();
+    }
+
+    @Override
+    public int getPort() {
+        return getConfig(WINRM_PORT);
+    }
+    
+    @Override
+    public NodeMetadata getNode() {
+        return node;
+    }
+    
+    @Override
+    public Template getTemplate() {
+        return template;
+    }
+    
+    @Override
+    public JcloudsLocation getParent() {
+        return jcloudsParent;
+    }
+    
+    @Override
+    public String getHostname() {
+        return node.getHostname();
+    }
+    
+    @Override
+    public Set<String> getPublicAddresses() {
+        return node.getPublicAddresses();
+    }
+    
+    @Override
+    public Set<String> getPrivateAddresses() {
+        return node.getPrivateAddresses();
+    }
+
+    @Override
+    public String getSubnetHostname() {
+        String publicHostname = jcloudsParent.getPublicHostname(node, 
Optional.<HostAndPort>absent(), config().getBag());
+        return publicHostname;
+    }
+
+    @Override
+    public String getSubnetIp() {
+        Optional<String> privateAddress = getPrivateAddress();
+        if (privateAddress.isPresent()) {
+            return privateAddress.get();
+        }
 
-public class JcloudsWinRmMachineLocation extends WinRmMachineLocation {
+        String hostname = jcloudsParent.getPublicHostname(node, 
Optional.<HostAndPort>absent(), config().getBag());
+        if (hostname != null && !Networking.isValidIp4(hostname)) {
+            try {
+                return InetAddress.getByName(hostname).getHostAddress();
+            } catch (UnknownHostException e) {
+                LOG.debug("Cannot resolve IP for hostname {} of machine {} (so 
returning hostname): {}", new Object[] {hostname, this, e});
+            }
+        }
+        return hostname;
+    }
 
+    protected Optional<String> getPrivateAddress() {
+        if (groovyTruth(node.getPrivateAddresses())) {
+            Iterator<String> pi = node.getPrivateAddresses().iterator();
+            while (pi.hasNext()) {
+                String p = pi.next();
+                // disallow local only addresses
+                if (Networking.isLocalOnly(p)) continue;
+                // other things may be public or private, but either way, 
return it
+                return Optional.of(p);
+            }
+        }
+        return Optional.absent();
+    }
+    
+    @Override
+    public String getJcloudsId() {
+        return node.getId();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
index b7f8400..889c7e3 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
@@ -21,7 +21,9 @@ package brooklyn.location.jclouds;
 import org.jclouds.compute.ComputeService;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
 
+import brooklyn.location.basic.SshMachineLocation;
 import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.ssh.SshTasks;
 import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
@@ -48,9 +50,9 @@ import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
 public class SudoTtyFixingCustomizer extends BasicJcloudsLocationCustomizer {
 
     @Override
-    public void customize(JcloudsLocation location, ComputeService 
computeService, JcloudsSshMachineLocation machine) {
-        DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(machine, 
OnFailingTask.FAIL)).orSubmitAndBlock();
+    public void customize(JcloudsLocation location, ComputeService 
computeService, JcloudsMachineLocation machine) {
+        Preconditions.checkArgument(machine instanceof SshMachineLocation, 
"machine must be SshMachineLocation, but is %s", machine.getClass());
+        
DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo((SshMachineLocation)machine,
 OnFailingTask.FAIL)).orSubmitAndBlock();
         DynamicTasks.waitForLast();
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
index 98edfcf..7d28a9f 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
@@ -40,7 +40,7 @@ import brooklyn.entity.Entity;
 import brooklyn.location.geo.LocalhostExternalIpLoader;
 import brooklyn.location.jclouds.BasicJcloudsLocationCustomizer;
 import brooklyn.location.jclouds.JcloudsLocation;
-import brooklyn.location.jclouds.JcloudsSshMachineLocation;
+import brooklyn.location.jclouds.JcloudsMachineLocation;
 import brooklyn.management.ManagementContext;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.net.Cidr;
@@ -151,13 +151,13 @@ public class JcloudsLocationSecurityGroupCustomizer 
extends BasicJcloudsLocation
     }
 
     /** @see 
#addPermissionsToLocation(brooklyn.location.jclouds.JcloudsSshMachineLocation, 
java.lang.Iterable) */
-    public JcloudsLocationSecurityGroupCustomizer 
addPermissionsToLocation(final JcloudsSshMachineLocation location, 
IpPermission... permissions) {
+    public JcloudsLocationSecurityGroupCustomizer 
addPermissionsToLocation(final JcloudsMachineLocation location, IpPermission... 
permissions) {
         addPermissionsToLocation(location, ImmutableList.copyOf(permissions));
         return this;
     }
 
     /** @see 
#addPermissionsToLocation(brooklyn.location.jclouds.JcloudsSshMachineLocation, 
java.lang.Iterable) */
-    public JcloudsLocationSecurityGroupCustomizer 
addPermissionsToLocation(final JcloudsSshMachineLocation location, 
SecurityGroupDefinition securityGroupDefinition) {
+    public JcloudsLocationSecurityGroupCustomizer 
addPermissionsToLocation(final JcloudsMachineLocation location, 
SecurityGroupDefinition securityGroupDefinition) {
         addPermissionsToLocation(location, 
securityGroupDefinition.getPermissions());
         return this;
     }
@@ -169,7 +169,7 @@ public class JcloudsLocationSecurityGroupCustomizer extends 
BasicJcloudsLocation
      * @param permissions The set of permissions to be applied to the location
      * @param location Location to gain permissions
      */
-    public JcloudsLocationSecurityGroupCustomizer 
addPermissionsToLocation(final JcloudsSshMachineLocation location, final 
Iterable<IpPermission> permissions) {
+    public JcloudsLocationSecurityGroupCustomizer 
addPermissionsToLocation(final JcloudsMachineLocation location, final 
Iterable<IpPermission> permissions) {
         ComputeService computeService = 
location.getParent().getComputeService();
         String nodeId = location.getNode().getId();
         addPermissionsToLocation(permissions, nodeId, computeService);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java
 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java
index e70ba89..62817c2 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java
@@ -524,7 +524,7 @@ public class JcloudsLocationTest implements 
JcloudsLocationConfig {
             
             // explicitly invoke this customizer, to comply with tests
             for (JcloudsLocationCustomizer customizer : 
getCustomizers(config().getBag())) {
-                customizer.customize(this, null, result);
+                customizer.customize(this, null, 
(JcloudsMachineLocation)result);
             }
 
             return result;
@@ -591,7 +591,7 @@ public class JcloudsLocationTest implements 
JcloudsLocationConfig {
             .configure(JcloudsLocationConfig.JCLOUDS_LOCATION_CUSTOMIZERS, 
ImmutableList.of(customizer))
             .configure(JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 1);
         FakeLocalhostWithParentJcloudsLocation ll = 
managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class).configure(allConfig.getAllConfig()));
-        JcloudsSshMachineLocation l = (JcloudsSshMachineLocation)ll.obtain();
+        JcloudsMachineLocation l = (JcloudsMachineLocation)ll.obtain();
         Mockito.verify(customizer, Mockito.times(1)).customize(ll, null, l);
         Mockito.verify(customizer, Mockito.never()).preRelease(l);
         Mockito.verify(customizer, Mockito.never()).postRelease(l);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index af08b2e..0f8e075 100644
--- a/pom.xml
+++ b/pom.xml
@@ -205,7 +205,7 @@
         <jsr311-api.version>1.1.1</jsr311-api.version>
         <maxmind.version>0.8.1</maxmind.version>
         <jna.version>4.0.0</jna.version>
-        <winrm4j.version>0.1.0-SNAPSHOT</winrm4j.version>
+        <winrm4j.version>0.1.0</winrm4j.version>
         <coverage.target>${working.dir}</coverage.target>
 
         <!-- Release -->

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java
 
b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java
index 92f4fa6..c34e342 100644
--- 
a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java
+++ 
b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java
@@ -48,8 +48,8 @@ public abstract class AbstractSoftwareProcessWinRmDriver 
extends AbstractSoftwar
 
     public AbstractSoftwareProcessWinRmDriver(EntityLocal entity, 
WinRmMachineLocation location) {
         super(entity, location);
-        entity.setAttribute(WINDOWS_USERNAME, 
location.config().get(WinRmMachineLocation.WINDOWS_USERNAME));
-        entity.setAttribute(WINDOWS_PASSWORD, 
location.config().get(WinRmMachineLocation.WINDOWS_PASSWORD));
+        entity.setAttribute(WINDOWS_USERNAME, 
location.config().get(WinRmMachineLocation.USER));
+        entity.setAttribute(WINDOWS_PASSWORD, 
location.config().get(WinRmMachineLocation.PASSWORD));
     }
 
     @Override
@@ -99,7 +99,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver 
extends AbstractSoftwar
         if (createParentDir) {
             createDirectory(getDirectory(target), "Creating resource 
directory");
         }
-        return copyTo(new File(source), new File(target));
+        return copyTo(new File(source), target);
     }
 
     @Override
@@ -107,7 +107,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver 
extends AbstractSoftwar
         if (createParentDir) {
             createDirectory(getDirectory(target), "Creating resource 
directory");
         }
-        return copyTo(source, new File(target));
+        return copyTo(source, target);
     }
 
     @Override
@@ -139,30 +139,30 @@ public abstract class AbstractSoftwareProcessWinRmDriver 
extends AbstractSoftwar
         return getLocation().executeScript(script).getStatusCode();
     }
 
-    public int executePowerShellNoRetry(List<String> psScript) {
+    public int executePsScriptNoRetry(List<String> psScript) {
         return getLocation().executePsScriptNoRetry(psScript).getStatusCode();
     }
 
-    public int executePowerShell(List<String> psScript) {
+    public int executePsScript(List<String> psScript) {
         return getLocation().executePsScript(psScript).getStatusCode();
     }
 
-    public int copyTo(File source, File destination) {
+    public int copyTo(File source, String destination) {
         return getLocation().copyTo(source, destination);
     }
 
-    public int copyTo(InputStream source, File destination) {
+    public int copyTo(InputStream source, String destination) {
         return getLocation().copyTo(source, destination);
     }
 
     public void rebootAndWait() {
         try {
-            executePowerShellNoRetry(ImmutableList.of("Restart-Computer 
-Force"));
+            executePsScriptNoRetry(ImmutableList.of("Restart-Computer 
-Force"));
         } catch (PyException e) {
             // Restarting the computer will cause the command to fail; ignore 
the exception and continue
         }
-        waitForWinRmStatus(false, 
entity.getConfig(VanillaWindowsProcess.REBOOT_UNAVAILABLE_TIMEOUT));
-        waitForWinRmStatus(true, 
entity.getConfig(VanillaWindowsProcess.REBOOT_AVAILABLE_TIMEOUT)).getWithError();
+        waitForWinRmStatus(false, 
entity.getConfig(VanillaWindowsProcess.REBOOT_BEGUN_TIMEOUT));
+        waitForWinRmStatus(true, 
entity.getConfig(VanillaWindowsProcess.REBOOT_COMPLETED_TIMEOUT)).getWithError();
     }
 
     private String getDirectory(String fileName) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java
 
b/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java
deleted file mode 100644
index 1ddb488..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.basic;
-
-public interface AbstractVanillaProcessDriver extends SoftwareProcessDriver {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java 
b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
index fe6d052..75b3573 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
@@ -18,6 +18,7 @@
  */
 package brooklyn.entity.basic;
 
+import java.util.Collection;
 import java.util.Map;
 
 import brooklyn.config.ConfigKey;
@@ -34,6 +35,7 @@ import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.reflect.TypeToken;
 
 public interface SoftwareProcess extends Entity, Startable {
@@ -43,6 +45,13 @@ public interface SoftwareProcess extends Entity, Startable {
     AttributeSensor<String> SUBNET_HOSTNAME = Attributes.SUBNET_HOSTNAME;
     AttributeSensor<String> SUBNET_ADDRESS = Attributes.SUBNET_ADDRESS;
 
+    @SuppressWarnings("serial")
+    ConfigKey<Collection<Integer>> REQUIRED_OPEN_LOGIN_PORTS = 
ConfigKeys.newConfigKey(
+            new TypeToken<Collection<Integer>>() {},
+            "requiredOpenLoginPorts",
+            "The port(s) to be opened, to allow login",
+            ImmutableSet.of(22));
+
     @SetFromFlag("startTimeout")
     ConfigKey<Duration> START_TIMEOUT = BrooklynConfigKeys.START_TIMEOUT;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java 
b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
index 1827485..a651f65 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
@@ -438,12 +438,12 @@ public abstract class SoftwareProcessImpl extends 
AbstractEntity implements Soft
     }
 
     /** returns the ports that this entity wants to use;
-     * default implementation returns 22 plus first value for each 
PortAttributeSensorAndConfigKey config key PortRange
-     * plus any ports defined with a config keys ending in .port 
+     * default implementation returns {@link 
SoftwareProcess#REQUIRED_OPEN_LOGIN_PORTS} plus first value 
+     * for each {@link PortAttributeSensorAndConfigKey} config key {@link 
PortRange}
+     * plus any ports defined with a config keys ending in {@code .port}.
      */
     protected Collection<Integer> getRequiredOpenPorts() {
-        // TODO: Should only open 22 *or* 5985. Perhaps a flag / ConfigKey on 
SoftwareProcessImpl?
-        Set<Integer> ports = MutableSet.of(22, 5985, 3389);
+        Set<Integer> ports = 
MutableSet.copyOf(getConfig(REQUIRED_OPEN_LOGIN_PORTS));
         Map<ConfigKey<?>, ?> allConfig = 
config().getBag().getAllConfigAsConfigKeyMap();
         Set<ConfigKey<?>> configKeys = Sets.newHashSet(allConfig.keySet());
         configKeys.addAll(getEntityType().getConfigKeys());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java
 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java
index e4e43ec..aa98086 100644
--- 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java
+++ 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java
@@ -18,6 +18,6 @@
  */
 package brooklyn.entity.basic;
 
-public interface VanillaSoftwareProcessDriver extends 
AbstractVanillaProcessDriver {
+public interface VanillaSoftwareProcessDriver extends SoftwareProcessDriver {
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java
index 4740bf6..ce49110 100644
--- 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java
+++ 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java
@@ -18,12 +18,20 @@
  */
 package brooklyn.entity.basic;
 
+import java.util.Collection;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.proxying.ImplementedBy;
 import brooklyn.util.time.Duration;
 
+import com.google.common.collect.ImmutableSet;
+
 @ImplementedBy(VanillaWindowsProcessImpl.class)
 public interface VanillaWindowsProcess extends AbstractVanillaProcess {
+    // 3389 is RDP; 5985 is WinRM (3389 isn't used by Brooklyn, but useful for 
the end-user subsequently)
+    ConfigKey<Collection<Integer>> REQUIRED_OPEN_LOGIN_PORTS = 
ConfigKeys.newConfigKeyWithDefault(
+            SoftwareProcess.REQUIRED_OPEN_LOGIN_PORTS,
+            ImmutableSet.of(5985, 3389));
     ConfigKey<String> PRE_INSTALL_POWERSHELL_COMMAND = 
ConfigKeys.newStringConfigKey("pre.install.powershell.command",
             "powershell command to run during the pre-install phase");
     ConfigKey<Boolean> PRE_INSTALL_REBOOT_REQUIRED = 
ConfigKeys.newBooleanConfigKey("pre.install.reboot.required",
@@ -46,9 +54,9 @@ public interface VanillaWindowsProcess extends 
AbstractVanillaProcess {
             "command to run during the install phase");
     ConfigKey<String> INSTALL_POWERSHELL_COMMAND = 
ConfigKeys.newStringConfigKey("install.powershell.command",
             "powershell command to run during the install phase");
-    ConfigKey<Duration> REBOOT_UNAVAILABLE_TIMEOUT = 
ConfigKeys.newDurationConfigKey("reboot.unavailable.timeout",
-            "duration to wait whilst waiting for a machine to become 
unavailable after a reboot", Duration.TWO_MINUTES);
-    // If automatic updates are enabled and there are updates waiting to be 
installed, thirty minutes may not be sufficient...
-    ConfigKey<Duration> REBOOT_AVAILABLE_TIMEOUT = 
ConfigKeys.newDurationConfigKey("reboot.unavailable.timeout",
-            "duration to wait whilst waiting for a machine to become 
unavailable after a reboot", Duration.minutes(30));
+    ConfigKey<Duration> REBOOT_BEGUN_TIMEOUT = 
ConfigKeys.newDurationConfigKey("reboot.begun.timeout",
+            "duration to wait whilst waiting for a machine to begin rebooting, 
and thus become unavailable", Duration.TWO_MINUTES);
+    // TODO If automatic updates are enabled and there are updates waiting to 
be installed, thirty minutes may not be sufficient...
+    ConfigKey<Duration> REBOOT_COMPLETED_TIMEOUT = 
ConfigKeys.newDurationConfigKey("reboot.completed.timeout",
+            "duration to wait whilst waiting for a machine to finish 
rebooting, and thus to become available again", Duration.minutes(30));
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java
 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java
index 04e60cf..7e9fd8c 100644
--- 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java
+++ 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java
@@ -18,6 +18,6 @@
  */
 package brooklyn.entity.basic;
 
-public interface VanillaWindowsProcessDriver extends 
AbstractVanillaProcessDriver {
+public interface VanillaWindowsProcessDriver extends SoftwareProcessDriver {
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java
 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java
index 7eac4a6..febed0f 100644
--- 
a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java
+++ 
b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java
@@ -18,6 +18,7 @@
  */
 package brooklyn.entity.basic;
 
+
 public class VanillaWindowsProcessImpl extends SoftwareProcessImpl implements 
VanillaWindowsProcess {
     @Override
     public Class getDriverInterface() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java 
b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
index a4f60e7..8c20253 100644
--- a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
@@ -22,14 +22,14 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.effector.AddSensor;
-import brooklyn.event.basic.Sensors;
 import brooklyn.util.config.ConfigBag;
+import brooklyn.util.flags.TypeCoercions;
 
-public class StaticSensor<T> extends AddSensor<Integer> {
+public class StaticSensor<T> extends AddSensor<T> {
 
-    public static final ConfigKey<Integer> STATIC_VALUE = 
ConfigKeys.newConfigKey(Integer.class, "static.value");
+    public static final ConfigKey<Object> STATIC_VALUE = 
ConfigKeys.newConfigKey(Object.class, "static.value");
 
-    private final Integer value;
+    private final Object value;
 
     public StaticSensor(ConfigBag params) {
         super(params);
@@ -39,6 +39,6 @@ public class StaticSensor<T> extends AddSensor<Integer> {
     @Override
     public void apply(EntityLocal entity) {
         super.apply(entity);
-        entity.setAttribute(Sensors.newIntegerSensor(name), value);
+        entity.setAttribute(sensor, (T) TypeCoercions.coerce(value, 
sensor.getType()));
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
 
b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
index e36d285..bed1cb9 100644
--- 
a/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
+++ 
b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
@@ -57,18 +57,18 @@ public class WindowsPerformanceCounterSensors implements 
EntityInitializer {
         WindowsPerformanceCounterFeed.Builder builder = 
WindowsPerformanceCounterFeed.builder()
                 .entity(entity);
         for (Map<String, String> sensorConfig : sensors) {
+            String name = sensorConfig.get("name");
             String sensorType = sensorConfig.get("sensorType");
             Class<?> clazz;
             try {
-                clazz = Strings.isNonEmpty(sensorType) ?
-                
((EntityInternal)entity).getManagementContext().getCatalog().getRootClassLoader().loadClass(sensorType)
 : String.class;
+                clazz = Strings.isNonEmpty(sensorType)
+                        ? 
((EntityInternal)entity).getManagementContext().getCatalog().getRootClassLoader().loadClass(sensorType)
 
+                        : String.class;
             } catch (ClassNotFoundException e) {
-                LOG.warn("Could not load type {} for sensor {}", sensorType, 
sensorConfig.get("name"));
-                clazz = String.class;
+                throw new IllegalStateException("Could not load type 
"+sensorType+" for sensor "+name, e);
             }
-            builder.addSensor(sensorConfig.get("counter"), 
Sensors.newSensor(clazz, sensorConfig.get("name"), 
sensorConfig.get("description")));
+            builder.addSensor(sensorConfig.get("counter"), 
Sensors.newSensor(clazz, name, sensorConfig.get("description")));
         }
         builder.build();
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java
 
b/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java
index 9115d62..a8bff64 100644
--- 
a/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java
+++ 
b/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java
@@ -53,7 +53,7 @@ import com.google.common.collect.Lists;
  * 
  * Different from {@link DynamicClusterWithAvailabilityZonesTest} in the use 
of {@link MultiLocation}.
  * However, the difference is important: the {@link SoftwareProcess} entity 
has two locations
- * (the {@link MachineProvisioningLocation} and the {@link MachineLocation}, 
which was perviously
+ * (the {@link MachineProvisioningLocation} and the {@link MachineLocation}, 
which was previously
  * causing a failure - now fixed and tested here.
  */
 public class DynamicClusterWithAvailabilityZonesMultiLocationTest extends 
BrooklynAppUnitTestSupport {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java 
b/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java
new file mode 100644
index 0000000..4b9a641
--- /dev/null
+++ b/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.entity.software;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.entity.basic.BasicEntity;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.event.basic.Sensors;
+import brooklyn.test.EntityTestUtils;
+import brooklyn.util.config.ConfigBag;
+
+import com.google.common.collect.ImmutableMap;
+
+public class StaticSensorTest extends BrooklynAppUnitTestSupport {
+
+    @Test
+    public void testAddsStaticSensorOfTypeString() {
+        BasicEntity entity = 
app.createAndManageChild(EntitySpec.create(BasicEntity.class)
+                .addInitializer(new 
StaticSensor<String>(ConfigBag.newInstance(ImmutableMap.of(
+                        StaticSensor.SENSOR_NAME, "myname",
+                        StaticSensor.SENSOR_TYPE, String.class.getName(),
+                        StaticSensor.STATIC_VALUE, "myval")))));
+        
+        EntityTestUtils.assertAttributeEquals(entity, 
Sensors.newSensor(String.class, "myname"), "myval");
+    }
+    
+    @Test
+    public void testAddsStaticSensorOfTypeInteger() {
+        BasicEntity entity = 
app.createAndManageChild(EntitySpec.create(BasicEntity.class)
+                .addInitializer(new 
StaticSensor<Integer>(ConfigBag.newInstance(ImmutableMap.of(
+                        StaticSensor.SENSOR_NAME, "myname",
+                        StaticSensor.SENSOR_TYPE, Integer.class.getName(),
+                        StaticSensor.STATIC_VALUE, "1")))));
+        
+        EntityTestUtils.assertAttributeEquals(entity, 
Sensors.newSensor(Integer.class, "myname"), 1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java
 
b/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java
new file mode 100644
index 0000000..735a23f
--- /dev/null
+++ 
b/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.location.basic;
+
+import static org.testng.Assert.assertEquals;
+import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.basic.Entities;
+import brooklyn.location.jclouds.JcloudsLocation;
+import brooklyn.location.jclouds.JcloudsWinRmMachineLocation;
+import brooklyn.management.internal.ManagementContextInternal;
+import brooklyn.test.entity.LocalManagementContextForTests;
+import brooklyn.test.entity.TestApplication;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class WinRmMachineLocationLiveTest {
+    
+    // FIXME failing locally with:
+    //   Caused by: Traceback (most recent call last):
+    //     File "__pyclasspath__/winrm/__init__.py", line 40, in run_cmd
+    //     File "__pyclasspath__/winrm/protocol.py", line 118, in open_shell
+    //     File "__pyclasspath__/winrm/protocol.py", line 190, in send_message
+    //     File "__pyclasspath__/winrm/transport.py", line 112, in send_message
+    //     winrm.exceptions.WinRMTransportError: 500 WinRMTransport. [Errno 
20001] getaddrinfo failed
+    //     at org.python.core.PyException.doRaise(PyException.java:226)
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(BrooklynAppLiveTestSupport.class);
+
+    protected JcloudsLocation loc;
+    protected TestApplication app;
+    protected ManagementContextInternal mgmt;
+
+    private JcloudsWinRmMachineLocation machine;
+    
+    @BeforeClass(alwaysRun=true)
+    public void setUpClass() throws Exception {
+        mgmt = new 
LocalManagementContextForTests(BrooklynProperties.Factory.newDefault());
+        JcloudsLocation loc = (JcloudsLocation) 
mgmt.getLocationRegistry().resolve("jclouds:aws-ec2:us-west-2", ImmutableMap.of(
+                "inboundPorts", ImmutableList.of(5985, 3389),
+                "displayName", "AWS Oregon (Windows)",
+                "imageId", "us-west-2/ami-8fd3f9bf",
+                "hardwareId", "m3.medium",
+                "useJcloudsSshInit", false));
+        machine = (JcloudsWinRmMachineLocation) loc.obtain();
+    }
+
+    @AfterClass(alwaysRun=true)
+    public void tearDownClass() throws Exception {
+        try {
+            if (machine != null) loc.release(machine);
+            if (mgmt != null) Entities.destroyAll(mgmt);
+        } catch (Throwable t) {
+            LOG.error("Caught exception in tearDown method", t);
+        } finally {
+            mgmt = null;
+        }
+    }
+
+    @Test(groups="Live")
+    public void testExecScript() throws Exception {
+        WinRmToolResponse response = machine.executeScript("echo true");
+        assertEquals(response.getStatusCode(), 0);
+        assertEquals(response.getStdErr(), "");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
----------------------------------------------------------------------
diff --git 
a/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
 
b/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
index 7c366eb..d82a7f7 100644
--- 
a/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
+++ 
b/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
@@ -1,6 +1,15 @@
-name: imageId us-west-2/ami-07390a37
+name: mssql
 
-location: AWS Oregon Win
+location:
+  jclouds:aws-ec2:us-west-2:
+    displayName: AWS Oregon (Windows)
+    imageId: us-west-2/ami-8fd3f9bf
+    hardwareId:  m3.medium
+    useJcloudsSshInit: false
+    templateOptions:
+      subnetId: subnet-a10e96c4
+      securityGroupIds: [['sg-a2d0c2c7']]
+      mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]
 
 services:
 - type: brooklyn.entity.basic.VanillaWindowsProcess

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
----------------------------------------------------------------------
diff --git 
a/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
 
b/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
new file mode 100644
index 0000000..f5ef36f
--- /dev/null
+++ 
b/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.entity.database.mssql;
+
+import java.io.StringReader;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import brooklyn.launcher.blueprints.AbstractBlueprintTest;
+import brooklyn.util.ResourceUtils;
+import brooklyn.util.text.TemplateProcessor;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Assumes that brooklyn.properties contains something like the following (but 
with real values!):
+ * 
+ * {@code
+ * test.mssql.download.url = http://myserver.com/sql2012.iso
+ * test.mssql.download.user = myname
+ * test.mssql.download.password = mypassword
+ * test.mssql.sa.password = mypassword
+ * test.mssql.instance.name = MYNAME
+ * }
+ */
+public class MssqlBlueprintLiveTest extends AbstractBlueprintTest {
+
+    // TODO Needs further testing
+    
+    @Test(groups={"Live"})
+    public void testMssql() throws Exception {
+        Map<String, String> substitutions = ImmutableMap.of(
+                "mssql.download.url", 
mgmt.getConfig().getFirst("test.mssql.download.url"),
+                "mssql.download.user", 
mgmt.getConfig().getFirst("test.mssql.download.user"),
+                "mssql.download.password", 
mgmt.getConfig().getFirst("test.mssql.download.password"),
+                "mssql.sa.password", 
mgmt.getConfig().getFirst("test.mssql.sa.password"),
+                "mssql.instance.name", 
mgmt.getConfig().getFirst("test.mssql.instance.name"));
+
+        String rawYaml = new 
ResourceUtils(this).getResourceAsString("mssql-test.yaml");
+        String yaml = TemplateProcessor.processTemplateContents(rawYaml, 
substitutions);
+        runTest(new StringReader(yaml));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/usage/launcher/src/test/resources/mssql-test.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/mssql-test.yaml 
b/usage/launcher/src/test/resources/mssql-test.yaml
new file mode 100644
index 0000000..2b31f74
--- /dev/null
+++ b/usage/launcher/src/test/resources/mssql-test.yaml
@@ -0,0 +1,60 @@
+#
+# 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.
+#
+
+# Duplicate of 
software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml,
+# but with template for download url, etc
+
+name: mssql
+
+location:
+  jclouds:aws-ec2:us-west-2:
+    displayName: AWS Oregon (Windows)
+    imageId: us-west-2/ami-8fd3f9bf
+    hardwareId: m3.medium
+    useJcloudsSshInit: false
+    templateOptions:
+      mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]
+
+services:
+- type: brooklyn.entity.basic.VanillaWindowsProcess
+  brooklyn.config:
+    templates.install:
+      classpath://brooklyn/entity/database/mssql/ConfigurationFile.ini: 
"C:\\ConfigurationFile.ini"
+      classpath://brooklyn/entity/database/mssql/installmssql.ps1: 
"C:\\installmssql.ps1"
+      classpath://brooklyn/entity/database/mssql/configuremssql.ps1: 
"C:\\configuremssql.ps1"
+      classpath://brooklyn/entity/database/mssql/launchmssql.bat: 
"C:\\launchmssql.bat"
+      classpath://brooklyn/entity/database/mssql/stopmssql.bat: 
"C:\\stopmssql.bat"
+    install.command: powershell -command "C:\\installmssql.ps1"
+    customize.command: powershell -command "C:\\configuremssql.ps1"
+    launch.command: "C:\\launchmssql.bat"
+    stop.command: "C:\\stopmssql.bat"
+    checkRunning.command: echo true
+
+    ## NOTE: Values must be supplied for the following
+    mssql.download.url: ${mssql.download.url}
+    mssql.download.user: ${mssql.download.user}
+    mssql.download.password: ${mssql.download.password}
+    mssql.sa.password: ${mssql.sa.password}
+    mssql.instance.name: ${mssql.instance.name}
+
+    ## The following is a list of *all* MSSQL features. Installation time and 
footprint can be greatly
+    ## reduced by removing unnecessary features
+    mssql.features: 
"SQLENGINE,REPLICATION,FULLTEXT,DQ,AS,RS,RS_SHP,DQC,BIDS,CONN,IS,BC,SDK,BOL,SSMS,ADV_SSMS,DREPLAY_CTLR,DREPLAY_CLT,SNAC_SDK"
+  provisioning.properties:
+    required.ports: 1433
\ No newline at end of file

Reply via email to