Basic support for Windows BYON with WinRM pre-configured
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/1fa59690 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/1fa59690 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/1fa59690 Branch: refs/heads/master Commit: 1fa596902d3cd70f3e58dc558a07d90dca837bfe Parents: 638d3e9 Author: Martin Harris <[email protected]> Authored: Mon Apr 6 13:13:18 2015 +0100 Committer: Richard Downer <[email protected]> Committed: Thu May 28 17:27:34 2015 +0100 ---------------------------------------------------------------------- core/pom.xml | 6 +- .../location/basic/ByonLocationResolver.java | 17 +++- .../location/basic/WinRmMachineLocation.java | 101 +++++++++++++++++++ .../basic/ByonLocationResolverTest.java | 66 ++++++++---- pom.xml | 1 + .../AbstractSoftwareProcessWinRmDriver.java | 43 ++++++++ 6 files changed, 212 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1fa59690/core/pom.xml ---------------------------------------------------------------------- diff --git a/core/pom.xml b/core/pom.xml index 27ba663..fddcd0a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -65,7 +65,11 @@ <classifier>tests</classifier> <scope>test</scope> </dependency> - + <dependency> + <groupId>io.cloudsoft.windows</groupId> + <artifactId>winrm4j</artifactId> + <version>${winrm4j.version}</version> + </dependency> <dependency> <groupId>net.schmizz</groupId> <artifactId>sshj</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1fa59690/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java b/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java index 86cf747..2ce37d2 100644 --- a/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java +++ b/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java @@ -25,8 +25,11 @@ import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import brooklyn.config.ConfigKey; +import brooklyn.entity.basic.ConfigKeys; import brooklyn.location.Location; import brooklyn.location.LocationSpec; +import brooklyn.location.MachineLocation; import brooklyn.management.internal.LocalLocationManager; import brooklyn.util.JavaGroovyEquivalents; import brooklyn.util.config.ConfigBag; @@ -34,6 +37,7 @@ import brooklyn.util.text.WildcardGlobs; import brooklyn.util.text.WildcardGlobs.PhraseTreatment; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; /** @@ -55,6 +59,12 @@ public class ByonLocationResolver extends AbstractLocationResolver { public static final String BYON = "byon"; + public static final ConfigKey<String> OS_FAMILY = ConfigKeys.newStringConfigKey("osfamily", "OS Family of the machine, either windows or linux", "linux"); + + public static final Map<String, Class<? extends MachineLocation>> OS_TO_MACHINE_LOCATION_TYPE = ImmutableMap.<String, Class<? extends MachineLocation>>of( + "windows", WinRmMachineLocation.class, + "linux", SshMachineLocation.class); + @Override public String getPrefix() { return BYON; @@ -77,6 +87,7 @@ public class ByonLocationResolver extends AbstractLocationResolver { Object hosts = config.getStringKey("hosts"); config.remove("hosts"); String user = (String)config.getStringKey("user"); + Class<? extends MachineLocation> locationClass = OS_TO_MACHINE_LOCATION_TYPE.get(config.get(OS_FAMILY)); List<String> hostAddresses; @@ -96,7 +107,7 @@ public class ByonLocationResolver extends AbstractLocationResolver { throw new IllegalArgumentException("Invalid location '"+spec+"'; at least one host must be defined"); } - List<SshMachineLocation> machines = Lists.newArrayList(); + List<MachineLocation> machines = Lists.newArrayList(); for (String host : hostAddresses) { String userHere = user; String hostHere = host; @@ -109,13 +120,13 @@ public class ByonLocationResolver extends AbstractLocationResolver { } catch (Exception e) { throw new IllegalArgumentException("Invalid host '"+hostHere+"' specified in '"+spec+"': "+e); } - LocationSpec<SshMachineLocation> locationSpec = LocationSpec.create(SshMachineLocation.class) + LocationSpec<? extends MachineLocation> locationSpec = LocationSpec.create(locationClass) .configure("address", hostHere.trim()) .configureIfNotNull(LocalLocationManager.CREATE_UNMANAGED, config.get(LocalLocationManager.CREATE_UNMANAGED)); if (JavaGroovyEquivalents.groovyTruth(userHere)) { locationSpec.configure("user", userHere.trim()); } - SshMachineLocation machine = managementContext.getLocationManager().createLocation(locationSpec); + MachineLocation machine = managementContext.getLocationManager().createLocation(locationSpec); machines.add(machine); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1fa59690/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 new file mode 100644 index 0000000..febf901 --- /dev/null +++ b/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java @@ -0,0 +1,101 @@ +/* + * 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 java.net.InetAddress; +import java.util.List; +import java.util.Set; + +import javax.annotation.Nullable; + +import brooklyn.config.ConfigKey; +import brooklyn.entity.basic.ConfigKeys; +import brooklyn.location.MachineDetails; +import brooklyn.location.MachineLocation; +import brooklyn.location.OsDetails; +import brooklyn.util.flags.SetFromFlag; +import io.cloudsoft.winrm4j.winrm.WinRmTool; +import io.cloudsoft.winrm4j.winrm.WinRmToolResponse; + +public class WinRmMachineLocation extends AbstractLocation implements MachineLocation { + + public static final ConfigKey<String> WINDOWS_USERNAME = ConfigKeys.newStringConfigKey("windows.username", + "Username to use when connecting to the remote machine"); + + public static final ConfigKey<String> WINDOWS_PASSWORD = ConfigKeys.newStringConfigKey("windows.password", + "Password to use when connecting to the remote machine"); + + @SetFromFlag + protected String user; + + @SetFromFlag(nullable = false) + protected InetAddress address; + + @Override + public InetAddress getAddress() { + return address; + } + + @Override + public OsDetails getOsDetails() { + return null; + } + + @Override + public MachineDetails getMachineDetails() { + return null; + } + + @Nullable + @Override + public String getHostname() { + return address.getHostAddress(); + } + + @Override + public Set<String> getPublicAddresses() { + return null; + } + + @Override + public Set<String> getPrivateAddresses() { + return null; + } + + public int executeScript(List<String> script) { + WinRmTool winRmTool = WinRmTool.connect(getHostname(), getUsername(), getPassword()); + WinRmToolResponse response = winRmTool.executeScript(script); + return response.getStatusCode(); + } + + public int executePsScript(List<String> psScript) { + WinRmTool winRmTool = WinRmTool.connect(getHostname(), getUsername(), getPassword()); + WinRmToolResponse response = winRmTool.executePs(psScript); + return response.getStatusCode(); + } + + public String getUsername() { + return config().get(WINDOWS_USERNAME); + } + + private String getPassword() { + return config().get(WINDOWS_PASSWORD); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1fa59690/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java b/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java index 2fb85e5..0d6e5ff 100644 --- a/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java +++ b/core/src/test/java/brooklyn/location/basic/ByonLocationResolverTest.java @@ -60,7 +60,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -public class ByonLocationResolverTest { +public class + ByonLocationResolverTest { private static final Logger log = LoggerFactory.getLogger(ByonLocationResolverTest.class); @@ -101,14 +102,14 @@ public class ByonLocationResolverTest { public void testNamedByonLocation() throws Exception { brooklynProperties.put("brooklyn.location.named.mynamed", "byon(hosts=\"1.1.1.1\")"); - FixedListMachineProvisioningLocation<SshMachineLocation> loc = resolve("named:mynamed"); + FixedListMachineProvisioningLocation<MachineLocation> loc = resolve("named:mynamed"); assertEquals(loc.obtain().getAddress(), InetAddress.getByName("1.1.1.1")); } @Test public void testPropertiesInSpec() throws Exception { - FixedListMachineProvisioningLocation<SshMachineLocation> loc = resolve("byon(privateKeyFile=myprivatekeyfile,hosts=\"1.1.1.1\")"); - SshMachineLocation machine = loc.obtain(); + FixedListMachineProvisioningLocation<MachineLocation> loc = resolve("byon(privateKeyFile=myprivatekeyfile,hosts=\"1.1.1.1\")"); + SshMachineLocation machine = (SshMachineLocation)loc.obtain(); assertEquals(machine.config().getBag().getStringKey("privateKeyFile"), "myprivatekeyfile"); assertEquals(machine.getAddress(), Networking.getInetAddressWithFixedName("1.1.1.1")); @@ -188,7 +189,7 @@ public class ByonLocationResolverTest { public void testNiceError() throws Exception { Asserts.assertFailsWith(new Runnable() { @Override public void run() { - FixedListMachineProvisioningLocation<SshMachineLocation> x = + FixedListMachineProvisioningLocation<MachineLocation> x = resolve("byon(hosts=\"1.1.1.{1,2}}\")"); log.error("got "+x+" but should have failed (your DNS is giving an IP for hostname '1.1.1.1}' (with the extra '}')"); } @@ -224,8 +225,8 @@ public class ByonLocationResolverTest { @Test public void testResolvesUserArg2() throws Exception { String spec = "byon(hosts=\"1.1.1.1\",user=bob)"; - FixedListMachineProvisioningLocation<SshMachineLocation> ll = resolve(spec); - SshMachineLocation l = ll.obtain(); + FixedListMachineProvisioningLocation<MachineLocation> ll = resolve(spec); + SshMachineLocation l = (SshMachineLocation)ll.obtain(); Assert.assertEquals("bob", l.getUser()); } @@ -281,8 +282,8 @@ public class ByonLocationResolverTest { String localTempDir = Os.mergePaths(Os.tmp(), "testResolvesUsernameAtHost"); brooklynProperties.put("brooklyn.location.byon.localTempDir", localTempDir); - FixedListMachineProvisioningLocation<SshMachineLocation> byon = resolve("byon(hosts=\"1.1.1.1\")"); - SshMachineLocation machine = byon.obtain(); + FixedListMachineProvisioningLocation<MachineLocation> byon = resolve("byon(hosts=\"1.1.1.1\",osFamily=\"windows\")"); + MachineLocation machine = byon.obtain(); assertEquals(machine.getConfig(SshMachineLocation.LOCAL_TEMP_DIR), localTempDir); } @@ -291,10 +292,10 @@ public class ByonLocationResolverTest { List<String> ips = ImmutableList.of("1.1.1.1", "1.1.1.6", "1.1.1.3", "1.1.1.4", "1.1.1.5"); String spec = "byon(hosts=\""+Joiner.on(",").join(ips)+"\")"; - MachineProvisioningLocation<SshMachineLocation> ll = resolve(spec); + MachineProvisioningLocation<MachineLocation> ll = resolve(spec); for (String expected : ips) { - SshMachineLocation obtained = ll.obtain(ImmutableMap.of()); + MachineLocation obtained = ll.obtain(ImmutableMap.of()); assertEquals(obtained.getAddress().getHostAddress(), expected); } } @@ -307,12 +308,41 @@ public class ByonLocationResolverTest { "name", "foo", "user", "myuser" ); - MachineProvisioningLocation<SshMachineLocation> provisioner = resolve(spec, flags); - SshMachineLocation location1 = provisioner.obtain(ImmutableMap.of()); + MachineProvisioningLocation<MachineLocation> provisioner = resolve(spec, flags); + SshMachineLocation location1 = (SshMachineLocation)provisioner.obtain(ImmutableMap.of()); Assert.assertEquals("myuser", location1.getUser()); Assert.assertEquals("1.1.1.1", location1.getAddress().getHostAddress()); } + @Test + public void testWindowsMachines() throws Exception { + brooklynProperties.put("brooklyn.location.byon.windows.username", "myuser"); + brooklynProperties.put("brooklyn.location.byon.windows.password", "mypassword"); + String spec = "byon"; + Map<String, ?> flags = ImmutableMap.of( + "hosts", ImmutableList.of("1.1.1.1", "2.2.2.2"), + "osfamily", "windows" + ); + MachineProvisioningLocation<MachineLocation> provisioner = resolve(spec, flags); + MachineLocation location = provisioner.obtain(ImmutableMap.of()); + + assertEquals(location.config().get(WinRmMachineLocation.WINDOWS_USERNAME), "myuser"); + assertEquals(location.config().get(WinRmMachineLocation.WINDOWS_PASSWORD), "mypassword"); + Assert.assertNotNull(provisioner); + } + + @Test + public void testNoneWindowsMachines() throws Exception { + String spec = "byon"; + Map<String, ?> flags = ImmutableMap.of( + "hosts", ImmutableList.of("1.1.1.1", "2.2.2.2"), + "osfamily", "linux" + ); + MachineProvisioningLocation<MachineLocation> provisioner = resolve(spec, flags); + MachineLocation location = provisioner.obtain(ImmutableMap.of()); + assertTrue(location instanceof SshMachineLocation, "Expected location to be SshMachineLocation, found " + location); + } + private void assertByonClusterEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<String> expectedHosts) { assertByonClusterEquals(cluster, expectedHosts, defaultNamePredicate); } @@ -362,15 +392,15 @@ public class ByonLocationResolverTest { } @SuppressWarnings("unchecked") - private FixedListMachineProvisioningLocation<SshMachineLocation> resolve(String val) { - return (FixedListMachineProvisioningLocation<SshMachineLocation>) managementContext.getLocationRegistry().resolve(val); + private FixedListMachineProvisioningLocation<MachineLocation> resolve(String val) { + return (FixedListMachineProvisioningLocation<MachineLocation>) managementContext.getLocationRegistry().resolve(val); } @SuppressWarnings("unchecked") - private FixedListMachineProvisioningLocation<SshMachineLocation> resolve(String val, Map<?, ?> locationFlags) { - return (FixedListMachineProvisioningLocation<SshMachineLocation>) managementContext.getLocationRegistry().resolve(val, locationFlags); + private FixedListMachineProvisioningLocation<MachineLocation> resolve(String val, Map<?, ?> locationFlags) { + return (FixedListMachineProvisioningLocation<MachineLocation>) managementContext.getLocationRegistry().resolve(val, locationFlags); } - + private static class UserHostTuple { final String username; final String hostname; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1fa59690/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 0747f8d..af08b2e 100644 --- a/pom.xml +++ b/pom.xml @@ -205,6 +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> <coverage.target>${working.dir}</coverage.target> <!-- Release --> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1fa59690/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 new file mode 100644 index 0000000..8d65bec --- /dev/null +++ b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessWinRmDriver.java @@ -0,0 +1,43 @@ +/* + * 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; + +import java.util.List; + +import brooklyn.location.basic.WinRmMachineLocation; + +public abstract class AbstractSoftwareProcessWinRmDriver extends AbstractSoftwareProcessDriver { + + public AbstractSoftwareProcessWinRmDriver(EntityLocal entity, WinRmMachineLocation location) { + super(entity, location); + } + + public WinRmMachineLocation getMachine() { + return (WinRmMachineLocation) getLocation(); + } + + public int execute(List<String> script) { + return getMachine().executeScript(script); + } + + public int executePowerShell(List<String> psScript) { + return getMachine().executePsScript(psScript); + } + +}
