Change conditional entity to reflect service state of optional child Propagate value for service.isUp and optional configurable set of sensors
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/ec3010e4 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/ec3010e4 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/ec3010e4 Branch: refs/heads/master Commit: ec3010e412440e3a20e2f5e973e0774335990546 Parents: b73cb73 Author: Andrew Donald Kennedy <[email protected]> Authored: Wed Aug 10 18:24:45 2016 +0100 Committer: Andrew Donald Kennedy <[email protected]> Committed: Sat Aug 20 17:15:13 2016 +0100 ---------------------------------------------------------------------- .../entity/stock/ConditionalEntity.java | 23 +++++- .../entity/stock/ConditionalEntityImpl.java | 82 +++++++++++++++++--- .../entity/stock/ConditionalEntityTest.java | 33 +++++++- 3 files changed, 124 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ec3010e4/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java index 0e0a112..c5f8d81 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java +++ b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java @@ -18,6 +18,8 @@ */ package org.apache.brooklyn.entity.stock; +import java.util.Collection; + import com.google.common.annotations.Beta; import com.google.common.reflect.TypeToken; @@ -44,6 +46,10 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag; * brooklyn.config: * proxy.port: 8080 * loadbalancer.serverpool: $brooklyn:entity("servers") + * conditional.entity.propagate: true + * conditional.entity.sensors: + * - $brooklyn:sensor("proxy.http.port") + * - $brooklyn:sensor("main.uri") * </pre> */ @Beta @@ -51,11 +57,22 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag; public interface ConditionalEntity extends BasicStartable { @SetFromFlag("entitySpec") - ConfigKey<EntitySpec<?>> CONDITIONAL_ENTITY_SPEC = ConfigKeys.newConfigKey(new TypeToken<EntitySpec<?>>() { }, "conditional.entity.spec", "The entity specification to be created"); + ConfigKey<EntitySpec<?>> CONDITIONAL_ENTITY_SPEC = ConfigKeys.newConfigKey(new TypeToken<EntitySpec<?>>() { }, + "conditional.entity.spec", "The entity specification to be created"); @SetFromFlag("create") - AttributeSensorAndConfigKey<Boolean, Boolean> CREATE_CONDITIONAL_ENTITY = ConfigKeys.newSensorAndConfigKey(Boolean.class, "conditional.entity.create", "Whether the entity should be created"); + AttributeSensorAndConfigKey<Boolean, Boolean> CREATE_CONDITIONAL_ENTITY = ConfigKeys.newSensorAndConfigKey(Boolean.class, + "conditional.entity.create", "Whether the entity should be created"); + + @SetFromFlag("propagateSensors") + ConfigKey<Boolean> PROPAGATE_CONDITIONAL_ENTITY_SENSORS = ConfigKeys.newBooleanConfigKey( + "conditional.entity.propagate", "Whether sensors are to be propagated from the child entity", Boolean.TRUE); + + @SetFromFlag("sensorsToPropagate") + ConfigKey<Collection<AttributeSensor<?>>> CONDITIONAL_ENTITY_SENSOR_LIST = ConfigKeys.newConfigKey(new TypeToken<Collection<AttributeSensor<?>>>() { }, + "conditional.entity.sensors", "Collection of sensors that are to be propagated from the child entity (all usual sensors if not set, or empty)"); - AttributeSensor<Entity> CONDITIONAL_ENTITY = Sensors.newSensor(Entity.class, "conditional.entity", "The created entity"); + AttributeSensor<Entity> CONDITIONAL_ENTITY = Sensors.newSensor(Entity.class, + "conditional.entity", "The created entity"); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ec3010e4/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java index 6c73a87..054b5b0 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java @@ -19,26 +19,88 @@ package org.apache.brooklyn.entity.stock; import java.util.Collection; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.sensor.AttributeSensor; +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.lifecycle.Lifecycle; +import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic; +import org.apache.brooklyn.core.entity.trait.Startable; +import org.apache.brooklyn.core.location.Locations; +import org.apache.brooklyn.enricher.stock.Enrichers; +import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.time.Duration; public class ConditionalEntityImpl extends BasicStartableImpl implements ConditionalEntity { + private static final Logger LOG = LoggerFactory.getLogger(BasicStartableImpl.class); + @Override public void start(Collection<? extends Location> locations) { - Entity child = sensors().get(CONDITIONAL_ENTITY); - EntitySpec<?> spec = config().get(CONDITIONAL_ENTITY_SPEC); - Boolean create = config().get(CREATE_CONDITIONAL_ENTITY); - - // Child not yet created; Entity spec is present; Create flag is true - if (child == null && spec != null && Boolean.TRUE.equals(create)) { - Entity created = addChild(EntitySpec.create(spec)); - sensors().set(CONDITIONAL_ENTITY, created); + try { + ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING); + sensors().set(Attributes.SERVICE_UP, false); + + // Block startup until other dependent components are available + Object val = config().get(START_LATCH); + if (val != null) { + LOG.debug("Finished waiting for start-latch in {}", this); + } + + Entity child = sensors().get(CONDITIONAL_ENTITY); + EntitySpec<?> spec = config().get(CONDITIONAL_ENTITY_SPEC); + Boolean create = config().get(CREATE_CONDITIONAL_ENTITY); + Boolean propagate = config().get(PROPAGATE_CONDITIONAL_ENTITY_SENSORS); + Set<AttributeSensor<?>> sensors = MutableSet.copyOf(config().get(CONDITIONAL_ENTITY_SENSOR_LIST)); + Duration timeout = config().get(BrooklynConfigKeys.START_TIMEOUT); + + addLocations(locations); + locations = Locations.getLocationsCheckingAncestors(locations, this); + LOG.info("Starting entity {}: {}", this, locations); + + // Child not yet created; Entity spec is present; Create flag is true + if (child == null && spec != null && Boolean.TRUE.equals(create)) { + child = addChild(EntitySpec.create(spec)); + sensors().set(CONDITIONAL_ENTITY, child); + + // Add enrichers for sensor propagateion + enrichers().add(Enrichers.builder().propagating(Startable.SERVICE_UP).from(child).build()); + if (Boolean.TRUE.equals(propagate)) { + if (sensors.isEmpty()) { + enrichers().add(Enrichers.builder().propagatingAllButUsualAnd().from(child).build()); + } else { + enrichers().add(Enrichers.builder().propagating(sensors).from(child).build()); + } + } + } + + // Start child if create flag is set; otherwise just set service.isUp + if (Boolean.TRUE.equals(create)) { + LOG.info("Starting child {}: {}", child, locations); + if (Entities.invokeEffectorWithArgs(this, child, Startable.START, locations).blockUntilEnded(timeout)) { + LOG.debug("Successfully started {} by {}", child, this); + } else { + throw new IllegalStateException(String.format("Timed out while %s was starting %s", this, child)); + } + } else { + LOG.debug("No child created, setting SERVICE_UP to true"); + sensors().set(Attributes.SERVICE_UP, true); + } + + ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING); + } catch (Throwable t) { + ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); + throw Exceptions.propagate(t); } - super.start(locations); } - } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ec3010e4/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java b/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java index 0e1a56e..7ef837c 100644 --- a/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java +++ b/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java @@ -19,17 +19,21 @@ package org.apache.brooklyn.entity.stock; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.core.entity.EntityAsserts; +import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.location.SimulatedLocation; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; import org.apache.brooklyn.core.test.entity.TestEntity; @@ -57,6 +61,33 @@ public class ConditionalEntityTest extends BrooklynAppUnitTestSupport { Entity child = Iterables.getOnlyElement(optional.getChildren()); assertTrue(child instanceof TestEntity); assertEquals(child, optional.sensors().get(ConditionalEntity.CONDITIONAL_ENTITY)); + + // The service.isUp sensor will have been propagated by default + EntityAsserts.assertAttributeEqualsEventually(child, Startable.SERVICE_UP, true); + EntityAsserts.assertAttributeEqualsEventually(optional, Startable.SERVICE_UP, true); + } + + @Test + public void testAddsConditionalAndPropagatesSensors() throws Exception { + optional = app.addChild(EntitySpec.create(ConditionalEntity.class) + .configure(ConditionalEntity.CREATE_CONDITIONAL_ENTITY, true) + .configure(ConditionalEntity.PROPAGATE_CONDITIONAL_ENTITY_SENSORS, true) + .configure(ConditionalEntity.CONDITIONAL_ENTITY_SENSOR_LIST, ImmutableList.<AttributeSensor<?>>of(TestEntity.SEQUENCE)) + .configure(ConditionalEntity.CONDITIONAL_ENTITY_SPEC, EntitySpec.create(TestEntity.class))); + app.start(ImmutableList.of(loc1)); + + assertEquals(optional.getChildren().size(), 1); + Entity child = Iterables.getOnlyElement(optional.getChildren()); + assertTrue(child instanceof TestEntity); + assertEquals(child, optional.sensors().get(ConditionalEntity.CONDITIONAL_ENTITY)); + + // Check that the configured sensors are propagated + child.sensors().set(TestEntity.SEQUENCE, 123); + EntityAsserts.assertAttributeEqualsEventually(child, TestEntity.SEQUENCE, 123); + EntityAsserts.assertAttributeEqualsEventually(optional, TestEntity.SEQUENCE, 123); + child.sensors().set(TestEntity.NAME, "frog"); + EntityAsserts.assertAttributeEqualsEventually(child, TestEntity.NAME, "frog"); + EntityAsserts.assertAttribute(optional, TestEntity.NAME, Predicates.isNull()); } @Test
