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 2021/08/06 13:27:33 UTC

[brooklyn-server] branch master updated (349ba81 -> bd4a04f)

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 349ba81  Merge pull request #1216 from jcabrerizo/feature/bump-vulnerable-version-2108
     new ad36919  clearer test for scope root -- add names
     new f062ce7  add test which fails for scope root - about to fix
     new 16c28fc  fix scope root evaluation, passes previous test
     new 9876944  ensure scopeRoot resovles to the root node of the blueprint _where the DSL is used_
     new 492e34f  more thorough way to replace scopeRoot with self
     new f0edbaf  update test which asserted the broken behaviour (with a TODO to fix it!)
     new f271667  fix another test with wrong scopeRoot semantics
     new 471003d  notes on unsupported cases for scopeRoot
     new bd4a04f  This closes #1217

The 9 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:
 .../camp/brooklyn/spi/creation/CampResolver.java   | 63 ++++++++++++++++--
 .../brooklyn/spi/dsl/methods/DslComponent.java     | 18 ++++-
 .../camp/brooklyn/ConfigParametersYamlTest.java    | 20 ++++--
 .../brooklyn/camp/brooklyn/EntitiesYamlTest.java   | 76 ++++++++++++++++------
 .../camp/brooklyn/ReferencingYamlTestEntity.java   |  6 ++
 .../camp/brooklyn/spi/dsl/DslYamlTest.java         | 41 +++++++++---
 .../org/apache/brooklyn/core/entity/Entities.java  | 11 ++++
 7 files changed, 193 insertions(+), 42 deletions(-)

[brooklyn-server] 05/09: more thorough way to replace scopeRoot with self

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 492e34f4dbc51cb29f937edd1365b238a8dbc4b3
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 13:32:07 2021 +0100

    more thorough way to replace scopeRoot with self
    
    but with some gaps, described by a TODO
---
 .../camp/brooklyn/spi/creation/CampResolver.java   | 46 +++++++++++++++-------
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
index 9d809d9..548bc1e 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
@@ -38,8 +38,11 @@ import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
 import org.apache.brooklyn.camp.BasicCampPlatform;
 import org.apache.brooklyn.camp.CampPlatform;
 import org.apache.brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.parse.DslParser;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
 import org.apache.brooklyn.config.ConfigKey;
@@ -129,9 +132,9 @@ class CampResolver {
             } else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Location.class)) {
                 spec = CampInternalUtils.createLocationSpec(planYaml, loader, encounteredTypes);
             } else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Application.class)) {
-                spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, true);
+                spec = createEntitySpecFromServicesBlock(mgmt, planYaml, loader, encounteredTypes, true);
             } else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Entity.class)) {
-                spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, false);
+                spec = createEntitySpecFromServicesBlock(mgmt, planYaml, loader, encounteredTypes, false);
             } else {
                 String msg = (item.getSuperTypes()==null || item.getSuperTypes().isEmpty()) ? "no supertypes declared" : "incompatible supertypes "+item.getSuperTypes();
                 String itemName = Strings.firstNonBlank(item.getSymbolicName(), BasicBrooklynCatalog.currentlyResolvingType.get(), "<unidentified>");
@@ -168,7 +171,7 @@ class CampResolver {
         }
     }
  
