You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2015/12/14 11:57:53 UTC

[4/6] incubator-brooklyn git commit: Test jcloudsLocation.releasePortForwarding

Test jcloudsLocation.releasePortForwarding


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/efadb4e5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/efadb4e5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/efadb4e5

Branch: refs/heads/master
Commit: efadb4e51cd0eb23ebdcb9ec6b053f48030df844
Parents: fa4da07
Author: Aled Sage <al...@gmail.com>
Authored: Thu Dec 3 19:55:52 2015 +0000
Committer: Mark McKenna <m4...@gmail.com>
Committed: Fri Dec 11 15:54:10 2015 +0000

----------------------------------------------------------------------
 .../location/jclouds/JcloudsLocation.java       |   5 -
 ...cloudsLocationReleasePortForwardingTest.java | 166 +++++++++++++++++++
 2 files changed, 166 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/efadb4e5/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 f368cdb..7578b8c 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
@@ -2515,11 +2515,6 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                         Tasks.setBlockingDetails(origDetails);
                     }
                 } else {
-                    // Not executing inside an execution context; can't submit!
-                    // It's not enough to just do:
-                    //     getManagementContext().getExecutionManager().submit(queueResult);
-                    // (see CompoundTask.submitIfNecessary, which gets called in ParallelTask).
-                    // Instead, we'll fall back to executing sequentially.
                     LOG.warn("Releasing port-forwarding of "+machine+" not executing in execution-context "
                             + "(e.g. not invoked inside effector); falling back to executing sequentially");
                     for (Runnable subtask : subtasks.values()) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/efadb4e5/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
new file mode 100644
index 0000000..aa69b69
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationReleasePortForwardingTest.java
@@ -0,0 +1,166 @@
+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().resolve("portForwardManager(scope=global)");
+        loc = (JcloudsLocation) mgmt.getLocationRegistry().resolve("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();
+    }
+}