You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2016/07/19 19:01:24 UTC

[1/5] brooklyn-server git commit: BROOKLYN-264: refactor wait-for-provision

Repository: brooklyn-server
Updated Branches:
  refs/heads/master aad12a62c -> af1aec58a


BROOKLYN-264: refactor wait-for-provision

We now mark the internal state as provisioning entirely in
MachineLifecycleEffectorTasks, and that is also where we wait for it
on stop(). This also allows us to test it as a unit test, rather than
needing a jclouds live test.


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

Branch: refs/heads/master
Commit: e74bc778cca888716b3d3cfeb27e30b394b8179e
Parents: 8f9d73e
Author: Aled Sage <al...@gmail.com>
Authored: Mon Jul 18 21:12:59 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Jul 18 21:15:00 2016 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/core/entity/Attributes.java |  12 -
 .../core/server/BrooklynServerConfig.java       |   5 -
 .../location/jclouds/JcloudsLocation.java       |   5 -
 .../MachineLifecycleEffectorTasks.java          | 151 ++++++++---
 .../ExpungingJcloudsLocationLiveTest.java       | 186 -------------
 .../SoftwareProcessStopsDuringStartTest.java    | 271 +++++++++++++++++++
 6 files changed, 381 insertions(+), 249 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e74bc778/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java b/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
index 95d1bcd..06fb7ab 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
@@ -144,18 +144,6 @@ public interface Attributes {
     
     AttributeSensor<URI> MAIN_URI = MainUri.MAIN_URI;
 
-    AttributeSensor<JcloudsProvisioningState> JCLOUDS_PROVISIONING_RUNNING = new BasicAttributeSensor(TypeToken.of(JcloudsProvisioningState.class), "jclouds.provisioning.running",
-            "Internal sensor. Please do NOT change its value across entities.", AttributeSensor.SensorPersistenceMode.NONE);
-    /**
-     * Used only by {@link org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks#doStop}
-     */
-    @Beta
-    enum JcloudsProvisioningState {
-        STARTED,
-        DONE,
-        NONE
-    }
-
     // this class is added because the MAIN_URI relies on a static initialization which unfortunately can't be added to an interface.
     class MainUri {
         private final static AttributeSensor<URI> MAIN_URI = Sensors.newSensor(URI.class, "main.uri", "Main URI for contacting the service/endpoint offered by this entity");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e74bc778/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java b/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java
index 33f1873..84cdfdb 100644
--- a/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java
+++ b/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java
@@ -31,7 +31,6 @@ import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.os.Os;
-import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -122,10 +121,6 @@ public class BrooklynServerConfig {
     public static final ConfigKey<Boolean> OSGI_CACHE_CLEAN = ConfigKeys.newBooleanConfigKey("brooklyn.osgi.cache.clean",
         "Whether to delete the OSGi directory before and after use; if unset, it will delete if the node ID forms part of the cache dir path (which by default it does) to avoid file leaks");
 
-    public static final ConfigKey<Duration> ENTITIES_STOP_WAIT_PROVISIONING_TIMEOUT = ConfigKeys.newDurationConfigKey("entities.stop.wait.provisioning.timeout",
-            "When stop is called on the Entity, it doesn't have a machine location instance so it doesn't have anything to ask to stop. To be able to stop the machine it has to wait for provisioning to complete. " +
-            "This ConfigKey sets the timeout for which the stop task will wait provisioning to complete.", Duration.FIVE_MINUTES);
-
     /** @see BrooklynServerPaths#getMgmtBaseDir(ManagementContext) */
     public static String getMgmtBaseDir(ManagementContext mgmt) {
         return BrooklynServerPaths.getMgmtBaseDir(mgmt);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e74bc778/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 14e310e..9e68259 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
@@ -63,7 +63,6 @@ import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.config.ConfigUtils;
 import org.apache.brooklyn.core.config.Sanitizer;
-import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.AbstractLocation;
 import org.apache.brooklyn.core.location.BasicMachineMetadata;
 import org.apache.brooklyn.core.location.LocationConfigKeys;
@@ -733,10 +732,6 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                     if (LOG.isDebugEnabled())
                         LOG.debug("NOTE: unused flags passed to obtain VM in "+setup.getDescription()+": "
                                 + Sanitizer.sanitize(setup.getUnusedConfig()));
-                Object callerContext = setup.get(JcloudsLocationConfig.CALLER_CONTEXT);
-                if (callerContext != null && callerContext instanceof Entity) {
-                    ((Entity)callerContext).sensors().set(Attributes.JCLOUDS_PROVISIONING_RUNNING, Attributes.JcloudsProvisioningState.STARTED);
-                }
                 nodes = computeService.createNodesInGroup(groupId, 1, template);
                 provisionTimestamp = Duration.of(provisioningStopwatch);
             } finally {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e74bc778/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
index 964e016..2e11120 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
@@ -28,18 +28,6 @@ import java.util.concurrent.Callable;
 
 import javax.annotation.Nullable;
 
-import org.apache.brooklyn.core.server.BrooklynServerConfig;
-import org.apache.brooklyn.util.repeat.Repeater;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
@@ -49,6 +37,7 @@ import org.apache.brooklyn.api.location.MachineManagementMixins.SuspendsMachines
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
@@ -61,6 +50,7 @@ import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle.Transition;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.entity.trait.StartableMethods;
@@ -71,6 +61,7 @@ import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.entity.machine.MachineInitTasks;
 import org.apache.brooklyn.entity.machine.ProvidesProvisioningFlags;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
@@ -79,11 +70,10 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess.RestartSoftwareP
 import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwareParameters;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwareParameters.StopMode;
 import org.apache.brooklyn.entity.stock.EffectorStartableImpl.StartParameters;
-import org.apache.brooklyn.util.collections.MutableSet;
-
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
@@ -92,9 +82,21 @@ import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.net.UserAndHostAndPort;
 import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.repeat.Repeater;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
 
 /**
  * Default skeleton for start/stop/restart tasks on machines.
@@ -121,12 +123,49 @@ public abstract class MachineLifecycleEffectorTasks {
 
     private static final Logger log = LoggerFactory.getLogger(MachineLifecycleEffectorTasks.class);
 
-    public static final ConfigKey<Boolean> ON_BOX_BASE_DIR_RESOLVED = ConfigKeys.newBooleanConfigKey("onbox.base.dir.resolved",
-        "Whether the on-box base directory has been resolved (for internal use)");
+    public static final ConfigKey<Boolean> ON_BOX_BASE_DIR_RESOLVED = ConfigKeys.newBooleanConfigKey(
+            "onbox.base.dir.resolved",
+            "Whether the on-box base directory has been resolved (for internal use)");
 
     public static final ConfigKey<Collection<? extends Location>> LOCATIONS = StartParameters.LOCATIONS;
-    public static final ConfigKey<Duration> STOP_PROCESS_TIMEOUT = ConfigKeys.newConfigKey(Duration.class,
-            "process.stop.timeout", "How long to wait for the processes to be stopped; use null to mean forever", Duration.TWO_MINUTES);
+    
+    public static final ConfigKey<Duration> STOP_PROCESS_TIMEOUT = ConfigKeys.newDurationConfigKey(
+            "process.stop.timeout", "How long to wait for the processes to be stopped; use null to mean forever", 
+            Duration.TWO_MINUTES);
+
+    @Beta
+    public static final ConfigKey<Duration> STOP_WAIT_PROVISIONING_TIMEOUT = ConfigKeys.newDurationConfigKey(
+            "stop.wait.provisioning.timeout",
+            "If stop is called on an entity while it is still provisioning the machine (such that "
+                    + "the provisioning cannot be safely interrupted), this is the length of time "
+                    + "to wait for the machine instance to become available so that it can be terminated. "
+                    + "If stop aborts before this point, the machine may be left running.", 
+            Duration.minutes(10));
+
+    @Beta
+    public static final AttributeSensor<ProvisioningTaskState> PROVISIONING_TASK_STATE = new BasicAttributeSensor<ProvisioningTaskState>(
+            TypeToken.of(ProvisioningTaskState.class), 
+            "provisioning.task.state",
+            "Internal transient sensor for tracking the provisioning of a machine (to better handle aborting)", 
+            AttributeSensor.SensorPersistenceMode.NONE);
+    
+    @Beta
+    public static final AttributeSensor<MachineLocation> PROVISIONED_MACHINE = new BasicAttributeSensor<MachineLocation>(
+            TypeToken.of(MachineLocation.class), 
+            "provisioning.task.machine",
+            "Internal transient sensor for tracking the machine being provisioned (to better handle aborting)", 
+            AttributeSensor.SensorPersistenceMode.NONE);
+    
+    /**
+     * Used only internally by {@link org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks}
+     * to track provisioning, so machine can be terminated if stopped while opaque provision call is being made.
+     */
+    @Beta
+    @VisibleForTesting
+    public enum ProvisioningTaskState {
+        RUNNING,
+        DONE;
+    }
 
     protected final MachineInitTasks machineInitTasks = new MachineInitTasks();
     
@@ -379,20 +418,30 @@ public abstract class MachineLifecycleEffectorTasks {
             if (!(location instanceof LocalhostMachineProvisioningLocation))
                 log.info("Starting {}, obtaining a new location instance in {} with ports {}", new Object[]{entity(), location, flags.get("inboundPorts")});
             entity().sensors().set(SoftwareProcess.PROVISIONING_LOCATION, location);
+            Transition expectedState = entity().sensors().get(Attributes.SERVICE_STATE_EXPECTED);
+            
+            // BROOKLYN-263: see corresponding code in doStop()
+            if (expectedState != null && (expectedState.getState() == Lifecycle.STOPPING || expectedState.getState() == Lifecycle.STOPPED)) {
+                throw new IllegalStateException("Provisioning aborted before even begun for "+entity()+" in "+location+" (presumably by a concurrent call to stop");
+            }
+            entity().sensors().set(PROVISIONING_TASK_STATE, ProvisioningTaskState.RUNNING);
+            
             MachineLocation machine;
             try {
                 machine = Tasks.withBlockingDetails("Provisioning machine in " + location, new ObtainLocationTask(location, flags));
-                if (machine == null)
-                    throw new NoMachinesAvailableException("Failed to obtain machine in " + location.toString());
-            } catch (Exception e) {
-                throw Exceptions.propagate(e);
+                entity().sensors().set(PROVISIONED_MACHINE, machine);
+            } finally {
+                entity().sensors().set(PROVISIONING_TASK_STATE, ProvisioningTaskState.DONE);
+            }
+            
+            if (machine == null) {
+                throw new NoMachinesAvailableException("Failed to obtain machine in " + location.toString());
             }
-
             if (log.isDebugEnabled())
                 log.debug("While starting {}, obtained new location instance {}", entity(),
-                        (machine instanceof SshMachineLocation ?
-                         machine + ", details " + ((SshMachineLocation) machine).getUser() + ":" + Sanitizer.sanitize(((SshMachineLocation) machine).config().getLocalBag())
-                                                               : machine));
+                        (machine instanceof SshMachineLocation
+                                ? machine + ", details " + ((SshMachineLocation) machine).getUser() + ":" + Sanitizer.sanitize(((SshMachineLocation) machine).config().getLocalBag())
+                                : machine));
             return machine;
         }
     }
@@ -444,9 +493,6 @@ public abstract class MachineLifecycleEffectorTasks {
                 }
             }
             entity().addLocations(ImmutableList.of((Location) machine));
-            if (entity().getAttribute(Attributes.JCLOUDS_PROVISIONING_RUNNING) != null) {
-                entity().sensors().remove(Attributes.JCLOUDS_PROVISIONING_RUNNING);
-            }
 
             // elsewhere we rely on (public) hostname being set _after_ subnet_hostname
             // (to prevent the tiny possibility of races resulting in hostname being returned
@@ -716,24 +762,47 @@ public abstract class MachineLifecycleEffectorTasks {
         DynamicTasks.queue("pre-stop", new PreStopCustomTask());
 
         // BROOKLYN-263:
-        // With this change the stop effector will wait for Location to provision so it can stop it.
-        // It will not retry if non-jclouds location is used in the entity.
+        // With this change the stop effector will wait for Location to provision so it can terminate
+        // the machine, if a provisioning request is in-progress.
+        //
+        // The ProvisionMachineTask stores transient internal state in PROVISIONING_TASK_STATE and
+        // PROVISIONED_MACHINE: it records when the provisioning is running and when done; and it
+        // records the final machine. We record the machine in the internal sensor (rather than 
+        // just relying on getLocations) because the latter is set much later in the start() 
+        // process.
+        //
+        // This code is a big improvement (previously there was a several-minute window in some 
+        // clouds where a call to stop() would leave the machine running). 
+        //
+        // However, there are still races. If the start() code has not yet reached the call to 
+        // location.obtain() then we won't wait, and the start() call won't know to abort. It's 
+        // fiddly to get that right, because we need to cope with restart() - so we mustn't leave 
+        // any state behind that will interfere with subsequent sequential calls to start().
+        // There is some attempt to handle it by ProvisionMachineTask checking if the expectedState
+        // is stopping/stopped.
         Maybe<MachineLocation> machine = Machines.findUniqueMachineLocation(entity().getLocations());
-        if (Attributes.JcloudsProvisioningState.STARTED.equals(entity().sensors().get(Attributes.JCLOUDS_PROVISIONING_RUNNING))
-                && machine.isAbsent()) {
-            entity().sensors().set(Attributes.JCLOUDS_PROVISIONING_RUNNING, null);
-            Repeater.create("Wait for a machine to appear")
+        ProvisioningTaskState provisioningState = entity().sensors().get(PROVISIONING_TASK_STATE);
+
+        if (machine.isAbsent() && provisioningState == ProvisioningTaskState.RUNNING) {
+            Duration maxWait = entity().config().get(STOP_WAIT_PROVISIONING_TIMEOUT);
+            log.info("When stopping {}, waiting for up to {} for the machine to finish provisioning, before terminating it", entity(), maxWait);
+            boolean success = Repeater.create("Wait for a machine to appear")
                     .until(new Callable<Boolean>() {
                         @Override
                         public Boolean call() throws Exception {
-                            return Machines.findUniqueMachineLocation(entity().getLocations()).isPresent();
-                        }
-                    })
-                    .every(Duration.FIVE_SECONDS)
-                    .limitTimeTo(entity().getManagementContext().getConfig().getConfig(BrooklynServerConfig.ENTITIES_STOP_WAIT_PROVISIONING_TIMEOUT))
+                            ProvisioningTaskState state = entity().sensors().get(PROVISIONING_TASK_STATE);
+                            return (state == ProvisioningTaskState.DONE);
+                        }})
+                    .backoffTo(Duration.FIVE_SECONDS)
+                    .limitTimeTo(maxWait)
                     .run();
-            machine = Machines.findUniqueMachineLocation(entity().getLocations());
+            if (!success) {
+                log.warn("When stopping {}, timed out after {} waiting for the machine to finish provisioning - machine may we left running", entity(), maxWait);
+            }
+            machine = Maybe.ofDisallowingNull(entity().sensors().get(PROVISIONED_MACHINE));
         }