-    private static EntitySpec<?> createEntitySpecFromServicesBlock(String plan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes, boolean isApplication) {
+    private static EntitySpec<?> createEntitySpecFromServicesBlock(ManagementContext mgmt, String plan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes, boolean isApplication) {
         CampPlatform camp = CampInternalUtils.getCampPlatform(loader.getManagementContext());
 
         // TODO instead of BasicBrooklynCatalog.attemptLegacySpecTransformers where candidate yaml has 'services:' prepended, try that in this method
@@ -186,7 +189,7 @@ class CampResolver {
             // the instantiator will have done that, and it knows if the plan
             // specified a wrapped app explicitly (whereas we don't easily know that here!)
 
-            fixScopeRootAtRoot(result);
+            fixScopeRootAtRoot(mgmt, result);
 
             return result;
             
@@ -199,26 +202,41 @@ class CampResolver {
 
     }
 
-    private static void fixScopeRootAtRoot(EntitySpec<?> node) {
+    private static void fixScopeRootAtRoot(ManagementContext mgmt, EntitySpec<?> node) {
         node.getConfig().entrySet().forEach(entry -> {
-            fixScopeRoot(entry.getValue(), newValue -> node.configure( (ConfigKey) entry.getKey(), newValue));
+            fixScopeRoot(mgmt, entry.getValue(), newValue -> node.configure( (ConfigKey) entry.getKey(), newValue));
         });
         node.getFlags().entrySet().forEach(entry -> {
-            fixScopeRoot(entry.getValue(), newValue -> node.configure( entry.getKey(), newValue));
+            fixScopeRoot(mgmt, entry.getValue(), newValue -> node.configure( entry.getKey(), newValue));
         });
     }
 
-    private static void fixScopeRoot(Object value, Consumer<Object> updater) {
+    private static void fixScopeRoot(ManagementContext mgmt, Object value, Consumer<Object> updater) {
         Function<String,String> fixString = v -> "$brooklyn:self()" + Strings.removeFromStart((String)v, "$brooklyn:scopeRoot()");
-        if (value instanceof String && ((String)value).startsWith("$brooklyn:scopeRoot()")) {
-            value = fixString.apply((String)value);
-            updater.accept(value);
-        } else if (value instanceof DslComponent) {
+        if (value instanceof String) {
+            if (((String)value).startsWith("$brooklyn:scopeRoot()")) {
+                updater.accept( fixString.apply((String)value) );
+            }
+            return;
+        }
+        if (value instanceof BrooklynDslDeferredSupplier) {
+            if (value.toString().startsWith("$brooklyn:scopeRoot()")) {
+                updater.accept(DslUtils.parseBrooklynDsl(mgmt, fixString.apply(value.toString())));
+                return;
+            }
+        }
+
+        if (value instanceof DslComponent) {
+            // superseded by above - no longer used?
             if ( ((DslComponent)value).getScope() == Scope.SCOPE_ROOT ) {
-                value = DslComponent.newInstanceChangingScope(Scope.THIS, (DslComponent) value, fixString);
-                updater.accept(value);
+                updater.accept( DslComponent.newInstanceChangingScope(Scope.THIS, (DslComponent) value, fixString) );
             }
+            return;
         }
+
+        // TODO replace within maps and strings; currently only supported at root of config or flags
+        // or have some way to gather the scope root components created and convert them all; easy enough for outer, but harder for nested DSL items,
+        // we need to update the dsl string as well as the items themselves
     }
 
 }
\ No newline at end of file

[brooklyn-server] 01/09: clearer test for scope root -- add names

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 ad3691956221e1a57faabab074f2b9bb38f6e4e6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 11:35:53 2021 +0100

    clearer test for scope root -- add names
---
 .../brooklyn/camp/brooklyn/EntitiesYamlTest.java   | 30 ++++++++++++++--------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index 3da5fe3..8aa75ef 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -536,59 +536,69 @@ public class EntitiesYamlTest extends AbstractYamlTest {
                 "  - id: ref_child",
                 "    item:",
                 "      type: " + ReferencingYamlTestEntity.class.getName(),
+                "      name: RC",
                 "      test.reference.root: $brooklyn:root()",
                 "      test.reference.scope_root: $brooklyn:scopeRoot()",
                 "      brooklyn.children:",
                 "      - type: " + ReferencingYamlTestEntity.class.getName(),
+                "        name: RC-child",
                 "        test.reference.root: $brooklyn:root()",
                 "        test.reference.scope_root: $brooklyn:scopeRoot()",
 
                 "  - id: ref_parent",
                 "    item:",
                 "      type: " + ReferencingYamlTestEntity.class.getName(),
+                "      name: RP",
                 "      test.reference.root: $brooklyn:root()",
                 "      test.reference.scope_root: $brooklyn:scopeRoot()",
                 "      brooklyn.children:",
                 "      - type: " + ReferencingYamlTestEntity.class.getName(),
+                "        name: RP-child",
                 "        test.reference.root: $brooklyn:root()",
                 "        test.reference.scope_root: $brooklyn:scopeRoot()",
                 "        brooklyn.children:",
-                "        - type: ref_child");
+                "        - type: ref_child",
+                "          name: RP-grandchild=RC");
         
         Entity app = createAndStartApplication(
                 "brooklyn.config:",
                 "  test.reference.root: $brooklyn:root()",
                 "  test.reference.scope_root: $brooklyn:scopeRoot()",
+                "name: APP",
                 "services:",
                 "- type: " + ReferencingYamlTestEntity.class.getName(),
+                "  name: APP-child",
                 "  test.reference.root: $brooklyn:root()",
                 "  test.reference.scope_root: $brooklyn:scopeRoot()",
                 "  brooklyn.children:",
                 "  - type: " + ReferencingYamlTestEntity.class.getName(),
+                "    name: APP-grandchild",
                 "    test.reference.root: $brooklyn:root()",
                 "    test.reference.scope_root: $brooklyn:scopeRoot()",
                 "    brooklyn.children:",
-                "    - type: ref_parent");
+                "    - type: ref_parent",
+                "      name: APP-greatgrandchild=RP");
         
-        assertScopes(app, app, app);
+        assertScopes(app, "APP", app, app);
         Entity e1 = nextChild(app);
-        assertScopes(e1, app, app);
+        assertScopes(e1, "APP-child", app, app);
         Entity e2 = nextChild(e1);
-        assertScopes(e2, app, app);
+        assertScopes(e2, "APP-grandchild", app, app);
         Entity e3 = nextChild(e2);
-        assertScopes(e3, app, e3);
+        assertScopes(e3, "APP-greatgrandchild=RP", app, e3);
         Entity e4 = nextChild(e3);
-        assertScopes(e4, app, e3);
+        assertScopes(e4, "RP-child", app, e3);
         Entity e5 = nextChild(e4);
-        assertScopes(e5, app, e5);
+        assertScopes(e5, "RP-grandchild=RC", app, e5);
         Entity e6 = nextChild(e5);
-        assertScopes(e6, app, e5);
+        assertScopes(e6, "RC-child", app, e5);
     }
     
     private static Entity nextChild(Entity entity) {
         return Iterables.getOnlyElement(entity.getChildren());
     }
-    private static void assertScopes(Entity entity, Entity root, Entity scopeRoot) {
+    private static void assertScopes(Entity entity, String name, Entity root, Entity scopeRoot) {
+        if (name!=null) assertEquals(entity.getDisplayName(), name);
         assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_ROOT), root);
         assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT), scopeRoot);
     }

