Repository: brooklyn-server Updated Branches: refs/heads/master bd8be34be -> 19e63db79
Added a default PortForwardManager Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/a1661224 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/a1661224 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/a1661224 Branch: refs/heads/master Commit: a166122426600ecbc0846ab9065ae4772bbcd196 Parents: 784e18f Author: graeme.miller <[email protected]> Authored: Fri Jun 3 12:14:09 2016 +0100 Committer: graeme.miller <[email protected]> Committed: Fri Jun 3 14:40:09 2016 +0100 ---------------------------------------------------------------------- .../location/access/BrooklynAccessUtils.java | 71 ++++--- .../access/BrooklynAccessUtilsTest.java | 14 ++ .../location/jclouds/JcloudsLocation.java | 56 +++--- ...easePortForwardingConfiguredDefaultTest.java | 30 +++ ...ocationReleasePortForwardingDefaultTest.java | 195 +++++++++++++++++++ ...cloudsLocationReleasePortForwardingTest.java | 184 ----------------- .../SoftwareProcessLocationUnmanageTest.java | 2 +- 7 files changed, 303 insertions(+), 249 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a1661224/core/src/main/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtils.java b/core/src/main/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtils.java index b36ddf6..8d5e777 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtils.java @@ -26,6 +26,7 @@ import org.apache.brooklyn.api.location.MachineLocation; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.BasicConfigKey; import org.apache.brooklyn.core.entity.Attributes; +import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.location.Machines; import org.apache.brooklyn.core.location.SupportsPortForwarding; import org.slf4j.Logger; @@ -59,46 +60,52 @@ public class BrooklynAccessUtils { public static HostAndPort getBrooklynAccessibleAddress(Entity entity, int port) { String host; - + + EntityInternal entityInternal = (EntityInternal) entity; + // look up port forwarding PortForwardManager pfw = entity.getConfig(PORT_FORWARDING_MANAGER); - if (pfw!=null) { - Collection<Location> ll = entity.getLocations(); - - synchronized (BrooklynAccessUtils.class) { - // TODO finer-grained synchronization - - for (MachineLocation machine : Iterables.filter(ll, MachineLocation.class)) { - HostAndPort hp = pfw.lookup(machine, port); + if (pfw == null) { + log.debug("No PortForwardManager, using default"); + pfw = (PortForwardManager) entityInternal.getManagementContext().getLocationRegistry().getLocationManaged("portForwardManager(scope=global)"); + } + + Collection<Location> ll = entity.getLocations(); + + synchronized (BrooklynAccessUtils.class) { + // TODO finer-grained synchronization + + for (MachineLocation machine : Iterables.filter(ll, MachineLocation.class)) { + HostAndPort hp = pfw.lookup(machine, port); + if (hp!=null) { + log.debug("BrooklynAccessUtils found port-forwarded address {} for entity {}, port {}, using machine {}", + new Object[] {hp, entity, port, machine}); + return hp; + } + } + + Maybe<SupportsPortForwarding> supportPortForwardingLoc = Machines.findUniqueElement(ll, SupportsPortForwarding.class); + if (supportPortForwardingLoc.isPresent()) { + Cidr source = entity.getConfig(MANAGEMENT_ACCESS_CIDR); + SupportsPortForwarding loc = supportPortForwardingLoc.get(); + if (source!=null) { + log.debug("BrooklynAccessUtils requesting new port-forwarding rule to access "+port+" on "+entity+" (at "+loc+", enabled for "+source+")"); + // TODO discuss, is this the best way to do it + // (will probably _create_ the port forwarding rule!) + HostAndPort hp = loc.getSocketEndpointFor(source, port); if (hp!=null) { - log.debug("BrooklynAccessUtils found port-forwarded address {} for entity {}, port {}, using machine {}", - new Object[] {hp, entity, port, machine}); + log.debug("BrooklynAccessUtils created port-forwarded address {} for entity {}, port {}, using {}", + new Object[] {hp, entity, port, loc}); return hp; } - } - - Maybe<SupportsPortForwarding> supportPortForwardingLoc = Machines.findUniqueElement(ll, SupportsPortForwarding.class); - if (supportPortForwardingLoc.isPresent()) { - Cidr source = entity.getConfig(MANAGEMENT_ACCESS_CIDR); - SupportsPortForwarding loc = supportPortForwardingLoc.get(); - if (source!=null) { - log.debug("BrooklynAccessUtils requesting new port-forwarding rule to access "+port+" on "+entity+" (at "+loc+", enabled for "+source+")"); - // TODO discuss, is this the best way to do it - // (will probably _create_ the port forwarding rule!) - HostAndPort hp = loc.getSocketEndpointFor(source, port); - if (hp!=null) { - log.debug("BrooklynAccessUtils created port-forwarded address {} for entity {}, port {}, using {}", - new Object[] {hp, entity, port, loc}); - 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, and " - +"have location supporting port forwarding "+loc); - } + } else { + log.warn("No "+MANAGEMENT_ACCESS_CIDR.getName()+" configured for "+entity+", so cannot forward " + +"port "+port+" "+"even though "+PORT_FORWARDING_MANAGER.getName()+" was supplied, and " + +"have location supporting port forwarding "+loc); } } } + host = entity.getAttribute(Attributes.HOSTNAME); if (host!=null) return HostAndPort.fromParts(host, port); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a1661224/core/src/test/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtilsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtilsTest.java b/core/src/test/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtilsTest.java index 592e281..dcd853a 100644 --- a/core/src/test/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/location/access/BrooklynAccessUtilsTest.java @@ -69,6 +69,20 @@ public class BrooklynAccessUtilsTest extends BrooklynAppUnitTestSupport { assertEquals(BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, privatePort), HostAndPort.fromParts(publicNatIp, publicNatPort)); } + + @Test + public void testBrooklynAccessibleAddressFindsPreexistingMappingFromDefaultPFM() throws Exception { + final int privatePort = 8080; + final String publicNatIp = "1.2.3.4"; + final int publicNatPort = 12000; + + SshMachineLocation machine = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) + .configure(SshMachineLocation.TCP_PORT_MAPPINGS, ImmutableMap.of(privatePort, publicNatIp+":"+publicNatPort))); + entity = app.createAndManageChild(EntitySpec.create(TestEntity.class) + .location(machine)); + + assertEquals(BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, privatePort), HostAndPort.fromParts(publicNatIp, publicNatPort)); + } @Test public void testBrooklynAccessibleAddressUsesPrivateHostPortIfNoMapping() throws Exception { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a1661224/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java index 71e3b01..e76c814 100644 --- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java +++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java @@ -820,15 +820,15 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im machineLocation = registerJcloudsSshMachineLocation(computeService, node, Optional.fromNullable(template), userCredentials, sshHostAndPortOverride, setup); } + PortForwardManager portForwardManager = setup.get(PORT_FORWARDING_MANAGER); + if (portForwardManager == null) { + LOG.debug("No PortForwardManager, using default"); + portForwardManager = (PortForwardManager) getManagementContext().getLocationRegistry().getLocationManaged("portForwardManager(scope=global)"); + } + if (usePortForwarding && sshHostAndPortOverride.isPresent()) { // Now that we have the sshMachineLocation, we can associate the port-forwarding address with it. - PortForwardManager portForwardManager = setup.get(PORT_FORWARDING_MANAGER); - if (portForwardManager != null) { - portForwardManager.associate(node.getId(), sshHostAndPortOverride.get(), machineLocation, node.getLoginPort()); - } else { - LOG.warn("No port-forward manager for {} so could not associate {} -> {} for {}", - new Object[] {this, node.getLoginPort(), sshHostAndPortOverride, machineLocation}); - } + portForwardManager.associate(node.getId(), sshHostAndPortOverride.get(), machineLocation, node.getLoginPort()); } if ("docker".equals(this.getProvider())) { @@ -836,16 +836,10 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im throw new UnsupportedOperationException("Docker not supported on Windows"); } Map<Integer, Integer> portMappings = JcloudsUtil.dockerPortMappingsFor(this, node.getId()); - PortForwardManager portForwardManager = setup.get(PORT_FORWARDING_MANAGER); - if (portForwardManager != null) { - for(Integer containerPort : portMappings.keySet()) { - Integer hostPort = portMappings.get(containerPort); - String dockerHost = ((JcloudsSshMachineLocation)machineLocation).getSshHostAndPort().getHostText(); - portForwardManager.associate(node.getId(), HostAndPort.fromParts(dockerHost, hostPort), machineLocation, containerPort); - } - } else { - LOG.warn("No port-forward manager for {} so could not associate docker port-mappings for {}", - this, machineLocation); + for(Integer containerPort : portMappings.keySet()) { + Integer hostPort = portMappings.get(containerPort); + String dockerHost = ((JcloudsSshMachineLocation)machineLocation).getSshHostAndPort().getHostText(); + portForwardManager.associate(node.getId(), HostAndPort.fromParts(dockerHost, hostPort), machineLocation, containerPort); } } @@ -2582,10 +2576,15 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im boolean usePortForwarding = Boolean.TRUE.equals(machine.getConfig(USE_PORT_FORWARDING)); final JcloudsPortForwarderExtension portForwarder = machine.getConfig(PORT_FORWARDER); - PortForwardManager portForwardManager = machine.getConfig(PORT_FORWARDING_MANAGER); final String nodeId = machine.getJcloudsId(); final Map<String, Runnable> subtasks = Maps.newLinkedHashMap(); + PortForwardManager portForwardManager = machine.getConfig(PORT_FORWARDING_MANAGER); + if (portForwardManager == null) { + LOG.debug("No PortForwardManager, using default"); + portForwardManager = (PortForwardManager) getManagementContext().getLocationRegistry().getLocationManaged("portForwardManager(scope=global)"); + } + if (portForwarder == null) { LOG.debug("No port-forwarding to close (because portForwarder null) on release of " + machine); } else { @@ -2617,15 +2616,10 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im } // 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 (nodeId != null) { - mappings.addAll(portForwardManager.getPortMappingWithPublicIpId(nodeId)); - } - } else { - mappings = ImmutableSet.of(); + Set<PortMapping> mappings = Sets.newLinkedHashSet(); + mappings.addAll(portForwardManager.getLocationPublicIpIds(machine)); + if (nodeId != null) { + mappings.addAll(portForwardManager.getPortMappingWithPublicIpId(nodeId)); } for (final PortMapping mapping : mappings) { @@ -2671,11 +2665,9 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im } // Forget all port mappings associated with this VM - if (portForwardManager != null) { - portForwardManager.forgetPortMappings(machine); - if (nodeId != null) { - portForwardManager.forgetPortMappings(nodeId); - } + portForwardManager.forgetPortMappings(machine); + if (nodeId != null) { + portForwardManager.forgetPortMappings(nodeId); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a1661224/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingConfiguredDefaultTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingConfiguredDefaultTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingConfiguredDefaultTest.java new file mode 100644 index 0000000..f5be196 --- /dev/null +++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingConfiguredDefaultTest.java @@ -0,0 +1,30 @@ +/* + * 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.jclouds; + +import org.apache.brooklyn.api.location.LocationSpec; + +//For this test, the port forward manager is set on the location +public class JcloudsLocationReleasePortForwardingConfiguredDefaultTest extends JcloudsLocationReleasePortForwardingDefaultTest { + + @Override + protected LocationSpec<JcloudsSshMachineLocation> extraSpecChanges(LocationSpec<JcloudsSshMachineLocation> spec) { + return spec.configure(JcloudsLocation.PORT_FORWARDING_MANAGER, portForwardManager); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a1661224/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingDefaultTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingDefaultTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingDefaultTest.java new file mode 100644 index 0000000..cbbaf52 --- /dev/null +++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingDefaultTest.java @@ -0,0 +1,195 @@ +/* + * 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.jclouds; + +import static org.testng.Assert.assertTrue; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.brooklyn.api.effector.Effector; +import org.apache.brooklyn.api.effector.ParameterType; +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.core.effector.EffectorAndBody; +import org.apache.brooklyn.core.effector.EffectorBody; +import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory; +import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.location.access.PortForwardManager; +import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport; +import org.apache.brooklyn.entity.stock.BasicEntity; +import org.apache.brooklyn.location.jclouds.networking.JcloudsPortForwarderExtension; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.util.core.config.ConfigBag; +import org.apache.brooklyn.util.net.Cidr; +import org.apache.brooklyn.util.net.Protocol; +import org.apache.brooklyn.util.time.Duration; +import org.apache.brooklyn.util.time.Time; +import org.jclouds.compute.domain.NodeMetadata; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Optional; +import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.net.HostAndPort; + +//For this test, the port forward manager is not set on the location, the default is used. +public class JcloudsLocationReleasePortForwardingDefaultTest extends BrooklynAppLiveTestSupport { + + protected Stopwatch stopwatch; + protected PortForwardManager portForwardManager; + protected JcloudsLocation loc; + protected NodeMetadata node; + protected JcloudsSshMachineLocation pseudoMachine; + protected RecordingJcloudsPortForwarderExtension portForwarder; + + @BeforeMethod(alwaysRun=true) + @Override + public void setUp() throws Exception { + super.setUp(); + stopwatch = Stopwatch.createStarted(); + portForwardManager = (PortForwardManager) mgmt.getLocationRegistry().getLocationManaged("portForwardManager(scope=global)"); + loc = (JcloudsLocation) mgmt.getLocationRegistry().getLocationManaged("jclouds:aws-ec2:us-east-1"); + + node = Mockito.mock(NodeMetadata.class); + Mockito.when(node.getId()).thenReturn("mynodeid"); + + portForwarder = new RecordingJcloudsPortForwarderExtension(stopwatch); + + LocationSpec<JcloudsSshMachineLocation> locationSpec = LocationSpec.create(JcloudsSshMachineLocation.class) + .configure("jcloudsParent", loc) + .configure("address", "1.1.1.1") + .configure("port", 2000) + .configure("user", "myname") + .configure("node", node) + .configure(JcloudsLocation.USE_PORT_FORWARDING, true) + .configure(JcloudsLocation.PORT_FORWARDER, portForwarder); + + locationSpec = extraSpecChanges(locationSpec); + + pseudoMachine = mgmt.getLocationManager().createLocation(locationSpec); + } + + //To be overidden by subclasses that need to change the spec + protected LocationSpec<JcloudsSshMachineLocation> extraSpecChanges(LocationSpec<JcloudsSshMachineLocation> spec) { + return spec; + } + + @Test(groups={"Live", "Live-sanity"}) + public void testReleasesSshPort() throws Exception { + execRelease(loc, pseudoMachine); + + Asserts.succeedsEventually(new Runnable() { + public void run() { + portForwarder.assertClosedEquals(ImmutableSet.of(HostAndPort.fromParts("1.1.1.1", 2000))); + }}); + } + + @Test(groups={"Live", "Live-sanity"}) + public void testReleasesRecordedMappedPortsConcurrently() throws Exception { + final List<HostAndPort> publicEndpoints = Lists.newArrayList(); + publicEndpoints.add(HostAndPort.fromString("1.1.1.1:2000")); + + for (int i = 0; i < 60; i++) { + HostAndPort publicEndpoint = HostAndPort.fromString("2.2.2.2:"+(2000+i)); + portForwardManager.associate("myid", publicEndpoint, pseudoMachine, 1+i); + publicEndpoints.add(publicEndpoint); + } + portForwarder.setSleepBeforeReturning(Duration.ONE_SECOND); + + Duration preReleaseTimestamp = Duration.of(stopwatch); + execRelease(loc, pseudoMachine); + + Asserts.succeedsEventually(new Runnable() { + public void run() { + portForwarder.assertClosedEquals(publicEndpoints); + }}); + + Duration releaseTime = Duration.of(stopwatch).subtract(preReleaseTimestamp); + + // If done sequentially, it would have taken 60 seconds. We'll allow 30 seconds + // because we've seen jenkins be extremely slow when running unit tests on apache + // shared infrastructure. + assertTrue(releaseTime.isShorterThan(Duration.THIRTY_SECONDS), "releaseTime="+releaseTime); + assertTrue(releaseTime.toMilliseconds() - Duration.ONE_SECOND.toMilliseconds() >= 0, "releaseTime="+releaseTime); + } + + /** + * Records calls to openPortForwarding and closePortForwarding. Optionally does a sleep during each call. + */ + static class RecordingJcloudsPortForwarderExtension implements JcloudsPortForwarderExtension { + private final List<List<Object>> calls = Lists.newCopyOnWriteArrayList(); + private final AtomicInteger nextPort = new AtomicInteger(11000); + private final Stopwatch stopwatch; + private Duration sleepBeforeReturning; + + public RecordingJcloudsPortForwarderExtension(Stopwatch stopwatch) { + this.stopwatch = stopwatch; + this.sleepBeforeReturning = Duration.ZERO; + } + public void setSleepBeforeReturning(Duration val) { + this.sleepBeforeReturning = val; + } + @Override + public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) { + calls.add(ImmutableList.of("open", Duration.of(stopwatch), node, targetPort, optionalPublicPort, protocol, accessingCidr)); + Time.sleep(sleepBeforeReturning); + if (optionalPublicPort.isPresent()) { + return HostAndPort.fromParts("2.2.2.2", optionalPublicPort.get()); + } else { + return HostAndPort.fromParts("2.2.2.2", nextPort.get()); + } + } + @Override + public void closePortForwarding(NodeMetadata node, int targetPort, HostAndPort publicHostAndPort, Protocol protocol) { + calls.add(ImmutableList.of("close", System.currentTimeMillis(), node, targetPort, publicHostAndPort, protocol)); + Time.sleep(sleepBeforeReturning); + } + public void assertClosedEquals(Iterable<? extends HostAndPort> expected) { + List<HostAndPort> closed = Lists.newArrayList(); + for (List<Object> call : calls) { + if ("close".equals(call.get(0))) closed.add((HostAndPort) call.get(4)); + } + Asserts.assertEqualsIgnoringOrder(closed, expected); + } + } + + // Task execution unfortunately assumes that it is executing inside an "execution context". + // It fails (only logging at debug!) if it is not. Therefore, we execute the releasePortForwarding + // inside an effector. + private void execRelease(final JcloudsLocation loc, final JcloudsSshMachineLocation machine) throws Exception { + EffectorBody<Void> effectorBody = new EffectorBody<Void>() { + public Void call(ConfigBag parameters) { + loc.releasePortForwarding(machine); + return null; + } + }; + Effector<Void> effector = new EffectorAndBody<Void>("myeffector", Void.class, ImmutableList.<ParameterType<?>>of(), "", + new EffectorBodyTaskFactory<Void>(effectorBody)); + EntityInternal entity = (EntityInternal) app.createAndManageChild(EntitySpec.create(BasicEntity.class)); + entity.getMutableEntityType().addEffector(effector); + entity.invoke(effector, ImmutableMap.<String, Object>of()).get(); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a1661224/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingTest.java deleted file mode 100644 index 57ba788..0000000 --- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingTest.java +++ /dev/null @@ -1,184 +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 org.apache.brooklyn.location.jclouds; - -import static org.testng.Assert.assertTrue; - -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.api.location.LocationSpec; -import org.apache.brooklyn.core.effector.EffectorAndBody; -import org.apache.brooklyn.core.effector.EffectorBody; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory; -import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.core.location.access.PortForwardManager; -import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport; -import org.apache.brooklyn.entity.stock.BasicEntity; -import org.apache.brooklyn.location.jclouds.networking.JcloudsPortForwarderExtension; -import org.apache.brooklyn.test.Asserts; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.net.Cidr; -import org.apache.brooklyn.util.net.Protocol; -import org.apache.brooklyn.util.time.Duration; -import org.apache.brooklyn.util.time.Time; -import org.jclouds.compute.domain.NodeMetadata; -import org.mockito.Mockito; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import com.google.common.base.Optional; -import com.google.common.base.Stopwatch; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.net.HostAndPort; - -public class JcloudsLocationReleasePortForwardingTest extends BrooklynAppLiveTestSupport { - - private Stopwatch stopwatch; - private PortForwardManager portForwardManager; - private JcloudsLocation loc; - private NodeMetadata node; - private JcloudsSshMachineLocation pseudoMachine; - private RecordingJcloudsPortForwarderExtension portForwarder; - - @BeforeMethod(alwaysRun=true) - @Override - public void setUp() throws Exception { - super.setUp(); - stopwatch = Stopwatch.createStarted(); - portForwardManager = (PortForwardManager) mgmt.getLocationRegistry().getLocationManaged("portForwardManager(scope=global)"); - loc = (JcloudsLocation) mgmt.getLocationRegistry().getLocationManaged("jclouds:aws-ec2:us-east-1"); - - node = Mockito.mock(NodeMetadata.class); - Mockito.when(node.getId()).thenReturn("mynodeid"); - - portForwarder = new RecordingJcloudsPortForwarderExtension(stopwatch); - pseudoMachine = mgmt.getLocationManager().createLocation(LocationSpec.create(JcloudsSshMachineLocation.class) - .configure("jcloudsParent", loc) - .configure("address", "1.1.1.1") - .configure("port", 2000) - .configure("user", "myname") - .configure("node", node) - .configure(JcloudsLocation.USE_PORT_FORWARDING, true) - .configure(JcloudsLocation.PORT_FORWARDER, portForwarder) - .configure(JcloudsLocation.PORT_FORWARDING_MANAGER, portForwardManager)); - } - - @Test(groups={"Live", "Live-sanity"}) - public void testReleasesSshPort() throws Exception { - execRelease(loc, pseudoMachine); - - Asserts.succeedsEventually(new Runnable() { - public void run() { - portForwarder.assertClosedEquals(ImmutableSet.of(HostAndPort.fromParts("1.1.1.1", 2000))); - }}); - } - - @Test(groups={"Live", "Live-sanity"}) - public void testReleasesRecordedMappedPortsConcurrently() throws Exception { - final List<HostAndPort> publicEndpoints = Lists.newArrayList(); - publicEndpoints.add(HostAndPort.fromString("1.1.1.1:2000")); - - for (int i = 0; i < 60; i++) { - HostAndPort publicEndpoint = HostAndPort.fromString("2.2.2.2:"+(2000+i)); - portForwardManager.associate("myid", publicEndpoint, pseudoMachine, 1+i); - publicEndpoints.add(publicEndpoint); - } - portForwarder.setSleepBeforeReturning(Duration.ONE_SECOND); - - Duration preReleaseTimestamp = Duration.of(stopwatch); - execRelease(loc, pseudoMachine); - - Asserts.succeedsEventually(new Runnable() { - public void run() { - portForwarder.assertClosedEquals(publicEndpoints); - }}); - - Duration releaseTime = Duration.of(stopwatch).subtract(preReleaseTimestamp); - - // If done sequentially, it would have taken 60 seconds. We'll allow 30 seconds - // because we've seen jenkins be extremely slow when running unit tests on apache - // shared infrastructure. - assertTrue(releaseTime.isShorterThan(Duration.THIRTY_SECONDS), "releaseTime="+releaseTime); - assertTrue(releaseTime.toMilliseconds() - Duration.ONE_SECOND.toMilliseconds() >= 0, "releaseTime="+releaseTime); - } - - /** - * Records calls to openPortForwarding and closePortForwarding. Optionally does a sleep during each call. - */ - static class RecordingJcloudsPortForwarderExtension implements JcloudsPortForwarderExtension { - private final List<List<Object>> calls = Lists.newCopyOnWriteArrayList(); - private final AtomicInteger nextPort = new AtomicInteger(11000); - private final Stopwatch stopwatch; - private Duration sleepBeforeReturning; - - public RecordingJcloudsPortForwarderExtension(Stopwatch stopwatch) { - this.stopwatch = stopwatch; - this.sleepBeforeReturning = Duration.ZERO; - } - public void setSleepBeforeReturning(Duration val) { - this.sleepBeforeReturning = val; - } - @Override - public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr) { - calls.add(ImmutableList.of("open", Duration.of(stopwatch), node, targetPort, optionalPublicPort, protocol, accessingCidr)); - Time.sleep(sleepBeforeReturning); - if (optionalPublicPort.isPresent()) { - return HostAndPort.fromParts("2.2.2.2", optionalPublicPort.get()); - } else { - return HostAndPort.fromParts("2.2.2.2", nextPort.get()); - } - } - @Override - public void closePortForwarding(NodeMetadata node, int targetPort, HostAndPort publicHostAndPort, Protocol protocol) { - calls.add(ImmutableList.of("close", System.currentTimeMillis(), node, targetPort, publicHostAndPort, protocol)); - Time.sleep(sleepBeforeReturning); - } - public void assertClosedEquals(Iterable<? extends HostAndPort> expected) { - List<HostAndPort> closed = Lists.newArrayList(); - for (List<Object> call : calls) { - if ("close".equals(call.get(0))) closed.add((HostAndPort) call.get(4)); - } - Asserts.assertEqualsIgnoringOrder(closed, expected); - } - } - - // Task execution unfortunately assumes that it is executing inside an "execution context". - // It fails (only logging at debug!) if it is not. Therefore, we execute the releasePortForwarding - // inside an effector. - private void execRelease(final JcloudsLocation loc, final JcloudsSshMachineLocation machine) throws Exception { - EffectorBody<Void> effectorBody = new EffectorBody<Void>() { - public Void call(ConfigBag parameters) { - loc.releasePortForwarding(machine); - return null; - } - }; - Effector<Void> effector = new EffectorAndBody<Void>("myeffector", Void.class, ImmutableList.<ParameterType<?>>of(), "", - new EffectorBodyTaskFactory<Void>(effectorBody)); - EntityInternal entity = (EntityInternal) app.createAndManageChild(EntitySpec.create(BasicEntity.class)); - entity.getMutableEntityType().addEffector(effector); - entity.invoke(effector, ImmutableMap.<String, Object>of()).get(); - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a1661224/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/SoftwareProcessLocationUnmanageTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/SoftwareProcessLocationUnmanageTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/SoftwareProcessLocationUnmanageTest.java index d8d9fd1..45f6c67 100644 --- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/SoftwareProcessLocationUnmanageTest.java +++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/SoftwareProcessLocationUnmanageTest.java @@ -52,7 +52,7 @@ public class SoftwareProcessLocationUnmanageTest extends BrooklynAppUnitTestSupp * identity and credential. The Docker host (or Swarm endpoint) needs to be configured * with TLS, and have "ubuntu:14:04" already pulled on the server. */ - @Test(groups={"Live", "WIP"}) + @Test(groups={"Live", "WIP"}, enabled = false) public void testDockerLocationUnmanagedOnStop() { LocationSpec<? extends Location> locationSpec = LocationSpec.create(JcloudsLocation.class) .configure(JcloudsLocation.CLOUD_PROVIDER, "docker")
