Initialize driver on rebind when on-fire Skip driver initialization only when the entity is permanently marked failed with SERVICE_STATE_EXPECTED=ON_FIRE. When only SERVICE_STATE_ACTUAL=ON_FIRE, but SERVICE_STATE_EXPECTED=RUNNING then the entity should still be operational.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/bc3ec900 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/bc3ec900 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/bc3ec900 Branch: refs/heads/master Commit: bc3ec900330120f83772a3345a3993e9657a570a Parents: d0cbcf3 Author: Svetoslav Neykov <[email protected]> Authored: Mon May 11 15:42:50 2015 +0300 Committer: Svetoslav Neykov <[email protected]> Committed: Thu May 14 17:40:10 2015 +0300 ---------------------------------------------------------------------- .../brooklyn/entity/basic/SoftwareProcess.java | 2 + .../entity/basic/SoftwareProcessImpl.java | 18 +++++--- .../basic/SoftwareProcessEntityRebindTest.java | 44 ++++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bc3ec900/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java index 3958e67..d91a719 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java +++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java @@ -22,6 +22,7 @@ import java.util.Map; import brooklyn.config.ConfigKey; import brooklyn.entity.Entity; +import brooklyn.entity.basic.Lifecycle.Transition; import brooklyn.entity.trait.Startable; import brooklyn.event.AttributeSensor; import brooklyn.event.basic.AttributeSensorAndConfigKey; @@ -233,6 +234,7 @@ public interface SoftwareProcess extends Entity, Startable { "Whether the process for the service is confirmed as running"); AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL; + AttributeSensor<Transition> SERVICE_STATE_EXPECTED = Attributes.SERVICE_STATE_EXPECTED; AttributeSensor<String> PID_FILE = Sensors.newStringSensor("softwareprocess.pid.file", "PID file"); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bc3ec900/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java index ce28efd..5eea26a 100644 --- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java +++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java @@ -31,11 +31,10 @@ import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.Sets; - import brooklyn.config.ConfigKey; import brooklyn.enricher.basic.AbstractEnricher; import brooklyn.entity.Entity; +import brooklyn.entity.basic.Lifecycle.Transition; import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic; import brooklyn.entity.drivers.DriverDependentEntity; import brooklyn.entity.drivers.EntityDriverManager; @@ -57,7 +56,6 @@ import brooklyn.util.collections.MutableMap; import brooklyn.util.collections.MutableSet; import brooklyn.util.config.ConfigBag; import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.flags.TypeCoercions; import brooklyn.util.task.DynamicTasks; import brooklyn.util.task.Tasks; import brooklyn.util.time.CountdownTimer; @@ -67,6 +65,7 @@ import brooklyn.util.time.Time; import com.google.common.base.Functions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; /** * An {@link Entity} representing a piece of software which can be installed, run, and controlled. @@ -350,12 +349,19 @@ public abstract class SoftwareProcessImpl extends AbstractEntity implements Soft @Override public void rebind() { - Lifecycle state = getAttribute(SERVICE_STATE_ACTUAL); - if (state == null || state != Lifecycle.RUNNING) { - log.warn("On rebind of {}, not calling software process rebind hooks because state is {}", this, state); + //SERVICE_STATE_ACTUAL might be ON_FIRE due to a temporary condition (problems map non-empty) + //Only if the expected state is ON_FIRE then the entity has permanently failed. + Transition expectedState = getAttribute(SERVICE_STATE_EXPECTED); + if (expectedState == null || expectedState.getState() != Lifecycle.RUNNING) { + log.warn("On rebind of {}, not calling software process rebind hooks because expected state is {}", this, expectedState); return; } + Lifecycle actualState = getAttribute(SERVICE_STATE_ACTUAL); + if (actualState == null || actualState != Lifecycle.RUNNING) { + log.warn("Rebinding entity {}, even though actual state is {}. Expected state is {}", new Object[] {this, actualState, expectedState}); + } + // e.g. rebinding to a running instance // FIXME For rebind, what to do about things in STARTING or STOPPING state? // FIXME What if location not set? http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bc3ec900/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java index 0cdf900..6911790 100644 --- a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java +++ b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java @@ -19,6 +19,8 @@ package brooklyn.entity.basic; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; import java.io.File; import java.util.Collection; @@ -31,6 +33,7 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import brooklyn.entity.BrooklynAppUnitTestSupport; +import brooklyn.entity.basic.ServiceStateLogic.ServiceProblemsLogic; import brooklyn.entity.basic.SoftwareProcessEntityTest.MyService; import brooklyn.entity.proxying.EntitySpec; import brooklyn.entity.rebind.RebindTestUtils; @@ -40,6 +43,7 @@ import brooklyn.location.NoMachinesAvailableException; import brooklyn.location.basic.AbstractLocation; import brooklyn.location.basic.SshMachineLocation; import brooklyn.management.ManagementContext; +import brooklyn.test.EntityTestUtils; import brooklyn.test.entity.TestApplication; import brooklyn.util.flags.SetFromFlag; @@ -89,6 +93,46 @@ public class SoftwareProcessEntityRebindTest extends BrooklynAppUnitTestSupport assertEquals(newLoc.inUseCount.get(), 0); } + @Test + public void testCreatesDriverAfterRebind() throws Exception { + origE = app.createAndManageChild(EntitySpec.create(MyService.class)); + //the entity skips enricher initialization, do it explicitly + origE.addEnricher(ServiceStateLogic.newEnricherForServiceStateFromProblemsAndUp()); + + MyProvisioningLocation origLoc = mgmt.getLocationManager().createLocation(LocationSpec.create(MyProvisioningLocation.class) + .displayName("mylocname")); + app.start(ImmutableList.of(origLoc)); + assertEquals(origE.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.RUNNING); + EntityTestUtils.assertAttributeEqualsEventually(origE, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + + ServiceProblemsLogic.updateProblemsIndicator((EntityLocal)origE, "test", "fire"); + EntityTestUtils.assertAttributeEqualsEventually(origE, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE); + + newApp = (TestApplication) rebind(); + MyService newE = (MyService) Iterables.getOnlyElement(newApp.getChildren()); + assertTrue(newE.getDriver() != null, "driver should be initialized"); + } + + @Test + public void testDoesNotCreateDriverAfterRebind() throws Exception { + origE = app.createAndManageChild(EntitySpec.create(MyService.class)); + //the entity skips enricher initialization, do it explicitly + origE.addEnricher(ServiceStateLogic.newEnricherForServiceStateFromProblemsAndUp()); + + MyProvisioningLocation origLoc = mgmt.getLocationManager().createLocation(LocationSpec.create(MyProvisioningLocation.class) + .displayName("mylocname")); + app.start(ImmutableList.of(origLoc)); + assertEquals(origE.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.RUNNING); + EntityTestUtils.assertAttributeEqualsEventually(origE, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + + ServiceStateLogic.setExpectedState(origE, Lifecycle.ON_FIRE); + EntityTestUtils.assertAttributeEqualsEventually(origE, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE); + + newApp = (TestApplication) rebind(); + MyService newE = (MyService) Iterables.getOnlyElement(newApp.getChildren()); + assertNull(newE.getDriver(), "driver should not be initialized because entity is in a permanent failure"); + } + private TestApplication rebind() throws Exception { RebindTestUtils.waitForPersisted(app); TestApplication result = (TestApplication) RebindTestUtils.rebind(mementoDir, getClass().getClassLoader());
