Adds BYON tcpPortMappings
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/9633236d Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/9633236d Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/9633236d Branch: refs/heads/master Commit: 9633236d9ee2adf6e63fab2682465944df78f667 Parents: c2e55c0 Author: Aled Sage <[email protected]> Authored: Mon Jul 20 23:31:53 2015 -0700 Committer: Aled Sage <[email protected]> Committed: Mon Jul 27 13:50:00 2015 +0100 ---------------------------------------------------------------------- .../location/basic/ByonLocationResolver.java | 47 ++++++++++--- .../location/basic/SshMachineLocation.java | 72 +++++++++++++------- .../location/basic/WinRmMachineLocation.java | 42 +++++++++--- .../camp/brooklyn/ByonLocationsYamlTest.java | 66 ++++++++++++++++-- 4 files changed, 175 insertions(+), 52 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9633236d/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 3695e3e..7838e24 100644 --- a/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java +++ b/core/src/main/java/brooklyn/location/basic/ByonLocationResolver.java @@ -27,6 +27,12 @@ import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.net.HostAndPort; + import brooklyn.config.ConfigKey; import brooklyn.entity.basic.ConfigKeys; import brooklyn.entity.basic.Sanitizer; @@ -41,12 +47,6 @@ import brooklyn.util.net.UserAndHostAndPort; 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; -import com.google.common.collect.Maps; -import com.google.common.net.HostAndPort; - /** * Examples of valid specs: * <ul> @@ -146,16 +146,33 @@ public class ByonLocationResolver extends AbstractLocationResolver { String osfamily = (String) machineConfig.remove(OS_FAMILY.getName()); String ssh = (String) machineConfig.remove("ssh"); String winrm = (String) machineConfig.remove("winrm"); + Map<Integer, String> tcpPortMappings = (Map<Integer, String>) machineConfig.get("tcpPortMappings"); + checkArgument(ssh != null ^ winrm != null, "Must specify exactly one of 'ssh' or 'winrm' for machine: %s", valSanitized); UserAndHostAndPort userAndHostAndPort; + String host; + int port; if (ssh != null) { - userAndHostAndPort = parseUserAndHostAndPort((String)ssh); + userAndHostAndPort = parseUserAndHostAndPort((String)ssh, 22); } else { - userAndHostAndPort = parseUserAndHostAndPort((String)winrm); + userAndHostAndPort = parseUserAndHostAndPort((String)winrm, 5985); + } + + // If there is a tcpPortMapping defined for the connection-port, then use that for ssh/winrm machine + port = userAndHostAndPort.getHostAndPort().getPort(); + if (tcpPortMappings != null && tcpPortMappings.containsKey(port)) { + String override = tcpPortMappings.get(port); + HostAndPort hostAndPortOverride = HostAndPort.fromString(override); + if (!hostAndPortOverride.hasPort()) { + throw new IllegalArgumentException("Invalid portMapping ('"+override+"') for port "+port+" in "+specForErrMsg); + } + port = hostAndPortOverride.getPort(); + host = hostAndPortOverride.getHostText().trim(); + } else { + host = userAndHostAndPort.getHostAndPort().getHostText().trim(); } - String host = userAndHostAndPort.getHostAndPort().getHostText().trim(); machineConfig.put("address", host); try { InetAddress.getByName(host); @@ -169,7 +186,7 @@ public class ByonLocationResolver extends AbstractLocationResolver { } if (userAndHostAndPort.getHostAndPort().hasPort()) { checkArgument(!vals.containsKey("port"), "Must not specify port twice for machine: %s", valSanitized); - machineConfig.put("port", userAndHostAndPort.getHostAndPort().getPort()); + machineConfig.put("port", port); } for (Map.Entry<String, ?> entry : defaults.entrySet()) { if (!machineConfig.containsKey(entry.getKey())) { @@ -187,7 +204,7 @@ public class ByonLocationResolver extends AbstractLocationResolver { protected LocationSpec<? extends MachineLocation> parseMachine(String val, Class<? extends MachineLocation> locationClass, Map<String, ?> defaults, String specForErrMsg) { Map<String, Object> machineConfig = Maps.newLinkedHashMap(); - + UserAndHostAndPort userAndHostAndPort = parseUserAndHostAndPort(val); String host = userAndHostAndPort.getHostAndPort().getHostText().trim(); @@ -222,4 +239,12 @@ public class ByonLocationResolver extends AbstractLocationResolver { } return UserAndHostAndPort.fromParts(userPart, HostAndPort.fromString(hostPart)); } + + private UserAndHostAndPort parseUserAndHostAndPort(String val, int defaultPort) { + UserAndHostAndPort result = parseUserAndHostAndPort(val); + if (!result.getHostAndPort().hasPort()) { + result = UserAndHostAndPort.fromParts(result.getUser(), result.getHostAndPort().getHostText(), defaultPort); + } + return result; + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9633236d/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java index 68f224d..8c06274 100644 --- a/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java +++ b/core/src/main/java/brooklyn/location/basic/SshMachineLocation.java @@ -20,10 +20,6 @@ package brooklyn.location.basic; import static brooklyn.util.GroovyJavaMethods.truth; -import com.google.common.annotations.Beta; - -import groovy.lang.Closure; - import java.io.Closeable; import java.io.File; import java.io.FileInputStream; @@ -52,6 +48,27 @@ import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.cache.RemovalListener; +import com.google.common.cache.RemovalNotification; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.net.HostAndPort; +import com.google.common.reflect.TypeToken; + import brooklyn.config.BrooklynLogging; import brooklyn.config.ConfigKey; import brooklyn.config.ConfigKey.HasConfigKey; @@ -66,6 +83,7 @@ import brooklyn.location.MachineLocation; import brooklyn.location.OsDetails; import brooklyn.location.PortRange; import brooklyn.location.PortSupplier; +import brooklyn.location.access.PortForwardManager; import brooklyn.management.Task; import brooklyn.util.ResourceUtils; import brooklyn.util.collections.MutableMap; @@ -96,26 +114,7 @@ import brooklyn.util.task.system.internal.ExecWithLoggingHelpers; import brooklyn.util.task.system.internal.ExecWithLoggingHelpers.ExecRunner; import brooklyn.util.text.Strings; import brooklyn.util.time.Duration; - -import com.google.common.base.Function; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.cache.RemovalListener; -import com.google.common.cache.RemovalNotification; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.net.HostAndPort; -import com.google.common.reflect.TypeToken; +import groovy.lang.Closure; /** * Operations on a machine that is accessible via ssh. @@ -153,6 +152,12 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat "Private addresses of this machine, e.g. those within the private network", null); + public static final ConfigKey<Map<Integer, String>> TCP_PORT_MAPPINGS = ConfigKeys.newConfigKey( + new TypeToken<Map<Integer, String>>() {}, + "tcpPortMappings", + "NAT'ed ports, giving the mapping from private TCP port to a public host:port", + null); + @SetFromFlag protected String user; @@ -251,6 +256,25 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat usedPorts = (usedPorts != null) ? Sets.newLinkedHashSet(usedPorts) : Sets.<Integer>newLinkedHashSet(); } + @Override + public void init() { + super.init(); + + // Register any pre-existing port-mappings with the PortForwardManager + Map<Integer, String> tcpPortMappings = getConfig(TCP_PORT_MAPPINGS); + if (tcpPortMappings != null) { + PortForwardManager pfm = (PortForwardManager) getManagementContext().getLocationRegistry().resolve("portForwardManager(scope=global)"); + for (Map.Entry<Integer, String> entry : tcpPortMappings.entrySet()) { + int targetPort = entry.getKey(); + HostAndPort publicEndpoint = HostAndPort.fromString(entry.getValue()); + if (!publicEndpoint.hasPort()) { + throw new IllegalArgumentException("Invalid portMapping ('"+entry.getValue()+"') for port "+targetPort+" in machine "+this); + } + pfm.associate(publicEndpoint.getHostText(), publicEndpoint, this, targetPort); + } + } + } + private final transient Object poolCacheMutex = new Object(); @Nonnull private LoadingCache<Map<String, ?>, Pool<SshTool>> getSshPoolCache() { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9633236d/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 54ee63a..3504ec0 100644 --- a/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java +++ b/core/src/main/java/brooklyn/location/basic/WinRmMachineLocation.java @@ -19,8 +19,6 @@ package brooklyn.location.basic; import static com.google.common.base.Preconditions.checkNotNull; -import io.cloudsoft.winrm4j.winrm.WinRmTool; -import io.cloudsoft.winrm4j.winrm.WinRmToolResponse; import java.io.File; import java.io.FileInputStream; @@ -30,6 +28,7 @@ import java.net.InetAddress; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; import javax.annotation.Nullable; @@ -38,22 +37,26 @@ import org.apache.commons.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Charsets; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.net.HostAndPort; +import com.google.common.reflect.TypeToken; + import brooklyn.config.ConfigKey; import brooklyn.entity.basic.ConfigKeys; import brooklyn.location.MachineDetails; import brooklyn.location.MachineLocation; import brooklyn.location.OsDetails; +import brooklyn.location.access.PortForwardManager; import brooklyn.util.exceptions.Exceptions; import brooklyn.util.stream.Streams; import brooklyn.util.time.Duration; import brooklyn.util.time.Time; - -import com.google.common.base.Charsets; -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.reflect.TypeToken; +import io.cloudsoft.winrm4j.winrm.WinRmTool; +import io.cloudsoft.winrm4j.winrm.WinRmToolResponse; public class WinRmMachineLocation extends AbstractLocation implements MachineLocation { @@ -98,6 +101,12 @@ public class WinRmMachineLocation extends AbstractLocation implements MachineLoc "Private addresses of this machine, e.g. those within the private network", null); + public static final ConfigKey<Map<Integer, String>> TCP_PORT_MAPPINGS = ConfigKeys.newConfigKey( + new TypeToken<Map<Integer, String>>() {}, + "tcpPortMappings", + "NAT'ed ports, giving the mapping from private TCP port to a public host:port", + null); + @Override public InetAddress getAddress() { return getConfig(ADDRESS); @@ -245,8 +254,21 @@ public class WinRmMachineLocation extends AbstractLocation implements MachineLoc @Override public void init() { super.init(); - } + // Register any pre-existing port-mappings with the PortForwardManager + Map<Integer, String> tcpPortMappings = getConfig(TCP_PORT_MAPPINGS); + if (tcpPortMappings != null) { + PortForwardManager pfm = (PortForwardManager) getManagementContext().getLocationRegistry().resolve("portForwardManager(scope=global)"); + for (Map.Entry<Integer, String> entry : tcpPortMappings.entrySet()) { + int targetPort = entry.getKey(); + HostAndPort publicEndpoint = HostAndPort.fromString(entry.getValue()); + if (!publicEndpoint.hasPort()) { + throw new IllegalArgumentException("Invalid portMapping ('"+entry.getValue()+"') for port "+targetPort+" in machine "+this); + } + pfm.associate(publicEndpoint.getHostText(), publicEndpoint, this, targetPort); + } + } + } public String getUser() { return config().get(USER); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9633236d/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java index 5ce0dac..3ddc5ad 100644 --- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java +++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java @@ -19,6 +19,7 @@ package io.brooklyn.camp.brooklyn; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; import java.io.StringReader; import java.util.Map; @@ -28,21 +29,23 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.Test; +import com.google.api.client.repackaged.com.google.common.base.Joiner; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.net.HostAndPort; + import brooklyn.entity.Entity; import brooklyn.entity.basic.ConfigKeys; import brooklyn.location.MachineLocation; +import brooklyn.location.access.PortForwardManager; import brooklyn.location.basic.FixedListMachineProvisioningLocation; import brooklyn.location.basic.LocationPredicates; import brooklyn.location.basic.SshMachineLocation; import brooklyn.location.basic.WinRmMachineLocation; import brooklyn.util.net.UserAndHostAndPort; -import com.google.api.client.repackaged.com.google.common.base.Joiner; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; - public class ByonLocationsYamlTest extends AbstractYamlTest { private static final Logger log = LoggerFactory.getLogger(ByonLocationsYamlTest.class); @@ -165,7 +168,56 @@ public class ByonLocationsYamlTest extends AbstractYamlTest { "mykey", "myval3")); assertEquals(machine3.getPrivateAddresses(), ImmutableSet.of("10.0.0.3")); } - + + @Test + @SuppressWarnings("unchecked") + public void testByonPortMapping() throws Exception { + String yaml = Joiner.on("\n").join( + "location:", + " byon:", + " hosts:", + " - ssh: 1.1.1.1:22", + " privateAddresses: [10.0.0.1]", + " tcpPortMappings: {22: \"83.222.229.1:12001\", 8080: \"83.222.229.1:12002\"}", + " password: mypassword", + " user: myuser", + " mykey: myval1", + " - winrm: 1.1.1.2:8985", + " privateAddresses: [10.0.0.2]", + " tcpPortMappings: {8985: \"83.222.229.2:12003\", 8080: \"83.222.229.2:12004\"}", + " password: mypassword", + " user: myuser", + " mykey: myval2", + " osfamily: windows", + "services:", + "- serviceType: brooklyn.entity.basic.BasicApplication"); + + Entity app = createStartWaitAndLogApplication(new StringReader(yaml)); + FixedListMachineProvisioningLocation<MachineLocation> loc = (FixedListMachineProvisioningLocation<MachineLocation>) Iterables.get(app.getLocations(), 0); + PortForwardManager pfm = (PortForwardManager) mgmt().getLocationRegistry().resolve("portForwardManager(scope=global)"); + + Set<MachineLocation> machines = loc.getAvailable(); + assertEquals(machines.size(), 2, "machines="+machines); + SshMachineLocation machine1 = (SshMachineLocation) Iterables.find(machines, LocationPredicates.configEqualTo(ConfigKeys.newStringConfigKey("mykey"), "myval1")); + WinRmMachineLocation machine2 = (WinRmMachineLocation) Iterables.find(machines, Predicates.instanceOf(WinRmMachineLocation.class)); + + assertMachine(machine1, UserAndHostAndPort.fromParts("myuser", "83.222.229.1", 12001), ImmutableMap.of( + SshMachineLocation.PASSWORD.getName(), "mypassword", + "mykey", "myval1")); + assertEquals(machine1.getPrivateAddresses(), ImmutableSet.of("10.0.0.1")); + assertEquals(pfm.lookup(machine1, 22), HostAndPort.fromParts("83.222.229.1", 12001)); + assertEquals(pfm.lookup(machine1, 8080), HostAndPort.fromParts("83.222.229.1", 12002)); + assertNull(pfm.lookup(machine1, 12345)); + + assertMachine(machine2, UserAndHostAndPort.fromParts("myuser", "83.222.229.2", 12003), ImmutableMap.of( + SshMachineLocation.PASSWORD.getName(), "mypassword", + "mykey", "myval2")); + assertEquals(machine2.getPrivateAddresses(), ImmutableSet.of("10.0.0.2")); + assertEquals(pfm.lookup(machine2, 8985), HostAndPort.fromParts("83.222.229.2", 12003)); + assertEquals(pfm.lookup(machine2, 8080), HostAndPort.fromParts("83.222.229.2", 12004)); + assertNull(pfm.lookup(machine2, 12345)); + } + private void assertMachine(SshMachineLocation machine, UserAndHostAndPort conn, Map<String, ?> config) { assertEquals(machine.getAddress().getHostAddress(), conn.getHostAndPort().getHostText()); assertEquals(machine.getPort(), conn.getHostAndPort().getPort());
