You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2022/10/24 00:18:51 UTC

[brooklyn-server] branch master updated (e535976362 -> 01a5817bda)

This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git


    from e535976362 fix some error handling edge cases
     new abcd84791c make regex condition use DOTALL mode
     new c1fb900595 unresolveable expressions in conditions are treated as absent not errors
     new 7ac4ca5e35 better logging for bundle metadata and errors
     new 01a5817bda fix bug where tags get set as config on rebind

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../brooklyn/camp/brooklyn/WorkflowYamlTest.java   | 32 +++++++-----
 .../core/mgmt/rebind/dto/MementosGenerators.java   | 61 ++++++++++++----------
 .../brooklyn/core/typereg/BundleUpgradeParser.java |  2 +-
 .../brooklyn/core/typereg/RegisteredTypes.java     |  7 +++
 .../core/workflow/WorkflowExecutionContext.java    |  2 +-
 .../workflow/WorkflowExpressionResolution.java     | 22 +++++++-
 .../util/core/predicates/DslPredicates.java        | 13 ++++-
 .../ResolutionFailureTreatedAsAbsent.java}         | 36 +++++--------
 .../workflow/WorkflowPersistReplayErrorsTest.java  | 12 +++++
 .../util/core/predicates/DslPredicateTest.java     | 13 ++++-
 .../jclouds/RebindJcloudsLocationTest.java         |  6 ++-
 11 files changed, 131 insertions(+), 75 deletions(-)
 copy core/src/main/java/org/apache/brooklyn/util/core/{sensor/SensorPredicates.java => predicates/ResolutionFailureTreatedAsAbsent.java} (51%)


[brooklyn-server] 04/04: fix bug where tags get set as config on rebind

Posted by he...@apache.org.
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 01a5817bda056f70c5477694945333a685a1bdc0
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Mon Oct 24 01:16:51 2022 +0100

    fix bug where tags get set as config on rebind
---
 .../core/mgmt/rebind/dto/MementosGenerators.java   | 61 ++++++++++++----------
 .../jclouds/RebindJcloudsLocationTest.java         |  6 ++-
 2 files changed, 36 insertions(+), 31 deletions(-)

diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index 187c1acf75..9fcfb8a926 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -205,7 +205,31 @@ public class MementosGenerators {
     public static LocationMemento newLocationMemento(Location location) {
         return newLocationMementoBuilder(location).build();
     }
-    
+
+    static Set<String> nonPersistableFlagNames(Object typeInstance, boolean forRemoval) {
+        MutableSet<String> result = MutableSet.copyOf(MutableMap.<String, Object>builder()
+                .putAll(typeInstance == null ? null : FlagUtils.getFieldsWithFlagsWithModifiers(typeInstance, Modifier.TRANSIENT))
+                .putAll(typeInstance == null ? null : FlagUtils.getFieldsWithFlagsWithModifiers(typeInstance, Modifier.STATIC))
+                .filterValues(Predicates.not(Predicates.instanceOf(ConfigKey.class)))
+                .build()
+                .keySet());
+        if (!forRemoval) {
+            result
+                .put("id")
+                .put("name")
+                .put("tags")
+                .put("brooklyn.tags");
+        }
+        return result;
+    }
+
+    static Map<String,Object> persistableFlagValues(Object typeInstance) {
+        return MutableMap.copyOf(MutableMap.<String, Object>builder()
+                .putAll(FlagUtils.getFieldsWithFlagsExcludingModifiers(typeInstance, Modifier.STATIC ^ Modifier.TRANSIENT))
+                .removeAll(nonPersistableFlagNames(typeInstance, false))
+                .build());
+    }
+
     /**
      * @deprecated since 0.7.0; use {@link #newBasicMemento(BrooklynObject)} instead
      */
@@ -214,21 +238,11 @@ public class MementosGenerators {
         BasicLocationMemento.Builder builder = BasicLocationMemento.builder();
         populateBrooklynObjectMementoBuilder(location, builder);
 
-        Set<String> nonPersistableFlagNames = MutableMap.<String,Object>builder()
-                .putAll(FlagUtils.getFieldsWithFlagsWithModifiers(location, Modifier.TRANSIENT))
-                .putAll(FlagUtils.getFieldsWithFlagsWithModifiers(location, Modifier.STATIC))
-                .put("id", String.class)
-                .filterValues(Predicates.not(Predicates.instanceOf(ConfigKey.class)))
-                .build()
-                .keySet();
-        Map<String, Object> persistableFlags = MutableMap.<String, Object>builder()
-                .putAll(FlagUtils.getFieldsWithFlagsExcludingModifiers(location, Modifier.STATIC ^ Modifier.TRANSIENT))
-                .removeAll(nonPersistableFlagNames)
-                .build();
-        ConfigBag persistableConfig = new ConfigBag().copy( ((LocationInternal)location).config().getLocalBag() ).removeAll(nonPersistableFlagNames);
+        ConfigBag persistableConfig = new ConfigBag().copy( ((LocationInternal)location).config().getLocalBag() )
+                .removeAll(nonPersistableFlagNames(location, true));
 
         builder.copyConfig(persistableConfig);
-        builder.locationConfig.putAll(persistableFlags);
+        builder.locationConfig.putAll(persistableFlagValues(location));
 
         Location parentLocation = location.getParent();
         builder.parent = (parentLocation != null) ? parentLocation.getId() : null;
@@ -253,7 +267,6 @@ public class MementosGenerators {
         // TODO persist config keys as well? Or only support those defined on policy class;
         // current code will lose the ConfigKey type on rebind for anything not defined on class.
         // Whereas entities support that.
-        // TODO Do we need the "nonPersistableFlagNames" that locations use?
         Map<ConfigKey<?>, Object> config = ((AbstractPolicy)policy).config().getInternalConfigMap().getAllConfigLocalRaw();
         for (Map.Entry<ConfigKey<?>, Object> entry : config.entrySet()) {
             ConfigKey<?> key = checkNotNull(entry.getKey(), "config=%s", config);
@@ -263,12 +276,7 @@ public class MementosGenerators {
 
         builder.highlights(policy.getHighlights());
 
-        Map<String, Object> persistableFlags = MutableMap.<String, Object>builder()
-                .putAll(FlagUtils.getFieldsWithFlagsExcludingModifiers(policy, Modifier.STATIC ^ Modifier.TRANSIENT))
-                .remove("id")
-                .remove("name")
-                .build();
-        builder.config.putAll(persistableFlags);
+        builder.config.putAll(persistableFlagValues(policy));
 
         return builder.build();
     }
@@ -285,7 +293,6 @@ public class MementosGenerators {
         // TODO persist config keys as well? Or only support those defined on policy class;
         // current code will lose the ConfigKey type on rebind for anything not defined on class.
         // Whereas entities support that.
-        // TODO Do we need the "nonPersistableFlagNames" that locations use?
         Map<ConfigKey<?>, Object> config = ((AbstractEnricher)enricher).config().getInternalConfigMap().getAllConfigLocalRaw();
         for (Map.Entry<ConfigKey<?>, Object> entry : config.entrySet()) {
             ConfigKey<?> key = checkNotNull(entry.getKey(), "config=%s", config);
@@ -293,12 +300,7 @@ public class MementosGenerators {
             builder.config.put(key.getName(), value); 
         }
         
-        Map<String, Object> persistableFlags = MutableMap.<String, Object>builder()
-                .putAll(FlagUtils.getFieldsWithFlagsExcludingModifiers(enricher, Modifier.STATIC ^ Modifier.TRANSIENT))
-                .remove("id")
-                .remove("name")
-                .build();
-        builder.config.putAll(persistableFlags);
+        builder.config.putAll(persistableFlagValues(enricher));
 
         return builder.build();
     }
@@ -315,13 +317,14 @@ public class MementosGenerators {
         // TODO persist config keys as well? Or only support those defined on policy class;
         // current code will lose the ConfigKey type on rebind for anything not defined on class.
         // Whereas entities support that.
-        // TODO Do we need the "nonPersistableFlagNames" that locations use?
         Map<ConfigKey<?>, Object> config = ((AbstractFeed)feed).config().getInternalConfigMap().getAllConfigLocalRaw();
         for (Map.Entry<ConfigKey<?>, Object> entry : config.entrySet()) {
             ConfigKey<?> key = checkNotNull(entry.getKey(), "config=%s", config);
             Object value = configValueToPersistable(entry.getValue(), feed, key.getName());
             builder.config.put(key.getName(), value); 
         }
+
+        // feed does not include flags
         
         return builder.build();
     }
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
index 9261758804..acf5065c85 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
@@ -41,9 +41,10 @@ public class RebindJcloudsLocationTest extends RebindTestFixtureWithApp {
     public void setUp() throws Exception {
         super.setUp();
         origLoc = (JcloudsLocation) origManagementContext.getLocationRegistry().getLocationManaged(LOC_SPEC);
+        origLoc.tags().addTag("Tag");
     }
 
-    // Previously, the rebound config contained "id" which was then passed to createTemporarySshMachineLocation, causing
+    // Previously, the rebound config contained "id" and "tags" which was then passed to createTemporarySshMachineLocation, causing
     // that to fail (because the LocationSpec should not have had "id" in its config)
     @Test
     public void testReboundConfigDoesNotContainId() throws Exception {
@@ -55,7 +56,8 @@ public class RebindJcloudsLocationTest extends RebindTestFixtureWithApp {
         ConfigBag config = ConfigBag.newInstanceCopying(newLocConfig);
         
         assertNull(newLocConfig.getStringKey(("id")));
-        
+        assertNull(newLocConfig.getStringKey(("tags")));
+
         SshMachineLocation tempMachine = newLoc.createTemporarySshMachineLocation(
                 HostAndPort.fromParts("localhost", 1234), 
                 LoginCredentials.builder().identity("myuser").password("mypass").noPrivateKey().build(), 


[brooklyn-server] 02/04: unresolveable expressions in conditions are treated as absent not errors

Posted by he...@apache.org.
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 c1fb900595a81b0ee9c0179b49db601305418809
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Sun Oct 23 20:38:14 2022 +0100

    unresolveable expressions in conditions are treated as absent not errors
---
 .../brooklyn/camp/brooklyn/WorkflowYamlTest.java   | 32 ++++++++++-------
 .../core/workflow/WorkflowExecutionContext.java    |  2 +-
 .../workflow/WorkflowExpressionResolution.java     | 22 ++++++++++--
 .../util/core/predicates/DslPredicates.java        | 10 +++++-
 .../ResolutionFailureTreatedAsAbsent.java          | 41 ++++++++++++++++++++++
 5 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java
index a77910a9f3..756f6d3efd 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java
@@ -68,6 +68,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
 import java.util.function.Predicate;
@@ -228,14 +229,15 @@ public class WorkflowYamlTest extends AbstractYamlTest {
             Duration d3 = Duration.of(sw).subtract(d2);
             // the next iteration should obey the time constraint specified above
             if (!timeCheckOrNullIfShouldFail.test(d3)) Asserts.fail("Timing error, took " + d3);
+
+            WorkflowExecutionContext lastWorkflowContext = new WorkflowStatePersistenceViaSensors(mgmt()).getWorkflows(entity).values().iterator().next();
+            List<Object> defs = lastWorkflowContext.getStepsDefinition();
+            // step definitions should not be resolved by jackson
+            defs.forEach(def -> Asserts.assertThat(def, d -> !(d instanceof WorkflowStepDefinition)));
         } else {
             EntityAsserts.assertAttributeEqualsContinually(entity, s, null);
+            Asserts.assertThat(new WorkflowStatePersistenceViaSensors(mgmt()).getWorkflows(entity).values(), Collection::isEmpty);
         }
-
-        WorkflowExecutionContext lastWorkflowContext = new WorkflowStatePersistenceViaSensors(mgmt()).getWorkflows(entity).values().iterator().next();
-        List<Object> defs = lastWorkflowContext.getStepsDefinition();
-        // step definitions should not be resolved by jackson
-        defs.forEach(def -> Asserts.assertThat(def, d -> !(d instanceof WorkflowStepDefinition)));
     }
 
     public void doTestWorkflowPolicy(String triggers, Predicate<Duration> timeCheckOrNullIfShouldFail) throws Exception {
@@ -551,15 +553,19 @@ public class WorkflowYamlTest extends AbstractYamlTest {
                 e -> Asserts.expectedFailureContainsIgnoreCase(e, "unresolveable", "regex"));
     }
     @Test
-    public void testConditionBadExpression() throws Exception {
-        // TODO would be nice if it could silently ignore this condition
-        // TODO also handle multi-line errors (eg from freemarker)
-        Asserts.assertFailsWith(() -> doTestCondition(Strings.lines(
+    public void testBadExpressionAllowedInCondition() throws Exception {
+        Asserts.assertEquals(doTestCondition(Strings.lines(
+                "any:",
+                "- target: ${bad_var}",
+                "  when: absent"
+        )), "expected failure");
+    }
+    @Test
+    public void testMultilineErrorMessageRegexHandling() throws Exception {
+        Asserts.assertEquals(doTestCondition(Strings.lines(
                 "any:",
-                    "- regex: .*oh no.*",
-                    "- target: ${bad_var}",
-                    "  when: absent")),
-                e -> Asserts.expectedFailureContainsIgnoreCase(e, "unresolveable", "bad_var"));
+                "- regex: .*oh no.*"
+        )), "expected failure");
     }
 
     Object doTestCondition(String lines) throws Exception {
diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java
index 849b980a90..3a4ee58864 100644
--- a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java
@@ -223,7 +223,7 @@ public class WorkflowExecutionContext {
         WorkflowStepResolution.resolveOnErrorSteps(w.getManagementContext(), w.onError);
 
         // some fields need to be resolved at setting time, in the context of the workflow
-        w.setCondition(w.resolveConfig(paramsDefiningWorkflow, WorkflowCommonConfig.CONDITION));
+        w.setCondition(w.resolveWrapped(paramsDefiningWorkflow.getStringKey(WorkflowCommonConfig.CONDITION.getName()), WorkflowCommonConfig.CONDITION.getTypeToken()));
 
         // finished -- checkpoint noting this has been created but not yet started
         w.status = WorkflowStatus.STAGED;
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 4f417eb744..a336f437ed 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
@@ -27,6 +27,7 @@ import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.core.predicates.ResolutionFailureTreatedAsAbsent;
 import org.apache.brooklyn.util.core.task.DeferredSupplier;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
 import org.apache.brooklyn.util.exceptions.Exceptions;
@@ -232,10 +233,15 @@ public class WorkflowExpressionResolution {
         try {
             result = TemplateProcessor.processTemplateContents("workflow", expression, model, true, false);
         } catch (Exception e) {
+            Exception e2 = e;
             if (!allowWaiting && Exceptions.isCausedByInterruptInAnyThread(e)) {
-                throw new IllegalArgumentException("Expression value '"+expression+"' unavailable and not permitted to wait: "+ Exceptions.collapseText(e), e);
+                e2 = new IllegalArgumentException("Expression value '"+expression+"' unavailable and not permitted to wait: "+ Exceptions.collapseText(e), e);
+            }
+            if (useWrappedValue) {
+                // in wrapped value mode, errors don't throw until accessed, and when used in conditions they can be tested as absent
+                return WrappedResolvedExpression.ofError(expression, new ResolutionFailureTreatedAsAbsent.ResolutionFailureTreatedAsAbsentDefaultException(e2));
             } else {
-                throw Exceptions.propagate(e);
+                throw Exceptions.propagate(e2);
             }
         } finally {
             if (!allowWaiting) {
@@ -265,18 +271,30 @@ public class WorkflowExpressionResolution {
     public static class WrappedResolvedExpression<T> implements DeferredSupplier<T> {
         String expression;
         T value;
+        Throwable error;
         public WrappedResolvedExpression() {}
         public WrappedResolvedExpression(String expression, T value) {
             this.expression = expression;
             this.value = value;
         }
+        public static WrappedResolvedExpression ofError(String expression, Throwable error) {
+            WrappedResolvedExpression result = new WrappedResolvedExpression(expression, null);
+            result.error = error;
+            return result;
+        }
         @Override
         public T get() {
+            if (error!=null) {
+                throw Exceptions.propagate(error);
+            }
             return value;
         }
         public String getExpression() {
             return expression;
         }
+        public Throwable getError() {
+            return error;
+        }
     }
 
 }
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java b/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
index f8558254ca..0ff98ce03d 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
@@ -706,7 +706,15 @@ public class DslPredicates {
                 ValueResolver<Object> resolver = Tasks.resolving(target).as(Object.class).allowDeepResolution(true).immediately(true);
                 Entity entity = getTypeFromValueOrContext(Entity.class, input);
                 if (entity!=null) resolver = resolver.context(entity);
-                result = resolver.getMaybe();
+                try {
+                    result = resolver.getMaybe();
+                } catch (Throwable t) {
+                    if (Exceptions.getCausalChain(t).stream().anyMatch(ti -> ti instanceof ResolutionFailureTreatedAsAbsent)) {
+                        result = Maybe.absent(t);
+                    } else {
+                        throw Exceptions.propagate(t);
+                    }
+                }
             }
 
             result = result.isPresent() ? super.resolveTargetAgainstInput(result.get()) : result;
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/predicates/ResolutionFailureTreatedAsAbsent.java b/core/src/main/java/org/apache/brooklyn/util/core/predicates/ResolutionFailureTreatedAsAbsent.java
new file mode 100644
index 0000000000..a3089b297b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/util/core/predicates/ResolutionFailureTreatedAsAbsent.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util.core.predicates;
+
+/** marker interface to indicate that a resolution failure should be treated as absent rather than failing immediately */
+public interface ResolutionFailureTreatedAsAbsent {
+
+    class ResolutionFailureTreatedAsAbsentDefaultException extends RuntimeException implements ResolutionFailureTreatedAsAbsent {
+        public ResolutionFailureTreatedAsAbsentDefaultException() {
+        }
+
+        public ResolutionFailureTreatedAsAbsentDefaultException(String message) {
+            super(message);
+        }
+
+        public ResolutionFailureTreatedAsAbsentDefaultException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public ResolutionFailureTreatedAsAbsentDefaultException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+}


[brooklyn-server] 03/04: better logging for bundle metadata and errors

Posted by he...@apache.org.
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 7ac4ca5e3529006844ab82653dc44631d8f03a1d
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Mon Oct 24 01:16:35 2022 +0100

    better logging for bundle metadata and errors
---
 .../java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java | 2 +-
 .../java/org/apache/brooklyn/core/typereg/RegisteredTypes.java     | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
index f3e2a5b028..89a77258e3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
@@ -609,7 +609,7 @@ public class BundleUpgradeParser {
             (i) -> { 
                 VersionedName targetTypeAtBundleVersion = new VersionedName(i.getSymbolicName(), bundle.getVersion());
                 if (!typeSupplierNames.contains(VersionedName.toOsgiVersionedName(targetTypeAtBundleVersion))) {
-                    throw new IllegalStateException("Bundle manifest declares it upgrades "+i+" "
+                    throw new IllegalStateException("Bundle manifest for "+bundle+" declares it upgrades "+i+" "
                         + "but does not declare an explicit target and does not contain inferred target "+targetTypeAtBundleVersion);
                 }
                 return targetTypeAtBundleVersion; 
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
index da1d5a97f8..f8fec6e810 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java
@@ -174,6 +174,13 @@ public class RegisteredTypes {
         }
         @Override public String getPlanYaml() { throw new UnsupportedOperationException(); }
         @Override public RebindSupport<CatalogItemMemento> getRebindSupport() { throw new UnsupportedOperationException(); }
+
+        @Override
+        public String toString() {
+            return "CatalogItemFromRegisteredType{" +
+                    "type=" + type +
+                    '}';
+        }
     }
     
     /** Preferred mechanism for defining a bean {@link RegisteredType}. 


[brooklyn-server] 01/04: make regex condition use DOTALL mode

Posted by he...@apache.org.
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 abcd84791c1824f36464423d60ab8f5745c88a60
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Sun Oct 23 20:06:43 2022 +0100

    make regex condition use DOTALL mode
---
 .../apache/brooklyn/util/core/predicates/DslPredicates.java |  3 ++-
 .../core/workflow/WorkflowPersistReplayErrorsTest.java      | 12 ++++++++++++
 .../brooklyn/util/core/predicates/DslPredicateTest.java     | 13 +++++++++++--
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java b/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
index 32a2003c4e..f8558254ca 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
@@ -73,6 +73,7 @@ import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.BiFunction;
 import java.util.function.Function;
+import java.util.regex.Pattern;
 
 public class DslPredicates {
 
@@ -416,7 +417,7 @@ public class DslPredicates {
                 return DslPredicates.coercedEqual(test, value);
             });
             checker.check(equals, result, DslPredicates::coercedEqual);
-            checker.check(regex, result, (test, value) -> asStringTestOrFalse(value, v -> v.matches(test)));
+            checker.check(regex, result, (test, value) -> asStringTestOrFalse(value, v -> Pattern.compile(test, Pattern.DOTALL).matcher(v).matches()));
             checker.check(glob, result, (test, value) -> asStringTestOrFalse(value, v -> WildcardGlobs.isGlobMatched(test, v)));
 
             checker.check(inRange, result, (test,value) ->
diff --git a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowPersistReplayErrorsTest.java b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowPersistReplayErrorsTest.java
index 24e08ccf5b..c0a93ee04b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowPersistReplayErrorsTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowPersistReplayErrorsTest.java
@@ -602,6 +602,18 @@ public class WorkflowPersistReplayErrorsTest extends RebindTestFixture<BasicAppl
         Asserts.assertEquals(lastWorkflowContext.currentStepIndex, (Integer) 0);
     }
 
+    @Test
+    public void testMultilineErrorRegex() throws IOException {
+        lastInvocation = runSteps(MutableList.of(
+                        MutableMap.of("step", "log ${var_does_not_exist}",
+                                "output", "should have failed",
+                                "on-error", MutableList.of(
+                                        MutableMap.of("step", "return error handled",
+                                                "condition", MutableMap.of("regex", ".*InvalidReference.*var_does_not_exist.*"))))),
+                null);
+        Asserts.assertEquals(lastInvocation.getUnchecked(), "error handled");
+    }
+
     @Test
     public void testTimeoutOnStep() throws Exception {
         doTestTimeout(false, true);
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/predicates/DslPredicateTest.java b/core/src/test/java/org/apache/brooklyn/util/core/predicates/DslPredicateTest.java
index a413c72591..ca605756fe 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/predicates/DslPredicateTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/predicates/DslPredicateTest.java
@@ -75,6 +75,11 @@ public class DslPredicateTest extends BrooklynMgmtUnitTestSupport {
         });
     }
 
+    DslPredicates.DslPredicate predicate(String key, Object value) {
+        return TypeCoercions.coerce(MutableMap.of(
+               key, value), DslPredicates.DslPredicate.class);
+    }
+
     @Test
     public void testGlob() {
         DslPredicates.DslPredicate p = TypeCoercions.coerce(MutableMap.of(
@@ -86,11 +91,15 @@ public class DslPredicateTest extends BrooklynMgmtUnitTestSupport {
 
     @Test
     public void testRegex() {
-        DslPredicates.DslPredicate p = TypeCoercions.coerce(MutableMap.of(
-                "regex", "x.*z"), DslPredicates.DslPredicate.class);
+        DslPredicates.DslPredicate p = predicate("regex", "x.*z");
         Asserts.assertTrue(p.test("xz"));
         Asserts.assertTrue(p.test("xaz"));
         Asserts.assertFalse(p.test("yxaz"));
+
+        Asserts.assertFalse(predicate("regex", "y").test("xyz"));
+        Asserts.assertFalse(predicate("regex", "y").test("y\nx"));
+        Asserts.assertTrue(predicate("regex", "y\\s+x").test("y\nx"));
+        Asserts.assertTrue(predicate("regex", ".*y.*").test("y\nx"));
     }
 
     @Test