[brooklyn-server] 04/09: ensure scopeRoot resovles to the root node of the blueprint _where the DSL is used_

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 987694403aae28046a94f11d730a55c9c08532f8
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 12:45:48 2021 +0100

    ensure scopeRoot resovles to the root node of the blueprint _where the DSL is used_
    
    even for nested (extended) types - do this by replacing the DSL expression _at parse time_
---
 .../camp/brooklyn/spi/creation/CampResolver.java   | 34 ++++++++++++++++++++--
 .../brooklyn/spi/dsl/methods/DslComponent.java     | 18 +++++++++++-
 .../brooklyn/camp/brooklyn/EntitiesYamlTest.java   | 12 ++------
 3 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
index 8ac1ecb..9d809d9 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
@@ -22,6 +22,8 @@ import com.google.common.annotations.Beta;
 import java.util.Set;
 
 import java.util.Stack;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
@@ -36,8 +38,11 @@ import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
 import org.apache.brooklyn.camp.BasicCampPlatform;
 import org.apache.brooklyn.camp.CampPlatform;
 import org.apache.brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
+import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.AbstractEntity;
@@ -176,11 +181,14 @@ class CampResolver {
 
             // above will unwrap but only if it's an Application (and it's permitted); 
             // but it doesn't know whether we need an App or if an Entity is okay  
-            if (!isApplication) return EntityManagementUtils.unwrapEntity(appSpec);
+            EntitySpec<?> result = !isApplication ? EntityManagementUtils.unwrapEntity(appSpec) : appSpec;
             // if we need an App then definitely *don't* unwrap here because
             // the instantiator will have done that, and it knows if the plan
             // specified a wrapped app explicitly (whereas we don't easily know that here!)
-            return appSpec;
+
+            fixScopeRootAtRoot(result);
+
+            return result;
             
         } else {
             if (at.getPlatformComponentTemplates()==null || at.getPlatformComponentTemplates().isEmpty()) {
@@ -191,4 +199,26 @@ class CampResolver {
 
     }
 
+    private static void fixScopeRootAtRoot(EntitySpec<?> node) {
+        node.getConfig().entrySet().forEach(entry -> {
+            fixScopeRoot(entry.getValue(), newValue -> node.configure( (ConfigKey) entry.getKey(), newValue));
+        });
+        node.getFlags().entrySet().forEach(entry -> {
+            fixScopeRoot(entry.getValue(), newValue -> node.configure( entry.getKey(), newValue));
+        });
+    }
+
+    private static void fixScopeRoot(Object value, Consumer<Object> updater) {
+        Function<String,String> fixString = v -> "$brooklyn:self()" + Strings.removeFromStart((String)v, "$brooklyn:scopeRoot()");
+        if (value instanceof String && ((String)value).startsWith("$brooklyn:scopeRoot()")) {
+            value = fixString.apply((String)value);
+            updater.accept(value);
+        } else if (value instanceof DslComponent) {
+            if ( ((DslComponent)value).getScope() == Scope.SCOPE_ROOT ) {
+                value = DslComponent.newInstanceChangingScope(Scope.THIS, (DslComponent) value, fixString);
+                updater.accept(value);
+            }
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index cf6fa2d..01c68e1 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.camp.brooklyn.spi.dsl.methods;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import java.util.Set;
+import java.util.function.Function;
 import static org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils.resolved;
 
 import java.util.Collection;
@@ -113,6 +114,20 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> implements
         }
     }
 
+    public static DslComponent newInstanceChangingScope(Scope scope, DslComponent old, Function<String,String> dslUpdateFn) {
+        DslComponent result;
+        if (old.componentIdSupplier!=null) result = new DslComponent(scope, old.componentIdSupplier);
+        else if (old.componentId!=null) result = new DslComponent(scope, old.componentId);
+        else result = new DslComponent(scope);
+
+        if (dslUpdateFn!=null && old.dsl instanceof String) {
+            result.dsl = dslUpdateFn.apply((String) old.dsl);
+        } else {
+            result.dsl = old.dsl;
+        }
+        return result;
+    }
+
     /**
      * Resolve componentId in the {@link Scope#GLOBAL} scope.
      * 
@@ -1028,7 +1043,8 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> implements
         DESCENDANT,
         ANCESTOR,
         ROOT,
-        /** highest ancestor where all items come from the same catalog item ID */
+        /** root node of blueprint where the the DSL is used; usually the depth in ancestor,
+         *  though specially treated in CampResolver to handle usage within blueprints */
         SCOPE_ROOT,
         THIS;
 
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index 4ee8a4c..e86ab1a 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -586,7 +586,8 @@ public class EntitiesYamlTest extends AbstractYamlTest {
         Entity e2 = nextChild(e1);
         assertScopes(e2, "APP-grandchild", app, app);
         Entity e3 = nextChild(e2);
-        assertScopes(e3, "APP-greatgrandchild=RP", app, e2, app);
+        // see logic in CampResolver which ensures scopeRoot in a nested blueprint refer to the root of that nested blueprint
+        assertScopes(e3, "APP-greatgrandchild=RP", app, e3, app);
         Entity e4 = nextChild(e3);
         assertScopes(e4, "RP-child", app, e3);
         Entity e5 = nextChild(e4);
@@ -622,14 +623,7 @@ public class EntitiesYamlTest extends AbstractYamlTest {
     private static void assertScopes(Entity entity, String name, Entity root, Entity scopeRoot, Entity scopeRoot2) {
         if (name!=null) assertEquals(entity.getDisplayName(), name);
         assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_ROOT), root);
-
-        Entity actualScopeRoot = entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT);
-        if (!actualScopeRoot.equals(scopeRoot) && !actualScopeRoot.equals(scopeRoot2)) {
-            Assert.fail("Wrong scope root; should be either "+scopeRoot+" or "+scopeRoot2+"; but is actually "+actualScopeRoot);
-        }
-        // TODO would be nice if we can capture which blueprint scopeRoot is used in - but this requires introspecting the DSL
-        // currently it will always equal scopeRoot2; if we could convert it to "self()" when the definition is loaded, that would solve it
-
+        assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT), scopeRoot);
         assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT2), scopeRoot2);
     }
 

