This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit b4fd8d634b44981f28d3c323b55acfdf3930478f Author: Alex Heneveld <[email protected]> AuthorDate: Fri Jun 30 13:08:45 2023 +0100 make attributeWhenReady in workflow not timeout/abort on start/stop or abort previous impl did it for all templates; now we do it just for workflow templates --- .../camp/brooklyn/WorkflowExpressionsYamlTest.java | 4 +- .../core/sensor/DependentConfiguration.java | 18 ++++---- .../workflow/WorkflowExpressionResolution.java | 2 +- .../brooklyn/util/core/text/TemplateProcessor.java | 48 ++++++++++++++++++---- 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java index 3036d535b1..0b11eabba1 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowExpressionsYamlTest.java @@ -226,7 +226,7 @@ public class WorkflowExpressionsYamlTest extends AbstractYamlTest { } @Test - public void testWorkflowExpressionAllowsOnFire() throws Exception { + public void testWorkflowTemplateExpressionAllowsOnFire() throws Exception { Entity entity = createEntity(); WorkflowExecutionContext workflow = invocationWorkflowOnLastEntity( " - step: transform ${entity.attributeWhenReady.foo} | wait | set foo_in_workflow", @@ -248,7 +248,7 @@ public class WorkflowExpressionsYamlTest extends AbstractYamlTest { } @Test - public void testDSLExpressionAbortWhenOnFire() throws Exception { + public void testBrooklynDslExpressionAbortWhenOnFire() throws Exception { createEntity(); WorkflowExecutionContext workflow = invocationWorkflowOnLastEntity( " - step: transform $brooklyn:attributeWhenReady(\"foo\") | wait | set foo_in_workflow", diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java index 351677bcb0..eb4ee249fa 100644 --- a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java +++ b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java @@ -114,14 +114,16 @@ public class DependentConfiguration { private DependentConfiguration() {} /** - * Default readiness is Groovy truth. - * + * Default readiness is Groovy truth, with timeout. * @see #attributeWhenReady(Entity, AttributeSensor, Predicate) */ public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor) { return attributeWhenReady(source, sensor, JavaGroovyEquivalents.groovyTruthPredicate()); } + /** + * @see #attributeWhenReadyAllowingOnFire(Entity, AttributeSensor, Predicate) + */ public static <T> Task<T> attributeWhenReadyAllowingOnFire(Entity source, AttributeSensor<T> sensor) { return attributeWhenReadyAllowingOnFire(source, sensor, JavaGroovyEquivalents.groovyTruthPredicate()); } @@ -136,7 +138,11 @@ public class DependentConfiguration { } /** returns an unsubmitted {@link Task} which blocks until the given sensor on the given source entity gives a value that satisfies ready, then returns that value; - * particular useful in Entity configuration where config will block until Tasks have a value + * particular useful in Entity configuration where config will block until Tasks have a value. + * This task will fail if the entity goes on fire and timeout after 1 minute if starting or stopping, + * so is suitable for use in contexts where there is not a straightforward way to bail out in the case of those events + * (such as resolving template files as part of an upload). + * If this is not desired see {@link #attributeWhenReadyAllowingOnFire(Entity, AttributeSensor, Predicate)}. */ public static <T> Task<T> attributeWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) { Builder<T, T> builder = builder().attributeWhenReady(source, sensor); @@ -145,11 +151,9 @@ public class DependentConfiguration { } - /** returns an unsubmitted {@link Task} which blocks until the given sensor on the given source entity gives a value that satisfies ready, then returns that value; - * particular useful in Entity configuration where config will block until Tasks have a value - */ + /** as {@link #attributeWhenReady(Entity, AttributeSensor, Predicate)} but with no timeout and not aborting if the entity goes on fire. */ public static <T> Task<T> attributeWhenReadyAllowingOnFire(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) { - Builder<T, T> builder = builder().attributeWhenReadyAllowingOnFire(source, sensor).timeoutIfStoppingOrDestroyed(Duration.ONE_MINUTE); + Builder<T, T> builder = builder().attributeWhenReadyAllowingOnFire(source, sensor); if (ready != null) builder.readiness(ready); return builder.build(); diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java index 76bc842329..14dde15a3a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExpressionResolution.java @@ -604,7 +604,7 @@ public class WorkflowExpressionResolution { boolean ourWait = interruptSetIfNeededToPreventWaiting(); try { - result = TemplateProcessor.processTemplateContents("workflow", expression, model, true, false, errorMode); + result = TemplateProcessor.processTemplateContentsForWorkflow("workflow", expression, model, true, false, errorMode); } catch (Exception e) { Exception e2 = e; if (wrappingMode.deferAndRetryErroneousExpressions) { diff --git a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java index 771fe150fb..ba65c16f7a 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java @@ -41,7 +41,6 @@ import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.effector.EffectorBase; 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.EntityInternal; import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.sensor.DependentConfiguration; @@ -87,6 +86,7 @@ public class TemplateProcessor { static ThreadLocalStack<Map<TemplateModel,Object>> TEMPLATE_MODEL_UNWRAP_CACHE = new ThreadLocalStack<>(true); static ThreadLocalStack<String> TEMPLATE_FILE_WANTING_LEGACY_SYNTAX = new ThreadLocalStack<>(true); + static ThreadLocalStack<Boolean> IS_FOR_WORKFLOW = new ThreadLocalStack<>(true); public interface UnwrappableTemplateModel { Maybe<Object> unwrap(); @@ -600,16 +600,19 @@ public class TemplateProcessor { return Maybe.of(entity); } - enum SensorResolutionMode { SENSOR_DEFINITION, ATTRIBUTE_VALUE, ATTRIBUTE_WHEN_READY } + enum SensorResolutionMode { SENSOR_DEFINITION, + ATTRIBUTE_VALUE, + ATTRIBUTE_WHEN_READY_FOR_TEMPLATES, + ATTRIBUTE_WHEN_READY_FOR_WORKFLOW } protected EntityAttributeTemplateModel(EntityInternal entity, SensorResolutionMode mode) { this.entity = entity; if (TEMPLATE_FILE_WANTING_LEGACY_SYNTAX.peek().isPresentAndNonNull()) { // in templates, we have only ever supported attribute when ready. preserve that for now, but warn of deprecation. - if (mode != SensorResolutionMode.ATTRIBUTE_WHEN_READY) { + if (mode != SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES) { log.warn("Using deprecated legacy attributeWhenReady behaviour of ${entity.attribute...} or ${entity.sensor...}. Template should be updated to use ${entity.attributeWhenReady...} if that is required: " + TEMPLATE_FILE_WANTING_LEGACY_SYNTAX.peek()); - mode = SensorResolutionMode.ATTRIBUTE_WHEN_READY; + mode = SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES; } } this.mode = mode; @@ -625,9 +628,12 @@ public class TemplateProcessor { Object result; try { result = - mode == SensorResolutionMode.ATTRIBUTE_WHEN_READY ? - ((EntityInternal)entity).getExecutionContext().get( DependentConfiguration.attributeWhenReadyAllowingOnFire(entity, + mode == SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES ? + ((EntityInternal)entity).getExecutionContext().get( DependentConfiguration.attributeWhenReady(entity, Sensors.builder(Object.class, key).persistence(AttributeSensor.SensorPersistenceMode.NONE).build())) + : mode == SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_WORKFLOW ? + ((EntityInternal)entity).getExecutionContext().get( DependentConfiguration.attributeWhenReadyAllowingOnFire(entity, + Sensors.builder(Object.class, key).persistence(AttributeSensor.SensorPersistenceMode.NONE).build())) : mode == SensorResolutionMode.ATTRIBUTE_VALUE ? entity.sensors().get( Sensors.newSensor(Object.class, key) ) : mode == SensorResolutionMode.SENSOR_DEFINITION ? @@ -679,8 +685,9 @@ public class TemplateProcessor { protected final EntityDriver driver; protected final ManagementContext mgmt; protected final DotSplittingTemplateModel extraSubstitutionsModel; + protected boolean isForWorkflow = false; - // TODO the extra substitutions here (and in LocationAndMapTemplateModel) could be replaced with + // note: the extra substitutions here (and in LocationAndMapTemplateModel) could be replaced with // FirstAvailableTemplateModel(entityModel, mapHashModel) protected EntityAndMapTemplateModel(ManagementContext mgmt, EntityInternal entity, EntityDriver driver) { @@ -690,6 +697,11 @@ public class TemplateProcessor { extraSubstitutionsModel = new DotSplittingTemplateModel(null); } + public EntityAndMapTemplateModel setIsForWorkflow(boolean isForWorkflow) { + this.isForWorkflow = isForWorkflow; + return this; + } + @Override public Maybe<Object> unwrap() { return Maybe.ofDisallowingNull(entity!=null ? entity : mgmt!=null ? mgmt : extraSubstitutionsModel.unwrap().orNull()); @@ -700,7 +712,15 @@ public class TemplateProcessor { } public static TemplateHashModel forEntity(Entity entity, Map<String,? extends Object> extraSubstitutions) { - return new FirstAvailableTemplateModel(new EntityAndMapTemplateModel(null, (EntityInternal) entity, null), wrappedBeanToHashOrNull(entity), dotOrNull(extraSubstitutions)); + EntityAndMapTemplateModel entityModel = new EntityAndMapTemplateModel(null, (EntityInternal) entity, null); + if (Boolean.TRUE.equals(IS_FOR_WORKFLOW.peek().orNull())) entityModel.setIsForWorkflow(true); + return new FirstAvailableTemplateModel(entityModel, wrappedBeanToHashOrNull(entity), dotOrNull(extraSubstitutions)); + } + + public static TemplateHashModel forEntityPossiblyInWorkflow(Entity entity, Map<String,? extends Object> extraSubstitutions, boolean isInWorkflow) { + return new FirstAvailableTemplateModel( + new EntityAndMapTemplateModel(null, (EntityInternal) entity, null).setIsForWorkflow(isInWorkflow), + wrappedBeanToHashOrNull(entity), dotOrNull(extraSubstitutions)); } public static TemplateHashModel forManagementContext(ManagementContext mgmt, Map<String,? extends Object> extraSubstitutions) { @@ -765,7 +785,8 @@ public class TemplateProcessor { return wrapAsTemplateModel( entity instanceof Group ? ((Group)entity).getMembers() : MutableList.of() ); if ("sensor".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_VALUE); if ("attribute".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_VALUE); - if ("attributeWhenReady".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_WHEN_READY); + if ("attributeWhenReady".equals(key)) return new EntityAttributeTemplateModel(entity, + isForWorkflow ? EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_WORKFLOW : EntityAttributeTemplateModel.SensorResolutionMode.ATTRIBUTE_WHEN_READY_FOR_TEMPLATES); // new option if ("sensor_definition".equals(key)) return new EntityAttributeTemplateModel(entity, EntityAttributeTemplateModel.SensorResolutionMode.SENSOR_DEFINITION); if ("effector".equals(key)) return wrapAsTemplateModel(Maps.transformValues(entity.getMutableEntityType().getEffectors(), EffectorBase::of)); @@ -983,6 +1004,15 @@ public class TemplateProcessor { } } + public static Object processTemplateContentsForWorkflow(String context, String templateContents, final TemplateHashModel substitutions, boolean allowSingleVariableObject, boolean logErrors, InterpolationErrorMode errorMode) { + try { + IS_FOR_WORKFLOW.push(true); + return processTemplateContents(context, templateContents, substitutions, allowSingleVariableObject, logErrors, errorMode); + } finally { + IS_FOR_WORKFLOW.pop(); + } + } + public enum InterpolationErrorMode { FAIL, BLANK,