+        entity().sensors().remove(PROVISIONING_TASK_STATE);
+        entity().sensors().remove(PROVISIONED_MACHINE);
 
         Task<List<?>> stoppingProcess = null;
         if (canStop(stopProcessMode, entity())) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e74bc778/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
deleted file mode 100644
index 4b49be4..0000000
--- a/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
+++ /dev/null
@@ -1,186 +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.entity;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityAsserts;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.core.location.LocationConfigKeys;
-import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
-import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
-import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
-import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
-import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.jclouds.aws.ec2.compute.AWSEC2ComputeService;
-import org.jclouds.compute.domain.ComputeMetadata;
-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 javax.annotation.Nullable;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
-
-import static org.apache.brooklyn.test.Asserts.*;
-
-public class ExpungingJcloudsLocationLiveTest extends BrooklynAppLiveTestSupport {
-    private static final Logger LOG = LoggerFactory.getLogger(ExpungingJcloudsLocationLiveTest.class);
-
-    protected BrooklynProperties brooklynProperties;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        // Don't let any defaults from brooklyn.properties (except credentials) interfere with test
-        brooklynProperties = BrooklynProperties.Factory.newDefault();
-
-        // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then that can cause "stdin: is not a tty")
-        brooklynProperties.remove("brooklyn.ssh.config.scriptHeader");
-
-        mgmt = new LocalManagementContextForTests(brooklynProperties);
-        super.setUp();
-    }
-
-    @Test
-    public void verifyExpungingMockedEntityIsQuick() throws Exception {
-        final EmptySoftwareProcess emptySoftwareProcess = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class));
-        executeInLimitedTime(new Callable<Void>() {
-            public Void call() {
-                app.start(ImmutableList.of(mgmt.getLocationManager().createLocation(TestApplication.LOCALHOST_PROVISIONER_SPEC)));
-                return null;
-            }
-        }, 2, TimeUnit.SECONDS);
-        EntityAsserts.assertEntityHealthy(emptySoftwareProcess);
-        assertNull(emptySoftwareProcess.getAttribute(Attributes.JCLOUDS_PROVISIONING_RUNNING));
-
-        executeInLimitedTime(new Callable<Void>() {
-            public Void call() {
-                Entities.destroy(app);
-                return null;
-            }
-        }, 1, TimeUnit.SECONDS);
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
-        assertNull(emptySoftwareProcess.getAttribute(Attributes.JCLOUDS_PROVISIONING_RUNNING));
-    }
-
-    @Test(groups = "Integration")
-    public void verifyExpungingByonLocationIsQuick() throws Exception {
-        final VanillaSoftwareProcess entity = app.addChild(EntitySpec.create(VanillaSoftwareProcess.class)
-                .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo install")
-                .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launch")
-                .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running"));
-        app.addLocations(ImmutableList.of(mgmt.getLocationFactory().createLocation(TestApplication.LOCALHOST_PROVISIONER_SPEC)));
-
-        EntityManagementUtils.start(app);
-
-        succeedsEventually(ImmutableMap.of("timeout", "4s"), new Callable<Boolean>() {
-            public Boolean call() {
-                assertTrue(entity.sensors().get(Attributes.SERVICE_UP));
-                assertNull(entity.getAttribute(Attributes.JCLOUDS_PROVISIONING_RUNNING));
-                return entity.sensors().get(Attributes.SERVICE_UP);
-            }
-        });
-
-        executeInLimitedTime(new Callable<Void>() {
-            public Void call() {
-                Entities.destroy(app);
-                return null;
-            }
-        }, 2, TimeUnit.SECONDS);
-        // Make sure that the entity will be stopped fast. Two seconds at most.
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
-    }
-
-    public static final String PROVIDER = "aws-ec2";
-    public static final String REGION_NAME = "us-west-2";
-    public static final String LOCATION_SPEC = PROVIDER + (REGION_NAME == null ? "" : ":" + REGION_NAME);
-
-    /**
-     * Verifies the behavior described in
-     * <a href="https://issues.apache.org/jira/browse/BROOKLYN-264">BROOKLYN-264 Stop app while VM still being provisioned: vm is left running when app is expunged</a>
-     * <ul>
-     *     <li>ApplicationResource.launch</li>
-     *     <li>wait a few seconds and EntityResponse.expunge</li>
-     *     <li>assert the image is on the cloud</li>
-     * </ul>
-     */
-    @Test(groups = {"Live"})
-    public void verifyJclousMachineIsExpungedWhenStoppedImmediatelyAfterStart() {
-        Map<String,String> flags = ImmutableMap.of("imageId", "us-west-2/ami-cd715dfd", LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS.getName(), "");
-        Map<String,?> allFlags = MutableMap.<String,Object>builder()
-                .put("tags", ImmutableList.of(getClass().getName()))
-                .putAll(flags)
-                .build();
-        JcloudsLocation jcloudsLocation = (JcloudsLocation)mgmt.getLocationRegistry().getLocationManaged(LOCATION_SPEC, allFlags);
-
-        final EmptySoftwareProcess emptySoftwareProcess = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class)
-                .configure(EmptySoftwareProcess.PROVISIONING_PROPERTIES.subKey(CloudLocationConfig.INBOUND_PORTS.getName()), ImmutableList.of(22)));
-
-        app.addLocations(ImmutableList.of(jcloudsLocation));
-
-        EntityManagementUtils.start(app);
-
-        succeedsEventually(ImmutableMap.of("timeout", "16s"), new Callable<Attributes.JcloudsProvisioningState>() {
-            public Attributes.JcloudsProvisioningState call() {
-                assertEquals(emptySoftwareProcess.getAttribute(Attributes.JCLOUDS_PROVISIONING_RUNNING), Attributes.JcloudsProvisioningState.STARTED);
-                return emptySoftwareProcess.getAttribute(Attributes.JCLOUDS_PROVISIONING_RUNNING);
-            }
-        });
-
-        long beginTime = System.currentTimeMillis();
-        Entities.destroyCatching(app);
-        LOG.info("Time for expunging: {}", System.currentTimeMillis() - beginTime);
-
-        NodeMetadata nodeMetadata = Iterables.getFirst(((AWSEC2ComputeService) jcloudsLocation.getComputeService()).listNodesDetailsMatching(new Predicate<ComputeMetadata>() {
-                @Override public boolean apply(@Nullable ComputeMetadata computeMetadata) {
-                    return ((NodeMetadata)computeMetadata).getGroup() == null ? false
-                            : Pattern.matches(
-                                "brooklyn-.*" + System.getProperty("user.name") + ".*emptysoftware.*"+emptySoftwareProcess.getId().substring(0, 4),
-                                ((NodeMetadata)computeMetadata).getGroup()
-                                );
-                }}),
-            null);
-        LOG.info("nodeMetadata found after app was created: {}", nodeMetadata);
-        assertTrue(nodeMetadata.getStatus().equals(NodeMetadata.Status.TERMINATED), "The application should be destroyed after stop effector was called.");
-    }
-
-    private <T> T executeInLimitedTime(Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
-        Future<T> future = Executors.newCachedThreadPool().submit(callable);
-        return future.get(timeout, timeUnit);
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e74bc778/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
new file mode 100644
index 0000000..8772253
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
@@ -0,0 +1,271 @@
+/*
+ * 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.entity.software.base;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.location.AbstractLocation;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.LogWatcher;
+import org.apache.brooklyn.test.LogWatcher.EventPredicates;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+public class SoftwareProcessStopsDuringStartTest extends BrooklynAppUnitTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(SoftwareProcessStopsDuringStartTest.class);
+    
+    private DelayedProvisioningLocation loc;
+    private EmptySoftwareProcess entity;
+    private ExecutorService executor;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = mgmt.getLocationManager().createLocation(LocationSpec.create(DelayedProvisioningLocation.class));
+        entity = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class));
+        executor = Executors.newCachedThreadPool();
+    }
+    
+    @Override
+    public void tearDown() throws Exception {
+        if (executor != null) {
+            executor.shutdownNow();
+        }
+        super.tearDown();
+    }
+    
+    @Test
+    public void testSequentialStartThenStop() throws Exception {
+        loc.getObtainResumeLatch(0).countDown();
+        
+        entity.start(ImmutableList.<Location>of(loc));
+        SshMachineLocation machine = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get();
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, machine);
+        
+        entity.stop();
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, null);
+        
+        assertEquals(loc.getCalls(), ImmutableList.of("obtain", "release"));
+    }
+
+    @Test
+    public void testSequentialStartStopStartStop() throws Exception {
+        // resume-latches created with zero - they will not block
+        loc.setObtainResumeLatches(ImmutableList.of(new CountDownLatch(0), new CountDownLatch(0)));
+        loc.setObtainCalledLatches(ImmutableList.of(new CountDownLatch(1), new CountDownLatch(1)));
+        
+        entity.start(ImmutableList.<Location>of(loc));
+        SshMachineLocation machine = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get();
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, machine);
+        
+        entity.stop();
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, null);
+
+        entity.start(ImmutableList.<Location>of(loc));
+        SshMachineLocation machine2 = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get();
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, machine2);
+
+        entity.stop();
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, null);
+
+        assertEquals(loc.getCalls(), ImmutableList.of("obtain", "release", "obtain", "release"));
+    }
+
+    @Test
+    public void testStopDuringProvisionWaitsForCompletion() throws Exception {
+        Future<?> startFuture = executor.submit(new Runnable() {
+            public void run() {
+                entity.start(ImmutableList.<Location>of(loc));
+            }});
+        loc.getObtainCalledLatch(0).await();
+        
+        // Calling stop - it should block
+        // TODO Nicer way of ensuring that stop is really waiting? We wait for the log message!
+        Future<?> stopFuture;
+        LogWatcher watcher = new LogWatcher(
+                MachineLifecycleEffectorTasks.class.getName(), 
+                ch.qos.logback.classic.Level.INFO,
+                EventPredicates.containsMessage("for the machine to finish provisioning, before terminating it") );
+        watcher.start();
+        try {
+            stopFuture = executor.submit(new Runnable() {
+                public void run() {
+                    entity.stop();
+                }});
+            watcher.assertHasEventEventually();
+        } finally {
+            watcher.close();
+        }
+        assertFalse(stopFuture.isDone());
+
+        // When the loc.obtain() call returns, that will allow stop() to complete
+        loc.getObtainResumeLatch(0).countDown();
+        stopFuture.get(Asserts.DEFAULT_LONG_TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS); // should be successful
+        try {
+            startFuture.get();
+        } catch (ExecutionException e) {
+            // might fail, depending how far it got before stop completed
+            LOG.info("start() failed during concurrent stop; acceptable", e);
+        }
+        
+        assertEquals(loc.getCalls(), ImmutableList.of("obtain", "release"));
+    }
+
+    @Test
+    public void testStopDuringProvisionTimesOut() throws Exception {
+        entity = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class)
+                .configure(MachineLifecycleEffectorTasks.STOP_WAIT_PROVISIONING_TIMEOUT, Duration.millis(100)));
+
+        executor.submit(new Runnable() {
+            public void run() {
+                entity.start(ImmutableList.<Location>of(loc));
+            }});
+        loc.getObtainCalledLatch(0).await();
+        
+        LogWatcher watcher = new LogWatcher(
+                MachineLifecycleEffectorTasks.class.getName(), 
+                ch.qos.logback.classic.Level.WARN,
+                EventPredicates.containsMessage("timed out after 100ms waiting for the machine to finish provisioning - machine may we left running") );
+
+        watcher.start();
+        try {
+            Stopwatch stopwatch = Stopwatch.createStarted();
+            entity.stop();
+            long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+            assertEquals(watcher.getEvents().size(), 1);
+            assertTrue(elapsed > (100 - 10), "elapsed="+elapsed);
+        } finally {
+            watcher.close();
+        }
+        
+        assertEquals(loc.getCalls(), ImmutableList.of("obtain"));
+    }
+    
+    public static class DelayedProvisioningLocation extends AbstractLocation implements MachineProvisioningLocation<SshMachineLocation> {
+        public List<CountDownLatch> obtainCalledLatches = MutableList.of(new CountDownLatch(1));
+        public List<CountDownLatch> obtainResumeLatches = MutableList.of(new CountDownLatch(1));
+        private Set<SshMachineLocation> obtainedMachines = Sets.newConcurrentHashSet();
+        private final List<String> calls = Lists.newCopyOnWriteArrayList();
+        private final AtomicInteger obtainCount = new AtomicInteger();
+        
+        public void setObtainResumeLatches(List<CountDownLatch> latches) {
+            this.obtainResumeLatches = latches;
+        }
+
+        public void setObtainCalledLatches(List<CountDownLatch> latches) {
+            this.obtainCalledLatches = latches;
+        }
+
+        public CountDownLatch getObtainCalledLatch(int count) {
+            return obtainCalledLatches.get(count);
+        }
+
+        public CountDownLatch getObtainResumeLatch(int count) {
+            return obtainResumeLatches.get(count);
+        }
+
+        public List<String> getCalls() {
+            return ImmutableList.copyOf(calls);
+        }
+
+        @Override
+        public SshMachineLocation obtain(Map<?,?> flags) throws NoMachinesAvailableException {
+            try {
+                int count = obtainCount.getAndIncrement();
+                calls.add("obtain");
+                getObtainCalledLatch(count).countDown();
+                getObtainResumeLatch(count).await();
+                
+                SshMachineLocation result = getManagementContext().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
+                        .parent(this)
+                        .configure(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName())
+                        .configure("address","localhost"));
+                obtainedMachines.add(result);
+                
+                SoftwareProcessStopsDuringStartTest.LOG.info("Simulated obtain of machine " + result);
+                return result;
+            } catch (InterruptedException e) {
+                throw Exceptions.propagate(e);
+            }
+        }
+
+        @Override
+        public void release(SshMachineLocation machine) {
+            calls.add("release");
+            SoftwareProcessStopsDuringStartTest.LOG.info("Simulated release of machine " + machine);
+            boolean removed = obtainedMachines.remove(machine);
+            if (!removed) {
+                throw new IllegalStateException("Unknown machine "+machine);
+            }
+        }
+
+        @Override
+        public Map<String,Object> getProvisioningFlags(Collection<String> tags) {
+            return Collections.emptyMap();
+        }
+
+        @Override
+        public MachineProvisioningLocation<SshMachineLocation> newSubLocation(Map<?, ?> newFlags) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}


[4/5] brooklyn-server git commit: BROOKLYN-264: rename config field to “internal_”

Posted by al...@apache.org.
BROOKLYN-264: rename config field to \u201cinternal_\u201d

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

Branch: refs/heads/master
Commit: f69e116f8b1ff4edbf4b0f7708f984da6bdb7458
Parents: e889df5
Author: Aled Sage <al...@gmail.com>
Authored: Tue Jul 19 15:58:17 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Jul 19 15:58:17 2016 +0100

----------------------------------------------------------------------
 .../MachineLifecycleEffectorTasks.java          | 20 ++++++++--------
 ...eProcessStopsDuringStartJcloudsLiveTest.java | 10 ++++----
 .../SoftwareProcessStopsDuringStartTest.java    | 24 ++++++++++----------
 3 files changed, 27 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f69e116f/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
index 75f7a06..fda9ad6 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
@@ -143,14 +143,14 @@ public abstract class MachineLifecycleEffectorTasks {
             Duration.minutes(10));
 
     @Beta
-    public static final AttributeSensor<ProvisioningTaskState> PROVISIONING_TASK_STATE = new BasicAttributeSensor<ProvisioningTaskState>(
+    public static final AttributeSensor<ProvisioningTaskState> INTERNAL_PROVISIONING_TASK_STATE = new BasicAttributeSensor<ProvisioningTaskState>(
             TypeToken.of(ProvisioningTaskState.class), 
             "internal.provisioning.task.state",
             "Internal transient sensor (do not use) for tracking the provisioning of a machine (to better handle aborting)", 
             AttributeSensor.SensorPersistenceMode.NONE);
     
     @Beta
-    public static final AttributeSensor<MachineLocation> PROVISIONED_MACHINE = new BasicAttributeSensor<MachineLocation>(
+    public static final AttributeSensor<MachineLocation> INTERNAL_PROVISIONED_MACHINE = new BasicAttributeSensor<MachineLocation>(
             TypeToken.of(MachineLocation.class), 
             "internal.provisioning.task.machine",
             "Internal transient sensor (do not use) for tracking the machine being provisioned (to better handle aborting)", 
@@ -424,14 +424,14 @@ public abstract class MachineLifecycleEffectorTasks {
             if (expectedState != null && (expectedState.getState() == Lifecycle.STOPPING || expectedState.getState() == Lifecycle.STOPPED)) {
                 throw new IllegalStateException("Provisioning aborted before even begun for "+entity()+" in "+location+" (presumably by a concurrent call to stop");
             }
-            entity().sensors().set(PROVISIONING_TASK_STATE, ProvisioningTaskState.RUNNING);
+            entity().sensors().set(INTERNAL_PROVISIONING_TASK_STATE, ProvisioningTaskState.RUNNING);
             
             MachineLocation machine;
             try {
                 machine = Tasks.withBlockingDetails("Provisioning machine in " + location, new ObtainLocationTask(location, flags));
-                entity().sensors().set(PROVISIONED_MACHINE, machine);
+                entity().sensors().set(INTERNAL_PROVISIONED_MACHINE, machine);
             } finally {
-                entity().sensors().set(PROVISIONING_TASK_STATE, ProvisioningTaskState.DONE);
+                entity().sensors().set(INTERNAL_PROVISIONING_TASK_STATE, ProvisioningTaskState.DONE);
             }
             
             if (machine == null) {
@@ -781,7 +781,7 @@ public abstract class MachineLifecycleEffectorTasks {
         // There is some attempt to handle it by ProvisionMachineTask checking if the expectedState
         // is stopping/stopped.
         Maybe<MachineLocation> machine = Machines.findUniqueMachineLocation(entity().getLocations());
-        ProvisioningTaskState provisioningState = entity().sensors().get(PROVISIONING_TASK_STATE);
+        ProvisioningTaskState provisioningState = entity().sensors().get(INTERNAL_PROVISIONING_TASK_STATE);
 
         if (machine.isAbsent() && provisioningState == ProvisioningTaskState.RUNNING) {
             Duration maxWait = entity().config().get(STOP_WAIT_PROVISIONING_TIMEOUT);
@@ -790,7 +790,7 @@ public abstract class MachineLifecycleEffectorTasks {
                     .until(new Callable<Boolean>() {
                         @Override
                         public Boolean call() throws Exception {
-                            ProvisioningTaskState state = entity().sensors().get(PROVISIONING_TASK_STATE);
+                            ProvisioningTaskState state = entity().sensors().get(INTERNAL_PROVISIONING_TASK_STATE);
                             return (state == ProvisioningTaskState.DONE);
                         }})
                     .backoffTo(Duration.FIVE_SECONDS)
@@ -799,10 +799,10 @@ public abstract class MachineLifecycleEffectorTasks {
             if (!success) {
                 log.warn("When stopping {}, timed out after {} waiting for the machine to finish provisioning - machine may we left running", entity(), maxWait);
             }
-            machine = Maybe.ofDisallowingNull(entity().sensors().get(PROVISIONED_MACHINE));
+            machine = Maybe.ofDisallowingNull(entity().sensors().get(INTERNAL_PROVISIONED_MACHINE));
         }
-        entity().sensors().remove(PROVISIONING_TASK_STATE);
-        entity().sensors().remove(PROVISIONED_MACHINE);
+        entity().sensors().remove(INTERNAL_PROVISIONING_TASK_STATE);
+        entity().sensors().remove(INTERNAL_PROVISIONED_MACHINE);
 
         Task<List<?>> stoppingProcess = null;
         if (canStop(stopProcessMode, entity())) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f69e116f/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java
index c43f739..a375406 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java
@@ -141,8 +141,8 @@ public class SoftwareProcessStopsDuringStartJcloudsLiveTest extends BrooklynAppL
             }
         }, Asserts.DEFAULT_LONG_TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS);
         EntityAsserts.assertEntityHealthy(entity);
-        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
-        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONED_MACHINE), Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get());
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE), Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get());
 
         executeInLimitedTime(new Callable<Void>() {
             public Void call() {
@@ -152,8 +152,8 @@ public class SoftwareProcessStopsDuringStartJcloudsLiveTest extends BrooklynAppL
         }, Asserts.DEFAULT_LONG_TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS);
         assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
         assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
-        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), null);
-        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONED_MACHINE), null);
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE), null);
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE), null);
     }
 
     /**
@@ -188,7 +188,7 @@ public class SoftwareProcessStopsDuringStartJcloudsLiveTest extends BrooklynAppL
         // Invoke async
         @SuppressWarnings("unused")
         Task<Void> startTask = Entities.invokeEffector(app, app, Startable.START, ImmutableMap.of("locations", MutableList.of()));
-        EntityAsserts.assertAttributeEqualsEventually(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.RUNNING);
+        EntityAsserts.assertAttributeEqualsEventually(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.RUNNING);
 
         Stopwatch stopwatch = Stopwatch.createStarted();
         Entities.destroyCatching(app);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f69e116f/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
index 49acdd2..06c991a 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
@@ -93,15 +93,15 @@ public class SoftwareProcessStopsDuringStartTest extends BrooklynAppUnitTestSupp
         
         entity.start(ImmutableList.<Location>of(loc));
         SshMachineLocation machine = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get();
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, machine);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE, machine);
         
         Stopwatch stopwatch = Stopwatch.createStarted();
         entity.stop();
         Duration stopDuration = Duration.of(stopwatch);
         assertTrue(Asserts.DEFAULT_LONG_TIMEOUT.isLongerThan(stopDuration), "stop took "+stopDuration);
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, null);
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE, null);
         
         assertEquals(loc.getCalls(), ImmutableList.of("obtain", "release"));
     }
@@ -114,21 +114,21 @@ public class SoftwareProcessStopsDuringStartTest extends BrooklynAppUnitTestSupp
         
         entity.start(ImmutableList.<Location>of(loc));
         SshMachineLocation machine = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get();
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, machine);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE, machine);
         
         entity.stop();
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, null);
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE, null);
 
         entity.start(ImmutableList.<Location>of(loc));
         SshMachineLocation machine2 = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get();
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, machine2);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE, machine2);
 
         entity.stop();
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, null);
-        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONING_TASK_STATE, null);
+        EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.INTERNAL_PROVISIONED_MACHINE, null);
 
         assertEquals(loc.getCalls(), ImmutableList.of("obtain", "release", "obtain", "release"));
     }


[2/5] brooklyn-server git commit: BROOKLYN-264: Revert tests for expunging

Posted by al...@apache.org.
BROOKLYN-264: Revert tests for expunging


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

Branch: refs/heads/master
Commit: 8f3c09fc6733f89fea16a14e89fc9c0461b6708b
Parents: e74bc77
Author: Valentin Aitken <bo...@gmail.com>
Authored: Tue Jul 19 09:16:52 2016 +0300
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Jul 19 10:11:38 2016 +0100

----------------------------------------------------------------------
 .../ExpungingJcloudsLocationLiveTest.java       | 186 +++++++++++++++++++
 1 file changed, 186 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8f3c09fc/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
new file mode 100644
index 0000000..658a36f
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.entity;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.location.LocationConfigKeys;
+import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
+import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.jclouds.aws.ec2.compute.AWSEC2ComputeService;
+import org.jclouds.compute.domain.ComputeMetadata;
+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 javax.annotation.Nullable;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+import static org.apache.brooklyn.test.Asserts.*;
+
+public class ExpungingJcloudsLocationLiveTest extends BrooklynAppLiveTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(ExpungingJcloudsLocationLiveTest.class);
+
+    protected BrooklynProperties brooklynProperties;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        // Don't let any defaults from brooklyn.properties (except credentials) interfere with test
+        brooklynProperties = BrooklynProperties.Factory.newDefault();
+
+        // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then that can cause "stdin: is not a tty")
+        brooklynProperties.remove("brooklyn.ssh.config.scriptHeader");
+
+        mgmt = new LocalManagementContextForTests(brooklynProperties);
+        super.setUp();
+    }
+
+    @Test
+    public void verifyExpungingMockedEntityIsQuick() throws Exception {
+        final EmptySoftwareProcess emptySoftwareProcess = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class));
+        executeInLimitedTime(new Callable<Void>() {
+            public Void call() {
+                app.start(ImmutableList.of(mgmt.getLocationManager().createLocation(TestApplication.LOCALHOST_PROVISIONER_SPEC)));
+                return null;
+            }
+        }, 2, TimeUnit.SECONDS);
+        EntityAsserts.assertEntityHealthy(emptySoftwareProcess);
+        assertEquals(emptySoftwareProcess.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+
+        executeInLimitedTime(new Callable<Void>() {
+            public Void call() {
+                Entities.destroy(app);
+                return null;
+            }
+        }, 1, TimeUnit.SECONDS);
+        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
+        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
+    }
+
+    @Test(groups = "Integration")
+    public void verifyExpungingByonLocationIsQuick() throws Exception {
+        final VanillaSoftwareProcess entity = app.addChild(EntitySpec.create(VanillaSoftwareProcess.class)
+                .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo install")
+                .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launch")
+                .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running"));
+        app.addLocations(ImmutableList.of(mgmt.getLocationFactory().createLocation(TestApplication.LOCALHOST_PROVISIONER_SPEC)));
+
+        EntityManagementUtils.start(app);
+
+        succeedsEventually(ImmutableMap.of("timeout", "4s"), new Callable<Boolean>() {
+            public Boolean call() {
+                assertTrue(entity.sensors().get(Attributes.SERVICE_UP));
+                assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+                return entity.sensors().get(Attributes.SERVICE_UP);
+            }
+        });
+
+        executeInLimitedTime(new Callable<Void>() {
+            public Void call() {
+                Entities.destroy(app);
+                return null;
+            }
+        }, 2, TimeUnit.SECONDS);
+        // Make sure that the entity will be stopped fast. Two seconds at most.
+        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
+        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
+    }
+
+    public static final String PROVIDER = "aws-ec2";
+    public static final String REGION_NAME = "us-west-2";
+    public static final String LOCATION_SPEC = PROVIDER + (REGION_NAME == null ? "" : ":" + REGION_NAME);
+
+    /**
+     * Verifies the behavior described in
+     * <a href="https://issues.apache.org/jira/browse/BROOKLYN-264">BROOKLYN-264 Stop app while VM still being provisioned: vm is left running when app is expunged</a>
+     * <ul>
+     *     <li>ApplicationResource.launch</li>
+     *     <li>wait a few seconds and EntityResponse.expunge</li>
+     *     <li>assert the image is on the cloud</li>
+     * </ul>
+     */
+    @Test(groups = {"Live"})
+    public void verifyJclousMachineIsExpungedWhenStoppedImmediatelyAfterStart() {
+        Map<String,String> flags = ImmutableMap.of("imageId", "us-west-2/ami-cd715dfd", LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS.getName(), "");
+        Map<String,?> allFlags = MutableMap.<String,Object>builder()
+                .put("tags", ImmutableList.of(getClass().getName()))
+                .putAll(flags)
+                .build();
+        JcloudsLocation jcloudsLocation = (JcloudsLocation)mgmt.getLocationRegistry().getLocationManaged(LOCATION_SPEC, allFlags);
+
+        final EmptySoftwareProcess emptySoftwareProcess = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class)
+                .configure(EmptySoftwareProcess.PROVISIONING_PROPERTIES.subKey(CloudLocationConfig.INBOUND_PORTS.getName()), ImmutableList.of(22)));
+
+        app.addLocations(ImmutableList.of(jcloudsLocation));
+
+        EntityManagementUtils.start(app);
+
+        succeedsEventually(ImmutableMap.of("timeout", "16s"), new Callable<MachineLifecycleEffectorTasks.ProvisioningTaskState>() {
+            public MachineLifecycleEffectorTasks.ProvisioningTaskState call() {
+                assertEquals(emptySoftwareProcess.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.RUNNING);
+                return emptySoftwareProcess.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE);
+            }
+        });
+
+        long beginTime = System.currentTimeMillis();
+        Entities.destroyCatching(app);
+        LOG.info("Time for expunging: {}", System.currentTimeMillis() - beginTime);
+
+        NodeMetadata nodeMetadata = Iterables.getFirst(((AWSEC2ComputeService) jcloudsLocation.getComputeService()).listNodesDetailsMatching(new Predicate<ComputeMetadata>() {
+                @Override public boolean apply(@Nullable ComputeMetadata computeMetadata) {
+                    return ((NodeMetadata)computeMetadata).getGroup() == null ? false
+                            : Pattern.matches(
+                                "brooklyn-.*" + System.getProperty("user.name") + ".*emptysoftware.*"+emptySoftwareProcess.getId().substring(0, 4),
+                                ((NodeMetadata)computeMetadata).getGroup()
+                                );
+                }}),
+            null);
+        LOG.info("nodeMetadata found after app was created: {}", nodeMetadata);
+        assertTrue(nodeMetadata.getStatus().equals(NodeMetadata.Status.TERMINATED), "The application should be destroyed after stop effector was called.");
+    }
+
+    private <T> T executeInLimitedTime(Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
+        Future<T> future = Executors.newCachedThreadPool().submit(callable);
+        return future.get(timeout, timeUnit);
+    }
+}


