Adds WinRm support for EC2 Windows instances

Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/fb18f534
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/fb18f534
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/fb18f534

Branch: refs/heads/master
Commit: fb18f534a6381d472cfa2b2ce07a239ac6c93f28
Parents: 1fa5969
Author: Martin Harris <[email protected]>
Authored: Wed Apr 8 15:41:14 2015 +0100
Committer: Richard Downer <[email protected]>
Committed: Thu May 28 17:27:34 2015 +0100

----------------------------------------------------------------------
 .../location/basic/WinRmMachineLocation.java    |  46 +++
 ...bstractCloudMachineProvisioningLocation.java |   6 +-
 .../location/cloud/CloudLocationConfig.java     |   4 +
 .../location/jclouds/BrooklynMachinePool.java   |  10 +-
 .../location/jclouds/JcloudsLocation.java       | 318 ++++++++++++++-----
 .../jclouds/JcloudsWinRmMachineLocation.java    |  25 ++
 .../jclouds/AbstractJcloudsLiveTest.java        |   2 +-
 .../JcloudsByonLocationResolverAwsLiveTest.java |   2 +-
 ...dsByonLocationResolverSoftlayerLiveTest.java |   2 +-
 .../location/jclouds/JcloudsLocationTest.java   |   7 +-
 .../location/jclouds/LiveTestEntity.java        |   2 +-
 .../provider/AbstractJcloudsLocationTest.java   |   2 +-
 .../zone/AwsAvailabilityZoneExtensionTest.java  |   2 +-
 .../entity/basic/SoftwareProcessImpl.java       |   5 +-
 14 files changed, 335 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java 
b/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
index febf901..0c53f15 100644
--- a/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java
@@ -33,6 +33,9 @@ import brooklyn.util.flags.SetFromFlag;
 import io.cloudsoft.winrm4j.winrm.WinRmTool;
 import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
 
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+
 public class WinRmMachineLocation extends AbstractLocation implements 
