You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/14 05:43:05 UTC
[36/54] incubator-brooklyn git commit: [BROOKLYN-162] Renaming
package brooklyn.location
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/ResourceUtils.java b/core/src/main/java/brooklyn/util/ResourceUtils.java
index a39f363..cb350af 100644
--- a/core/src/main/java/brooklyn/util/ResourceUtils.java
+++ b/core/src/main/java/brooklyn/util/ResourceUtils.java
@@ -53,7 +53,7 @@ import org.slf4j.LoggerFactory;
import brooklyn.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
import brooklyn.catalog.internal.CatalogUtils;
import brooklyn.internal.BrooklynInitialization;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.management.classloading.JavaBrooklynClassLoadingContext;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.exceptions.Exceptions;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/file/ArchiveTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/file/ArchiveTasks.java b/core/src/main/java/brooklyn/util/file/ArchiveTasks.java
index 9c6ed2f..b183f62 100644
--- a/core/src/main/java/brooklyn/util/file/ArchiveTasks.java
+++ b/core/src/main/java/brooklyn/util/file/ArchiveTasks.java
@@ -23,7 +23,7 @@ import java.util.Map;
import org.apache.brooklyn.api.management.TaskAdaptable;
import org.apache.brooklyn.api.management.TaskFactory;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.ResourceUtils;
import brooklyn.util.net.Urls;
import brooklyn.util.task.Tasks;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/file/ArchiveUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/file/ArchiveUtils.java b/core/src/main/java/brooklyn/util/file/ArchiveUtils.java
index e8233c2..d072b70 100644
--- a/core/src/main/java/brooklyn/util/file/ArchiveUtils.java
+++ b/core/src/main/java/brooklyn/util/file/ArchiveUtils.java
@@ -31,7 +31,7 @@ import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.ResourceUtils;
import brooklyn.util.collections.MutableList;
import brooklyn.util.collections.MutableMap;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java
index 31f654c..bd9e96e 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java
@@ -22,7 +22,7 @@ import org.apache.brooklyn.api.management.TaskFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.config.ConfigBag;
// cannot be (cleanly) instantiated due to nested generic self-referential type; however trivial subclasses do allow it
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java b/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java
index 1d265dc..9553b4f 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.api.management.TaskWrapper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.config.ConfigBag;
import brooklyn.util.exceptions.Exceptions;
import brooklyn.util.os.Os;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java
index 381341a..e2c5502 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java
@@ -25,7 +25,7 @@ import org.apache.brooklyn.api.management.TaskFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.stream.KnownSizeInputStream;
import brooklyn.util.stream.ReaderInputStream;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java b/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java
index ec99dc8..185e819 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java
@@ -20,7 +20,7 @@ package brooklyn.util.task.ssh;
import java.io.InputStream;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.config.ConfigBag;
import com.google.common.base.Supplier;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
index bf01bfe..b13b43c 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
@@ -35,10 +35,10 @@ import brooklyn.config.ConfigKey;
import brooklyn.config.ConfigUtils;
import brooklyn.entity.basic.BrooklynTaskTags;
import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.location.Location;
-import brooklyn.location.basic.AbstractLocation;
-import brooklyn.location.basic.LocationInternal;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.location.basic.AbstractLocation;
+import org.apache.brooklyn.location.basic.LocationInternal;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.ResourceUtils;
import brooklyn.util.config.ConfigBag;
import brooklyn.util.internal.ssh.SshTool;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java
index c78ce5d..86764f3 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java
@@ -20,7 +20,7 @@ package brooklyn.util.task.ssh.internal;
import com.google.common.base.Preconditions;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.config.ConfigBag;
import brooklyn.util.task.system.ProcessTaskFactory;
import brooklyn.util.task.system.ProcessTaskWrapper;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java
index a7c6994..efc14db 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java
@@ -20,8 +20,7 @@ package brooklyn.util.task.ssh.internal;
import java.util.List;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.task.system.ProcessTaskWrapper;
import com.google.common.base.Function;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java b/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java
index f43e47a..407111c 100644
--- a/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java
+++ b/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java
@@ -23,7 +23,7 @@ import java.util.Map;
import org.apache.brooklyn.api.management.TaskFactory;
import brooklyn.config.ConfigKey;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.internal.ssh.SshTool;
import brooklyn.util.task.system.ProcessTaskStub.ScriptReturnType;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java b/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java
index 9fd19e7..df37691 100644
--- a/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java
+++ b/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java
@@ -22,7 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.config.ConfigBag;
import brooklyn.util.text.Strings;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java b/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java
index 5aa84c0..e41a9a9 100644
--- a/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java
+++ b/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java
@@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
import brooklyn.config.ConfigKey;
import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.stream.Streams;
import brooklyn.util.task.TaskBuilder;
import brooklyn.util.task.system.ProcessTaskFactory;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java b/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java
index f39d7b6..c2b8907 100644
--- a/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java
+++ b/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java
@@ -28,7 +28,7 @@ import java.util.Map;
import org.slf4j.Logger;
import brooklyn.config.ConfigKey;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.config.ConfigBag;
import brooklyn.util.flags.TypeCoercions;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java b/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java
index 9b40c7f..e6eb831 100644
--- a/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java
+++ b/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java
@@ -23,7 +23,7 @@ import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.config.ConfigBag;
import brooklyn.util.internal.ssh.ShellTool;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/util/text/TemplateProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/text/TemplateProcessor.java b/core/src/main/java/brooklyn/util/text/TemplateProcessor.java
index 8fdaebb..f936e93 100644
--- a/core/src/main/java/brooklyn/util/text/TemplateProcessor.java
+++ b/core/src/main/java/brooklyn/util/text/TemplateProcessor.java
@@ -37,7 +37,7 @@ import brooklyn.entity.basic.Entities;
import brooklyn.entity.basic.EntityInternal;
import brooklyn.event.basic.DependentConfiguration;
import brooklyn.event.basic.Sensors;
-import brooklyn.location.Location;
+import org.apache.brooklyn.location.Location;
import brooklyn.management.internal.ManagementContextInternal;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.exceptions.Exceptions;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java b/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java
new file mode 100644
index 0000000..eebee14
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java
@@ -0,0 +1,143 @@
+/*
+ * 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 org.apache.brooklyn.location.access;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.location.Location;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.event.basic.BasicConfigKey;
+import org.apache.brooklyn.location.MachineLocation;
+import org.apache.brooklyn.location.basic.Machines;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.basic.SupportsPortForwarding;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.net.Cidr;
+import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.Tasks;
+import brooklyn.util.task.ssh.SshTasks;
+import brooklyn.util.task.system.ProcessTaskWrapper;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Supplier;
+import com.google.common.net.HostAndPort;
+
+public class BrooklynAccessUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(BrooklynAccessUtils.class);
+
+ public static final ConfigKey<PortForwardManager> PORT_FORWARDING_MANAGER = new BasicConfigKey<PortForwardManager>(
+ PortForwardManager.class, "brooklyn.portforwarding.manager", "A port-forwarding manager to use at an entity "
+ + "or a location, where supported; note this should normally be a serializable client instance to prevent "
+ + "the creation of multiple disconnected instances via config duplication");
+
+ public static final ConfigKey<Cidr> MANAGEMENT_ACCESS_CIDR = new BasicConfigKey<Cidr>(
+ Cidr.class, "brooklyn.portforwarding.management.cidr", "CIDR to enable by default for port-forwarding for management",
+ null); // TODO should be a list
+
+ public static HostAndPort getBrooklynAccessibleAddress(Entity entity, int port) {
+ String host;
+
+ // look up port forwarding
+ PortForwardManager pfw = entity.getConfig(PORT_FORWARDING_MANAGER);
+ if (pfw!=null) {
+ Collection<Location> ll = entity.getLocations();
+ Maybe<SupportsPortForwarding> machine = Machines.findUniqueElement(ll, SupportsPortForwarding.class);
+ if (machine.isPresent()) {
+ synchronized (BrooklynAccessUtils.class) {
+ // TODO finer-grained synchronization
+
+ HostAndPort hp = pfw.lookup((MachineLocation)machine.get(), port);
+ if (hp!=null) return hp;
+
+ Location l = (Location) machine.get();
+ if (l instanceof SupportsPortForwarding) {
+ Cidr source = entity.getConfig(MANAGEMENT_ACCESS_CIDR);
+ if (source!=null) {
+ log.debug("BrooklynAccessUtils requesting new port-forwarding rule to access "+port+" on "+entity+" (at "+l+", enabled for "+source+")");
+ // TODO discuss, is this the best way to do it
+ // (will probably _create_ the port forwarding rule!)
+ hp = ((SupportsPortForwarding) l).getSocketEndpointFor(source, port);
+ if (hp!=null) return hp;
+ } else {
+ log.warn("No "+MANAGEMENT_ACCESS_CIDR.getName()+" configured for "+entity+", so cannot forward port "+port+" " +
+ "even though "+PORT_FORWARDING_MANAGER.getName()+" was supplied");
+ }
+ }
+ }
+ }
+ }
+
+ host = entity.getAttribute(Attributes.HOSTNAME);
+ if (host!=null) return HostAndPort.fromParts(host, port);
+
+ throw new IllegalStateException("Cannot find way to access port "+port+" on "+entity+" from Brooklyn (no host.name)");
+ }
+
+ /** attempts to resolve hostnameTarget from origin
+ * @return null if it definitively can't be resolved,
+ * best-effort IP address if possible, or blank if we could not run ssh or make sense of the output */
+ public static String getResolvedAddress(Entity entity, SshMachineLocation origin, String hostnameTarget) {
+ ProcessTaskWrapper<Integer> task = SshTasks.newSshExecTaskFactory(origin, "ping -c 1 -t 1 "+hostnameTarget)
+ .summary("checking resolution of "+hostnameTarget).allowingNonZeroExitCode().newTask();
+ DynamicTasks.queueIfPossible(task).orSubmitAndBlock(entity).asTask().blockUntilEnded();
+ if (task.asTask().isError()) {
+ log.warn("ping could not be run, at "+entity+" / "+origin+": "+Tasks.getError(task.asTask()));
+ return "";
+ }
+ if (task.getExitCode()==null || task.getExitCode()!=0) {
+ if (task.getExitCode()!=null && task.getExitCode()<10) {
+ // small number means ping failed to resolve or ping the hostname
+ log.debug("not able to resolve "+hostnameTarget+" from "+origin+" for "+entity+" because exit code was "+task.getExitCode());
+ return null;
+ }
+ // large number means ping probably did not run
+ log.warn("ping not run as expected, at "+entity+" / "+origin+" (code "+task.getExitCode()+"):\n"+task.getStdout().trim()+" --- "+task.getStderr().trim());
+ return "";
+ }
+ String out = task.getStdout();
+ try {
+ String line1 = Strings.getFirstLine(out);
+ String ip = Strings.getFragmentBetween(line1, "(", ")");
+ if (Strings.isNonBlank(ip))
+ return ip;
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ /* ignore non-parseable output */
+ }
+ if (out.contains("127.0.0.1")) return "127.0.0.1";
+ return "";
+ }
+
+ public static Supplier<String> resolvedAddressSupplier(final Entity entity, final SshMachineLocation origin, final String hostnameTarget) {
+ return new Supplier<String>() {
+ @Override
+ public String get() {
+ return getResolvedAddress(entity, origin, hostnameTarget);
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManager.java b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManager.java
new file mode 100644
index 0000000..922231b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManager.java
@@ -0,0 +1,327 @@
+/*
+ * 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 org.apache.brooklyn.location.access;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import org.apache.brooklyn.location.Location;
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.net.HostAndPort;
+
+import java.util.Collection;
+
+/**
+ * Acts as a registry for existing port mappings (e.g. the public endpoints for accessing specific
+ * ports on private VMs). This could be using DNAT, or iptables port-forwarding, or Docker port-mapping
+ * via the host, or any other port mapping approach.
+ *
+ * Also controls the allocation of ports via {@link #acquirePublicPort(String)}
+ * (e.g. for port-mapping with DNAT, then which port to use for the public side).
+ *
+ * Implementations typically will not know anything about what the firewall/IP actually is, they just
+ * handle a unique identifier for it.
+ *
+ * To use, see {@link PortForwardManagerLocationResolver}, with code such as
+ * {@code managementContext.getLocationRegistry().resolve("portForwardManager(scope=global)")}.
+ *
+ * @see PortForwardManagerImpl for implementation notes and considerations.
+ */
+@Beta
+public interface PortForwardManager extends Location {
+
+ @Beta
+ class AssociationMetadata {
+ private final String publicIpId;
+ private final HostAndPort publicEndpoint;
+ private final Location location;
+ private final int privatePort;
+
+ /**
+ * Users are discouraged from calling this constructor; the signature may change in future releases.
+ * Instead, instances will be created automatically by Brooklyn to be passed to the
+ * {@link AssociationListener#onAssociationCreated(AssociationMetadata)} method.
+ */
+ public AssociationMetadata(String publicIpId, HostAndPort publicEndpoint, Location location, int privatePort) {
+ this.publicIpId = publicIpId;
+ this.publicEndpoint = publicEndpoint;
+ this.location = location;
+ this.privatePort = privatePort;
+ }
+
+ public String getPublicIpId() {
+ return publicIpId;
+ }
+
+ public HostAndPort getPublicEndpoint() {
+ return publicEndpoint;
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+
+ public int getPrivatePort() {
+ return privatePort;
+ }
+
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("publicIpId", publicIpId)
+ .add("publicEndpoint", publicEndpoint)
+ .add("location", location)
+ .add("privatePort", privatePort)
+ .toString();
+ }
+ }
+
+ @Beta
+ interface AssociationListener {
+ void onAssociationCreated(AssociationMetadata metadata);
+ void onAssociationDeleted(AssociationMetadata metadata);
+ }
+
+ /**
+ * The intention is that there is one PortForwardManager instance per "scope". If you
+ * use global, then it will be a shared instance (for that management context). If you
+ * pass in your own name (e.g. "docker-fjie3") then it will shared with just any other
+ * places that use that same location spec (e.g. {@code portForwardManager(scope=docker-fjie3)}).
+ */
+ // TODO Note: using name "scope" rather than "brooklyn.portForwardManager.scope" so that location spec
+ // "portForwardManager(scope=global)" works, rather than having to do
+ // portForwardManager(brooklyn.portForwardManager.scope=global).
+ // The config being read by the PortForwardManagerLocationResolver doesn't respect @SetFromFlag("scope").
+ public static final ConfigKey<String> SCOPE = ConfigKeys.newStringConfigKey(
+ "scope",
+ "The scope that this applies to, defaulting to global",
+ "global");
+
+ @Beta
+ public static final ConfigKey<Integer> PORT_FORWARD_MANAGER_STARTING_PORT = ConfigKeys.newIntegerConfigKey(
+ "brooklyn.portForwardManager.startingPort",
+ "The starting port for assigning port numbers, such as for DNAT",
+ 11000);
+
+ public String getScope();
+
+ /**
+ * Reserves a unique public port on the given publicIpId.
+ * <p>
+ * Often followed by {@link #associate(String, HostAndPort, int)} or {@link #associate(String, HostAndPort, Location, int)}
+ * to enable {@link #lookup(String, int)} or {@link #lookup(Location, int)} respectively.
+ */
+ public int acquirePublicPort(String publicIpId);
+
+ /**
+ * Records a location and private port against a public endpoint (ip and port),
+ * to support {@link #lookup(Location, int)}.
+ * <p>
+ * Superfluous if {@link #acquirePublicPort(String, Location, int)} was used,
+ * but strongly recommended if {@link #acquirePublicPortExplicit(String, int)} was used
+ * e.g. if the location is not known ahead of time.
+ */
+ public void associate(String publicIpId, HostAndPort publicEndpoint, Location l, int privatePort);
+
+ /**
+ * Records a mapping for publicIpId:privatePort to a public endpoint, such that it can
+ * subsequently be looked up using {@link #lookup(String, int)}.
+ */
+ public void associate(String publicIpId, HostAndPort publicEndpoint, int privatePort);
+
+ /**
+ * Registers a listener, which will be notified each time a new port mapping is associated. See {@link #associate(String, HostAndPort, int)}
+ * and {@link #associate(String, HostAndPort, Location, int)}.
+ */
+ @Beta
+ public void addAssociationListener(AssociationListener listener, Predicate<? super AssociationMetadata> filter);
+
+ @Beta
+ public void removeAssociationListener(AssociationListener listener);
+
+ /**
+ * Returns the public ip hostname and public port for use contacting the given endpoint.
+ * <p>
+ * Will return null if:
+ * <ul>
+ * <li>No publicPort is associated with this location and private port.
+ * <li>No publicIpId is associated with this location and private port.
+ * <li>No publicIpHostname is recorded against the associated publicIpId.
+ * </ul>
+ * Conceivably this may have to be access-location specific.
+ *
+ * @see #recordPublicIpHostname(String, String)
+ */
+ public HostAndPort lookup(Location l, int privatePort);
+
+ /**
+ * Returns the public endpoint (host and port) for use contacting the given endpoint.
+ *
+ * Expects a previous call to {@link #associate(String, HostAndPort, int)}, to register
+ * the endpoint.
+ *
+ * Will return null if there has not been a public endpoint associated with this pairing.
+ */
+ public HostAndPort lookup(String publicIpId, int privatePort);
+
+ /**
+ * Clears the given port mapping, returning true if there was a match.
+ */
+ public boolean forgetPortMapping(String publicIpId, int publicPort);
+
+ /**
+ * Clears the port mappings associated with the given location, returning true if there were any matches.
+ */
+ public boolean forgetPortMappings(Location location);
+
+ /**
+ * Clears the port mappings associated with the given publicIpId, returning true if there were any matches.
+ */
+ public boolean forgetPortMappings(String publicIpId);
+
+ public String toVerboseString();
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Deprecated
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Reserves a unique public port for the purpose of forwarding to the given target,
+ * associated with a given location for subsequent lookup purpose.
+ * <p>
+ * If already allocated, returns the previously allocated.
+ *
+ * @deprecated since 0.7.0; use {@link #acquirePublicPort(String)}, and then use {@link #associate(String, HostAndPort, int)} or {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Deprecated
+ public int acquirePublicPort(String publicIpId, Location l, int privatePort);
+
+ /**
+ * Returns old mapping if it existed, null if it is new.
+ *
+ * @deprecated since 0.7.0; use {@link #associate(String, HostAndPort, int)} or {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Deprecated
+ public PortMapping acquirePublicPortExplicit(String publicIpId, int port);
+
+ /**
+ * Records a location and private port against a publicIp and public port,
+ * to support {@link #lookup(Location, int)}.
+ * <p>
+ * Superfluous if {@link #acquirePublicPort(String, Location, int)} was used,
+ * but strongly recommended if {@link #acquirePublicPortExplicit(String, int)} was used
+ * e.g. if the location is not known ahead of time.
+ *
+ * @deprecated Use {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Deprecated
+ public void associate(String publicIpId, int publicPort, Location l, int privatePort);
+
+ /**
+ * Records a public hostname or address to be associated with the given publicIpId for lookup purposes.
+ * <p>
+ * Conceivably this may have to be access-location specific.
+ *
+ * @deprecated Use {@link #associate(String, HostAndPort, int)} or {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Deprecated
+ public void recordPublicIpHostname(String publicIpId, String hostnameOrPublicIpAddress);
+
+ /**
+ * Returns a recorded public hostname or address.
+ *
+ * @deprecated Use {@link #lookup(String, int)} or {@link #lookup(Location, int)}
+ */
+ @Deprecated
+ public String getPublicIpHostname(String publicIpId);
+
+ /**
+ * Clears a previous call to {@link #recordPublicIpHostname(String, String)}.
+ *
+ * @deprecated Use {@link #forgetPortMapping(String, int)} or {@link #forgetPortMappings(Location)}
+ */
+ @Deprecated
+ public boolean forgetPublicIpHostname(String publicIpId);
+
+ /**
+ * Returns true if this implementation is a client which is immutable/safe for serialization
+ * i.e. it delegates to something on an entity or location elsewhere.
+ *
+ * @deprecated since 0.7.0; no need to separate client-proxy from impl
+ */
+ @Deprecated
+ public boolean isClient();
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Deprecated; just internal
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the port mapping for a given publicIpId and public port.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Deprecated
+ public PortMapping getPortMappingWithPublicSide(String publicIpId, int publicPort);
+
+ /**
+ * Returns the subset of port mappings associated with a given public IP ID.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Deprecated
+ public Collection<PortMapping> getPortMappingWithPublicIpId(String publicIpId);
+
+ /**
+ * @see {@link #forgetPortMapping(String, int)} and {@link #forgetPortMappings(Location)}
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Deprecated
+ public boolean forgetPortMapping(PortMapping m);
+
+ /**
+ * Returns the public host and port for use accessing the given mapping.
+ * <p>
+ * Conceivably this may have to be access-location specific.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Deprecated
+ public HostAndPort getPublicHostAndPort(PortMapping m);
+
+ /**
+ * Returns the subset of port mappings associated with a given location.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Deprecated
+ public Collection<PortMapping> getLocationPublicIpIds(Location l);
+
+ /**
+ * Returns the mapping to a given private port, or null if none.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Deprecated
+ public PortMapping getPortMappingWithPrivateSide(Location l, int privatePort);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerAuthority.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerAuthority.java b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerAuthority.java
new file mode 100644
index 0000000..da7d098
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerAuthority.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.apache.brooklyn.location.access;
+
+
+import org.apache.brooklyn.api.entity.Entity;
+
+import brooklyn.entity.basic.EntityInternal;
+
+/**
+ * @deprecated since 0.7.0; use {@link PortForwardManagerImpl}
+ */
+@Deprecated
+public class PortForwardManagerAuthority extends PortForwardManagerImpl {
+ private Entity owningEntity;
+
+ public PortForwardManagerAuthority() {
+ }
+
+ public PortForwardManagerAuthority(Entity owningEntity) {
+ this.owningEntity = owningEntity;
+ }
+
+ protected void onChanged() {
+ if (owningEntity != null) {
+ ((EntityInternal) owningEntity).requestPersist();
+ } else {
+ super.onChanged();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerClient.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerClient.java b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerClient.java
new file mode 100644
index 0000000..09aea72
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerClient.java
@@ -0,0 +1,406 @@
+/*
+ * 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 org.apache.brooklyn.location.access;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.event.AttributeSensor;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+import org.apache.brooklyn.location.Location;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.net.HostAndPort;
+
+/**
+ * @deprecated since 0.7.0; just use the {@link PortForwardManager}, or a direct reference to its impl {@link PortForwardManagerImpl}
+ */
+@Deprecated
+public class PortForwardManagerClient implements PortForwardManager {
+
+ private static final long serialVersionUID = -295204304305332895L;
+
+ protected final Supplier<PortForwardManager> delegateSupplier;
+ private transient volatile PortForwardManager _delegate;
+
+ protected PortForwardManagerClient(Supplier<PortForwardManager> supplier) {
+ this.delegateSupplier = supplier;
+ }
+
+ /** creates an instance given a supplier;
+ * the supplier should be brooklyn-persistable, that is to say
+ * references should be in terms of entities/locations
+ * which can retrieve an authoritative source even under cloning */
+ public static PortForwardManager fromSupplier(Supplier<PortForwardManager> supplier) {
+ return new PortForwardManagerClient(supplier);
+ }
+
+ /** creates an instance given an entity and an interface method it implements to retrieve the PortForwardManager */
+ public static PortForwardManager fromMethodOnEntity(final Entity entity, final String getterMethodOnEntity) {
+ Preconditions.checkNotNull(entity);
+ Preconditions.checkNotNull(getterMethodOnEntity);
+ return new PortForwardManagerClient(new Supplier<PortForwardManager>() {
+ @Override
+ public PortForwardManager get() {
+ PortForwardManager result;
+ try {
+ result = (PortForwardManager) entity.getClass().getMethod(getterMethodOnEntity).invoke(entity);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ throw new IllegalStateException("Cannot invoke "+getterMethodOnEntity+" on "+entity+" ("+entity.getClass()+"): "+e, e);
+ }
+ if (result==null)
+ throw new IllegalStateException("No PortForwardManager available via "+getterMethodOnEntity+" on "+entity+" (returned null)");
+ return result;
+ }
+ });
+ }
+
+ /** creates an instance given an entity and {@link AttributeSensor} to retrieve the PortForwardManager */
+ public static PortForwardManager fromAttributeOnEntity(final Entity entity, final AttributeSensor<PortForwardManager> attributeOnEntity) {
+ Preconditions.checkNotNull(entity);
+ Preconditions.checkNotNull(attributeOnEntity);
+ return new PortForwardManagerClient(new Supplier<PortForwardManager>() {
+ @Override
+ public PortForwardManager get() {
+ PortForwardManager result = entity.getAttribute(attributeOnEntity);
+ if (result==null)
+ throw new IllegalStateException("No PortForwardManager available via "+attributeOnEntity+" on "+entity+" (returned null)");
+ return result;
+ }
+ });
+ }
+
+ protected PortForwardManager getDelegate() {
+ if (_delegate==null) {
+ _delegate = delegateSupplier.get();
+ }
+ return _delegate;
+ }
+
+ @Override
+ public int acquirePublicPort(String publicIpId) {
+ return getDelegate().acquirePublicPort(publicIpId);
+ }
+
+ @Override
+ public void associate(String publicIpId, HostAndPort publicEndpoint, Location l, int privatePort) {
+ getDelegate().associate(publicIpId, publicEndpoint, l, privatePort);
+ }
+
+ @Override
+ public void associate(String publicIpId, HostAndPort publicEndpoint, int privatePort) {
+ getDelegate().associate(publicIpId, publicEndpoint, privatePort);
+ }
+
+ @Override
+ public HostAndPort lookup(Location l, int privatePort) {
+ return getDelegate().lookup(l, privatePort);
+ }
+
+ @Override
+ public HostAndPort lookup(String publicIpId, int privatePort) {
+ return getDelegate().lookup(publicIpId, privatePort);
+ }
+
+ @Override
+ public boolean forgetPortMapping(String publicIpId, int publicPort) {
+ return getDelegate().forgetPortMapping(publicIpId, publicPort);
+ }
+
+ @Override
+ public boolean forgetPortMappings(Location location) {
+ return getDelegate().forgetPortMappings(location);
+ }
+
+ @Override
+ public boolean forgetPortMappings(String publicIpId) {
+ return getDelegate().forgetPortMappings(publicIpId);
+ }
+
+ @Override
+ public String getId() {
+ return getDelegate().getId();
+ }
+
+ @Override
+ public String getScope() {
+ return getDelegate().getScope();
+ }
+
+ @Override
+ public void addAssociationListener(AssociationListener listener, Predicate<? super AssociationMetadata> filter) {
+ getDelegate().addAssociationListener(listener, filter);
+ }
+
+ @Override
+ public void removeAssociationListener(AssociationListener listener) {
+ getDelegate().removeAssociationListener(listener);
+ }
+
+ @Override
+ public String toVerboseString() {
+ return getClass().getName()+"[wrapping="+getDelegate().toVerboseString()+"]";
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Deprecated
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Reserves a unique public port for the purpose of forwarding to the given target,
+ * associated with a given location for subsequent lookup purpose.
+ * <p>
+ * If already allocated, returns the previously allocated.
+ *
+ * @deprecated since 0.7.0; use {@link #acquirePublicPort(String)}, and then use {@link #associate(String, HostAndPort, int)} or {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Override
+ @Deprecated
+ public int acquirePublicPort(String publicIpId, Location l, int privatePort) {
+ return getDelegate().acquirePublicPort(publicIpId, l, privatePort);
+ }
+
+ /**
+ * Returns old mapping if it existed, null if it is new.
+ *
+ * @deprecated since 0.7.0; use {@link #associate(String, HostAndPort, int)} or {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Override
+ @Deprecated
+ public PortMapping acquirePublicPortExplicit(String publicIpId, int publicPort) {
+ return getDelegate().acquirePublicPortExplicit(publicIpId, publicPort);
+ }
+
+ /**
+ * Records a location and private port against a publicIp and public port,
+ * to support {@link #lookup(Location, int)}.
+ * <p>
+ * Superfluous if {@link #acquirePublicPort(String, Location, int)} was used,
+ * but strongly recommended if {@link #acquirePublicPortExplicit(String, int)} was used
+ * e.g. if the location is not known ahead of time.
+ *
+ * @deprecated Use {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Override
+ @Deprecated
+ public void associate(String publicIpId, int publicPort, Location l, int privatePort) {
+ getDelegate().associate(publicIpId, publicPort, l, privatePort);
+ }
+
+ /**
+ * Records a public hostname or address to be associated with the given publicIpId for lookup purposes.
+ * <p>
+ * Conceivably this may have to be access-location specific.
+ *
+ * @deprecated Use {@link #associate(String, HostAndPort, int)} or {@link #associate(String, HostAndPort, Location, int)}
+ */
+ @Override
+ @Deprecated
+ public void recordPublicIpHostname(String publicIpId, String hostnameOrPublicIpAddress) {
+ getDelegate().recordPublicIpHostname(publicIpId, hostnameOrPublicIpAddress);
+ }
+
+ /**
+ * Returns a recorded public hostname or address.
+ *
+ * @deprecated Use {@link #lookup(String, int)} or {@link #lookup(Location, int)}
+ */
+ @Override
+ @Deprecated
+ public String getPublicIpHostname(String publicIpId) {
+ return getDelegate().getPublicIpHostname(publicIpId);
+ }
+
+ /**
+ * Clears a previous call to {@link #recordPublicIpHostname(String, String)}.
+ *
+ * @deprecated Use {@link #forgetPortMapping(String, int)} or {@link #forgetPortMapping(Location, int)}
+ */
+ @Override
+ @Deprecated
+ public boolean forgetPublicIpHostname(String publicIpId) {
+ return getDelegate().forgetPublicIpHostname(publicIpId);
+ }
+
+ @Override
+ @Deprecated
+ public boolean isClient() {
+ return true;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Deprecated; just internal
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the port mapping for a given publicIpId and public port.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Override
+ @Deprecated
+ public PortMapping getPortMappingWithPublicSide(String publicIpId, int publicPort) {
+ return getDelegate().getPortMappingWithPublicSide(publicIpId, publicPort);
+ }
+
+ /**
+ * Returns the subset of port mappings associated with a given public IP ID.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Override
+ @Deprecated
+ public Collection<PortMapping> getPortMappingWithPublicIpId(String publicIpId) {
+ return getDelegate().getPortMappingWithPublicIpId(publicIpId);
+ }
+
+ /**
+ * @see #forgetPortMapping(String, int)
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Override
+ @Deprecated
+ public boolean forgetPortMapping(PortMapping m) {
+ return getDelegate().forgetPortMapping(m);
+ }
+
+ /**
+ * Returns the public host and port for use accessing the given mapping.
+ * <p>
+ * Conceivably this may have to be access-location specific.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Override
+ @Deprecated
+ public HostAndPort getPublicHostAndPort(PortMapping m) {
+ return getDelegate().getPublicHostAndPort(m);
+ }
+
+ /**
+ * Returns the subset of port mappings associated with a given location.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Override
+ @Deprecated
+ public Collection<PortMapping> getLocationPublicIpIds(Location l) {
+ return getDelegate().getLocationPublicIpIds(l);
+ }
+
+ /**
+ * Returns the mapping to a given private port, or null if none.
+ *
+ * @deprecated since 0.7.0; this method will be internal only
+ */
+ @Override
+ @Deprecated
+ public PortMapping getPortMappingWithPrivateSide(Location l, int privatePort) {
+ return getDelegate().getPortMappingWithPrivateSide(l, privatePort);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName()+"[id="+getId()+"]";
+ }
+
+ @Override
+ public String getDisplayName() {
+ return getDelegate().getDisplayName();
+ }
+
+ @Override
+ public Location getParent() {
+ return getDelegate().getParent();
+ }
+
+ @Override
+ public Collection<Location> getChildren() {
+ return getDelegate().getChildren();
+ }
+
+ @Override
+ public void setParent(Location newParent) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean containsLocation(Location potentialDescendent) {
+ return getDelegate().containsLocation(potentialDescendent);
+ }
+
+ @Override
+ public <T> T getConfig(ConfigKey<T> key) {
+ return getDelegate().getConfig(key);
+ }
+
+ @Override
+ public <T> T getConfig(HasConfigKey<T> key) {
+ return getDelegate().getConfig(key);
+ }
+
+ @Override
+ public boolean hasConfig(ConfigKey<?> key, boolean includeInherited) {
+ return getDelegate().hasConfig(key, includeInherited);
+ }
+
+ @Override
+ public Map<String, Object> getAllConfig(boolean includeInherited) {
+ return getDelegate().getAllConfig(includeInherited);
+ }
+
+ @Override
+ public boolean hasExtension(Class<?> extensionType) {
+ return getDelegate().hasExtension(extensionType);
+ }
+
+ @Override
+ public <T> T getExtension(Class<T> extensionType) {
+ return getDelegate().getExtension(extensionType);
+ }
+
+ @Override
+ public String getCatalogItemId() {
+ return getDelegate().getCatalogItemId();
+ }
+
+ @Override
+ public TagSupport tags() {
+ return getDelegate().tags();
+ }
+
+ @Override
+ public <T> T setConfig(ConfigKey<T> key, T val) {
+ return getDelegate().setConfig(key, val);
+ }
+
+ @Override
+ public ConfigurationSupport config() {
+ return getDelegate().config();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerImpl.java b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerImpl.java
new file mode 100644
index 0000000..6493f30
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerImpl.java
@@ -0,0 +1,506 @@
+/*
+ * 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 org.apache.brooklyn.location.access;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.entity.rebind.RebindContext;
+import org.apache.brooklyn.api.entity.rebind.RebindSupport;
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.location.basic.AbstractLocation;
+import org.apache.brooklyn.mementos.LocationMemento;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.rebind.BasicLocationRebindSupport;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.net.HostAndPort;
+
+/**
+ *
+ * @author aled
+ *
+ * TODO This implementation is not efficient, and currently has a cap of about 50000 rules.
+ * Need to improve the efficiency and scale.
+ * A quick win could be to use a different portReserved counter for each publicIpId,
+ * when calling acquirePublicPort?
+ *
+ * TODO Callers need to be more careful in acquirePublicPort for which ports are actually in use.
+ * If multiple apps sharing the same public-ip (e.g. in the same vcloud-director vOrg) then they
+ * must not allocate the same public port (e.g. ensure they share the same PortForwardManager
+ * by using the same scope in
+ * {@code managementContext.getLocationRegistry().resolve("portForwardManager(scope=global)")}.
+ * However, this still doesn't check if the port is *actually* available. For example, if a
+ * different Brooklyn instance is also deploying there then we can get port conflicts, or if
+ * some ports in that range are already in use (e.g. due to earlier dev/test runs) then this
+ * will not be respected. Callers should probably figure out the port number themselves, but
+ * that also leads to concurrency issues.
+ *
+ * TODO The publicIpId means different things to different callers:
+ * <ul>
+ * <li> In acquirePublicPort() it is (often?) an identifier of the actual public ip.
+ * <li> In later calls to associate(), it is (often?) an identifier for the target machine
+ * such as the jcloudsMachine.getJcloudsId().
+ * </ul>
+ */
+@SuppressWarnings("serial")
+public class PortForwardManagerImpl extends AbstractLocation implements PortForwardManager {
+
+ private static final Logger log = LoggerFactory.getLogger(PortForwardManagerImpl.class);
+
+ protected final Map<String,PortMapping> mappings = new LinkedHashMap<String,PortMapping>();
+
+ private final Map<AssociationListener, Predicate<? super AssociationMetadata>> associationListeners = new ConcurrentHashMap<AssociationListener, Predicate<? super AssociationMetadata>>();
+
+ @Deprecated
+ protected final Map<String,String> publicIpIdToHostname = new LinkedHashMap<String,String>();
+
+ // horrible hack -- see javadoc above
+ private final AtomicInteger portReserved = new AtomicInteger(11000);
+
+ private final Object mutex = new Object();
+
+ public PortForwardManagerImpl() {
+ super();
+ if (isLegacyConstruction()) {
+ log.warn("Deprecated construction of "+PortForwardManagerImpl.class.getName()+"; instead use location resolver");
+ }
+ }
+
+ @Override
+ public void init() {
+ super.init();
+ Integer portStartingPoint;
+ Object rawPort = getAllConfigBag().getStringKey(PORT_FORWARD_MANAGER_STARTING_PORT.getName());
+ if (rawPort != null) {
+ portStartingPoint = getConfig(PORT_FORWARD_MANAGER_STARTING_PORT);
+ } else {
+ portStartingPoint = getManagementContext().getConfig().getConfig(PORT_FORWARD_MANAGER_STARTING_PORT);
+ }
+ portReserved.set(portStartingPoint);
+ log.debug(this+" set initial port to "+portStartingPoint);
+ }
+
+ // TODO Need to use attributes for these so they are persisted (once a location is an entity),
+ // rather than this deprecated approach of custom fields.
+ @Override
+ public RebindSupport<LocationMemento> getRebindSupport() {
+ return new BasicLocationRebindSupport(this) {
+ @Override public LocationMemento getMemento() {
+ Map<String, PortMapping> mappingsCopy;
+ Map<String,String> publicIpIdToHostnameCopy;
+ synchronized (mutex) {
+ mappingsCopy = MutableMap.copyOf(mappings);
+ publicIpIdToHostnameCopy = MutableMap.copyOf(publicIpIdToHostname);
+ }
+ return getMementoWithProperties(MutableMap.<String,Object>of(
+ "mappings", mappingsCopy,
+ "portReserved", portReserved.get(),
+ "publicIpIdToHostname", publicIpIdToHostnameCopy));
+ }
+ @Override
+ protected void doReconstruct(RebindContext rebindContext, LocationMemento memento) {
+ super.doReconstruct(rebindContext, memento);
+ mappings.putAll( Preconditions.checkNotNull((Map<String, PortMapping>) memento.getCustomField("mappings"), "mappings was not serialized correctly"));
+ portReserved.set( (Integer)memento.getCustomField("portReserved"));
+ publicIpIdToHostname.putAll( Preconditions.checkNotNull((Map<String, String>)memento.getCustomField("publicIpIdToHostname"), "publicIpIdToHostname was not serialized correctly") );
+ }
+ };
+ }
+
+ @Override
+ public int acquirePublicPort(String publicIpId) {
+ int port;
+ synchronized (mutex) {
+ // far too simple -- see javadoc above
+ port = getNextPort();
+
+ // TODO When delete deprecated code, stop registering PortMapping until associate() is called
+ PortMapping mapping = new PortMapping(publicIpId, port, null, -1);
+ log.debug(this+" allocating public port "+port+" on "+publicIpId+" (no association info yet)");
+
+ mappings.put(makeKey(publicIpId, port), mapping);
+ }
+ onChanged();
+ return port;
+ }
+
+ protected int getNextPort() {
+ // far too simple -- see javadoc above
+ return portReserved.getAndIncrement();
+ }
+
+ @Override
+ public void associate(String publicIpId, HostAndPort publicEndpoint, Location l, int privatePort) {
+ associateImpl(publicIpId, publicEndpoint, l, privatePort);
+ emitAssociationCreatedEvent(publicIpId, publicEndpoint, l, privatePort);
+ }
+
+ @Override
+ public void associate(String publicIpId, HostAndPort publicEndpoint, int privatePort) {
+ associateImpl(publicIpId, publicEndpoint, null, privatePort);
+ emitAssociationCreatedEvent(publicIpId, publicEndpoint, null, privatePort);
+ }
+
+ protected void associateImpl(String publicIpId, HostAndPort publicEndpoint, Location l, int privatePort) {
+ synchronized (mutex) {
+ String publicIp = publicEndpoint.getHostText();
+ int publicPort = publicEndpoint.getPort();
+ recordPublicIpHostname(publicIpId, publicIp);
+ PortMapping mapping = new PortMapping(publicIpId, publicEndpoint, l, privatePort);
+ PortMapping oldMapping = getPortMappingWithPublicSide(publicIpId, publicPort);
+ log.debug(this+" associating public "+publicEndpoint+" on "+publicIpId+" with private port "+privatePort+" at "+l+" ("+mapping+")"
+ +(oldMapping == null ? "" : " (overwriting "+oldMapping+" )"));
+ mappings.put(makeKey(publicIpId, publicPort), mapping);
+ }
+ onChanged();
+ }
+
+ private void emitAssociationCreatedEvent(String publicIpId, HostAndPort publicEndpoint, Location location, int privatePort) {
+ AssociationMetadata metadata = new AssociationMetadata(publicIpId, publicEndpoint, location, privatePort);
+ for (Map.Entry<AssociationListener, Predicate<? super AssociationMetadata>> entry : associationListeners.entrySet()) {
+ if (entry.getValue().apply(metadata)) {
+ try {
+ entry.getKey().onAssociationCreated(metadata);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ log.warn("Exception thrown when emitting association creation event " + metadata, e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public HostAndPort lookup(Location l, int privatePort) {
+ synchronized (mutex) {
+ for (PortMapping m: mappings.values()) {
+ if (l.equals(m.target) && privatePort == m.privatePort)
+ return getPublicHostAndPort(m);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public HostAndPort lookup(String publicIpId, int privatePort) {
+ synchronized (mutex) {
+ for (PortMapping m: mappings.values()) {
+ if (publicIpId.equals(m.publicIpId) && privatePort==m.privatePort)
+ return getPublicHostAndPort(m);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean forgetPortMapping(String publicIpId, int publicPort) {
+ PortMapping old;
+ synchronized (mutex) {
+ old = mappings.remove(makeKey(publicIpId, publicPort));
+ if (old != null) {
+ emitAssociationDeletedEvent(associationMetadataFromPortMapping(old));
+ }
+ log.debug("cleared port mapping for "+publicIpId+":"+publicPort+" - "+old);
+ }
+ if (old != null) onChanged();
+ return (old != null);
+ }
+
+ @Override
+ public boolean forgetPortMappings(Location l) {
+ List<PortMapping> result = Lists.newArrayList();
+ synchronized (mutex) {
+ for (Iterator<PortMapping> iter = mappings.values().iterator(); iter.hasNext();) {
+ PortMapping m = iter.next();
+ if (l.equals(m.target)) {
+ iter.remove();
+ result.add(m);
+ emitAssociationDeletedEvent(associationMetadataFromPortMapping(m));
+ }
+ }
+ }
+ if (log.isDebugEnabled()) log.debug("cleared all port mappings for "+l+" - "+result);
+ if (!result.isEmpty()) {
+ onChanged();
+ }
+ return !result.isEmpty();
+ }
+
+ @Override
+ public boolean forgetPortMappings(String publicIpId) {
+ List<PortMapping> result = Lists.newArrayList();
+ synchronized (mutex) {
+ for (Iterator<PortMapping> iter = mappings.values().iterator(); iter.hasNext();) {
+ PortMapping m = iter.next();
+ if (publicIpId.equals(m.publicIpId)) {
+ iter.remove();
+ result.add(m);
+ emitAssociationDeletedEvent(associationMetadataFromPortMapping(m));
+ }
+ }
+ }
+ if (log.isDebugEnabled()) log.debug("cleared all port mappings for "+publicIpId+" - "+result);
+ if (!result.isEmpty()) {
+ onChanged();
+ }
+ return !result.isEmpty();
+ }
+
+ private void emitAssociationDeletedEvent(AssociationMetadata metadata) {
+ for (Map.Entry<AssociationListener, Predicate<? super AssociationMetadata>> entry : associationListeners.entrySet()) {
+ if (entry.getValue().apply(metadata)) {
+ try {
+ entry.getKey().onAssociationDeleted(metadata);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ log.warn("Exception thrown when emitting association creation event " + metadata, e);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected ToStringHelper string() {
+ int size;
+ synchronized (mutex) {
+ size = mappings.size();
+ }
+ return super.string().add("scope", getScope()).add("mappingsSize", size);
+ }
+
+ @Override
+ public String toVerboseString() {
+ String mappingsStr;
+ synchronized (mutex) {
+ mappingsStr = mappings.toString();
+ }
+ return string().add("mappings", mappingsStr).toString();
+ }
+
+ @Override
+ public String getScope() {
+ return checkNotNull(getConfig(SCOPE), "scope");
+ }
+
+ @Override
+ public boolean isClient() {
+ return false;
+ }
+
+ @Override
+ public void addAssociationListener(AssociationListener listener, Predicate<? super AssociationMetadata> filter) {
+ associationListeners.put(listener, filter);
+ }
+
+ @Override
+ public void removeAssociationListener(AssociationListener listener) {
+ associationListeners.remove(listener);
+ }
+
+ protected String makeKey(String publicIpId, int publicPort) {
+ return publicIpId+":"+publicPort;
+ }
+
+ private AssociationMetadata associationMetadataFromPortMapping(PortMapping portMapping) {
+ String publicIpId = portMapping.getPublicEndpoint().getHostText();
+ HostAndPort publicEndpoint = portMapping.getPublicEndpoint();
+ Location location = portMapping.getTarget();
+ int privatePort = portMapping.getPrivatePort();
+ return new AssociationMetadata(publicIpId, publicEndpoint, location, privatePort);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Internal state, for generating memento
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ public List<PortMapping> getPortMappings() {
+ synchronized (mutex) {
+ return ImmutableList.copyOf(mappings.values());
+ }
+ }
+
+ public Map<String, Integer> getPortCounters() {
+ return ImmutableMap.of("global", portReserved.get());
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Deprecated
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ @Deprecated
+ public PortMapping acquirePublicPortExplicit(String publicIpId, int port) {
+ PortMapping mapping = new PortMapping(publicIpId, port, null, -1);
+ log.debug("assigning explicit public port "+port+" at "+publicIpId);
+ PortMapping result;
+ synchronized (mutex) {
+ result = mappings.put(makeKey(publicIpId, port), mapping);
+ }
+ onChanged();
+ return result;
+ }
+
+ @Override
+ @Deprecated
+ public boolean forgetPortMapping(PortMapping m) {
+ return forgetPortMapping(m.publicIpId, m.publicPort);
+ }
+
+ @Override
+ @Deprecated
+ public void recordPublicIpHostname(String publicIpId, String hostnameOrPublicIpAddress) {
+ log.debug("recording public IP "+publicIpId+" associated with "+hostnameOrPublicIpAddress);
+ synchronized (mutex) {
+ String old = publicIpIdToHostname.put(publicIpId, hostnameOrPublicIpAddress);
+ if (old!=null && !old.equals(hostnameOrPublicIpAddress))
+ log.warn("Changing hostname recorded against public IP "+publicIpId+"; from "+old+" to "+hostnameOrPublicIpAddress);
+ }
+ onChanged();
+ }
+
+ @Override
+ @Deprecated
+ public String getPublicIpHostname(String publicIpId) {
+ synchronized (mutex) {
+ return publicIpIdToHostname.get(publicIpId);
+ }
+ }
+
+ @Override
+ @Deprecated
+ public boolean forgetPublicIpHostname(String publicIpId) {
+ log.debug("forgetting public IP "+publicIpId+" association");
+ boolean result;
+ synchronized (mutex) {
+ result = (publicIpIdToHostname.remove(publicIpId) != null);
+ }
+ onChanged();
+ return result;
+ }
+
+ @Override
+ @Deprecated
+ public int acquirePublicPort(String publicIpId, Location l, int privatePort) {
+ int publicPort;
+ synchronized (mutex) {
+ PortMapping old = getPortMappingWithPrivateSide(l, privatePort);
+ // only works for 1 public IP ID per location (which is the norm)
+ if (old!=null && old.publicIpId.equals(publicIpId)) {
+ log.debug("request to acquire public port at "+publicIpId+" for "+l+":"+privatePort+", reusing old assignment "+old);
+ return old.getPublicPort();
+ }
+
+ publicPort = acquirePublicPort(publicIpId);
+ log.debug("request to acquire public port at "+publicIpId+" for "+l+":"+privatePort+", allocating "+publicPort);
+ associateImpl(publicIpId, publicPort, l, privatePort);
+ }
+ onChanged();
+ return publicPort;
+ }
+
+ @Override
+ @Deprecated
+ public void associate(String publicIpId, int publicPort, Location l, int privatePort) {
+ synchronized (mutex) {
+ associateImpl(publicIpId, publicPort, l, privatePort);
+ }
+ onChanged();
+ }
+
+ protected void associateImpl(String publicIpId, int publicPort, Location l, int privatePort) {
+ synchronized (mutex) {
+ PortMapping mapping = new PortMapping(publicIpId, publicPort, l, privatePort);
+ PortMapping oldMapping = getPortMappingWithPublicSide(publicIpId, publicPort);
+ log.debug("associating public port "+publicPort+" on "+publicIpId+" with private port "+privatePort+" at "+l+" ("+mapping+")"
+ +(oldMapping == null ? "" : " (overwriting "+oldMapping+" )"));
+ mappings.put(makeKey(publicIpId, publicPort), mapping);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Internal only; make protected when deprecated interface method removed
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public HostAndPort getPublicHostAndPort(PortMapping m) {
+ if (m.publicEndpoint == null) {
+ String hostname = getPublicIpHostname(m.publicIpId);
+ if (hostname==null)
+ throw new IllegalStateException("No public hostname associated with "+m.publicIpId+" (mapping "+m+")");
+ return HostAndPort.fromParts(hostname, m.publicPort);
+ } else {
+ return m.publicEndpoint;
+ }
+ }
+
+ @Override
+ public PortMapping getPortMappingWithPublicSide(String publicIpId, int publicPort) {
+ synchronized (mutex) {
+ return mappings.get(makeKey(publicIpId, publicPort));
+ }
+ }
+
+ @Override
+ public Collection<PortMapping> getPortMappingWithPublicIpId(String publicIpId) {
+ List<PortMapping> result = new ArrayList<PortMapping>();
+ synchronized (mutex) {
+ for (PortMapping m: mappings.values())
+ if (publicIpId.equals(m.publicIpId)) result.add(m);
+ }
+ return result;
+ }
+
+ /** returns the subset of port mappings associated with a given location */
+ @Override
+ public Collection<PortMapping> getLocationPublicIpIds(Location l) {
+ List<PortMapping> result = new ArrayList<PortMapping>();
+ synchronized (mutex) {
+ for (PortMapping m: mappings.values())
+ if (l.equals(m.getTarget())) result.add(m);
+ }
+ return result;
+ }
+
+ @Override
+ public PortMapping getPortMappingWithPrivateSide(Location l, int privatePort) {
+ synchronized (mutex) {
+ for (PortMapping m: mappings.values())
+ if (l.equals(m.getTarget()) && privatePort==m.privatePort) return m;
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java
new file mode 100644
index 0000000..dcb9048
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java
@@ -0,0 +1,90 @@
+/*
+ * 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 org.apache.brooklyn.location.access;
+
+import java.util.Map;
+
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.location.LocationRegistry;
+import org.apache.brooklyn.location.LocationSpec;
+import org.apache.brooklyn.location.basic.LocationConfigUtils;
+import org.apache.brooklyn.location.basic.LocationInternal;
+import org.apache.brooklyn.location.basic.LocationPredicates;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.brooklyn.location.basic.AbstractLocationResolver;
+import brooklyn.util.config.ConfigBag;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+public class PortForwardManagerLocationResolver extends AbstractLocationResolver {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PortForwardManagerLocationResolver.class);
+
+ public static final String PREFIX = "portForwardManager";
+
+ @Override
+ public String getPrefix() {
+ return PREFIX;
+ }
+
+ @Override
+ public Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry) {
+ ConfigBag config = extractConfig(locationFlags, spec, registry);
+ Map globalProperties = registry.getProperties();
+ String namedLocation = (String) locationFlags.get(LocationInternal.NAMED_SPEC_NAME.getName());
+ String scope = config.get(PortForwardManager.SCOPE);
+
+ Optional<Location> result = Iterables.tryFind(managementContext.getLocationManager().getLocations(),
+ Predicates.and(
+ Predicates.instanceOf(PortForwardManager.class),
+ LocationPredicates.configEqualTo(PortForwardManager.SCOPE, scope)));
+
+ if (result.isPresent()) {
+ return result.get();
+ } else {
+ PortForwardManager loc = managementContext.getLocationManager().createLocation(LocationSpec.create(PortForwardManagerImpl.class)
+ .configure(config.getAllConfig())
+ .configure(LocationConfigUtils.finalAndOriginalSpecs(spec, locationFlags, globalProperties, namedLocation)));
+
+ if (LOG.isDebugEnabled()) LOG.debug("Created "+loc+" for scope "+scope);
+ return loc;
+ }
+ }
+
+ @Override
+ protected Class<? extends Location> getLocationType() {
+ return PortForwardManager.class;
+ }
+
+ @Override
+ protected SpecParser getSpecParser() {
+ return new AbstractLocationResolver.SpecParser(getPrefix()).setExampleUsage("\"portForwardManager\" or \"portForwardManager(scope=global)\"");
+ }
+
+ @Override
+ protected ConfigBag extractConfig(Map<?,?> locationFlags, String spec, LocationRegistry registry) {
+ ConfigBag config = super.extractConfig(locationFlags, spec, registry);
+ config.putAsStringKeyIfAbsent("name", "localhost");
+ return config;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/org/apache/brooklyn/location/access/PortMapping.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/PortMapping.java b/core/src/main/java/org/apache/brooklyn/location/access/PortMapping.java
new file mode 100644
index 0000000..086b67c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/access/PortMapping.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 org.apache.brooklyn.location.access;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.location.Location;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.net.HostAndPort;
+
+public class PortMapping {
+
+ final String publicIpId;
+ final HostAndPort publicEndpoint;
+ final int publicPort;
+
+ final Location target;
+ final int privatePort;
+ // TODO CIDR's ?
+
+ public PortMapping(String publicIpId, HostAndPort publicEndpoint, Location target, int privatePort) {
+ this.publicIpId = checkNotNull(publicIpId, "publicIpId");
+ this.publicEndpoint = checkNotNull(publicEndpoint, "publicEndpoint");
+ this.publicPort = publicEndpoint.getPort();
+ this.target = target;
+ this.privatePort = privatePort;
+ }
+
+ public PortMapping(String publicIpId, int publicPort, Location target, int privatePort) {
+ this.publicIpId = checkNotNull(publicIpId, "publicIpId");
+ this.publicEndpoint = null;
+ this.publicPort = publicPort;
+ this.target = target;
+ this.privatePort = privatePort;
+ }
+
+ // In a release after 0.7.0, this will no longer be @Nullable
+ @Beta
+ @Nullable
+ public HostAndPort getPublicEndpoint() {
+ return publicEndpoint;
+ }
+
+ public int getPublicPort() {
+ return publicPort;
+ }
+
+ public Location getTarget() {
+ return target;
+ }
+
+ public int getPrivatePort() {
+ return privatePort;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("publicIpId", publicIpId+":"+publicPort)
+ .add("publicEndpoint", (publicEndpoint == null ? publicPort : publicEndpoint))
+ .add("targetLocation", target)
+ .add("targetPort", privatePort)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PortMapping)) return false;
+ PortMapping opm = (PortMapping)obj;
+ return Objects.equal(publicIpId, opm.publicIpId) &&
+ Objects.equal(publicPort, opm.publicPort) &&
+ Objects.equal(target, opm.target) &&
+ Objects.equal(privatePort, opm.privatePort);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(publicIpId, publicPort, target, privatePort);
+ }
+
+}
\ No newline at end of file