[3/5] brooklyn-server git commit: BROOKLYN-264: renames + updates live test

Posted by al...@apache.org.
BROOKLYN-264: renames + updates live test

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

Branch: refs/heads/master
Commit: e889df538ca3b6acbfbf3c534412edbd336295bb
Parents: 8f3c09f
Author: Aled Sage <al...@gmail.com>
Authored: Tue Jul 19 11:57:15 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Jul 19 11:57:15 2016 +0100

----------------------------------------------------------------------
 .../MachineLifecycleEffectorTasks.java          |   8 +-
 .../ExpungingJcloudsLocationLiveTest.java       | 186 ---------------
 ...eProcessStopsDuringStartJcloudsLiveTest.java | 231 +++++++++++++++++++
 .../SoftwareProcessStopsDuringStartTest.java    |  47 ++++
 4 files changed, 282 insertions(+), 190 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e889df53/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
index 2e11120..75f7a06 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
@@ -145,15 +145,15 @@ public abstract class MachineLifecycleEffectorTasks {
     @Beta
     public static final AttributeSensor<ProvisioningTaskState> PROVISIONING_TASK_STATE = new BasicAttributeSensor<ProvisioningTaskState>(
             TypeToken.of(ProvisioningTaskState.class), 
-            "provisioning.task.state",
-            "Internal transient sensor for tracking the provisioning of a machine (to better handle aborting)", 
+            "internal.provisioning.task.state",
+            "Internal transient sensor (do not use) for tracking the provisioning of a machine (to better handle aborting)", 
             AttributeSensor.SensorPersistenceMode.NONE);
     
     @Beta
     public static final AttributeSensor<MachineLocation> PROVISIONED_MACHINE = new BasicAttributeSensor<MachineLocation>(
             TypeToken.of(MachineLocation.class), 
-            "provisioning.task.machine",
-            "Internal transient sensor for tracking the machine being provisioned (to better handle aborting)", 
+            "internal.provisioning.task.machine",
+            "Internal transient sensor (do not use) for tracking the machine being provisioned (to better handle aborting)", 
             AttributeSensor.SensorPersistenceMode.NONE);
     
     /**

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e889df53/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
deleted file mode 100644
index 658a36f..0000000
--- a/software/base/src/test/java/org/apache/brooklyn/entity/ExpungingJcloudsLocationLiveTest.java
+++ /dev/null
@@ -1,186 +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.entity;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityAsserts;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.core.location.LocationConfigKeys;
-import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
-import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
-import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
-import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
-import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
-import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.jclouds.aws.ec2.compute.AWSEC2ComputeService;
-import org.jclouds.compute.domain.ComputeMetadata;
-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 javax.annotation.Nullable;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
-
-import static org.apache.brooklyn.test.Asserts.*;
-
-public class ExpungingJcloudsLocationLiveTest extends BrooklynAppLiveTestSupport {
-    private static final Logger LOG = LoggerFactory.getLogger(ExpungingJcloudsLocationLiveTest.class);
-
-    protected BrooklynProperties brooklynProperties;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        // Don't let any defaults from brooklyn.properties (except credentials) interfere with test
-        brooklynProperties = BrooklynProperties.Factory.newDefault();
-
-        // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then that can cause "stdin: is not a tty")
-        brooklynProperties.remove("brooklyn.ssh.config.scriptHeader");
-
-        mgmt = new LocalManagementContextForTests(brooklynProperties);
-        super.setUp();
-    }
-
-    @Test
-    public void verifyExpungingMockedEntityIsQuick() throws Exception {
-        final EmptySoftwareProcess emptySoftwareProcess = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class));
-        executeInLimitedTime(new Callable<Void>() {
-            public Void call() {
-                app.start(ImmutableList.of(mgmt.getLocationManager().createLocation(TestApplication.LOCALHOST_PROVISIONER_SPEC)));
-                return null;
-            }
-        }, 2, TimeUnit.SECONDS);
-        EntityAsserts.assertEntityHealthy(emptySoftwareProcess);
-        assertEquals(emptySoftwareProcess.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
-
-        executeInLimitedTime(new Callable<Void>() {
-            public Void call() {
-                Entities.destroy(app);
-                return null;
-            }
-        }, 1, TimeUnit.SECONDS);
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
-    }
-
-    @Test(groups = "Integration")
-    public void verifyExpungingByonLocationIsQuick() throws Exception {
-        final VanillaSoftwareProcess entity = app.addChild(EntitySpec.create(VanillaSoftwareProcess.class)
-                .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo install")
-                .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launch")
-                .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running"));
-        app.addLocations(ImmutableList.of(mgmt.getLocationFactory().createLocation(TestApplication.LOCALHOST_PROVISIONER_SPEC)));
-
-        EntityManagementUtils.start(app);
-
-        succeedsEventually(ImmutableMap.of("timeout", "4s"), new Callable<Boolean>() {
-            public Boolean call() {
-                assertTrue(entity.sensors().get(Attributes.SERVICE_UP));
-                assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
-                return entity.sensors().get(Attributes.SERVICE_UP);
-            }
-        });
-
-        executeInLimitedTime(new Callable<Void>() {
-            public Void call() {
-                Entities.destroy(app);
-                return null;
-            }
-        }, 2, TimeUnit.SECONDS);
-        // Make sure that the entity will be stopped fast. Two seconds at most.
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
-        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
-    }
-
-    public static final String PROVIDER = "aws-ec2";
-    public static final String REGION_NAME = "us-west-2";
-    public static final String LOCATION_SPEC = PROVIDER + (REGION_NAME == null ? "" : ":" + REGION_NAME);
-
-    /**
-     * Verifies the behavior described in
-     * <a href="https://issues.apache.org/jira/browse/BROOKLYN-264">BROOKLYN-264 Stop app while VM still being provisioned: vm is left running when app is expunged</a>
-     * <ul>
-     *     <li>ApplicationResource.launch</li>
-     *     <li>wait a few seconds and EntityResponse.expunge</li>
-     *     <li>assert the image is on the cloud</li>
-     * </ul>
-     */
-    @Test(groups = {"Live"})
-    public void verifyJclousMachineIsExpungedWhenStoppedImmediatelyAfterStart() {
-        Map<String,String> flags = ImmutableMap.of("imageId", "us-west-2/ami-cd715dfd", LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS.getName(), "");
-        Map<String,?> allFlags = MutableMap.<String,Object>builder()
-                .put("tags", ImmutableList.of(getClass().getName()))
-                .putAll(flags)
-                .build();
-        JcloudsLocation jcloudsLocation = (JcloudsLocation)mgmt.getLocationRegistry().getLocationManaged(LOCATION_SPEC, allFlags);
-
-        final EmptySoftwareProcess emptySoftwareProcess = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class)
-                .configure(EmptySoftwareProcess.PROVISIONING_PROPERTIES.subKey(CloudLocationConfig.INBOUND_PORTS.getName()), ImmutableList.of(22)));
-
-        app.addLocations(ImmutableList.of(jcloudsLocation));
-
-        EntityManagementUtils.start(app);
-
-        succeedsEventually(ImmutableMap.of("timeout", "16s"), new Callable<MachineLifecycleEffectorTasks.ProvisioningTaskState>() {
-            public MachineLifecycleEffectorTasks.ProvisioningTaskState call() {
-                assertEquals(emptySoftwareProcess.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.RUNNING);
-                return emptySoftwareProcess.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE);
-            }
-        });
-
-        long beginTime = System.currentTimeMillis();
-        Entities.destroyCatching(app);
-        LOG.info("Time for expunging: {}", System.currentTimeMillis() - beginTime);
-
-        NodeMetadata nodeMetadata = Iterables.getFirst(((AWSEC2ComputeService) jcloudsLocation.getComputeService()).listNodesDetailsMatching(new Predicate<ComputeMetadata>() {
-                @Override public boolean apply(@Nullable ComputeMetadata computeMetadata) {
-                    return ((NodeMetadata)computeMetadata).getGroup() == null ? false
-                            : Pattern.matches(
-                                "brooklyn-.*" + System.getProperty("user.name") + ".*emptysoftware.*"+emptySoftwareProcess.getId().substring(0, 4),
-                                ((NodeMetadata)computeMetadata).getGroup()
-                                );
-                }}),
-            null);
-        LOG.info("nodeMetadata found after app was created: {}", nodeMetadata);
-        assertTrue(nodeMetadata.getStatus().equals(NodeMetadata.Status.TERMINATED), "The application should be destroyed after stop effector was called.");
-    }
-
-    private <T> T executeInLimitedTime(Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
-        Future<T> future = Executors.newCachedThreadPool().submit(callable);
-        return future.get(timeout, timeUnit);
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e889df53/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java
new file mode 100644
index 0000000..c43f739
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartJcloudsLiveTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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.entity.software.base;
+
+import static org.apache.brooklyn.test.Asserts.assertEquals;
+import static org.apache.brooklyn.test.Asserts.assertNotNull;
+import static org.apache.brooklyn.test.Asserts.assertTrue;
+import static org.apache.brooklyn.test.Asserts.fail;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.location.ProvisioningLocation;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.location.LocationConfigKeys;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.entity.AbstractEc2LiveTest;
+import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
+import org.apache.brooklyn.location.byon.FixedListMachineProvisioningLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.util.time.Duration;
+import org.jclouds.aws.ec2.compute.AWSEC2ComputeService;
+import org.jclouds.compute.domain.ComputeMetadata;
+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 com.google.common.base.Predicate;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class SoftwareProcessStopsDuringStartJcloudsLiveTest extends BrooklynAppLiveTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(SoftwareProcessStopsDuringStartJcloudsLiveTest.class);
+
+    // same image as in AbstractEc2LiveTest.test_CentOS_6_3
+    // Image: {id=us-east-1/ami-a96b01c0, providerId=ami-a96b01c0, name=CentOS-6.3-x86_64-GA-EBS-02-85586466-5b6c-4495-b580-14f72b4bcf51-ami-bb9af1d2.1, location={scope=REGION, id=us-east-1, description=us-east-1, parent=aws-ec2, iso3166Codes=[US-VA]}, os={family=centos, arch=paravirtual, version=6.3, description=aws-marketplace/CentOS-6.3-x86_64-GA-EBS-02-85586466-5b6c-4495-b580-14f72b4bcf51-ami-bb9af1d2.1, is64Bit=true}, description=CentOS-6.3-x86_64-GA-EBS-02 on EBS x86_64 20130527:1219, version=bb9af1d2.1, status=AVAILABLE[available], loginUser=root, userMetadata={owner=679593333241, rootDeviceType=ebs, virtualizationType=paravirtual, hypervisor=xen}})
+    public static final String PROVIDER = "aws-ec2";
+    public static final String REGION_NAME = "us-east-1";
+    public static final String IMAGE_ID = "us-east-1/ami-a96b01c0";
+    public static final String HARDWARE_ID = AbstractEc2LiveTest.SMALL_HARDWARE_ID;
+    public static final String LOCATION_SPEC = PROVIDER + (REGION_NAME == null ? "" : ":" + REGION_NAME);
+
+    protected BrooklynProperties brooklynProperties;
+
+    protected ExecutorService executor;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        // Don't let any defaults from brooklyn.properties (except credentials) interfere with test
+        brooklynProperties = BrooklynProperties.Factory.newDefault();
+
+        // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then that can cause "stdin: is not a tty")
+        brooklynProperties.remove("brooklyn.ssh.config.scriptHeader");
+
+        mgmt = new LocalManagementContextForTests(brooklynProperties);
+        super.setUp();
+        
+        executor = Executors.newCachedThreadPool();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (executor != null) {
+            executor.shutdownNow();
+        }
+        super.tearDown();
+    }
+    
+    // Integration because takes approx 1 seconds
+    @Test(groups = "Integration")
+    public void testStartStopSequentiallyIsQuickInLocalhost() throws Exception {
+        LocalhostMachineProvisioningLocation localLoc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                .configure(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName()));
+        runStartStopSequentiallyIsQuick(localLoc);
+    }
+    
+    // Integration because takes approx 1 seconds
+    @Test(groups = "Integration")
+    public void testStartStopSequentiallyIsQuickInByon() throws Exception {
+        FixedListMachineProvisioningLocation<?> byonLoc = mgmt.getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class)
+                .configure(FixedListMachineProvisioningLocation.MACHINE_SPECS, ImmutableList.<LocationSpec<? extends MachineLocation>>of(
+                        LocationSpec.create(SshMachineLocation.class)
+                                .configure("address", "1.2.3.4")
+                                .configure(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName()))));
+        runStartStopSequentiallyIsQuick(byonLoc);
+    }
+    
+    protected void runStartStopSequentiallyIsQuick(final ProvisioningLocation<?> loc) throws Exception {
+        final EmptySoftwareProcess entity = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class)
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true));
+        
+        executeInLimitedTime(new Callable<Void>() {
+            public Void call() {
+                app.start(ImmutableList.of(loc));
+                return null;
+            }
+        }, Asserts.DEFAULT_LONG_TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS);
+        EntityAsserts.assertEntityHealthy(entity);
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONED_MACHINE), Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get());
+
+        executeInLimitedTime(new Callable<Void>() {
+            public Void call() {
+                Entities.destroy(app);
+                return null;
+            }
+        }, Asserts.DEFAULT_LONG_TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS);
+        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_ACTUAL), Lifecycle.STOPPED);
+        assertEquals(app.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STOPPED);
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE), null);
+        assertEquals(entity.getAttribute(MachineLifecycleEffectorTasks.PROVISIONED_MACHINE), null);
+    }
+
+    /**
+     * Verifies the behavior described in
+     * <a href="https://issues.apache.org/jira/browse/BROOKLYN-264">BROOKLYN-264 Stop app while VM still being provisioned: vm is left running when app is expunged</a>
+     * <ul>
+     *     <li>Launch the app
+     *     <li>wait a few seconds (for entity internal state to indicate the provisioning is happening)
+     *     <li>Expunge the app (thus calling stop on the entity)
+     *     <li>assert the image is terminated (using jclouds directly to query the cloud api)
+     * </ul>
+     */
+    @Test(groups = {"Live"})
+    public void testJclousMachineIsExpungedWhenStoppedDuringStart() throws Exception {
+        Map<String,?> allFlags = ImmutableMap.<String,Object>builder()
+                .put("tags", ImmutableList.of(getClass().getName()))
+                .put(JcloudsLocation.IMAGE_ID.getName(), IMAGE_ID)
+                .put(JcloudsLocation.HARDWARE_ID.getName(), HARDWARE_ID)
+                .put(LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS.getName(), "")
+                .put(JcloudsLocation.MACHINE_CREATE_ATTEMPTS.getName(), 1)
+                .put(JcloudsLocation.OPEN_IPTABLES.getName(), true)
+                .build();
+        JcloudsLocation jcloudsLocation = (JcloudsLocation)mgmt.getLocationRegistry().getLocationManaged(LOCATION_SPEC, allFlags);
+
+        final VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class)
+                .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo install")
+                .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo launch")
+                .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo running"));
+
+        app.addLocations(ImmutableList.of(jcloudsLocation));
+
+        // Invoke async
+        @SuppressWarnings("unused")
+        Task<Void> startTask = Entities.invokeEffector(app, app, Startable.START, ImmutableMap.of("locations", MutableList.of()));
+        EntityAsserts.assertAttributeEqualsEventually(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.RUNNING);
+
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        Entities.destroyCatching(app);
+        LOG.info("Time for expunging: {}", Duration.of(stopwatch));
+
+        NodeMetadata nodeMetadata = Iterables.getFirst(((AWSEC2ComputeService) jcloudsLocation.getComputeService()).listNodesDetailsMatching(new Predicate<ComputeMetadata>() {
+                @Override public boolean apply(@Nullable ComputeMetadata computeMetadata) {
+                    return ((NodeMetadata)computeMetadata).getGroup() == null 
+                            ? false
+                            : Pattern.matches(
+                                "brooklyn-.*" + System.getProperty("user.name") + ".*vanillasoftware.*"+entity.getId().substring(0, 4),
+                                ((NodeMetadata)computeMetadata).getGroup()
+                                );
+                }}),
+            null);
+        assertNotNull(nodeMetadata, "node matching node found");
+        LOG.info("nodeMetadata found after app was created: {}", nodeMetadata);
+        
+        // If pending (e.g. "status=PENDING[shutting-down]"), wait for it to transition
+        Stopwatch pendingStopwatch = Stopwatch.createStarted();
+        Duration maxPendingWait = Duration.FIVE_MINUTES;
+        while (maxPendingWait.isLongerThan(Duration.of(pendingStopwatch)) && nodeMetadata.getStatus() == NodeMetadata.Status.PENDING) {
+            Thread.sleep(1000);
+            nodeMetadata = ((AWSEC2ComputeService) jcloudsLocation.getComputeService()).getNodeMetadata(nodeMetadata.getId());
+        }
+        
+        if (nodeMetadata.getStatus() != NodeMetadata.Status.TERMINATED) {
+            // Try to terminate the VM - don't want test to leave it behind!
+            String errMsg = "The application should be destroyed after stop effector was called: status="+nodeMetadata.getStatus()+"; node="+nodeMetadata;
+            LOG.error(errMsg);
+            jcloudsLocation.getComputeService().destroyNode(nodeMetadata.getId());
+            fail(errMsg);
+        }
+    }
+
+    private <T> T executeInLimitedTime(Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
+        Future<T> future = executor.submit(callable);
+        return future.get(timeout, timeUnit);
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e889df53/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
index 8772253..49acdd2 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessStopsDuringStartTest.java
@@ -96,7 +96,10 @@ public class SoftwareProcessStopsDuringStartTest extends BrooklynAppUnitTestSupp
         EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, MachineLifecycleEffectorTasks.ProvisioningTaskState.DONE);
         EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, machine);
         