[brooklyn-server] 08/09: notes on unsupported cases for scopeRoot

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 471003d76487fe92372a0f70f1336e2554185360
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 14:07:07 2021 +0100

    notes on unsupported cases for scopeRoot
---
 .../camp/brooklyn/spi/creation/CampResolver.java   | 27 ++++++++++++---------
 .../camp/brooklyn/spi/dsl/DslYamlTest.java         | 28 ++++++++++++++++++++++
 2 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
index 548bc1e..ca27432 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
@@ -213,12 +213,13 @@ class CampResolver {
 
     private static void fixScopeRoot(ManagementContext mgmt, Object value, Consumer<Object> updater) {
         Function<String,String> fixString = v -> "$brooklyn:self()" + Strings.removeFromStart((String)v, "$brooklyn:scopeRoot()");
-        if (value instanceof String) {
-            if (((String)value).startsWith("$brooklyn:scopeRoot()")) {
-                updater.accept( fixString.apply((String)value) );
-            }
-            return;
-        }
+        // TODO better approach to replacing scopeRoot
+        // we could replace within maps and strings, and inside DSL; currently only supported at root of config or flags
+        // but that's hard, we'd need to rebuild those maps and strings, which might be inside objects;
+        // and we'd need to replace references to scopeRoot inside a DSL, eg formatString;
+        // better would be to collect the DSL items we just created, and convert those if they belong to the now-root node (possibly promoted);
+        // it is a rare edge case however, so for now we use this poor-man's logic which captures the most common case --
+        // see DslYamlTest.testDslScopeRootEdgeCases
         if (value instanceof BrooklynDslDeferredSupplier) {
             if (value.toString().startsWith("$brooklyn:scopeRoot()")) {
                 updater.accept(DslUtils.parseBrooklynDsl(mgmt, fixString.apply(value.toString())));
@@ -226,17 +227,21 @@ class CampResolver {
             }
         }
 
+        // don't think blocks below here ever get used...
+        if (value instanceof String) {
+            if (((String)value).startsWith("$brooklyn:scopeRoot()")) {
+                updater.accept( fixString.apply((String)value) );
+            }
+            return;
+        }
+
         if (value instanceof DslComponent) {
-            // superseded by above - no longer used?
+            // superseded by above - no longer used
             if ( ((DslComponent)value).getScope() == Scope.SCOPE_ROOT ) {
                 updater.accept( DslComponent.newInstanceChangingScope(Scope.THIS, (DslComponent) value, fixString) );
             }
             return;
         }
-
-        // TODO replace within maps and strings; currently only supported at root of config or flags
-        // or have some way to gather the scope root components created and convert them all; easy enough for outer, but harder for nested DSL items,
-        // we need to update the dsl string as well as the items themselves
     }
 
 }
\ No newline at end of file
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java
index 71238c9..d0128f6 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java
@@ -15,6 +15,7 @@
  */
 package org.apache.brooklyn.camp.brooklyn.spi.dsl;
 
+import org.apache.brooklyn.core.entity.EntityAsserts;
 import static org.testng.Assert.assertEquals;
 
 import java.util.Map;
@@ -270,6 +271,33 @@ public class DslYamlTest extends AbstractYamlTest {
     }
 
     @Test
+    public void testDslScopeRootEdgeCases() throws Exception {
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  version: " + TEST_VERSION,
+                "  items:",
+                "  - id: simple-item",
+                "    itemType: entity",
+                "    item:",
+                "      type: "+ BasicEntity.class.getName(),
+                "      brooklyn.config:",
+                "        v: 1",
+                "        refInDsl: $brooklyn:formatString(\"%s\", scopeRoot().config(\"v\"))",
+                "        refInMap:",
+                "          v: $brooklyn:scopeRoot().config(\"v\")");
+
+        final Entity app = createAndStartApplication(
+                "services:",
+                "- type: simple-item",
+                "brooklyn.config:",
+                "  v: 2");
+        Entity child = Iterables.get(app.getChildren(), 0);
+        // TODO - these should both be 1, but scopeRoot for the simple-item goes to the blueprint where it is used; see notes in CampResolver.fixScopeRoot
+        Asserts.assertEquals( child.getConfig(ConfigKeys.newConfigKey(Object.class, "refInDsl")), "2" );
+        Asserts.assertEquals( child.getConfig(ConfigKeys.newConfigKey(Object.class, "refInMap")), MutableMap.of("v", 2) );
+    }
+
+    @Test
     public void testDslConfig() throws Exception {
         final Entity app = createAndStartApplication(
                 "services:",

[brooklyn-server] 02/09: add test which fails for scope root - about to fix

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 f062ce7dc8da2f2ebeaf3dc275a1380e779a42f6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 11:40:27 2021 +0100

    add test which fails for scope root - about to fix
    
    relying on catalog item id is not reliable to determine the containing definition;
    it works if there is no catalog item id (eg we refer to a class),
    but if we refer to another catalog item id the scope root / containment check is not correct.
    
    instead we should use the "depth_in_ancestor" tag -- PR to follow
---
 .../brooklyn/camp/brooklyn/EntitiesYamlTest.java   | 38 +++++++++++++++-------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index 8aa75ef..44cdfe0 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -526,59 +526,58 @@ public class EntitiesYamlTest extends AbstractYamlTest {
             }
         }
     }
