Adds PROVISION_LATCH config Behaviour as other latches. Used in MachineLifecycleEffectorTasks.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/620e4c18 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/620e4c18 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/620e4c18 Branch: refs/heads/master Commit: 620e4c187666137c69396397805b6413716c2075 Parents: 9645e8c Author: Sam Corbett <[email protected]> Authored: Thu Jun 11 15:07:31 2015 +0100 Committer: Sam Corbett <[email protected]> Committed: Thu Jun 11 15:07:31 2015 +0100 ---------------------------------------------------------------------- .../entity/basic/BrooklynConfigKeys.java | 1 + software/base/pom.xml | 7 ++ .../software/MachineLifecycleEffectorTasks.java | 3 +- .../MachineLifecycleEffectorTasksTest.java | 82 ++++++++++++++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/620e4c18/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java b/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java index 25972c6..3c641cb 100644 --- a/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java +++ b/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java @@ -143,6 +143,7 @@ public class BrooklynConfigKeys { * component is up, but this entity does not care about the dependent component's actual config values. */ + public static final ConfigKey<Boolean> PROVISION_LATCH = newBooleanConfigKey("provision.latch", "Latch for blocking location provision until ready"); public static final ConfigKey<Boolean> START_LATCH = newBooleanConfigKey("start.latch", "Latch for blocking start until ready"); public static final ConfigKey<Boolean> SETUP_LATCH = newBooleanConfigKey("setup.latch", "Latch for blocking setup until ready"); public static final ConfigKey<Boolean> PRE_INSTALL_RESOURCES_LATCH = newBooleanConfigKey("resources.preInstall.latch", "Latch for blocking pre-install resources until ready"); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/620e4c18/software/base/pom.xml ---------------------------------------------------------------------- diff --git a/software/base/pom.xml b/software/base/pom.xml index 443b8cd..ba077ce 100644 --- a/software/base/pom.xml +++ b/software/base/pom.xml @@ -141,6 +141,13 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.apache.brooklyn</groupId> + <artifactId>brooklyn-locations-jclouds</artifactId> + <version>${project.version}</version> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> + <dependency> <groupId>mx4j</groupId> <artifactId>mx4j-tools</artifactId> <scope>test</scope> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/620e4c18/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java index 9c929bb..2ba42f7 100644 --- a/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java +++ b/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java @@ -25,7 +25,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; - import javax.annotation.Nullable; import org.slf4j.Logger; @@ -275,6 +274,8 @@ public abstract class MachineLifecycleEffectorTasks { return DynamicTasks.queue(Tasks.<MachineLocation>builder().name("provisioning ("+location.getDisplayName()+")").body( new Callable<MachineLocation>() { public MachineLocation call() throws Exception { + // Blocks if a latch was configured. + entity().getConfig(BrooklynConfigKeys.PROVISION_LATCH); final Map<String,Object> flags = obtainProvisioningFlags(location); if (!(location instanceof LocalhostMachineProvisioningLocation)) log.info("Starting {}, obtaining a new location instance in {} with ports {}", new Object[] {entity(), location, flags.get("inboundPorts")}); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/620e4c18/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java b/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java index 2e73ca7..24fa657 100644 --- a/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java +++ b/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java @@ -19,14 +19,41 @@ package brooklyn.entity.software; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.util.List; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +import brooklyn.entity.Entity; +import brooklyn.entity.basic.BasicEntity; import brooklyn.entity.basic.BasicEntityImpl; +import brooklyn.entity.basic.BrooklynConfigKeys; +import brooklyn.entity.basic.BrooklynTaskTags; +import brooklyn.entity.basic.EmptySoftwareProcess; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.EntityLocal; import brooklyn.entity.basic.Lifecycle; import brooklyn.entity.basic.SoftwareProcess; import brooklyn.entity.basic.SoftwareProcess.StopSoftwareParameters.StopMode; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.entity.trait.Startable; +import brooklyn.event.AttributeSensor; +import brooklyn.event.basic.DependentConfiguration; +import brooklyn.event.basic.Sensors; +import brooklyn.location.jclouds.BailOutJcloudsLocation; +import brooklyn.management.Task; +import brooklyn.test.Asserts; +import brooklyn.test.entity.TestApplication; +import brooklyn.util.task.TaskInternal; +import brooklyn.util.time.Duration; public class MachineLifecycleEffectorTasksTest { public static boolean canStop(StopMode stopMode, boolean isEntityStopped) { @@ -54,4 +81,59 @@ public class MachineLifecycleEffectorTasksTest { assertEquals(canStop, expected); } + @Test + public void testProvisionLatchObeyed() throws Exception { + + AttributeSensor<Boolean> ready = Sensors.newBooleanSensor("readiness"); + + TestApplication app = TestApplication.Factory.newManagedInstanceForTests(); + BasicEntity triggerEntity = app.createAndManageChild(EntitySpec.create(BasicEntity.class)); + + EmptySoftwareProcess entity = app.createAndManageChild(EntitySpec.create(EmptySoftwareProcess.class) + .configure(BrooklynConfigKeys.PROVISION_LATCH, DependentConfiguration.attributeWhenReady(triggerEntity, ready))); + + final Task<Void> task = Entities.invokeEffector(app, app, Startable.START, ImmutableMap.of( + "locations", ImmutableList.of(BailOutJcloudsLocation.newBailOutJcloudsLocation(app.getManagementContext())))); + + assertEffectorBlockingDetailsEventually(entity, "Waiting for config " + BrooklynConfigKeys.PROVISION_LATCH.getName()); + + Asserts.succeedsContinually(new Runnable() { + @Override + public void run() { + assertFalse(task.isDone()); + } + }); + try { + ((EntityLocal) triggerEntity).setAttribute(ready, true); + task.get(Duration.THIRTY_SECONDS); + } catch (Throwable t) { + // BailOut location throws but we don't care. + } finally { + Entities.destroyAll(app.getManagementContext()); + } + } + + private void assertEffectorBlockingDetailsEventually(final Entity entity, final String blockingDetailsSnippet) { + Asserts.succeedsEventually(new Runnable() { + @Override public void run() { + Task<?> entityTask = Iterables.getOnlyElement(entity.getApplication().getManagementContext().getExecutionManager().getTasksWithAllTags( + ImmutableList.of(BrooklynTaskTags.EFFECTOR_TAG, BrooklynTaskTags.tagForContextEntity(entity)))); + String blockingDetails = getBlockingDetails(entityTask); + assertTrue(blockingDetails.contains(blockingDetailsSnippet)); + }}); + } + + private String getBlockingDetails(Task<?> task) { + List<TaskInternal<?>> taskChain = Lists.newArrayList(); + TaskInternal<?> taskI = (TaskInternal<?>) task; + while (taskI != null) { + taskChain.add(taskI); + if (taskI.getBlockingDetails() != null) { + return taskI.getBlockingDetails(); + } + taskI = (TaskInternal<?>) taskI.getBlockingTask(); + } + throw new IllegalStateException("No blocking details for "+task+" (walked task chain "+taskChain+")"); + } + }
