Java tutorial
/* * Copyright 2013-2014 by Cloudsoft Corporation Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package brooklyn.networking.portforwarding; import java.net.URI; import java.util.List; import java.util.Map; import org.jclouds.ContextBuilder; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.docker.DockerApi; import org.jclouds.docker.domain.Container; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; import org.jclouds.sshj.config.SshjSshClientModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicates; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.net.HostAndPort; import com.google.inject.Module; import brooklyn.entity.Entity; import brooklyn.location.Location; import brooklyn.location.MachineLocation; import brooklyn.location.PortRange; import brooklyn.location.access.PortForwardManager; import brooklyn.location.access.PortForwardManagerAuthority; import brooklyn.location.jclouds.JcloudsLocation; import brooklyn.location.jclouds.JcloudsSshMachineLocation; import brooklyn.networking.subnet.PortForwarder; import brooklyn.util.net.Cidr; import brooklyn.util.net.Protocol; public class DockerPortForwarder implements PortForwarder { private static final Logger log = LoggerFactory.getLogger(DockerPortForwarder.class); private final PortForwardManager portForwardManager; private String dockerEndpoint; private String dockerHostname; private String dockerIdentity; private String dockerCredential; public DockerPortForwarder() { this(new PortForwardManagerAuthority()); } public DockerPortForwarder(PortForwardManager portForwardManager) { this.portForwardManager = portForwardManager; } public void init(String dockerHostIp, int dockerHostPort) { this.dockerEndpoint = URI.create("http://" + dockerHostIp + ":" + dockerHostPort).toASCIIString(); this.dockerHostname = dockerHostIp; this.dockerIdentity = "notused"; this.dockerCredential = "notused"; } public void init(URI endpoint) { init(endpoint, "notused", "notused"); } public void init(URI endpoint, String identity, String credential) { this.dockerEndpoint = endpoint.toASCIIString(); this.dockerHostname = endpoint.getHost(); this.dockerIdentity = identity; this.dockerCredential = credential; } public void init(Iterable<? extends Location> locations) { Optional<? extends Location> jcloudsLoc = Iterables.tryFind(locations, Predicates.instanceOf(JcloudsLocation.class)); String provider = (jcloudsLoc.isPresent()) ? ((JcloudsLocation) jcloudsLoc.get()).getProvider() : null; String endpoint = (jcloudsLoc.isPresent()) ? ((JcloudsLocation) jcloudsLoc.get()).getEndpoint() : null; String identity = (jcloudsLoc.isPresent()) ? ((JcloudsLocation) jcloudsLoc.get()).getIdentity() : null; String credential = (jcloudsLoc.isPresent()) ? ((JcloudsLocation) jcloudsLoc.get()).getCredential() : null; if (jcloudsLoc.isPresent() && "docker".equals(provider)) { init(URI.create(endpoint), identity, credential); } else { throw new IllegalStateException("Cannot infer docker host URI from locations: " + locations); } } public PortForwardManager getPortForwardManager() { return portForwardManager; } @Override public String openGateway() { // IP of port-forwarder already exists return dockerHostname; } @Override public String openStaticNat(Entity serviceToOpen) { throw new UnsupportedOperationException("Can only open individual ports; not static nat with iptables"); } @Override public void openFirewallPort(Entity entity, int port, Protocol protocol, Cidr accessingCidr) { // TODO If port is already open in docker port-mapping then no-op; otherwise UnsupportedOperationException currently if (log.isDebugEnabled()) log.debug("no-op in {} for openFirewallPort({}, {}, {}, {})", new Object[] { this, entity, port, protocol, accessingCidr }); } @Override public void openFirewallPortRange(Entity entity, PortRange portRange, Protocol protocol, Cidr accessingCidr) { // TODO If port is already open in docker port-mapping then no-op; otherwise UnsupportedOperationException currently if (log.isDebugEnabled()) log.debug("no-op in {} for openFirewallPortRange({}, {}, {}, {})", new Object[] { this, entity, portRange, protocol, accessingCidr }); } @Override public HostAndPort openPortForwarding(MachineLocation targetMachine, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) { String targetIp = targetMachine.getAddress().getHostAddress(); if (targetIp == null) { throw new IllegalStateException("Failed to open port-forwarding for machine " + targetMachine + " because its" + " location has no target ip: " + targetMachine); } HostAndPort targetSide = HostAndPort.fromParts(targetIp, targetPort); HostAndPort newFrontEndpoint = openPortForwarding(targetSide, optionalPublicPort, protocol, accessingCidr); log.debug("Enabled port-forwarding for {} port {} (VM {}), via {}", new Object[] { targetMachine, targetPort, targetMachine, newFrontEndpoint }); return newFrontEndpoint; } @Override public HostAndPort openPortForwarding(HostAndPort targetSide, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) { // FIXME Does this actually open the port forwarding? Or just record that the port is supposed to be open? PortForwardManager pfw = getPortForwardManager(); int publicPort; if (optionalPublicPort.isPresent()) { publicPort = optionalPublicPort.get(); pfw.acquirePublicPortExplicit(dockerHostname, publicPort); } else { publicPort = pfw.acquirePublicPort(dockerHostname); } return HostAndPort.fromParts(dockerHostname, publicPort); } public Map<Integer, Integer> getPortMappings(MachineLocation targetMachine) { ComputeServiceContext context = ContextBuilder.newBuilder("docker").endpoint(dockerEndpoint) .credentials(dockerIdentity, dockerCredential) .modules(ImmutableSet.<Module>of(new SLF4JLoggingModule(), new SshjSshClientModule())) .build(ComputeServiceContext.class); DockerApi api = context.unwrapApi(DockerApi.class); String containerId = ((JcloudsSshMachineLocation) targetMachine).getJcloudsId(); Container container = api.getRemoteApi().inspectContainer(containerId); context.close(); Map<Integer, Integer> portMappings = Maps.newLinkedHashMap(); if (container.getNetworkSettings() == null) return portMappings; for (Map.Entry<String, List<Map<String, String>>> entrySet : container.getNetworkSettings().getPorts() .entrySet()) { String containerPort = Iterables.get(Splitter.on("/").split(entrySet.getKey()), 0); String hostPort = Iterables.getOnlyElement( Iterables.transform(entrySet.getValue(), new Function<Map<String, String>, String>() { @Override public String apply(Map<String, String> hostIpAndPort) { return hostIpAndPort.get("HostPort"); } })); portMappings.put(Integer.parseInt(containerPort), Integer.parseInt(hostPort)); } return portMappings; } @Override public boolean isClient() { return false; } }