MachineLocation {
 
     public static final ConfigKey<String> WINDOWS_USERNAME = 
ConfigKeys.newStringConfigKey("windows.username",
@@ -85,6 +88,10 @@ public class WinRmMachineLocation extends AbstractLocation 
implements MachineLoc
     }
 
     public int executePsScript(List<String> psScript) {
+        // FIXME: Remove this!
+        System.out.println("Host: " + getHostname());
+        System.out.println("User: " + getUsername());
+        System.out.println("Password: " + getPassword());
         WinRmTool winRmTool = WinRmTool.connect(getHostname(), getUsername(), 
getPassword());
         WinRmToolResponse response = winRmTool.executePs(psScript);
         return response.getStatusCode();
@@ -98,4 +105,43 @@ public class WinRmMachineLocation extends AbstractLocation 
implements MachineLoc
         return config().get(WINDOWS_PASSWORD);
     }
 
+    public static String getDefaultUserMetadataString() {
+        return "winrm quickconfig -q & " +
+                "winrm set winrm/config/service/auth @{Basic=\"true\"} & " +
+                "winrm set winrm/config/client @{AllowUnencrypted=\"true\"} & 
" +
+                "winrm set winrm/config/service @{AllowUnencrypted=\"true\"} & 
" +
+                "netsh advfirewall firewall add rule name=RDP dir=in 
protocol=tcp localport=3389 action=allow profile=any & " +
+                "netsh advfirewall firewall add rule name=WinRM dir=in 
protocol=tcp localport=5985 action=allow profile=any & " +
+                // Using an encoded command necessitates the need to escape. 
The unencoded command is as follows:
+                // $RDP = Get-WmiObject -Class Win32_TerminalServiceSetting 
-ComputerName $env:computername -Namespace root\CIMV2\TerminalServices 
-Authentication PacketPrivacy
+                // $Result = $RDP.SetAllowTSConnections(1,1)
+                "powershell -EncodedCommand 
JABSAEQAUAAgAD0AIABHAGUAdAAtAFcAbQBpAE8AYgBqAGUAYwB0ACAALQBDAGwAYQBzAHMAI" +
+                        
"ABXAGkAbgAzADIAXwBUAGUAcgBtAGkAbgBhAGwAUwBlAHIAdgBpAGMAZQBTAGUAdAB0AGkAbgBnACAALQBDAG8AbQBwA"
 +
+                        
"HUAdABlAHIATgBhAG0AZQAgACQAZQBuAHYAOgBjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQAgAC0ATgBhAG0AZQBzAHAAY"
 +
+                        
"QBjAGUAIAByAG8AbwB0AFwAQwBJAE0AVgAyAFwAVABlAHIAbQBpAG4AYQBsAFMAZQByAHYAaQBjAGUAcwAgAC0AQQB1A"
 +
+                        
"HQAaABlAG4AdABpAGMAYQB0AGkAbwBuACAAUABhAGMAawBlAHQAUAByAGkAdgBhAGMAeQANAAoAJABSAGUAcwB1AGwAd"
 +
+                        
"AAgAD0AIAAkAFIARABQAC4AUwBlAHQAQQBsAGwAbwB3AFQAUwBDAG8AbgBuAGUAYwB0AGkAbwBuAHMAKAAxACwAMQApAA==";
+        /* TODO: Find out why scripts with new line characters aren't working 
on AWS. The following appears as if it *should*
+           work but doesn't - the script simply isn't run. By connecting to 
the machine via RDP, you can get the script
+           from 'http://169.254.169.254/latest/user-data', and running it at 
the command prompt works, but for some
+           reason the script isn't run when the VM is provisioned
+        */
+//        return Joiner.on("\r\n").join(ImmutableList.of(
+//                "winrm quickconfig -q",
+//                "winrm set winrm/config/service/auth @{Basic=\"true\"}",
+//                "winrm set winrm/config/client @{AllowUnencrypted=\"true\"}",
+//                "winrm set winrm/config/service 
@{AllowUnencrypted=\"true\"}",
+//                "netsh advfirewall firewall add rule name=RDP dir=in 
protocol=tcp localport=3389 action=allow profile=any",
+//                "netsh advfirewall firewall add rule name=WinRM dir=in 
protocol=tcp localport=5985 action=allow profile=any",
+//                // Using an encoded command necessitates the need to escape. 
The unencoded command is as follows:
+//                // $RDP = Get-WmiObject -Class Win32_TerminalServiceSetting 
-ComputerName $env:computername -Namespace root\CIMV2\TerminalServices 
-Authentication PacketPrivacy
+//                // $Result = $RDP.SetAllowTSConnections(1,1)
+//                "powershell -EncodedCommand 
JABSAEQAUAAgAD0AIABHAGUAdAAtAFcAbQBpAE8AYgBqAGUAYwB0ACAALQBDAGwAYQBzAHMAI" +
+//                        
"ABXAGkAbgAzADIAXwBUAGUAcgBtAGkAbgBhAGwAUwBlAHIAdgBpAGMAZQBTAGUAdAB0AGkAbgBnACAALQBDAG8AbQBwA"
 +
+//                        
"HUAdABlAHIATgBhAG0AZQAgACQAZQBuAHYAOgBjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQAgAC0ATgBhAG0AZQBzAHAAY"
 +
+//                        
"QBjAGUAIAByAG8AbwB0AFwAQwBJAE0AVgAyAFwAVABlAHIAbQBpAG4AYQBsAFMAZQByAHYAaQBjAGUAcwAgAC0AQQB1A"
 +
+//                        
"HQAaABlAG4AdABpAGMAYQB0AGkAbwBuACAAUABhAGMAawBlAHQAUAByAGkAdgBhAGMAeQANAAoAJABSAGUAcwB1AGwAd"
 +
+//                        
"AAgAD0AIAAkAFIARABQAC4AUwBlAHQAQQBsAGwAbwB3AFQAUwBDAG8AbgBuAGUAYwB0AGkAbwBuAHMAKAAxACwAMQApAA=="
+//        ));
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/core/src/main/java/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
 
b/core/src/main/java/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
index 9486bd1..36b9914 100644
--- 
a/core/src/main/java/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
+++ 
b/core/src/main/java/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
@@ -21,8 +21,8 @@ package brooklyn.location.cloud;
 import java.util.Collection;
 import java.util.Map;
 
-import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
+import brooklyn.location.MachineLocation;
 import brooklyn.location.MachineProvisioningLocation;
 import brooklyn.location.basic.AbstractLocation;
 import brooklyn.location.basic.SshMachineLocation;
@@ -30,8 +30,8 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.internal.ssh.SshTool;
 
-public abstract class AbstractCloudMachineProvisioningLocation extends 
AbstractLocation 
-implements MachineProvisioningLocation<SshMachineLocation>, 
CloudLocationConfig 
+public abstract class AbstractCloudMachineProvisioningLocation extends 
AbstractLocation
+implements MachineProvisioningLocation<MachineLocation>, CloudLocationConfig
 {
    public AbstractCloudMachineProvisioningLocation() {
       super();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/core/src/main/java/brooklyn/location/cloud/CloudLocationConfig.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/location/cloud/CloudLocationConfig.java 
b/core/src/main/java/brooklyn/location/cloud/CloudLocationConfig.java
index 6c941a3..9134af7 100644
--- a/core/src/main/java/brooklyn/location/cloud/CloudLocationConfig.java
+++ b/core/src/main/java/brooklyn/location/cloud/CloudLocationConfig.java
@@ -69,6 +69,10 @@ public interface CloudLocationConfig {
             "Whether and how long to wait for a newly provisioned VM to be 
accessible via ssh; " +
             "if 'false', won't check; if 'true' uses default duration; 
otherwise accepts a time string e.g. '5m' (the default) or a number of 
milliseconds", "5m");
 
+    public static final ConfigKey<String> WAIT_FOR_WINRM_AVAILABLE = 
ConfigKeys.newStringConfigKey("waitForWinRmAvailable",
+            "Whether and how long to wait for a newly provisioned VM to be 
accessible via WinRm; " +
+                    "if 'false', won't check; if 'true' uses default duration; 
otherwise accepts a time string e.g. '30m' (the default) or a number of 
milliseconds", "30m");
+
     public static final ConfigKey<Boolean> LOG_CREDENTIALS = 
ConfigKeys.newBooleanConfigKey(
             "logCredentials", 
             "Whether to log credentials of a new VM - strongly recommended 
never be used in production, as it is a big security hole!",

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/locations/jclouds/src/main/java/brooklyn/location/jclouds/BrooklynMachinePool.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/BrooklynMachinePool.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/BrooklynMachinePool.java
index f503fce..889012e 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/BrooklynMachinePool.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/BrooklynMachinePool.java
@@ -31,7 +31,9 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.Entity;
 import brooklyn.entity.trait.Startable;
+import brooklyn.location.MachineLocation;
 import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.location.basic.WinRmMachineLocation;
 import brooklyn.location.jclouds.pool.MachinePool;
 import brooklyn.location.jclouds.pool.MachineSet;
 import brooklyn.location.jclouds.pool.ReusableMachineTemplate;
@@ -117,7 +119,13 @@ public class BrooklynMachinePool extends MachinePool {
             // TODO this in parallel
             JcloudsSshMachineLocation m;
             try {
-                m = location.obtain(MutableMap.of("callerContext", 
""+this+"("+template+")"), template);
+                MachineLocation machineLocation = 
location.obtain(MutableMap.of("callerContext", ""+this+"("+template+")"), 
template);
+                // Class has been deprecated since 0.6.0, and prior to that, 
obtain would have returned a JcloudsSshMachineLocation
+                if (machineLocation instanceof JcloudsSshMachineLocation) {
+                    m = (JcloudsSshMachineLocation) machineLocation;
+                } else {
+                    throw new UnsupportedOperationException("Cannot create 
WinRmMachineLocation");
+                }
             } catch (Exception e) {
                 throw Throwables.propagate(e);
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index 69cfea6..de0dfad 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -107,6 +107,7 @@ import brooklyn.location.basic.LocationConfigKeys;
 import brooklyn.location.basic.LocationConfigUtils;
 import brooklyn.location.basic.LocationConfigUtils.OsCredential;
 import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.location.basic.WinRmMachineLocation;
 import brooklyn.location.cloud.AbstractCloudMachineProvisioningLocation;
 import brooklyn.location.cloud.AvailabilityZoneExtension;
 import brooklyn.location.cloud.names.AbstractCloudMachineNamer;
@@ -149,6 +150,8 @@ import brooklyn.util.text.Strings;
 import brooklyn.util.text.TemplateProcessor;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
+import io.cloudsoft.winrm4j.pywinrm.Session;
+import io.cloudsoft.winrm4j.pywinrm.WinRMFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Charsets;
@@ -181,7 +184,7 @@ import com.google.common.reflect.TypeToken;
  * Configuration flags are defined in {@link JcloudsLocationConfig}.
  */
 @SuppressWarnings("serial")
-public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation 
implements JcloudsLocationConfig, 
RichMachineProvisioningLocation<SshMachineLocation>, LocationWithObjectStore {
+public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation 
implements JcloudsLocationConfig, 
RichMachineProvisioningLocation<MachineLocation>, LocationWithObjectStore {
 
     // TODO After converting from Groovy to Java, this is now very bad code! 
It relies entirely on putting
     // things into and taking them out of maps; it's not type-safe, and it's 
thus very error-prone.
@@ -209,8 +212,8 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
     private final Map<String,Map<String, ? extends Object>> tagMapping = 
Maps.newLinkedHashMap();
 
     @SetFromFlag // so it's persisted
-    private final Map<JcloudsSshMachineLocation,String> vmInstanceIds = 
Maps.newLinkedHashMap();
-
+    private final Map<MachineLocation,String> vmInstanceIds = 
Maps.newLinkedHashMap();
+    
     static { Networking.init(); }
 
     public JcloudsLocation() {
@@ -508,14 +511,13 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
     }
 
     // ----------------- obtaining a new machine ------------------------
-
-    public JcloudsSshMachineLocation obtain() throws 
NoMachinesAvailableException {
+    public MachineLocation obtain() throws NoMachinesAvailableException {
         return obtain(MutableMap.of());
     }
-    public JcloudsSshMachineLocation obtain(TemplateBuilder tb) throws 
NoMachinesAvailableException {
+    public MachineLocation obtain(TemplateBuilder tb) throws 
NoMachinesAvailableException {
         return obtain(MutableMap.of(), tb);
     }
-    public JcloudsSshMachineLocation obtain(Map<?,?> flags, TemplateBuilder 
tb) throws NoMachinesAvailableException {
+    public MachineLocation obtain(Map<?,?> flags, TemplateBuilder tb) throws 
NoMachinesAvailableException {
         return obtain(MutableMap.builder().putAll(flags).put(TEMPLATE_BUILDER, 
tb).build());
     }
 
@@ -524,7 +526,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
      * as well as ACCESS_IDENTITY and ACCESS_CREDENTIAL,
      * plus any further properties to specify e.g. images, hardware profiles, 
accessing user
      * (for initial login, and a user potentially to create for subsequent ie 
normal access) */
-    public JcloudsSshMachineLocation obtain(Map<?,?> flags) throws 
NoMachinesAvailableException {
+    public MachineLocation obtain(Map<?,?> flags) throws 
NoMachinesAvailableException {
         ConfigBag setup = ConfigBag.newInstanceExtending(config().getBag(), 
flags);
         Integer attempts = setup.get(MACHINE_CREATE_ATTEMPTS);
         List<Exception> exceptions = Lists.newArrayList();
@@ -553,7 +555,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         }
     }
 
-    protected JcloudsSshMachineLocation obtainOnce(ConfigBag setup) throws 
NoMachinesAvailableException {
+    protected MachineLocation obtainOnce(ConfigBag setup) throws 
NoMachinesAvailableException {
         AccessController.Response access = 
getManagementContext().getAccessController().canProvisionLocation(this);
         if (!access.isAllowed()) {
             throw new IllegalStateException("Access controller forbids 
provisioning in "+this+": "+access.getMsg());
@@ -570,8 +572,8 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         CloudMachineNamer cloudMachineNamer = getCloudMachineNamer(setup);
         String groupId = elvis(setup.get(GROUP_ID), 
cloudMachineNamer.generateNewGroupId(setup));
         NodeMetadata node = null;
-        JcloudsSshMachineLocation sshMachineLocation = null;
-
+        MachineLocation machineLocation = null;
+        
         try {
             LOG.info("Creating VM "+setup.getDescription()+" in "+this);
 
@@ -639,6 +641,14 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
             if (node == null)
                 throw new IllegalStateException("No nodes returned by jclouds 
create-nodes in " + setup.getDescription());
 
+            boolean windows = 
node.getOperatingSystem().getFamily().equals(OsFamily.WINDOWS);
+
+            if (windows) {
+                // FIXME: Tidy this up and allow for user-specified credentials
+                setup.put(USER, node.getCredentials().getUser());
+                setup.put(PASSWORD, 
node.getCredentials().getOptionalPassword().orNull());
+            }
+
             // Setup port-forwarding, if required
             Optional<HostAndPort> sshHostAndPortOverride;
             if (usePortForwarding) {
@@ -652,10 +662,12 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                 sshHostAndPortOverride = Optional.absent();
             }
 
-            if (waitForSshable && skipJcloudsSshing) {
+            if (waitForSshable && skipJcloudsSshing && !windows) {
                 // once that host:port is definitely reachable, we can create 
the user
                 waitForReachable(computeService, node, sshHostAndPortOverride, 
node.getCredentials(), setup);
                 userCredentials = createUser(computeService, node, 
sshHostAndPortOverride, setup);
+            } else if (windows) {
+                waitForWinRmAvailable(node, node.getCredentials(), setup);
             }
 
             // Figure out which login-credentials to use
@@ -682,42 +694,55 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
             setup.putIfNotNull(JcloudsLocationConfig.PRIVATE_KEY_DATA, 
userCredentials.getOptionalPrivateKey().orNull());
 
             // Wait for the VM to be reachable over SSH
-            if (waitForSshable) {
+            if (waitForSshable && !windows) {
                 waitForReachable(computeService, node, sshHostAndPortOverride, 
userCredentials, setup);
             } else {
                 LOG.debug("Skipping ssh check for {} ({}) due to config 
waitForSshable=false", node, setup.getDescription());
             }
             usableTimestamp = Duration.of(provisioningStopwatch);
 
+            JcloudsSshMachineLocation jcloudsSshMachineLocation = null;
+            WinRmMachineLocation winRmMachineLocation = null;
             // Create a JcloudsSshMachineLocation, and register it
-            sshMachineLocation = 
registerJcloudsSshMachineLocation(computeService, node, userCredentials, 
sshHostAndPortOverride, setup);
-            if (template!=null && sshMachineLocation.getTemplate()==null) {
-                sshMachineLocation.template = template;
+            if (windows) {
+                // FIMXE: Need to write WinRM equivalent of getPublicHostname
+                String hostName = node.getPublicAddresses().iterator().next();
+                winRmMachineLocation = registerWinRmMachineLocation(hostName, 
setup);
+                machineLocation = winRmMachineLocation;
+            } else {
+                jcloudsSshMachineLocation = 
registerJcloudsSshMachineLocation(computeService, node, userCredentials, 
sshHostAndPortOverride, setup);
+                machineLocation = jcloudsSshMachineLocation;
+                if (template!=null && 
jcloudsSshMachineLocation.getTemplate()==null) {
+                    jcloudsSshMachineLocation.template = template;
+                }
             }
 
             if (usePortForwarding && sshHostAndPortOverride.isPresent()) {
                 // Now that we have the sshMachineLocation, we can associate 
the port-forwarding address with it.
                 PortForwardManager portForwardManager = 
setup.get(PORT_FORWARDING_MANAGER);
                 if (portForwardManager != null) {
-                    portForwardManager.associate(node.getId(), 
sshHostAndPortOverride.get(), sshMachineLocation, node.getLoginPort());
+                    portForwardManager.associate(node.getId(), 
sshHostAndPortOverride.get(), machineLocation, node.getLoginPort());
                 } else {
                     LOG.warn("No port-forward manager for {} so could not 
associate {} -> {} for {}",
-                            new Object[] {this, node.getLoginPort(), 
sshHostAndPortOverride, sshMachineLocation});
+                            new Object[] {this, node.getLoginPort(), 
sshHostAndPortOverride, machineLocation});
                 }
             }
 
             if ("docker".equals(this.getProvider())) {
+                if (windows) {
+                    throw new UnsupportedOperationException("Docker not 
supported on Windows");
+                }
                 Map<Integer, Integer> portMappings = 
JcloudsUtil.dockerPortMappingsFor(this, node.getId());
                 PortForwardManager portForwardManager = 
setup.get(PORT_FORWARDING_MANAGER);
                 if (portForwardManager != null) {
                     for(Integer containerPort : portMappings.keySet()) {
                         Integer hostPort = portMappings.get(containerPort);
-                        String dockerHost = 
sshMachineLocation.getSshHostAndPort().getHostText();
-                        portForwardManager.associate(node.getId(), 
HostAndPort.fromParts(dockerHost, hostPort), sshMachineLocation, containerPort);
+                        String dockerHost = 
jcloudsSshMachineLocation.getSshHostAndPort().getHostText();
+                        portForwardManager.associate(node.getId(), 
HostAndPort.fromParts(dockerHost, hostPort), jcloudsSshMachineLocation, 
containerPort);
                     }
                 } else {
                     LOG.warn("No port-forward manager for {} so could not 
associate docker port-mappings for {}",
-                            this, sshMachineLocation);
+                            this, jcloudsSshMachineLocation);
                 }
             }
 
@@ -729,80 +754,105 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                 List<String> setupScripts = 
setup.get(JcloudsLocationConfig.CUSTOM_MACHINE_SETUP_SCRIPT_URL_LIST);
                 Collection<String> allScripts = new 
MutableList<String>().appendIfNotNull(setupScript).appendAll(setupScripts);
                 for (String setupScriptItem : allScripts) {
-                    if (Strings.isNonBlank(setupScriptItem)) {
-                        customisationForLogging.add("custom setup script 
"+setupScriptItem);
+                    if (Strings.isNonBlank(setupScript)) {
+                        customisationForLogging.add("custom setup script " + 
setupScript);
 
                         String setupVarsString = 
setup.get(JcloudsLocationConfig.CUSTOM_MACHINE_SETUP_SCRIPT_VARS);
                         Map<String, String> substitutions = (setupVarsString 
!= null)
                                 ? 
Splitter.on(",").withKeyValueSeparator(":").split(setupVarsString)
                                 : ImmutableMap.<String, String>of();
-                        String scriptContent =  
ResourceUtils.create(this).getResourceAsString(setupScriptItem);
+                        String scriptContent = 
ResourceUtils.create(this).getResourceAsString(setupScriptItem);
                         String script = 
TemplateProcessor.processTemplateContents(scriptContent, 
getManagementContext(), substitutions);
-                        sshMachineLocation.execCommands("Customizing node " + 
this + " with script " + setupScriptItem, ImmutableList.of(script));
+                        if (windows) {
+                            
winRmMachineLocation.executeScript(ImmutableList.copyOf((script.replace("\r", 
"").split("\n"))));
+                        } else {
+                            
jcloudsSshMachineLocation.execCommands("Customizing node " + this, 
ImmutableList.of(script));
+                        }
                     }
                 }
 
                 if 
(setup.get(JcloudsLocationConfig.MAP_DEV_RANDOM_TO_DEV_URANDOM)) {
-                    customisationForLogging.add("point /dev/random to 
urandom");
+                    if (windows) {
+                        LOG.warn("Ignoring flag MAP_DEV_RANDOM_TO_DEV_URANDOM 
on Windows location {}", winRmMachineLocation);
+                    } else {
+                        customisationForLogging.add("point /dev/random to 
urandom");
 
-                    sshMachineLocation.execCommands("using urandom instead of 
random",
-                            Arrays.asList("sudo mv /dev/random 
/dev/random-real", "sudo ln -s /dev/urandom /dev/random"));
+                        jcloudsSshMachineLocation.execCommands("using urandom 
instead of random",
+                                Arrays.asList("sudo mv /dev/random 
/dev/random-real", "sudo ln -s /dev/urandom /dev/random"));
+                    }
                 }
 
 
                 if (setup.get(GENERATE_HOSTNAME)) {
-                    customisationForLogging.add("configure hostname");
+                    if (windows) {
+                        // TODO: Generate Windows Hostname
+                        LOG.warn("Ignoring flag GENERATE_HOSTNAME on Windows 
location {}", winRmMachineLocation);
+                    } else {
+                        customisationForLogging.add("configure hostname");
 
-                    sshMachineLocation.execCommands("Generate hostname " + 
node.getName(),
-                            Arrays.asList("sudo hostname " + node.getName(),
-                                    "sudo sed -i \"s/HOSTNAME=.*/HOSTNAME=" + 
node.getName() + "/g\" /etc/sysconfig/network",
-                                    "sudo bash -c \"echo 127.0.0.1   
`hostname` >> /etc/hosts\"")
-                   );
+                        jcloudsSshMachineLocation.execCommands("Generate 
hostname " + node.getName(),
+                                Arrays.asList("sudo hostname " + 
node.getName(),
+                                        "sudo sed -i 
\"s/HOSTNAME=.*/HOSTNAME=" + node.getName() + "/g\" /etc/sysconfig/network",
+                                        "sudo bash -c \"echo 127.0.0.1   
`hostname` >> /etc/hosts\"")
+                        );
+                    }
                 }
 
                 if (setup.get(OPEN_IPTABLES)) {
-                    @SuppressWarnings("unchecked")
-                    Iterable<Integer> inboundPorts = (Iterable<Integer>) 
setup.get(INBOUND_PORTS);
-
-                    if (inboundPorts == null || 
Iterables.isEmpty(inboundPorts)) {
-                        LOG.info("No ports to open in iptables (no inbound 
ports) for {} at {}", sshMachineLocation, this);
+                    if (windows) {
+                        LOG.warn("Ignoring flag OPEN_IPTABLES on Windows 
location {}", winRmMachineLocation);
                     } else {
-                        customisationForLogging.add("open iptables");
-
-                        List<String> iptablesRules = 
createIptablesRulesForNetworkInterface(inboundPorts);
-                        
iptablesRules.add(IptablesCommands.saveIptablesRules());
-                        List<String> batch = Lists.newArrayList();
-                        // Some entities, such as Riak (erlang based) have a 
huge range of ports, which leads to a script that
-                        // is too large to run (fails with a broken pipe). 
Batch the rules into batches of 50
-                        for (String rule : iptablesRules) {
-                            batch.add(rule);
-                            if (batch.size() == 50) {
-                                sshMachineLocation.execCommands("Inserting 
iptables rules, 50 command batch", batch);
-                                batch.clear();
+                        @SuppressWarnings("unchecked")
+                        Iterable<Integer> inboundPorts = (Iterable<Integer>) 
setup.get(INBOUND_PORTS);
+
+                        if (inboundPorts == null || 
Iterables.isEmpty(inboundPorts)) {
+                            LOG.info("No ports to open in iptables (no inbound 
ports) for {} at {}", jcloudsSshMachineLocation, this);
+                        } else {
+                            customisationForLogging.add("open iptables");
+
+                            List<String> iptablesRules = 
createIptablesRulesForNetworkInterface(inboundPorts);
+                            
iptablesRules.add(IptablesCommands.saveIptablesRules());
+                            List<String> batch = Lists.newArrayList();
+                            // Some entities, such as Riak (erlang based) have 
a huge range of ports, which leads to a script that
+                            // is too large to run (fails with a broken pipe). 
Batch the rules into batches of 50
+                            for (String rule : iptablesRules) {
+                                batch.add(rule);
+                                if (batch.size() == 50) {
+                                    
jcloudsSshMachineLocation.execCommands("Inserting iptables rules, 50 command 
batch", batch);
+                                    batch.clear();
+                                }
                             }
+                            if (batch.size() > 0) {
+                                
jcloudsSshMachineLocation.execCommands("Inserting iptables rules", batch);
+                            }
+                            jcloudsSshMachineLocation.execCommands("List 
iptables rules", ImmutableList.of(IptablesCommands.listIptablesRule()));
                         }
-                        if (batch.size() > 0) {
-                            sshMachineLocation.execCommands("Inserting 
iptables rules", batch);
-                        }
-                        sshMachineLocation.execCommands("List iptables rules", 
ImmutableList.of(IptablesCommands.listIptablesRule()));
                     }
                 }
 
                 if (setup.get(STOP_IPTABLES)) {
-                    customisationForLogging.add("stop iptables");
+                    if (windows) {
+                        LOG.warn("Ignoring flag OPEN_IPTABLES on Windows 
location {}", winRmMachineLocation);
+                    } else {
+                        customisationForLogging.add("stop iptables");
 
-                    List<String> cmds = 
ImmutableList.of(IptablesCommands.iptablesServiceStop(), 
IptablesCommands.iptablesServiceStatus());
-                    sshMachineLocation.execCommands("Stopping iptables", cmds);
+                        List<String> cmds = 
ImmutableList.of(IptablesCommands.iptablesServiceStop(), 
IptablesCommands.iptablesServiceStatus());
+                        jcloudsSshMachineLocation.execCommands("Stopping 
iptables", cmds);
+                    }
                 }
 
                 List<String> extraKeyUrlsToAuth = 
setup.get(EXTRA_PUBLIC_KEY_URLS_TO_AUTH);
                 if (extraKeyUrlsToAuth!=null && !extraKeyUrlsToAuth.isEmpty()) 
{
-                    List<String> extraKeyDataToAuth = MutableList.of();
-                    for (String keyUrl: extraKeyUrlsToAuth) {
-                        
extraKeyDataToAuth.add(ResourceUtils.create().getResourceAsString(keyUrl));
+                    if (windows) {
+                        LOG.warn("Ignoring flag EXTRA_PUBLIC_KEY_URLS_TO_AUTH 
on Windows location", winRmMachineLocation);
+                    } else {
+                        List<String> extraKeyDataToAuth = MutableList.of();
+                        for (String keyUrl : extraKeyUrlsToAuth) {
+                            
extraKeyDataToAuth.add(ResourceUtils.create().getResourceAsString(keyUrl));
+                        }
+                        jcloudsSshMachineLocation.execCommands("Authorizing 
ssh keys",
+                                ImmutableList.of(new 
AuthorizeRSAPublicKeys(extraKeyDataToAuth).render(org.jclouds.scriptbuilder.domain.OsFamily.UNIX)));
                     }
-                    sshMachineLocation.execCommands("Authorizing ssh keys",
-                        ImmutableList.of(new 
AuthorizeRSAPublicKeys(extraKeyDataToAuth).render(org.jclouds.scriptbuilder.domain.OsFamily.UNIX)));
                 }
 
             } else {
@@ -812,24 +862,48 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
 
             // Apply any optional app-specific customization.
             for (JcloudsLocationCustomizer customizer : getCustomizers(setup)) 
{
-                customizer.customize(this, computeService, sshMachineLocation);
+                if (windows) {
+                    LOG.warn("Ignoring customizer {} on Windows location {}", 
customizer, winRmMachineLocation);
+                    // TODO: WinRm based JcloudsLocationCustomizer
+                } else {
+                    customizer.customize(this, computeService, 
jcloudsSshMachineLocation);
+                }
             }
 
             customizedTimestamp = Duration.of(provisioningStopwatch);
 
-            LOG.info("Finished VM "+setup.getDescription()+" creation:"
-                    + " 
"+sshMachineLocation.getUser()+"@"+sshMachineLocation.getAddress()+":"+sshMachineLocation.getPort()
-                    + (Boolean.TRUE.equals(setup.get(LOG_CREDENTIALS))
-                              ? "password=" + 
userCredentials.getOptionalPassword().or("<absent>")
-                                      + " && key=" + 
userCredentials.getOptionalPrivateKey().or("<absent>")
-                              : "")
-                    + " ready after 
"+Duration.of(provisioningStopwatch).toStringRounded()
-                    + " ("+template+" template built in 
"+Duration.of(templateTimestamp).toStringRounded()+";"
-                    + " "+node+" provisioned in 
"+Duration.of(provisionTimestamp).subtract(templateTimestamp).toStringRounded()+";"
-                    + " "+sshMachineLocation+" ssh usable in 
"+Duration.of(usableTimestamp).subtract(provisionTimestamp).toStringRounded()+";"
-                    + " and os customized in 
"+Duration.of(customizedTimestamp).subtract(usableTimestamp).toStringRounded()+"
 - "+Joiner.on(", ").join(customisationForLogging)+")");
-
-            return sshMachineLocation;
+            String logMessage;
+
+            if (windows) {
+                // TODO: More complete logging for WinRmMachineLocation
+                // FIXME: Remove try-catch!
+                try {
+                    logMessage = "Finished VM " + setup.getDescription() + " 
creation:"
+                            + " " + 
winRmMachineLocation.getConfig(WinRmMachineLocation.WINDOWS_USERNAME) + "@" + 
machineLocation.getAddress()
+                            + " username=" + winRmMachineLocation.getUsername()
+                            + " ready after " + 
Duration.of(provisioningStopwatch).toStringRounded()
+                            + " (" + template + " template built in " + 
Duration.of(templateTimestamp).toStringRounded() + ";"
+                            + " " + node + " provisioned in " + 
Duration.of(provisionTimestamp).subtract(templateTimestamp).toStringRounded() + 
";";
+                } catch (Exception e){
+                    logMessage = Arrays.toString(e.getStackTrace());
+                }
+            } else {
+                logMessage = "Finished VM "+setup.getDescription()+" creation:"
+                        + " 
"+jcloudsSshMachineLocation.getUser()+"@"+machineLocation.getAddress()+":"+jcloudsSshMachineLocation.getPort()
+                        + (Boolean.TRUE.equals(setup.get(LOG_CREDENTIALS))
+                        ? "password=" + 
userCredentials.getOptionalPassword().or("<absent>")
+                        + " && key=" + 
userCredentials.getOptionalPrivateKey().or("<absent>")
+                        : "")
+                        + " ready after 
"+Duration.of(provisioningStopwatch).toStringRounded()
+                        + " ("+template+" template built in 
"+Duration.of(templateTimestamp).toStringRounded()+";"
+                        + " "+node+" provisioned in 
"+Duration.of(provisionTimestamp).subtract(templateTimestamp).toStringRounded()+";"
+                        + " "+jcloudsSshMachineLocation+" ssh usable in 
"+Duration.of(usableTimestamp).subtract(provisionTimestamp).toStringRounded()+";"
+                        + " and os customized in 
"+Duration.of(customizedTimestamp).subtract(usableTimestamp).toStringRounded()+"
 - "+Joiner.on(", ").join(customisationForLogging)+")";
+            }
+            
+            LOG.info(logMessage);
+
+            return machineLocation;
         } catch (Exception e) {
             if (e instanceof RunNodesException && 
((RunNodesException)e).getNodeErrors().size() > 0) {
                 node = 
Iterables.get(((RunNodesException)e).getNodeErrors().keySet(), 0);
@@ -842,8 +916,8 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
             LOG.debug(Throwables.getStackTraceAsString(e));
 
             if (destroyNode) {
-                if (sshMachineLocation != null) {
-                    releaseSafely(sshMachineLocation);
+                if (machineLocation != null) {
+                    releaseSafely(machineLocation);
                 } else {
                     releaseNodeSafely(node);
                 }
@@ -853,6 +927,52 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         }
     }
 
+    private void waitForWinRmAvailable(final NodeMetadata node, final 
LoginCredentials expectedCredentials, ConfigBag setup) {
+        // TODO: Reduce / remove duplication between this and waitForReachable
+        String waitForWinRmAvailable = setup.get(WAIT_FOR_WINRM_AVAILABLE);
+        checkArgument(!"false".equalsIgnoreCase(waitForWinRmAvailable), 
"waitForWinRmAvailable called despite waitForWinRmAvailable=%s", 
waitForWinRmAvailable);
+
+        long delayMs = -1;
+        try {
+            delayMs = Time.parseTimeString(""+waitForWinRmAvailable);
+        } catch (Exception e) {
+            // normal if 'true'; just fall back to default
+        }
+        if (delayMs<0)
+            delayMs = 
Time.parseTimeString(WAIT_FOR_WINRM_AVAILABLE.getDefaultValue());
+
+        // FIXME: remove this
+        LOG.info("Address: " + node.getPublicAddresses().iterator().next());
+        LOG.info("User: " + expectedCredentials.getUser());
+        LOG.info("Password: " + 
expectedCredentials.getOptionalPassword().get());
+        final Session session = 
WinRMFactory.INSTANCE.createSession(node.getPublicAddresses().iterator().next(),
+                expectedCredentials.getUser(), 
expectedCredentials.getOptionalPassword().get());
+
+        Callable<Boolean> checker = new Callable<Boolean>() {
+            public Boolean call() {
+                return session.run_cmd("hostname").getStatusCode() == 0;
+            }};
+
+        Stopwatch stopwatch = Stopwatch.createStarted();
+
+        ReferenceWithError<Boolean> reachable = new Repeater()
+                .every(1, SECONDS)
+                .until(checker)
+                .limitTimeTo(delayMs, MILLISECONDS)
+                .runKeepingError();
+
+        if (!reachable.getWithoutError()) {
+            throw new IllegalStateException("WinRm failed for "+
+                    
expectedCredentials.getUser()+"@"+node.getPublicAddresses().iterator().next()+" 
("+setup.getDescription()+") after waiting "+
+                    Time.makeTimeStringRounded(delayMs), reachable.getError());
+        }
+
+        LOG.debug("VM {}: is available via WinRm after {} on {}@{}",new 
Object[] {
+                setup.getDescription(), Time.makeTimeStringRounded(stopwatch),
+                expectedCredentials.getUser(), 
node.getPublicAddresses().iterator().next()});
+
+    }
+
 
     // ------------- constructing the template, etc ------------------------
 
@@ -955,7 +1075,11 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                     public void apply(TemplateOptions t, ConfigBag props, 
Object v) {
                         if (t instanceof EC2TemplateOptions) {
                             if (v==null) return;
-                            
((EC2TemplateOptions)t).userData(v.toString().getBytes());
+                            String data = v.toString();
+                            if (!(data.startsWith("<script>") || 
data.startsWith("<powershell>"))) {
+                                data = "<script> " + data + " </script>";
+                            }
+                            ((EC2TemplateOptions)t).userData(data.getBytes());
                             // TODO avail in next jclouds thanks to 
@andreaturli
 //                          } else if (t instanceof SoftLayerTemplateOptions) {
 //                              
((SoftLayerTemplateOptions)t).userData(Strings.toString(v));
@@ -1247,6 +1371,12 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         }
         TemplateOptions options = template.getOptions();
 
+        if 
(template.getImage().getOperatingSystem().getFamily().equals(OsFamily.WINDOWS)) 
{
+            if 
(!(config.containsKey(JcloudsLocationConfig.USER_METADATA_STRING) || 
config.containsKey(JcloudsLocationConfig.USER_METADATA_MAP))) {
+                config.put(JcloudsLocationConfig.USER_METADATA_STRING, 
WinRmMachineLocation.getDefaultUserMetadataString());
+            }
+        }
+               
         for (Map.Entry<ConfigKey<?>, CustomizeTemplateOptions> entry : 
SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES.entrySet()) {
             ConfigKey<?> key = entry.getKey();
             CustomizeTemplateOptions code = entry.getValue();
@@ -1803,6 +1933,26 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         }
     }
 
+    protected WinRmMachineLocation registerWinRmMachineLocation(String 
vmHostname, ConfigBag setup) {
+        WinRmMachineLocation winRmMachineLocation = 
createWinRmMachineLocation(vmHostname, setup);
+        winRmMachineLocation.setParent(this);
+        return winRmMachineLocation;
+    }
+
+    protected WinRmMachineLocation createWinRmMachineLocation(String 
vmHostname, ConfigBag setup) {
+        if (isManaged()) {
+            return 
getManagementContext().getLocationManager().createLocation(LocationSpec.create(WinRmMachineLocation.class)
+                    .configure("displayName", vmHostname)
+                    .configure("address", vmHostname)
+                    .configure("user", getUser(setup))
+                    .configure(WinRmMachineLocation.WINDOWS_USERNAME, 
setup.get(USER))
+                    .configure(WinRmMachineLocation.WINDOWS_PASSWORD, 
setup.get(PASSWORD))
+            );
+        } else {
+            throw new UnsupportedOperationException("Cannot create 
WinRmMachineLocation because " + this + " is not managed");
+        }
+    }
+
     // -------------- give back the machines------------------
 
     protected Map<String,Object> extractSshConfig(ConfigBag setup, 
NodeMetadata node) {
@@ -1838,7 +1988,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
 
 
     @Override
-    public void release(SshMachineLocation machine) {
+    public void release(MachineLocation machine) {
         String instanceId = vmInstanceIds.remove(machine);
         if (instanceId == null) {
             LOG.info("Attempted release of unknown machine "+machine+" in 
"+toString());
@@ -1866,7 +2016,9 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         }
 
         try {
-            releasePortForwarding(machine);
+            if (!machine.getMachineDetails().getOsDetails().isWindows()) {
+                releasePortForwarding((SshMachineLocation)machine);
+            }
         } catch (Exception e) {
             LOG.error("Problem releasing port-forwarding for machine 
"+machine+" in "+this+", instance id "+instanceId+
                 "; ignoring and continuing, "
@@ -1904,7 +2056,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         }
     }
 
-    protected void releaseSafely(SshMachineLocation machine) {
+    protected void releaseSafely(MachineLocation machine) {
         try {
             release(machine);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/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
new file mode 100644
index 0000000..02a46a5
--- /dev/null
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
@@ -0,0 +1,25 @@
+/*
+ * 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 brooklyn.location.basic.WinRmMachineLocation;
+
+public class JcloudsWinRmMachineLocation extends WinRmMachineLocation {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/locations/jclouds/src/test/java/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
index eb65251..a95d5e1 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
@@ -141,7 +141,7 @@ public class AbstractJcloudsLiveTest {
     // Use this utility method to ensure machines are released on tearDown
     protected JcloudsSshMachineLocation obtainMachine(Map<?, ?> conf) throws 
Exception {
         assertNotNull(jcloudsLocation);
-        JcloudsSshMachineLocation result = jcloudsLocation.obtain(conf);
+        JcloudsSshMachineLocation result = 
(JcloudsSshMachineLocation)jcloudsLocation.obtain(conf);
         machines.add(checkNotNull(result, "result"));
         return result;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
index ae2ec25..822bae0 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverAwsLiveTest.java
@@ -54,7 +54,7 @@ public class JcloudsByonLocationResolverAwsLiveTest extends 
AbstractJcloudsLiveT
     public void setUpClass() throws Exception {
         classManagementContext = newManagementContext();
         classEc2Loc = (JcloudsLocation) 
classManagementContext.getLocationRegistry().resolve(AWS_LOCATION_SPEC);
-        classEc2Vm = classEc2Loc.obtain(MutableMap.<String,Object>builder()
+        classEc2Vm = 
(JcloudsSshMachineLocation)classEc2Loc.obtain(MutableMap.<String,Object>builder()
                 .put("hardwareId", AWS_EC2_SMALL_HARDWARE_ID)
                 .put("inboundPorts", ImmutableList.of(22))
                 .build());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
index e04d20c..b60d4e8 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsByonLocationResolverSoftlayerLiveTest.java
@@ -52,7 +52,7 @@ public class JcloudsByonLocationResolverSoftlayerLiveTest 
extends AbstractJcloud
     public void setUpClass() throws Exception {
         classManagementContext = newManagementContext();
         classEc2Loc = (JcloudsLocation) 
classManagementContext.getLocationRegistry().resolve(SOFTLAYER_LOCATION_SPEC);
-        classVm = classEc2Loc.obtain(MutableMap.<String,Object>builder()
+        classVm = 
(JcloudsSshMachineLocation)classEc2Loc.obtain(MutableMap.<String,Object>builder()
                 .put("inboundPorts", ImmutableList.of(22))
                 .build());
         slVmUser = classVm.getUser();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/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 b133457..e70ba89 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java
@@ -45,6 +45,7 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.location.LocationSpec;
+import brooklyn.location.MachineLocation;
 import brooklyn.location.NoMachinesAvailableException;
 import brooklyn.location.basic.LocationConfigKeys;
 import brooklyn.location.cloud.names.CustomMachineNamer;
@@ -547,7 +548,7 @@ public class JcloudsLocationTest implements 
JcloudsLocationConfig {
             .configure(LocationConfigKeys.LONGITUDE, -20d)
             .configure(JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 1);
         FakeLocalhostWithParentJcloudsLocation ll = 
managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class).configure(allConfig.getAllConfig()));
-        JcloudsSshMachineLocation l = ll.obtain();
+        MachineLocation l = ll.obtain();
         log.info("loc:" +l);
         HostGeoInfo geo = HostGeoInfo.fromLocation(l);
         log.info("geo: "+geo);
@@ -571,7 +572,7 @@ public class JcloudsLocationTest implements 
JcloudsLocationConfig {
         FakeLocalhostWithParentJcloudsLocation ll = 
managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class)
             .configure(new 
JcloudsPropertiesFromBrooklynProperties().getJcloudsProperties("softlayer", 
"wdc01", null, managementContext.getBrooklynProperties()))
             .configure(allConfig.getAllConfig()));
-        JcloudsSshMachineLocation l = ll.obtain();
+        MachineLocation l = ll.obtain();
         log.info("loc:" +l);
         HostGeoInfo geo = HostGeoInfo.fromLocation(l);
         log.info("geo: "+geo);
@@ -590,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 = ll.obtain();
+        JcloudsSshMachineLocation l = (JcloudsSshMachineLocation)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/fb18f534/locations/jclouds/src/test/java/brooklyn/location/jclouds/LiveTestEntity.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/LiveTestEntity.java 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/LiveTestEntity.java
index 837e7a6..39e5f0d 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/LiveTestEntity.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/LiveTestEntity.java
@@ -58,7 +58,7 @@ public interface LiveTestEntity extends TestEntity {
             addLocations(locs);
             provisioningLocation = (JcloudsLocation) Iterables.find(locs, 
Predicates.instanceOf(JcloudsLocation.class));
             try {
-                obtainedLocation = 
provisioningLocation.obtain(((LocationInternal)provisioningLocation).config().getBag().getAllConfig());
+                obtainedLocation = 
(JcloudsSshMachineLocation)provisioningLocation.obtain(((LocationInternal)provisioningLocation).config().getBag().getAllConfig());
             } catch (NoMachinesAvailableException e) {
                 throw Throwables.propagate(e);
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/locations/jclouds/src/test/java/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
index 5b6e09d..89d3f27 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/provider/AbstractJcloudsLocationTest.java
@@ -153,7 +153,7 @@ public abstract class AbstractJcloudsLocationTest {
     // Use this utility method to ensure machines are released on tearDown
     protected SshMachineLocation obtainMachine(Map flags) {
         try {
-            SshMachineLocation result = loc.obtain(flags);
+            SshMachineLocation result = (SshMachineLocation)loc.obtain(flags);
             machines.add(result);
             return result;
         } catch (NoMachinesAvailableException nmae) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/locations/jclouds/src/test/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtensionTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtensionTest.java
 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtensionTest.java
index 19804e5..cf5bece 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtensionTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtensionTest.java
@@ -95,7 +95,7 @@ public class AwsAvailabilityZoneExtensionTest {
         JcloudsLocation subLocation = (JcloudsLocation) 
Iterables.getOnlyElement(subLocations);
         JcloudsSshMachineLocation machine = null;
         try {
-            machine = subLocation.obtain(ImmutableMap.builder()
+            machine = 
(JcloudsSshMachineLocation)subLocation.obtain(ImmutableMap.builder()
                     .put(JcloudsLocation.IMAGE_ID, US_EAST_IMAGE_ID)
                     .put(JcloudsLocation.HARDWARE_ID, SMALL_HARDWARE_ID)
                     .put(JcloudsLocation.INBOUND_PORTS, ImmutableList.of(22))

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fb18f534/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 aed7185..1827485 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
@@ -442,11 +442,12 @@ public abstract class SoftwareProcessImpl extends 
AbstractEntity implements Soft
      * plus any ports defined with a config keys ending in .port 
      */
     protected Collection<Integer> getRequiredOpenPorts() {
-        Set<Integer> ports = MutableSet.of(22);
+        // TODO: Should only open 22 *or* 5985. Perhaps a flag / ConfigKey on 
SoftwareProcessImpl?
+        Set<Integer> ports = MutableSet.of(22, 5985, 3389);
         Map<ConfigKey<?>, ?> allConfig = 
config().getBag().getAllConfigAsConfigKeyMap();
         Set<ConfigKey<?>> configKeys = Sets.newHashSet(allConfig.keySet());
         configKeys.addAll(getEntityType().getConfigKeys());
-        
+
         for (ConfigKey<?> k: configKeys) {
             if (PortRange.class.isAssignableFrom(k.getType())) {
                 PortRange p = (PortRange)getConfig(k);

Reply via email to