Repository: incubator-brooklyn Updated Branches: refs/heads/master 88fbe107c -> bcd39d589
PortForwarding: delete on JcloudsLocation.release - Adds JcloudsPortForwarderExtension.closePortForwarding - Adds PortForwardManager.forgetPortMappings(publicIpId) - Fix jcloudsSshMachineLocation.getSshHostAndPort() - Replace JcloudsPortforwardingLiveTest with JcloudsPortForwardingStubbedLiveTest Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/02d77d5e Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/02d77d5e Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/02d77d5e Branch: refs/heads/master Commit: 02d77d5ec8dead0767f9a65a36ea41102996f87c Parents: 88fbe10 Author: Aled Sage <[email protected]> Authored: Fri Jan 23 16:56:30 2015 +0000 Committer: Aled Sage <[email protected]> Committed: Tue Jan 27 12:39:41 2015 +0000 ---------------------------------------------------------------------- .../location/access/PortForwardManager.java | 5 + .../access/PortForwardManagerClient.java | 5 + .../location/access/PortForwardManagerImpl.java | 21 ++- .../brooklyn/location/access/PortMapping.java | 11 ++ .../location/jclouds/JcloudsLocation.java | 72 ++++++++- .../JcloudsPortForwarderExtension.java | 2 + .../JcloudsPortForwardingLiveTest.java | 117 -------------- .../JcloudsPortForwardingStubbedLiveTest.java | 154 +++++++++++++++++++ 8 files changed, 265 insertions(+), 122 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/core/src/main/java/brooklyn/location/access/PortForwardManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/access/PortForwardManager.java b/core/src/main/java/brooklyn/location/access/PortForwardManager.java index 00bcb75..6f93a4a 100644 --- a/core/src/main/java/brooklyn/location/access/PortForwardManager.java +++ b/core/src/main/java/brooklyn/location/access/PortForwardManager.java @@ -128,6 +128,11 @@ public interface PortForwardManager extends Location { */ 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(); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/core/src/main/java/brooklyn/location/access/PortForwardManagerClient.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/access/PortForwardManagerClient.java b/core/src/main/java/brooklyn/location/access/PortForwardManagerClient.java index f3767fd..7b7c091 100644 --- a/core/src/main/java/brooklyn/location/access/PortForwardManagerClient.java +++ b/core/src/main/java/brooklyn/location/access/PortForwardManagerClient.java @@ -134,6 +134,11 @@ public class PortForwardManagerClient implements PortForwardManager { } @Override + public boolean forgetPortMappings(String publicIpId) { + return getDelegate().forgetPortMappings(publicIpId); + } + + @Override public String getId() { return getDelegate().getId(); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java b/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java index c9a596b..16b8371 100644 --- a/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java +++ b/core/src/main/java/brooklyn/location/access/PortForwardManagerImpl.java @@ -199,7 +199,7 @@ public class PortForwardManagerImpl extends AbstractLocation implements PortForw if (publicIpId.equals(m.publicIpId) && privatePort==m.privatePort) return getPublicHostAndPort(m); } -} + } return null; } @@ -234,6 +234,25 @@ public class PortForwardManagerImpl extends AbstractLocation implements PortForw } @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); + } + } + } + if (log.isDebugEnabled()) log.debug("cleared all port mappings for "+publicIpId+" - "+result); + if (!result.isEmpty()) { + onChanged(); + } + return !result.isEmpty(); + } + + @Override protected ToStringHelper string() { int size; synchronized (mutex) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/core/src/main/java/brooklyn/location/access/PortMapping.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/access/PortMapping.java b/core/src/main/java/brooklyn/location/access/PortMapping.java index 85f49ce..aaf0ca5 100644 --- a/core/src/main/java/brooklyn/location/access/PortMapping.java +++ b/core/src/main/java/brooklyn/location/access/PortMapping.java @@ -19,8 +19,12 @@ package brooklyn.location.access; import static com.google.common.base.Preconditions.checkNotNull; + +import javax.annotation.Nullable; + import brooklyn.location.Location; +import com.google.common.annotations.Beta; import com.google.common.base.Objects; import com.google.common.net.HostAndPort; @@ -50,6 +54,13 @@ public class PortMapping { 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; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java index 3640117..fb78a44 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java @@ -96,6 +96,7 @@ import brooklyn.location.MachineManagementMixins.MachineMetadata; import brooklyn.location.MachineManagementMixins.RichMachineProvisioningLocation; import brooklyn.location.NoMachinesAvailableException; import brooklyn.location.access.PortForwardManager; +import brooklyn.location.access.PortMapping; import brooklyn.location.basic.BasicMachineMetadata; import brooklyn.location.basic.LocationConfigKeys; import brooklyn.location.basic.LocationConfigUtils; @@ -1581,7 +1582,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im return getManagementContext().getLocationManager().createLocation(LocationSpec.create(JcloudsSshMachineLocation.class) .configure("displayName", vmHostname) .configure("address", address) - .configure("port", sshHostAndPort.isPresent() ? sshHostAndPort.get().getPort() : node.getLoginPort()) + .configure(JcloudsSshMachineLocation.SSH_PORT, sshHostAndPort.isPresent() ? sshHostAndPort.get().getPort() : node.getLoginPort()) .configure("user", getUser(setup)) // don't think "config" does anything .configure(sshConfig) @@ -1663,14 +1664,27 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im LOG.info("Releasing machine {} in {}, instance id {}", new Object[] {machine, this, instanceId}); - removeChild(machine); - + Exception tothrow = null; + try { + releasePortForwarding(machine); + } catch (Exception e) { + LOG.error("Problem releasing port-forwarding for machine "+machine+" in "+this+", instance id "+instanceId+ + "; discarding instance and continuing...", e); + tothrow = e; + } + try { releaseNode(instanceId); } catch (Exception e) { LOG.error("Problem releasing machine "+machine+" in "+this+", instance id "+instanceId+ "; discarding instance and continuing...", e); - throw Exceptions.propagate(e); + tothrow = e; + } + + removeChild(machine); + + if (tothrow != null) { + throw Exceptions.propagate(tothrow); } } @@ -1714,6 +1728,56 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im } } + protected void releasePortForwarding(SshMachineLocation machine) { + // TODO Implementation needs revisisted. It relies on deprecated PortForwardManager methods. + + boolean usePortForwarding = Boolean.TRUE.equals(machine.getConfig(USE_PORT_FORWARDING)); + JcloudsPortForwarderExtension portForwarder = machine.getConfig(PORT_FORWARDER); + PortForwardManager portForwardManager = machine.getConfig(PORT_FORWARDING_MANAGER); + NodeMetadata node = (machine instanceof JcloudsSshMachineLocation) ? ((JcloudsSshMachineLocation) machine).getNode() : null; + + if (portForwarder == null) { + LOG.debug("No port-forwarding to close (because portForwarder null) on release of " + machine); + } else { + // Release the port-forwarding for the login-port, which was explicilty created by JcloudsLocation + if (usePortForwarding && node != null) { + HostAndPort sshHostAndPortOverride = machine.getSshHostAndPort(); + LOG.debug("Closing port-forwarding at {} for machine {}: {}->{}", new Object[] {this, machine, sshHostAndPortOverride, node.getLoginPort()}); + portForwarder.closePortForwarding(node, node.getLoginPort(), sshHostAndPortOverride, Protocol.TCP); + } + + // Get all the other port-forwarding mappings for this VM, and release all of those + Set<PortMapping> mappings; + if (portForwardManager != null) { + mappings = Sets.newLinkedHashSet(); + mappings.addAll(portForwardManager.getLocationPublicIpIds(machine)); + if (node != null) { + mappings.addAll(portForwardManager.getPortMappingWithPublicIpId(node.getId())); + } + } else { + mappings = ImmutableSet.of(); + } + + for (PortMapping mapping : mappings) { + HostAndPort publicEndpoint = mapping.getPublicEndpoint(); + int targetPort = mapping.getPrivatePort(); + Protocol protocol = Protocol.TCP; + if (publicEndpoint != null) { + LOG.debug("Closing port-forwarding at {} for machine {}: {}->{}", new Object[] {this, machine, publicEndpoint, targetPort}); + portForwarder.closePortForwarding(node, targetPort, publicEndpoint, protocol); + } + } + } + + // Forget all port mappings associated with this VM + if (portForwardManager != null) { + portForwardManager.forgetPortMappings(machine); + if (node != null) { + portForwardManager.forgetPortMappings(node.getId()); + } + } + } + // ------------ support methods -------------------- /** http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java index e3921b8..adfdde3 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java @@ -40,4 +40,6 @@ public interface JcloudsPortForwarderExtension { * will know about the mapped port. */ public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr); + + public void closePortForwarding(NodeMetadata node, int targetPort, HostAndPort publicHostAndPort, Protocol protocol); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingLiveTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingLiveTest.java b/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingLiveTest.java deleted file mode 100644 index c9d8393..0000000 --- a/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingLiveTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.location.jclouds.networking; - -import static org.testng.Assert.assertEquals; - -import java.util.List; -import java.util.Map; - -import org.jclouds.compute.domain.NodeMetadata; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import brooklyn.config.ConfigKey; -import brooklyn.location.jclouds.AbstractJcloudsLiveTest; -import brooklyn.location.jclouds.JcloudsLocation; -import brooklyn.location.jclouds.JcloudsSshMachineLocation; -import brooklyn.location.jclouds.networking.JcloudsPortForwarderExtension; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.net.Cidr; -import brooklyn.util.net.Protocol; - -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.net.HostAndPort; - -/** - * Tests different login options for ssh keys, passwords, etc. - */ -public class JcloudsPortForwardingLiveTest extends AbstractJcloudsLiveTest { - - private static final Logger LOG = LoggerFactory.getLogger(JcloudsPortForwardingLiveTest.class); - - public static final String AWS_EC2_REGION_NAME = AWS_EC2_USEAST_REGION_NAME; - public static final String AWS_EC2_LOCATION_SPEC = "jclouds:" + AWS_EC2_PROVIDER + ":" + AWS_EC2_REGION_NAME; - - // Image: {id=us-east-1/ami-7d7bfc14, providerId=ami-7d7bfc14, name=RightImage_CentOS_6.3_x64_v5.8.8.5, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=centos, arch=paravirtual, version=6.0, description=rightscale-us-east/RightImage_CentOS_6.3_x64_v5.8.8.5.manifest.xml, is64Bit=true}, description=rightscale-us-east/RightImage_CentOS_6.3_x64_v5.8.8.5.manifest.xml, version=5.8.8.5, status=AVAILABLE[available], loginUser=root, userMetadata={owner=411009282317, rootDeviceType=instance-store, virtualizationType=paravirtual, hypervisor=xen}} - public static final String AWS_EC2_CENTOS_IMAGE_ID = "us-east-1/ami-7d7bfc14"; - - @BeforeMethod(alwaysRun=true) - @Override - public void setUp() throws Exception { - super.setUp(); - jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve(AWS_EC2_LOCATION_SPEC); - } - - @Test(groups = {"Live"}) - protected void testPortForwardingCallsForwarder() throws Exception { - final List<HostAndPort> forwards = Lists.newCopyOnWriteArrayList(); - - JcloudsSshMachineLocation machine = obtainEc2Machine(ImmutableMap.<ConfigKey<?>,Object>of( - JcloudsLocation.USE_PORT_FORWARDING, true, - JcloudsLocation.PORT_FORWARDER, new JcloudsPortForwarderExtension() { - @Override public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) { - String vmIp = Iterables.get(Iterables.concat(node.getPublicAddresses(), node.getPrivateAddresses()), 0); - HostAndPort result = HostAndPort.fromParts(vmIp, targetPort); - forwards.add(result); - return result; - } - })); - - assertEquals(forwards.size(), 1, "forwards="+forwards+"; machine="+machine); - assertEquals(machine.getAddress().getHostAddress(), forwards.get(0).getHostText(), "actual="+forwards+"; machine="+machine); - assertEquals(machine.getPort(), forwards.get(0).getPort(), "forwards="+forwards+"; machine="+machine); - assertSshable(machine); - } - - @Test(groups = {"Live"}) - protected void testPortForwardingUsesGivenPort() throws Exception { - final List<HostAndPort> forwards = Lists.newCopyOnWriteArrayList(); - - JcloudsSshMachineLocation machine = obtainEc2Machine(ImmutableMap.<ConfigKey<?>,Object>of( - JcloudsLocation.WAIT_FOR_SSHABLE, false, - JcloudsLocation.USE_PORT_FORWARDING, true, - JcloudsLocation.PORT_FORWARDER, new JcloudsPortForwarderExtension() { - @Override public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) { - HostAndPort result = HostAndPort.fromParts("1.2.3.4", 12345); - forwards.add(result); - return result; - } - })); - - assertEquals(forwards.size(), 1, "forwards="+forwards+"; machine="+machine); - assertEquals(machine.getAddress().getHostAddress(), "1.2.3.4", "forwards="+forwards+"; machine="+machine); - assertEquals(machine.getPort(), 12345, "forwards="+forwards+"; machine="+machine); - } - - private JcloudsSshMachineLocation obtainEc2Machine(Map<?,?> conf) throws Exception { - return obtainMachine(MutableMap.<Object,Object>builder() - .putAll(conf) - .putIfAbsent("imageId", AWS_EC2_CENTOS_IMAGE_ID) - .putIfAbsent("hardwareId", AWS_EC2_SMALL_HARDWARE_ID) - .putIfAbsent("inboundPorts", ImmutableList.of(22)) - .build()); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/02d77d5e/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java b/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java new file mode 100644 index 0000000..f562ebf --- /dev/null +++ b/locations/jclouds/src/test/java/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedLiveTest.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package brooklyn.location.jclouds.networking; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import java.util.List; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadata.Status; +import org.jclouds.compute.domain.NodeMetadataBuilder; +import org.jclouds.compute.domain.Template; +import org.jclouds.domain.LoginCredentials; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.config.ConfigKey; +import brooklyn.location.access.PortForwardManager; +import brooklyn.location.access.PortForwardManagerImpl; +import brooklyn.location.jclouds.AbstractJcloudsStubbedLiveTest; +import brooklyn.location.jclouds.JcloudsLocation; +import brooklyn.location.jclouds.JcloudsSshMachineLocation; +import brooklyn.util.net.Cidr; +import brooklyn.util.net.Protocol; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.net.HostAndPort; + +/** + * The VM creation is stubbed out, but it still requires live access (i.e. real account credentials) + * to generate the template etc. + * + * We supply a ComputeServiceRegistry that delegates to the real instance for everything except + * VM creation and deletion. For those operations, it delegates to a NodeCreator that + * returns a dummy NodeMetadata, recording all calls made to it. + */ +public class JcloudsPortForwardingStubbedLiveTest extends AbstractJcloudsStubbedLiveTest { + + @SuppressWarnings("unused") + private static final Logger LOG = LoggerFactory.getLogger(JcloudsPortForwardingStubbedLiveTest.class); + + static class RecordingJcloudsPortForwarderExtension implements JcloudsPortForwarderExtension { + int nextPublicPort = 12345; + final List<List<Object>> opens = Lists.newCopyOnWriteArrayList(); + final List<List<Object>> closes = Lists.newCopyOnWriteArrayList(); + + @Override public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) { + opens.add(ImmutableList.of(node, targetPort, optionalPublicPort, protocol, accessingCidr)); + return HostAndPort.fromParts("1.2.3.4", nextPublicPort++); + } + @Override public void closePortForwarding(NodeMetadata node, int targetPort, HostAndPort publicHostAndPort, Protocol protocol) { + closes.add(ImmutableList.of(node, targetPort, publicHostAndPort, protocol)); + } + } + + @Override + protected NodeCreator newNodeCreator() { + return new NodeCreator() { + @Override + protected NodeMetadata newNode(String group, Template template) { + NodeMetadata result = new NodeMetadataBuilder() + .id("myid") + .credentials(LoginCredentials.builder().identity("myuser").credential("mypassword").build()) + .loginPort(22) + .status(Status.RUNNING) + .publicAddresses(ImmutableList.of("173.194.32.123")) + .privateAddresses(ImmutableList.of("172.168.10.11")) + .build(); + return result; + } + }; + } + + @Test(groups = {"Live", "Live-sanity"}) + protected void testPortForwardingCallsForwarder() throws Exception { + RecordingJcloudsPortForwarderExtension portForwarder = new RecordingJcloudsPortForwarderExtension(); + + JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.<ConfigKey<?>,Object>of( + JcloudsLocation.USE_PORT_FORWARDING, true, + JcloudsLocation.PORT_FORWARDER, portForwarder)); + + NodeMetadata created = nodeCreator.created.get(0); + assertEquals(nodeCreator.created.size(), 1, "created="+nodeCreator.created+"; machine="+machine); + assertEquals(machine.getNode(), created); + assertEquals(portForwarder.opens.size(), 1, "opens="+portForwarder.opens+"; machine="+machine); + assertEquals(portForwarder.opens.get(0).get(0), created); + assertEquals(portForwarder.opens.get(0).get(1), 22); + assertEquals(portForwarder.opens.get(0).get(3), Protocol.TCP); + assertEquals(portForwarder.opens.get(0).get(4), Cidr.UNIVERSAL); + assertEquals(machine.getSshHostAndPort(), HostAndPort.fromParts("1.2.3.4", 12345)); + + releaseMachine(machine); + String destroyed = nodeCreator.destroyed.get(0); + assertEquals(nodeCreator.destroyed.size(), 1, "destroyed="+nodeCreator.destroyed+"; machine="+machine); + assertEquals(destroyed, created.getId()); + assertEquals(portForwarder.closes.size(), 1, "closes="+portForwarder.closes+"; machine="+machine); + assertEquals(portForwarder.closes.get(0).get(0), created); + assertEquals(portForwarder.closes.get(0).get(1), 22); + assertEquals(portForwarder.closes.get(0).get(2), HostAndPort.fromParts("1.2.3.4", 12345)); + assertEquals(portForwarder.closes.get(0).get(3), Protocol.TCP); + } + + @Test(groups = {"Live", "Live-sanity"}) + protected void testDeregistersWithPortForwardManagerOnRelease() throws Exception { + PortForwardManager pfm = new PortForwardManagerImpl(); + + RecordingJcloudsPortForwarderExtension portForwarder = new RecordingJcloudsPortForwarderExtension(); + + JcloudsSshMachineLocation machine = obtainMachine(ImmutableMap.<ConfigKey<?>,Object>of( + JcloudsLocation.PORT_FORWARDER, portForwarder, + JcloudsLocation.PORT_FORWARDING_MANAGER, pfm)); + + // Add an association for this machine - expect that to be deleted when the machine is released. + HostAndPort publicHostAndPort = HostAndPort.fromParts("1.2.3.4", 1234); + pfm.associate("mypublicip", publicHostAndPort, machine, 80); + assertEquals(pfm.lookup(machine, 80), publicHostAndPort); + assertEquals(pfm.lookup("mypublicip", 80), publicHostAndPort); + + // Release + releaseMachine(machine); + + // Expect to have been cleared from PortForwardManager's records + assertNull(pfm.lookup(machine, 80)); + assertNull(pfm.lookup("mypublicip", 80)); + + // And for port-forwarding to have been closed + assertEquals(portForwarder.closes.size(), 1, "closes="+portForwarder.closes+"; machine="+machine); + assertEquals(portForwarder.closes.get(0).get(1), 80); + assertEquals(portForwarder.closes.get(0).get(2), HostAndPort.fromParts("1.2.3.4", 1234)); + assertEquals(portForwarder.closes.get(0).get(3), Protocol.TCP); + } +}
