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

[3/6] brooklyn-server git commit: Handle pre/post/launch errors in AbstractSoftwareProcessDriver restart

Handle pre/post/launch errors in AbstractSoftwareProcessDriver restart

Previously if any phase errored (e.g. a post-launch comment exited with a
non-zero code) the entity would be stuck in the 'starting' state.

Fixes https://issues.apache.org/jira/browse/BROOKLYN-371


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

Branch: refs/heads/master
Commit: a974d3d9e5e8207b64000187eaf88daccd8ef91a
Parents: dacf18b
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Mon Oct 24 11:43:15 2016 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Fri Oct 28 14:35:12 2016 +0100

----------------------------------------------------------------------
 .../base/AbstractSoftwareProcessDriver.java     | 48 ++++++----
 .../SoftwareProcessRestartIntegrationTest.java  | 99 ++++++++++++++++++++
 2 files changed, 128 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a974d3d9/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessDriver.java
index aaa7cde..f04206f 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessDriver.java
@@ -305,25 +305,35 @@ public abstract class AbstractSoftwareProcessDriver implements SoftwareProcessDr
             }
         });
 
-        if (doFullStartOnRestart()) {
-            DynamicTasks.waitForLast();
-            ServiceStateLogic.setExpectedState(getEntity(), Lifecycle.STARTING);
-            start();
-        } else {
-            DynamicTasks.queue("pre-launch-command", new Runnable() { public void run() {
-                ServiceStateLogic.setExpectedState(getEntity(), Lifecycle.STARTING);
-                runPreLaunchCommand();
-            }});
-            DynamicTasks.queue("launch (main)", new Runnable() { public void run() {
-                launch();
-            }});
-            DynamicTasks.queue("post-launch-command", new Runnable() { public void run() {
-                runPostLaunchCommand();
-            }});
-            DynamicTasks.queue("post-launch", new Runnable() { public void run() {
-                postLaunch();
-            }});
-        }
+        DynamicTasks.queue("restart", new Runnable() {
+            public void run() {
+                try {
+                    if (doFullStartOnRestart()) {
+                        DynamicTasks.waitForLast();
+                        ServiceStateLogic.setExpectedState(getEntity(), Lifecycle.STARTING);
+                        start();
+                    } else {
+                        DynamicTasks.queue("pre-launch-command", new Runnable() { public void run() {
+                            ServiceStateLogic.setExpectedState(getEntity(), Lifecycle.STARTING);
+                            runPreLaunchCommand();
+                        }});
+                        DynamicTasks.queue("launch (main)", new Runnable() { public void run() {
+                            launch();
+                        }});
+                        DynamicTasks.queue("post-launch-command", new Runnable() { public void run() {
+                            runPostLaunchCommand();
+                        }});
+                        DynamicTasks.queue("post-launch", new Runnable() { public void run() {
+                            postLaunch();
+                        }});
+                    }
+                    DynamicTasks.waitForLast();
+                } catch (Exception e) {
+                    ServiceStateLogic.setExpectedState(entity, Lifecycle.ON_FIRE);
+                    throw Exceptions.propagate(e);
+                }
+            }
+        });
     }
 
     @Beta

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a974d3d9/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRestartIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRestartIntegrationTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRestartIntegrationTest.java
new file mode 100644
index 0000000..71d6b38
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRestartIntegrationTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.Attributes;
+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.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.test.Asserts;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+public class SoftwareProcessRestartIntegrationTest extends BrooklynAppUnitTestSupport {
+
+    @DataProvider(name = "errorPhase")
+    public Object[][] errorPhases() {
+        return new Object[][]{
+                {SoftwareProcess.PRE_LAUNCH_COMMAND},
+                {VanillaSoftwareProcess.LAUNCH_COMMAND},
+                {SoftwareProcess.POST_LAUNCH_COMMAND},
+        };
+    }
+
+    @Test(dataProvider = "errorPhase", groups = "Integration")
+    public void testEntityOnFireAfterRestartingWhenLaunchCommandFails(ConfigKey<String> key) {
+        VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class)
+                .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "true")
+                .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "true")
+                .configure(key, "exit 1"));
+        try {
+            app.start(ImmutableList.of(app.newLocalhostProvisioningLocation()));
+            Asserts.shouldHaveFailedPreviously("entity has launch command that does not complete successfully");
+        } catch (Exception e) {
+            // expected
+        }
+
+        LastTwoServiceStatesListener listener = new LastTwoServiceStatesListener();
+        entity.subscriptions().subscribe(entity, Attributes.SERVICE_STATE_ACTUAL, listener);
+
+        EntityAsserts.assertAttributeEquals(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE);
+        entity.invoke(Startable.RESTART, ImmutableMap.<String, Object>of(
+                SoftwareProcess.RestartSoftwareParameters.RESTART_CHILDREN.getName(), false,
+                SoftwareProcess.RestartSoftwareParameters.RESTART_MACHINE.getName(), false));
+
+        List<Lifecycle> expected = ImmutableList.of(Lifecycle.STARTING, Lifecycle.ON_FIRE);
+        Asserts.eventually(listener, Predicates.equalTo(expected));
+    }
+
+    public static class LastTwoServiceStatesListener implements SensorEventListener<Lifecycle>, Supplier<List<Lifecycle>> {
+        final Lifecycle[] events = new Lifecycle[2];
+
+        @Override
+        public void onEvent(SensorEvent<Lifecycle> event) {
+            synchronized (events) {
+                events[0] = events[1];
+                events[1] = event.getValue();
+            }
+        }
+
+        @Override
+        public List<Lifecycle> get() {
+            synchronized (events) {
+                return Lists.newArrayList(events);
+            }
+        }
+    }
+
+
+}