-    
-    @Test
-    public void testScopeReferences() throws Exception {
+
+    private void doTestScopeReferences(String reference) throws Exception {
         addCatalogItems(
                 "brooklyn.catalog:",
                 "  itemType: entity",
                 "  items:",
                 "  - id: ref_child",
                 "    item:",
-                "      type: " + ReferencingYamlTestEntity.class.getName(),
+                "      type: " + reference,
                 "      name: RC",
                 "      test.reference.root: $brooklyn:root()",
                 "      test.reference.scope_root: $brooklyn:scopeRoot()",
                 "      brooklyn.children:",
-                "      - type: " + ReferencingYamlTestEntity.class.getName(),
+                "      - type: " + reference,
                 "        name: RC-child",
                 "        test.reference.root: $brooklyn:root()",
                 "        test.reference.scope_root: $brooklyn:scopeRoot()",
 
                 "  - id: ref_parent",
                 "    item:",
-                "      type: " + ReferencingYamlTestEntity.class.getName(),
+                "      type: " + reference,
                 "      name: RP",
                 "      test.reference.root: $brooklyn:root()",
                 "      test.reference.scope_root: $brooklyn:scopeRoot()",
                 "      brooklyn.children:",
-                "      - type: " + ReferencingYamlTestEntity.class.getName(),
+                "      - type: " + reference,
                 "        name: RP-child",
                 "        test.reference.root: $brooklyn:root()",
                 "        test.reference.scope_root: $brooklyn:scopeRoot()",
                 "        brooklyn.children:",
                 "        - type: ref_child",
                 "          name: RP-grandchild=RC");
-        
+
         Entity app = createAndStartApplication(
                 "brooklyn.config:",
                 "  test.reference.root: $brooklyn:root()",
                 "  test.reference.scope_root: $brooklyn:scopeRoot()",
                 "name: APP",
                 "services:",
-                "- type: " + ReferencingYamlTestEntity.class.getName(),
+                "- type: " + reference,
                 "  name: APP-child",
                 "  test.reference.root: $brooklyn:root()",
                 "  test.reference.scope_root: $brooklyn:scopeRoot()",
                 "  brooklyn.children:",
-                "  - type: " + ReferencingYamlTestEntity.class.getName(),
+                "  - type: " + reference,
                 "    name: APP-grandchild",
                 "    test.reference.root: $brooklyn:root()",
                 "    test.reference.scope_root: $brooklyn:scopeRoot()",
                 "    brooklyn.children:",
                 "    - type: ref_parent",
                 "      name: APP-greatgrandchild=RP");
-        
+
         assertScopes(app, "APP", app, app);
         Entity e1 = nextChild(app);
         assertScopes(e1, "APP-child", app, app);
@@ -593,6 +592,23 @@ public class EntitiesYamlTest extends AbstractYamlTest {
         Entity e6 = nextChild(e5);
         assertScopes(e6, "RC-child", app, e5);
     }
+    @Test
+    public void testScopeReferences() throws Exception {
+        doTestScopeReferences(ReferencingYamlTestEntity.class.getName());
+    }
+
+    @Test(groups="WIP")
+    public void testScopeReferencesComplex() throws Exception {
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  itemType: entity",
+                "  items:",
+                "  - id: ref_entity",
+                "    item:",
+                "      type: " + ReferencingYamlTestEntity.class.getName(),
+                "      name: RE");
+        doTestScopeReferences("ref_entity");
+    }
     
     private static Entity nextChild(Entity entity) {
         return Iterables.getOnlyElement(entity.getChildren());

[brooklyn-server] 03/09: fix scope root evaluation, passes previous test

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 16c28fc0a11ec0b5bc56588f16604c3f35b4f56a
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 12:22:19 2021 +0100

    fix scope root evaluation, passes previous test
    
    changes semantics however for when used on the root node;
    test is more flexible in this case
---
 .../brooklyn/camp/brooklyn/EntitiesYamlTest.java   | 26 +++++++++++++++++-----
 .../camp/brooklyn/ReferencingYamlTestEntity.java   |  6 +++++
 .../org/apache/brooklyn/core/entity/Entities.java  | 11 +++++++++
 3 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index 44cdfe0..4ee8a4c 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -557,7 +557,8 @@ public class EntitiesYamlTest extends AbstractYamlTest {
                 "        test.reference.scope_root: $brooklyn:scopeRoot()",
                 "        brooklyn.children:",
                 "        - type: ref_child",
-                "          name: RP-grandchild=RC");
+                "          name: RP-grandchild=RC",
+                "          test.reference.scope_root2: $brooklyn:scopeRoot()");
 
         Entity app = createAndStartApplication(
                 "brooklyn.config:",
@@ -576,7 +577,8 @@ public class EntitiesYamlTest extends AbstractYamlTest {
                 "    test.reference.scope_root: $brooklyn:scopeRoot()",
                 "    brooklyn.children:",
                 "    - type: ref_parent",
-                "      name: APP-greatgrandchild=RP");
+                "      name: APP-greatgrandchild=RP",
+                "      test.reference.scope_root2: $brooklyn:scopeRoot()");
 
         assertScopes(app, "APP", app, app);
         Entity e1 = nextChild(app);
@@ -584,20 +586,21 @@ public class EntitiesYamlTest extends AbstractYamlTest {
         Entity e2 = nextChild(e1);
         assertScopes(e2, "APP-grandchild", app, app);
         Entity e3 = nextChild(e2);
-        assertScopes(e3, "APP-greatgrandchild=RP", app, e3);
+        assertScopes(e3, "APP-greatgrandchild=RP", app, e2, app);
         Entity e4 = nextChild(e3);
         assertScopes(e4, "RP-child", app, e3);
         Entity e5 = nextChild(e4);
-        assertScopes(e5, "RP-grandchild=RC", app, e5);
+        assertScopes(e5, "RP-grandchild=RC", app, e5, e3);
         Entity e6 = nextChild(e5);
         assertScopes(e6, "RC-child", app, e5);
     }
+
     @Test
     public void testScopeReferences() throws Exception {
         doTestScopeReferences(ReferencingYamlTestEntity.class.getName());
     }
 
-    @Test(groups="WIP")
+    @Test
     public void testScopeReferencesComplex() throws Exception {
         addCatalogItems(
                 "brooklyn.catalog:",
@@ -614,9 +617,20 @@ public class EntitiesYamlTest extends AbstractYamlTest {
         return Iterables.getOnlyElement(entity.getChildren());
     }
     private static void assertScopes(Entity entity, String name, Entity root, Entity scopeRoot) {
+        assertScopes(entity, name, root, scopeRoot, null);
+    }
+    private static void assertScopes(Entity entity, String name, Entity root, Entity scopeRoot, Entity scopeRoot2) {
         if (name!=null) assertEquals(entity.getDisplayName(), name);
         assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_ROOT), root);
-        assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT), scopeRoot);
+
+        Entity actualScopeRoot = entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT);
+        if (!actualScopeRoot.equals(scopeRoot) && !actualScopeRoot.equals(scopeRoot2)) {
+            Assert.fail("Wrong scope root; should be either "+scopeRoot+" or "+scopeRoot2+"; but is actually "+actualScopeRoot);
+        }
+        // TODO would be nice if we can capture which blueprint scopeRoot is used in - but this requires introspecting the DSL
+        // currently it will always equal scopeRoot2; if we could convert it to "self()" when the definition is loaded, that would solve it
+
+        assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT2), scopeRoot2);
     }
 
     private void checkReferences(final Entity entity, Map<ConfigKey<Entity>, Entity> keyToEntity) throws Exception {
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
index 7a8ac59..bc13ecf 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
@@ -20,7 +20,9 @@ package org.apache.brooklyn.camp.brooklyn;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigInheritance;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.BasicConfigInheritance;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 
 import com.google.common.reflect.TypeToken;
@@ -35,6 +37,10 @@ public interface ReferencingYamlTestEntity extends Entity {
     public static final ConfigKey<Entity> TEST_REFERENCE_SCOPE_ROOT = BasicConfigKey.builder(new TypeToken<Entity>(){})
             .name("test.reference.scope_root")
             .build();
+    public static final ConfigKey<Entity> TEST_REFERENCE_SCOPE_ROOT2 = BasicConfigKey.builder(new TypeToken<Entity>(){})
+            .name("test.reference.scope_root2")
+            .runtimeInheritance(BasicConfigInheritance.NEVER_INHERITED)
+            .build();
     @SuppressWarnings("serial")
     public static final ConfigKey<Entity> TEST_REFERENCE_APP = BasicConfigKey.builder(new TypeToken<Entity>(){})
             .name("test.reference.app")
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
index f794793..cd28df8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.core.entity;
 
+import org.apache.brooklyn.core.mgmt.BrooklynTags;
 import static org.apache.brooklyn.util.guava.Functionals.isSatisfied;
 
 import java.io.Closeable;
@@ -1149,6 +1150,16 @@ public class Entities {
 
     public static Entity catalogItemScopeRoot(Entity entity) {
         Entity root = entity;
+
+        Integer depth = BrooklynTags.getDepthInAncestorTag(root.tags().getTags());
+        if (depth!=null && depth>0) {
+            while (depth>0) {
+                root = root.getParent();
+                depth--;
+            }
+            return root;
+        }
+
         while (root.getParent() != null &&
                 root != root.getParent() &&
                 Objects.equal(root.getParent().getCatalogItemId(), root.getCatalogItemId())) {

[brooklyn-server] 06/09: update test which asserted the broken behaviour (with a TODO to fix it!)

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 f0edbaf1e722286a6bfe58d8f533ddfa50d10f92
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 13:44:46 2021 +0100

    update test which asserted the broken behaviour (with a TODO to fix it!)
---
 .../apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java  | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java
index 5a72d08..71238c9 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslYamlTest.java
@@ -260,18 +260,13 @@ public class DslYamlTest extends AbstractYamlTest {
                 "  - type: wrapping-simple");
         Entity child1 = Iterables.get(app.getChildren(), 0);
         Entity child2 = Iterables.get(app.getChildren(), 1);
-        assertScopeRoot(child1, false);
-        // TODO Not the result I'd expect - in both cases the entity argument should the the scopeRoot element, not its child
-        assertScopeRoot(child2, true);
+        assertChildScopeRootReferenceIs(child1);
+        assertChildScopeRootReferenceIs(child2);
     }
 
-    private void assertScopeRoot(Entity entity, boolean isScopeBugged) throws Exception {
+    private void assertChildScopeRootReferenceIs(Entity entity) throws Exception {
         Entity child = Iterables.getOnlyElement(entity.getChildren());
-        if (!isScopeBugged) {
-            assertEquals(getConfigEventually(child, DEST), entity);
-        } else {
-            assertEquals(getConfigEventually(child, DEST), child);
-        }
+        assertEquals(getConfigEventually(child, DEST), entity);
     }
 
     @Test

[brooklyn-server] 09/09: This closes #1217

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 bd4a04fe172579637e61b22a0772737c0f2765fa
Merge: 349ba81 471003d
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 14:27:28 2021 +0100

    This closes #1217

 .../camp/brooklyn/spi/creation/CampResolver.java   | 63 ++++++++++++++++--
 .../brooklyn/spi/dsl/methods/DslComponent.java     | 18 ++++-
 .../camp/brooklyn/ConfigParametersYamlTest.java    | 20 ++++--
 .../brooklyn/camp/brooklyn/EntitiesYamlTest.java   | 76 ++++++++++++++++------
 .../camp/brooklyn/ReferencingYamlTestEntity.java   |  6 ++
 .../camp/brooklyn/spi/dsl/DslYamlTest.java         | 41 +++++++++---
 .../org/apache/brooklyn/core/entity/Entities.java  | 11 ++++
 7 files changed, 193 insertions(+), 42 deletions(-)

[brooklyn-server] 07/09: fix another test with wrong scopeRoot semantics

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 f27166742f2e4ac28e55fe6b86e4e8917d0a7bdc
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Aug 6 13:52:19 2021 +0100

    fix another test with wrong scopeRoot semantics
---
 .../camp/brooklyn/ConfigParametersYamlTest.java      | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
index 24d715b..c2c965e 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigParametersYamlTest.java
@@ -662,8 +662,11 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
                 "- type: wrapper-entity",
                 "  brooklyn.config:",
                 "    key4: $brooklyn:config(\"my.param.key\")",
-                "    key4.from.root: $brooklyn:scopeRoot().config(\"my.param.key\")");
-        
+                "    key4.from.root: $brooklyn:scopeRoot().config(\"my.other.key\")",
+                "    my.other.key: notUsed",
+                "brooklyn.config:",
+                "  my.other.key: otherDefaultValue");
+
         Entity app = createStartWaitAndLogApplication(yaml);
         final TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
         assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("my.param.key")), "myDefaultValInOuter");
@@ -671,7 +674,8 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
         assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key3")), "myDefaultValInOuter");
         assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key3.from.root")), "myDefaultValInOuter");
         assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key4")), "myDefaultValInOuter");
-        assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key4.from.root")), "myDefaultValInOuter");
+        // scopeRoot in this context now correctly goes to application root; previously (before 2021-08) it looked at the place where the wrapper-entity was defined
+        assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key4.from.root")), "otherDefaultValue");
     }
     
     @Test
