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);
