http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java new file mode 100644 index 0000000..accda93 --- /dev/null +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsMachineLocation.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package brooklyn.location.jclouds; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; + +import brooklyn.location.MachineLocation; +import brooklyn.location.basic.HasSubnetHostname; + +public interface JcloudsMachineLocation extends MachineLocation, HasSubnetHostname { + + @Override + public JcloudsLocation getParent(); + + public NodeMetadata getNode(); + + public Template getTemplate(); + + public String getJcloudsId(); + + /** In most clouds, the public hostname is the only way to ensure VMs in different zones can access each other. */ + @Override + public String getSubnetHostname(); + + String getUser(); + + int getPort(); +}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java index c715ad5..6e98e3a 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsSshMachineLocation.java @@ -68,7 +68,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.net.HostAndPort; import com.google.common.util.concurrent.ListenableFuture; -public class JcloudsSshMachineLocation extends SshMachineLocation implements HasSubnetHostname { +public class JcloudsSshMachineLocation extends SshMachineLocation implements JcloudsMachineLocation { private static final Logger LOG = LoggerFactory.getLogger(JcloudsSshMachineLocation.class); private static final long serialVersionUID = -443866395634771659L; @@ -133,14 +133,17 @@ public class JcloudsSshMachineLocation extends SshMachineLocation implements Has .toString(); } + @Override public NodeMetadata getNode() { return node; } + @Override public Template getTemplate() { return template; } + @Override public JcloudsLocation getParent() { return jcloudsParent; } @@ -199,6 +202,7 @@ public class JcloudsSshMachineLocation extends SshMachineLocation implements Has return Optional.absent(); } + @Override public String getJcloudsId() { return node.getId(); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java index 02a46a5..150d5ff 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java @@ -18,8 +18,133 @@ */ package brooklyn.location.jclouds; +import static brooklyn.util.JavaGroovyEquivalents.groovyTruth; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Iterator; +import java.util.Set; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import brooklyn.location.basic.WinRmMachineLocation; +import brooklyn.util.flags.SetFromFlag; +import brooklyn.util.net.Networking; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.net.HostAndPort; + +public class JcloudsWinRmMachineLocation extends WinRmMachineLocation implements JcloudsMachineLocation { + + private static final Logger LOG = LoggerFactory.getLogger(JcloudsWinRmMachineLocation.class); + + @SetFromFlag + JcloudsLocation jcloudsParent; + + @SetFromFlag + NodeMetadata node; + + @SetFromFlag + Template template; + + public JcloudsWinRmMachineLocation() { + } + + @Override + public String toVerboseString() { + return Objects.toStringHelper(this).omitNullValues() + .add("id", getId()).add("name", getDisplayName()) + .add("user", getUser()) + .add("address", getAddress()) + .add("port", getPort()) + .add("node", getNode()) + .add("jcloudsId", getJcloudsId()) + .add("privateAddresses", node.getPrivateAddresses()) + .add("publicAddresses", node.getPublicAddresses()) + .add("parentLocation", getParent()) + .add("osDetails", getOsDetails()) + .toString(); + } + + @Override + public int getPort() { + return getConfig(WINRM_PORT); + } + + @Override + public NodeMetadata getNode() { + return node; + } + + @Override + public Template getTemplate() { + return template; + } + + @Override + public JcloudsLocation getParent() { + return jcloudsParent; + } + + @Override + public String getHostname() { + return node.getHostname(); + } + + @Override + public Set<String> getPublicAddresses() { + return node.getPublicAddresses(); + } + + @Override + public Set<String> getPrivateAddresses() { + return node.getPrivateAddresses(); + } + + @Override + public String getSubnetHostname() { + String publicHostname = jcloudsParent.getPublicHostname(node, Optional.<HostAndPort>absent(), config().getBag()); + return publicHostname; + } + + @Override + public String getSubnetIp() { + Optional<String> privateAddress = getPrivateAddress(); + if (privateAddress.isPresent()) { + return privateAddress.get(); + } -public class JcloudsWinRmMachineLocation extends WinRmMachineLocation { + String hostname = jcloudsParent.getPublicHostname(node, Optional.<HostAndPort>absent(), config().getBag()); + if (hostname != null && !Networking.isValidIp4(hostname)) { + try { + return InetAddress.getByName(hostname).getHostAddress(); + } catch (UnknownHostException e) { + LOG.debug("Cannot resolve IP for hostname {} of machine {} (so returning hostname): {}", new Object[] {hostname, this, e}); + } + } + return hostname; + } + protected Optional<String> getPrivateAddress() { + if (groovyTruth(node.getPrivateAddresses())) { + Iterator<String> pi = node.getPrivateAddresses().iterator(); + while (pi.hasNext()) { + String p = pi.next(); + // disallow local only addresses + if (Networking.isLocalOnly(p)) continue; + // other things may be public or private, but either way, return it + return Optional.of(p); + } + } + return Optional.absent(); + } + + @Override + public String getJcloudsId() { + return node.getId(); + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java index b7f8400..889c7e3 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java @@ -21,7 +21,9 @@ package brooklyn.location.jclouds; import org.jclouds.compute.ComputeService; import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import brooklyn.location.basic.SshMachineLocation; import brooklyn.util.task.DynamicTasks; import brooklyn.util.task.ssh.SshTasks; import brooklyn.util.task.ssh.SshTasks.OnFailingTask; @@ -48,9 +50,9 @@ import brooklyn.util.task.ssh.SshTasks.OnFailingTask; public class SudoTtyFixingCustomizer extends BasicJcloudsLocationCustomizer { @Override - public void customize(JcloudsLocation location, ComputeService computeService, JcloudsSshMachineLocation machine) { - DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(machine, OnFailingTask.FAIL)).orSubmitAndBlock(); + public void customize(JcloudsLocation location, ComputeService computeService, JcloudsMachineLocation machine) { + Preconditions.checkArgument(machine instanceof SshMachineLocation, "machine must be SshMachineLocation, but is %s", machine.getClass()); + DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo((SshMachineLocation)machine, OnFailingTask.FAIL)).orSubmitAndBlock(); DynamicTasks.waitForLast(); } - } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java index 98edfcf..7d28a9f 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java @@ -40,7 +40,7 @@ import brooklyn.entity.Entity; import brooklyn.location.geo.LocalhostExternalIpLoader; import brooklyn.location.jclouds.BasicJcloudsLocationCustomizer; import brooklyn.location.jclouds.JcloudsLocation; -import brooklyn.location.jclouds.JcloudsSshMachineLocation; +import brooklyn.location.jclouds.JcloudsMachineLocation; import brooklyn.management.ManagementContext; import brooklyn.util.exceptions.Exceptions; import brooklyn.util.net.Cidr; @@ -151,13 +151,13 @@ public class JcloudsLocationSecurityGroupCustomizer extends BasicJcloudsLocation } /** @see #addPermissionsToLocation(brooklyn.location.jclouds.JcloudsSshMachineLocation, java.lang.Iterable) */ - public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsSshMachineLocation location, IpPermission... permissions) { + public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsMachineLocation location, IpPermission... permissions) { addPermissionsToLocation(location, ImmutableList.copyOf(permissions)); return this; } /** @see #addPermissionsToLocation(brooklyn.location.jclouds.JcloudsSshMachineLocation, java.lang.Iterable) */ - public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsSshMachineLocation location, SecurityGroupDefinition securityGroupDefinition) { + public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsMachineLocation location, SecurityGroupDefinition securityGroupDefinition) { addPermissionsToLocation(location, securityGroupDefinition.getPermissions()); return this; } @@ -169,7 +169,7 @@ public class JcloudsLocationSecurityGroupCustomizer extends BasicJcloudsLocation * @param permissions The set of permissions to be applied to the location * @param location Location to gain permissions */ - public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsSshMachineLocation location, final Iterable<IpPermission> permissions) { + public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsMachineLocation location, final Iterable<IpPermission> permissions) { ComputeService computeService = location.getParent().getComputeService(); String nodeId = location.getNode().getId(); addPermissionsToLocation(permissions, nodeId, computeService); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java index e70ba89..62817c2 100644 --- a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java +++ b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java @@ -524,7 +524,7 @@ public class JcloudsLocationTest implements JcloudsLocationConfig { // explicitly invoke this customizer, to comply with tests for (JcloudsLocationCustomizer customizer : getCustomizers(config().getBag())) { - customizer.customize(this, null, result); + customizer.customize(this, null, (JcloudsMachineLocation)result); } return result; @@ -591,7 +591,7 @@ public class JcloudsLocationTest implements JcloudsLocationConfig { .configure(JcloudsLocationConfig.JCLOUDS_LOCATION_CUSTOMIZERS, ImmutableList.of(customizer)) .configure(JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 1); FakeLocalhostWithParentJcloudsLocation ll = managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class).configure(allConfig.getAllConfig())); - JcloudsSshMachineLocation l = (JcloudsSshMachineLocation)ll.obtain(); + JcloudsMachineLocation l = (JcloudsMachineLocation)ll.obtain(); Mockito.verify(customizer, Mockito.times(1)).customize(ll, null, l); Mockito.verify(customizer, Mockito.never()).preRelease(l); Mockito.verify(customizer, Mockito.never()).postRelease(l); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index af08b2e..0f8e075 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ <jsr311-api.version>1.1.1</jsr311-api.version> <maxmind.version>0.8.1</maxmind.version> <jna.version>4.0.0</jna.version> - <winrm4j.version>0.1.0-SNAPSHOT</winrm4j.version> + <winrm4j.version>0.1.0</winrm4j.version> <coverage.target>${working.dir}</coverage.target> <!-- Release --> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java index 92f4fa6..c34e342 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java +++ b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java @@ -48,8 +48,8 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar public AbstractSoftwareProcessWinRmDriver(EntityLocal entity, WinRmMachineLocation location) { super(entity, location); - entity.setAttribute(WINDOWS_USERNAME, location.config().get(WinRmMachineLocation.WINDOWS_USERNAME)); - entity.setAttribute(WINDOWS_PASSWORD, location.config().get(WinRmMachineLocation.WINDOWS_PASSWORD)); + entity.setAttribute(WINDOWS_USERNAME, location.config().get(WinRmMachineLocation.USER)); + entity.setAttribute(WINDOWS_PASSWORD, location.config().get(WinRmMachineLocation.PASSWORD)); } @Override @@ -99,7 +99,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar if (createParentDir) { createDirectory(getDirectory(target), "Creating resource directory"); } - return copyTo(new File(source), new File(target)); + return copyTo(new File(source), target); } @Override @@ -107,7 +107,7 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar if (createParentDir) { createDirectory(getDirectory(target), "Creating resource directory"); } - return copyTo(source, new File(target)); + return copyTo(source, target); } @Override @@ -139,30 +139,30 @@ public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwar return getLocation().executeScript(script).getStatusCode(); } - public int executePowerShellNoRetry(List<String> psScript) { + public int executePsScriptNoRetry(List<String> psScript) { return getLocation().executePsScriptNoRetry(psScript).getStatusCode(); } - public int executePowerShell(List<String> psScript) { + public int executePsScript(List<String> psScript) { return getLocation().executePsScript(psScript).getStatusCode(); } - public int copyTo(File source, File destination) { + public int copyTo(File source, String destination) { return getLocation().copyTo(source, destination); } - public int copyTo(InputStream source, File destination) { + public int copyTo(InputStream source, String destination) { return getLocation().copyTo(source, destination); } public void rebootAndWait() { try { - executePowerShellNoRetry(ImmutableList.of("Restart-Computer -Force")); + executePsScriptNoRetry(ImmutableList.of("Restart-Computer -Force")); } catch (PyException e) { // Restarting the computer will cause the command to fail; ignore the exception and continue } - waitForWinRmStatus(false, entity.getConfig(VanillaWindowsProcess.REBOOT_UNAVAILABLE_TIMEOUT)); - waitForWinRmStatus(true, entity.getConfig(VanillaWindowsProcess.REBOOT_AVAILABLE_TIMEOUT)).getWithError(); + waitForWinRmStatus(false, entity.getConfig(VanillaWindowsProcess.REBOOT_BEGUN_TIMEOUT)); + waitForWinRmStatus(true, entity.getConfig(VanillaWindowsProcess.REBOOT_COMPLETED_TIMEOUT)).getWithError(); } private String getDirectory(String fileName) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java b/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java deleted file mode 100644 index 1ddb488..0000000 --- a/software/base/src/main/java/brooklyn/entity/basic/AbstractVanillaProcessDriver.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.entity.basic; - -public interface AbstractVanillaProcessDriver extends SoftwareProcessDriver { -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java index fe6d052..75b3573 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java +++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java @@ -18,6 +18,7 @@ */ package brooklyn.entity.basic; +import java.util.Collection; import java.util.Map; import brooklyn.config.ConfigKey; @@ -34,6 +35,7 @@ import brooklyn.util.flags.SetFromFlag; import brooklyn.util.time.Duration; import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; public interface SoftwareProcess extends Entity, Startable { @@ -43,6 +45,13 @@ public interface SoftwareProcess extends Entity, Startable { AttributeSensor<String> SUBNET_HOSTNAME = Attributes.SUBNET_HOSTNAME; AttributeSensor<String> SUBNET_ADDRESS = Attributes.SUBNET_ADDRESS; + @SuppressWarnings("serial") + ConfigKey<Collection<Integer>> REQUIRED_OPEN_LOGIN_PORTS = ConfigKeys.newConfigKey( + new TypeToken<Collection<Integer>>() {}, + "requiredOpenLoginPorts", + "The port(s) to be opened, to allow login", + ImmutableSet.of(22)); + @SetFromFlag("startTimeout") ConfigKey<Duration> START_TIMEOUT = BrooklynConfigKeys.START_TIMEOUT; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java index 1827485..a651f65 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java +++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java @@ -438,12 +438,12 @@ public abstract class SoftwareProcessImpl extends AbstractEntity implements Soft } /** returns the ports that this entity wants to use; - * default implementation returns 22 plus first value for each PortAttributeSensorAndConfigKey config key PortRange - * plus any ports defined with a config keys ending in .port + * default implementation returns {@link SoftwareProcess#REQUIRED_OPEN_LOGIN_PORTS} plus first value + * for each {@link PortAttributeSensorAndConfigKey} config key {@link PortRange} + * plus any ports defined with a config keys ending in {@code .port}. */ protected Collection<Integer> getRequiredOpenPorts() { - // TODO: Should only open 22 *or* 5985. Perhaps a flag / ConfigKey on SoftwareProcessImpl? - Set<Integer> ports = MutableSet.of(22, 5985, 3389); + Set<Integer> ports = MutableSet.copyOf(getConfig(REQUIRED_OPEN_LOGIN_PORTS)); Map<ConfigKey<?>, ?> allConfig = config().getBag().getAllConfigAsConfigKeyMap(); Set<ConfigKey<?>> configKeys = Sets.newHashSet(allConfig.keySet()); configKeys.addAll(getEntityType().getConfigKeys()); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java index e4e43ec..aa98086 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java +++ b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessDriver.java @@ -18,6 +18,6 @@ */ package brooklyn.entity.basic; -public interface VanillaSoftwareProcessDriver extends AbstractVanillaProcessDriver { +public interface VanillaSoftwareProcessDriver extends SoftwareProcessDriver { } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java index 4740bf6..ce49110 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java +++ b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcess.java @@ -18,12 +18,20 @@ */ package brooklyn.entity.basic; +import java.util.Collection; + import brooklyn.config.ConfigKey; import brooklyn.entity.proxying.ImplementedBy; import brooklyn.util.time.Duration; +import com.google.common.collect.ImmutableSet; + @ImplementedBy(VanillaWindowsProcessImpl.class) public interface VanillaWindowsProcess extends AbstractVanillaProcess { + // 3389 is RDP; 5985 is WinRM (3389 isn't used by Brooklyn, but useful for the end-user subsequently) + ConfigKey<Collection<Integer>> REQUIRED_OPEN_LOGIN_PORTS = ConfigKeys.newConfigKeyWithDefault( + SoftwareProcess.REQUIRED_OPEN_LOGIN_PORTS, + ImmutableSet.of(5985, 3389)); ConfigKey<String> PRE_INSTALL_POWERSHELL_COMMAND = ConfigKeys.newStringConfigKey("pre.install.powershell.command", "powershell command to run during the pre-install phase"); ConfigKey<Boolean> PRE_INSTALL_REBOOT_REQUIRED = ConfigKeys.newBooleanConfigKey("pre.install.reboot.required", @@ -46,9 +54,9 @@ public interface VanillaWindowsProcess extends AbstractVanillaProcess { "command to run during the install phase"); ConfigKey<String> INSTALL_POWERSHELL_COMMAND = ConfigKeys.newStringConfigKey("install.powershell.command", "powershell command to run during the install phase"); - ConfigKey<Duration> REBOOT_UNAVAILABLE_TIMEOUT = ConfigKeys.newDurationConfigKey("reboot.unavailable.timeout", - "duration to wait whilst waiting for a machine to become unavailable after a reboot", Duration.TWO_MINUTES); - // If automatic updates are enabled and there are updates waiting to be installed, thirty minutes may not be sufficient... - ConfigKey<Duration> REBOOT_AVAILABLE_TIMEOUT = ConfigKeys.newDurationConfigKey("reboot.unavailable.timeout", - "duration to wait whilst waiting for a machine to become unavailable after a reboot", Duration.minutes(30)); + ConfigKey<Duration> REBOOT_BEGUN_TIMEOUT = ConfigKeys.newDurationConfigKey("reboot.begun.timeout", + "duration to wait whilst waiting for a machine to begin rebooting, and thus become unavailable", Duration.TWO_MINUTES); + // TODO If automatic updates are enabled and there are updates waiting to be installed, thirty minutes may not be sufficient... + ConfigKey<Duration> REBOOT_COMPLETED_TIMEOUT = ConfigKeys.newDurationConfigKey("reboot.completed.timeout", + "duration to wait whilst waiting for a machine to finish rebooting, and thus to become available again", Duration.minutes(30)); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java index 04e60cf..7e9fd8c 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java +++ b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessDriver.java @@ -18,6 +18,6 @@ */ package brooklyn.entity.basic; -public interface VanillaWindowsProcessDriver extends AbstractVanillaProcessDriver { +public interface VanillaWindowsProcessDriver extends SoftwareProcessDriver { } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java index 7eac4a6..febed0f 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java +++ b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessImpl.java @@ -18,6 +18,7 @@ */ package brooklyn.entity.basic; + public class VanillaWindowsProcessImpl extends SoftwareProcessImpl implements VanillaWindowsProcess { @Override public Class getDriverInterface() { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java index a4f60e7..8c20253 100644 --- a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java +++ b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java @@ -22,14 +22,14 @@ import brooklyn.config.ConfigKey; import brooklyn.entity.basic.ConfigKeys; import brooklyn.entity.basic.EntityLocal; import brooklyn.entity.effector.AddSensor; -import brooklyn.event.basic.Sensors; import brooklyn.util.config.ConfigBag; +import brooklyn.util.flags.TypeCoercions; -public class StaticSensor<T> extends AddSensor<Integer> { +public class StaticSensor<T> extends AddSensor<T> { - public static final ConfigKey<Integer> STATIC_VALUE = ConfigKeys.newConfigKey(Integer.class, "static.value"); + public static final ConfigKey<Object> STATIC_VALUE = ConfigKeys.newConfigKey(Object.class, "static.value"); - private final Integer value; + private final Object value; public StaticSensor(ConfigBag params) { super(params); @@ -39,6 +39,6 @@ public class StaticSensor<T> extends AddSensor<Integer> { @Override public void apply(EntityLocal entity) { super.apply(entity); - entity.setAttribute(Sensors.newIntegerSensor(name), value); + entity.setAttribute(sensor, (T) TypeCoercions.coerce(value, sensor.getType())); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java index e36d285..bed1cb9 100644 --- a/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java +++ b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java @@ -57,18 +57,18 @@ public class WindowsPerformanceCounterSensors implements EntityInitializer { WindowsPerformanceCounterFeed.Builder builder = WindowsPerformanceCounterFeed.builder() .entity(entity); for (Map<String, String> sensorConfig : sensors) { + String name = sensorConfig.get("name"); String sensorType = sensorConfig.get("sensorType"); Class<?> clazz; try { - clazz = Strings.isNonEmpty(sensorType) ? - ((EntityInternal)entity).getManagementContext().getCatalog().getRootClassLoader().loadClass(sensorType) : String.class; + clazz = Strings.isNonEmpty(sensorType) + ? ((EntityInternal)entity).getManagementContext().getCatalog().getRootClassLoader().loadClass(sensorType) + : String.class; } catch (ClassNotFoundException e) { - LOG.warn("Could not load type {} for sensor {}", sensorType, sensorConfig.get("name")); - clazz = String.class; + throw new IllegalStateException("Could not load type "+sensorType+" for sensor "+name, e); } - builder.addSensor(sensorConfig.get("counter"), Sensors.newSensor(clazz, sensorConfig.get("name"), sensorConfig.get("description"))); + builder.addSensor(sensorConfig.get("counter"), Sensors.newSensor(clazz, name, sensorConfig.get("description"))); } builder.build(); } - } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java b/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java index 9115d62..a8bff64 100644 --- a/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java +++ b/software/base/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesMultiLocationTest.java @@ -53,7 +53,7 @@ import com.google.common.collect.Lists; * * Different from {@link DynamicClusterWithAvailabilityZonesTest} in the use of {@link MultiLocation}. * However, the difference is important: the {@link SoftwareProcess} entity has two locations - * (the {@link MachineProvisioningLocation} and the {@link MachineLocation}, which was perviously + * (the {@link MachineProvisioningLocation} and the {@link MachineLocation}, which was previously * causing a failure - now fixed and tested here. */ public class DynamicClusterWithAvailabilityZonesMultiLocationTest extends BrooklynAppUnitTestSupport { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java b/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java new file mode 100644 index 0000000..4b9a641 --- /dev/null +++ b/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package brooklyn.entity.software; + +import org.testng.annotations.Test; + +import brooklyn.entity.BrooklynAppUnitTestSupport; +import brooklyn.entity.basic.BasicEntity; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.event.basic.Sensors; +import brooklyn.test.EntityTestUtils; +import brooklyn.util.config.ConfigBag; + +import com.google.common.collect.ImmutableMap; + +public class StaticSensorTest extends BrooklynAppUnitTestSupport { + + @Test + public void testAddsStaticSensorOfTypeString() { + BasicEntity entity = app.createAndManageChild(EntitySpec.create(BasicEntity.class) + .addInitializer(new StaticSensor<String>(ConfigBag.newInstance(ImmutableMap.of( + StaticSensor.SENSOR_NAME, "myname", + StaticSensor.SENSOR_TYPE, String.class.getName(), + StaticSensor.STATIC_VALUE, "myval"))))); + + EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(String.class, "myname"), "myval"); + } + + @Test + public void testAddsStaticSensorOfTypeInteger() { + BasicEntity entity = app.createAndManageChild(EntitySpec.create(BasicEntity.class) + .addInitializer(new StaticSensor<Integer>(ConfigBag.newInstance(ImmutableMap.of( + StaticSensor.SENSOR_NAME, "myname", + StaticSensor.SENSOR_TYPE, Integer.class.getName(), + StaticSensor.STATIC_VALUE, "1"))))); + + EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(Integer.class, "myname"), 1); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java b/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java new file mode 100644 index 0000000..735a23f --- /dev/null +++ b/software/base/src/test/java/brooklyn/location/basic/WinRmMachineLocationLiveTest.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package brooklyn.location.basic; + +import static org.testng.Assert.assertEquals; +import io.cloudsoft.winrm4j.winrm.WinRmToolResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import brooklyn.config.BrooklynProperties; +import brooklyn.entity.BrooklynAppLiveTestSupport; +import brooklyn.entity.basic.Entities; +import brooklyn.location.jclouds.JcloudsLocation; +import brooklyn.location.jclouds.JcloudsWinRmMachineLocation; +import brooklyn.management.internal.ManagementContextInternal; +import brooklyn.test.entity.LocalManagementContextForTests; +import brooklyn.test.entity.TestApplication; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class WinRmMachineLocationLiveTest { + + // FIXME failing locally with: + // Caused by: Traceback (most recent call last): + // File "__pyclasspath__/winrm/__init__.py", line 40, in run_cmd + // File "__pyclasspath__/winrm/protocol.py", line 118, in open_shell + // File "__pyclasspath__/winrm/protocol.py", line 190, in send_message + // File "__pyclasspath__/winrm/transport.py", line 112, in send_message + // winrm.exceptions.WinRMTransportError: 500 WinRMTransport. [Errno 20001] getaddrinfo failed + // at org.python.core.PyException.doRaise(PyException.java:226) + + private static final Logger LOG = LoggerFactory.getLogger(BrooklynAppLiveTestSupport.class); + + protected JcloudsLocation loc; + protected TestApplication app; + protected ManagementContextInternal mgmt; + + private JcloudsWinRmMachineLocation machine; + + @BeforeClass(alwaysRun=true) + public void setUpClass() throws Exception { + mgmt = new LocalManagementContextForTests(BrooklynProperties.Factory.newDefault()); + JcloudsLocation loc = (JcloudsLocation) mgmt.getLocationRegistry().resolve("jclouds:aws-ec2:us-west-2", ImmutableMap.of( + "inboundPorts", ImmutableList.of(5985, 3389), + "displayName", "AWS Oregon (Windows)", + "imageId", "us-west-2/ami-8fd3f9bf", + "hardwareId", "m3.medium", + "useJcloudsSshInit", false)); + machine = (JcloudsWinRmMachineLocation) loc.obtain(); + } + + @AfterClass(alwaysRun=true) + public void tearDownClass() throws Exception { + try { + if (machine != null) loc.release(machine); + if (mgmt != null) Entities.destroyAll(mgmt); + } catch (Throwable t) { + LOG.error("Caught exception in tearDown method", t); + } finally { + mgmt = null; + } + } + + @Test(groups="Live") + public void testExecScript() throws Exception { + WinRmToolResponse response = machine.executeScript("echo true"); + assertEquals(response.getStatusCode(), 0); + assertEquals(response.getStdErr(), ""); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml ---------------------------------------------------------------------- diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml b/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml index 7c366eb..d82a7f7 100644 --- a/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml +++ b/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml @@ -1,6 +1,15 @@ -name: imageId us-west-2/ami-07390a37 +name: mssql -location: AWS Oregon Win +location: + jclouds:aws-ec2:us-west-2: + displayName: AWS Oregon (Windows) + imageId: us-west-2/ami-8fd3f9bf + hardwareId: m3.medium + useJcloudsSshInit: false + templateOptions: + subnetId: subnet-a10e96c4 + securityGroupIds: [['sg-a2d0c2c7']] + mapNewVolumeToDeviceName: ["/dev/sda1", 100, true] services: - type: brooklyn.entity.basic.VanillaWindowsProcess http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java ---------------------------------------------------------------------- diff --git a/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java b/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java new file mode 100644 index 0000000..f5ef36f --- /dev/null +++ b/usage/launcher/src/test/java/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package brooklyn.entity.database.mssql; + +import java.io.StringReader; +import java.util.Map; + +import org.testng.annotations.Test; + +import brooklyn.launcher.blueprints.AbstractBlueprintTest; +import brooklyn.util.ResourceUtils; +import brooklyn.util.text.TemplateProcessor; + +import com.google.common.collect.ImmutableMap; + +/** + * Assumes that brooklyn.properties contains something like the following (but with real values!): + * + * {@code + * test.mssql.download.url = http://myserver.com/sql2012.iso + * test.mssql.download.user = myname + * test.mssql.download.password = mypassword + * test.mssql.sa.password = mypassword + * test.mssql.instance.name = MYNAME + * } + */ +public class MssqlBlueprintLiveTest extends AbstractBlueprintTest { + + // TODO Needs further testing + + @Test(groups={"Live"}) + public void testMssql() throws Exception { + Map<String, String> substitutions = ImmutableMap.of( + "mssql.download.url", mgmt.getConfig().getFirst("test.mssql.download.url"), + "mssql.download.user", mgmt.getConfig().getFirst("test.mssql.download.user"), + "mssql.download.password", mgmt.getConfig().getFirst("test.mssql.download.password"), + "mssql.sa.password", mgmt.getConfig().getFirst("test.mssql.sa.password"), + "mssql.instance.name", mgmt.getConfig().getFirst("test.mssql.instance.name")); + + String rawYaml = new ResourceUtils(this).getResourceAsString("mssql-test.yaml"); + String yaml = TemplateProcessor.processTemplateContents(rawYaml, substitutions); + runTest(new StringReader(yaml)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c37f241/usage/launcher/src/test/resources/mssql-test.yaml ---------------------------------------------------------------------- diff --git a/usage/launcher/src/test/resources/mssql-test.yaml b/usage/launcher/src/test/resources/mssql-test.yaml new file mode 100644 index 0000000..2b31f74 --- /dev/null +++ b/usage/launcher/src/test/resources/mssql-test.yaml @@ -0,0 +1,60 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Duplicate of software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml, +# but with template for download url, etc + +name: mssql + +location: + jclouds:aws-ec2:us-west-2: + displayName: AWS Oregon (Windows) + imageId: us-west-2/ami-8fd3f9bf + hardwareId: m3.medium + useJcloudsSshInit: false + templateOptions: + mapNewVolumeToDeviceName: ["/dev/sda1", 100, true] + +services: +- type: brooklyn.entity.basic.VanillaWindowsProcess + brooklyn.config: + templates.install: + classpath://brooklyn/entity/database/mssql/ConfigurationFile.ini: "C:\\ConfigurationFile.ini" + classpath://brooklyn/entity/database/mssql/installmssql.ps1: "C:\\installmssql.ps1" + classpath://brooklyn/entity/database/mssql/configuremssql.ps1: "C:\\configuremssql.ps1" + classpath://brooklyn/entity/database/mssql/launchmssql.bat: "C:\\launchmssql.bat" + classpath://brooklyn/entity/database/mssql/stopmssql.bat: "C:\\stopmssql.bat" + install.command: powershell -command "C:\\installmssql.ps1" + customize.command: powershell -command "C:\\configuremssql.ps1" + launch.command: "C:\\launchmssql.bat" + stop.command: "C:\\stopmssql.bat" + checkRunning.command: echo true + + ## NOTE: Values must be supplied for the following + mssql.download.url: ${mssql.download.url} + mssql.download.user: ${mssql.download.user} + mssql.download.password: ${mssql.download.password} + mssql.sa.password: ${mssql.sa.password} + mssql.instance.name: ${mssql.instance.name} + + ## The following is a list of *all* MSSQL features. Installation time and footprint can be greatly + ## reduced by removing unnecessary features + mssql.features: "SQLENGINE,REPLICATION,FULLTEXT,DQ,AS,RS,RS_SHP,DQC,BIDS,CONN,IS,BC,SDK,BOL,SSMS,ADV_SSMS,DREPLAY_CTLR,DREPLAY_CLT,SNAC_SDK" + provisioning.properties: + required.ports: 1433 \ No newline at end of file