@@ -714,8 +718,11 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
                 "- type: wrapper-entity",
                 "  brooklyn.config:",
                 "    key4: $brooklyn:config(\"my.param.key\")",
-                "    key4.from.root: $brooklyn:scopeRoot().config(\"my.param.key\")");
-        
+                "    key4.from.root: $brooklyn:scopeRoot().config(\"my.other.key\")",
+                "    my.other.key: notUsed",
+                "brooklyn.config:",
+                "  my.other.key: otherDefaultValue");
+
         Entity app = createStartWaitAndLogApplication(yaml);
         final TestEntity entity = (TestEntity) Iterables.getOnlyElement(app.getChildren());
         LOG.info("Config keys declared on "+entity+": "+entity.config().findKeysDeclared(Predicates.alwaysTrue()));
@@ -728,7 +735,8 @@ public class ConfigParametersYamlTest extends AbstractYamlRebindTest {
         assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key3")), "myDefaultVal");
         assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key3.from.root")), "myDefaultVal");
         assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key4")), "myDefaultVal");
-        assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key4.from.root")), "myDefaultVal");
+        // scopeRoot in this context now correctly goes to application root; previously (before 2021-08) it looked at the place where the wrapper-entity was defined
+        assertEquals(entity.config().get(ConfigKeys.newStringConfigKey("key4.from.root")), "otherDefaultValue");
     }
     
     @Test