+        Stopwatch stopwatch = Stopwatch.createStarted();
         entity.stop();
+        Duration stopDuration = Duration.of(stopwatch);
+        assertTrue(Asserts.DEFAULT_LONG_TIMEOUT.isLongerThan(stopDuration), "stop took "+stopDuration);
         EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONING_TASK_STATE, null);
         EntityAsserts.assertAttributeEquals(entity, MachineLifecycleEffectorTasks.PROVISIONED_MACHINE, null);
         
@@ -200,13 +203,53 @@ public class SoftwareProcessStopsDuringStartTest extends BrooklynAppUnitTestSupp
         assertEquals(loc.getCalls(), ImmutableList.of("obtain"));
     }
     
+    @Test
+    public void testStopWhenProvisionFails() throws Exception {
+        loc.setObtainToFail(0);
+        
+        executor.submit(new Runnable() {
+            public void run() {
+                entity.start(ImmutableList.<Location>of(loc));
+            }});
+        loc.getObtainCalledLatch(0).await();
+        
+        // Calling stop - it should block
+        // TODO Nicer way of ensuring that stop is really waiting? We wait for the log message!
+        Future<?> stopFuture;
+        LogWatcher watcher = new LogWatcher(
+                MachineLifecycleEffectorTasks.class.getName(), 
+                ch.qos.logback.classic.Level.INFO,
+                EventPredicates.containsMessage("for the machine to finish provisioning, before terminating it") );
+        watcher.start();
+        try {
+            stopFuture = executor.submit(new Runnable() {
+                public void run() {
+                    entity.stop();
+                }});
+            watcher.assertHasEventEventually();
+        } finally {
+            watcher.close();
+        }
+        assertFalse(stopFuture.isDone());
+
+        // When the loc.obtain() call throws exception, that will allow stop() to complete.
+        // It must not wait for the full 10 minutes.
+        loc.getObtainResumeLatch(0).countDown();
+        stopFuture.get(Asserts.DEFAULT_LONG_TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS); // should be successful
+    }
+    
     public static class DelayedProvisioningLocation extends AbstractLocation implements MachineProvisioningLocation<SshMachineLocation> {
+        public List<Integer> obtainsToFail = MutableList.of();
         public List<CountDownLatch> obtainCalledLatches = MutableList.of(new CountDownLatch(1));
         public List<CountDownLatch> obtainResumeLatches = MutableList.of(new CountDownLatch(1));
         private Set<SshMachineLocation> obtainedMachines = Sets.newConcurrentHashSet();
         private final List<String> calls = Lists.newCopyOnWriteArrayList();
         private final AtomicInteger obtainCount = new AtomicInteger();
         
+        public void setObtainToFail(int index) {
+            this.obtainsToFail.add(index);
+        }
+
         public void setObtainResumeLatches(List<CountDownLatch> latches) {
             this.obtainResumeLatches = latches;
         }
@@ -235,6 +278,10 @@ public class SoftwareProcessStopsDuringStartTest extends BrooklynAppUnitTestSupp
                 getObtainCalledLatch(count).countDown();
                 getObtainResumeLatch(count).await();
                 
+                if (obtainsToFail.contains(count)) {
+                    throw new RuntimeException("Simulate failure in obtain");
+                }
+                
                 SshMachineLocation result = getManagementContext().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
                         .parent(this)
                         .configure(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName())


[5/5] brooklyn-server git commit: This closes #266

Posted by al...@apache.org.
This closes #266


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

Branch: refs/heads/master
Commit: af1aec58a1beda2d1028b6fcbbe8c5c46be2f6a0
Parents: aad12a6 f69e116
Author: Aled Sage <al...@gmail.com>
Authored: Tue Jul 19 20:01:01 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Jul 19 20:01:01 2016 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/core/entity/Attributes.java |  12 -
 .../core/server/BrooklynServerConfig.java       |   5 -
 .../location/jclouds/JcloudsLocation.java       |   5 -
 .../MachineLifecycleEffectorTasks.java          | 151 ++++++---
 .../ExpungingJcloudsLocationLiveTest.java       | 186 -----------
 ...eProcessStopsDuringStartJcloudsLiveTest.java | 231 ++++++++++++++
 .../SoftwareProcessStopsDuringStartTest.java    | 318 +++++++++++++++++++
 7 files changed, 659 insertions(+), 249 deletions(-)
----------------------------------------------------------------------