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/12/03 14:07:34 UTC

[brooklyn-server] branch master updated: don't allow bundles to be activated to provide classes we need

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


The following commit(s) were added to refs/heads/master by this push:
     new d48d92b  don't allow bundles to be activated to provide classes we need
d48d92b is described below

commit d48d92b4727d462571a62a6969e6020e1408bbf7
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Fri Dec 3 14:04:45 2021 +0000

    don't allow bundles to be activated to provide classes we need
    
    this prevents persisted bundles being upgraded from being resolved (and failing sometimes)
    where they (might) contain a class being referenced by the initial catalog
    
    add'l fix for fix 2d20fffa2407e4da48fe6edeebc3335e140edccb from 2021-09-14
---
 .../catalog/internal/CatalogInitialization.java    |  5 +-
 .../brooklyn/util/core/ClassLoaderUtils.java       | 21 ++++--
 .../brooklyn/util/core/ClassLoaderUtilsTest.java   | 81 +++++++++++-----------
 3 files changed, 63 insertions(+), 44 deletions(-)

diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
index b65e1c7..8ff5180 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
@@ -258,6 +258,9 @@ public class CatalogInitialization implements ManagementContextInjectable {
             // so that OSGi unique IDs might be picked up when initial catalog is populated
             Map<InstallableManagedBundle, OsgiBundleInstallationResult> persistenceInstalls = installPersistedBundlesDontStart(persistedState.getBundles(), exceptionHandler, rebindLogger);
 
+            // now we install and start the bundles from the catalog;
+            // 2021-12-03 now this only will look for classes in active bundles, so it won't resolve persisted bundles
+            // and we can safely filter them out later
             populateInitialCatalogImpl(true);
 
             final Maybe<OsgiManager> maybesOsgiManager = managementContext.getOsgiManager();
@@ -274,7 +277,7 @@ public class CatalogInitialization implements ManagementContextInjectable {
 
             PersistedCatalogState filteredPersistedState = filterBundlesAndCatalogInPersistedState(persistedState, rebindLogger);
 
-            // previously we effectively installed here, after populating; but now we do it before and then uninstall if needed, to preserve IDs
+            // 2021-09-14 previously we effectively installed here, after populating; but now we do it earlier and then uninstall if needed, to preserve IDs
 //            Map<InstallableManagedBundle, OsgiBundleInstallationResult> persistenceInstalls = installPersistedBundlesDontStart(filteredPersistedState.getBundles(), exceptionHandler, rebindLogger);
 
             try {
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
index c8011b9..5d446d5 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
@@ -40,6 +40,7 @@ import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.typereg.BundleUpgradeParser.CatalogUpgrades;
 import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.LoaderDispatcher.ClassLoaderDispatcher;
 import org.apache.brooklyn.util.core.LoaderDispatcher.MultipleResourceLoaderDispatcher;
 import org.apache.brooklyn.util.core.LoaderDispatcher.ResourceLoaderDispatcher;
@@ -457,14 +458,26 @@ public class ClassLoaderUtils {
         }
         List<Bundle> bundles = Osgis.bundleFinder(framework)
             .satisfying(createBundleMatchingPredicate())
+            .satisfying(b -> b.getState() == Bundle.ACTIVE)  // 2021-12-03 we now require them to be started, to prevent activation of persisted bundles too early
             .findAll();
+        Map<Bundle,Throwable> errors = MutableMap.of();
         for (Bundle b : bundles) {
-            Maybe<T> item = dispatcher.tryLoadFrom(b, className);
-            if (item.isPresent()) {
-                return item;
+            try {
+                Maybe<T> item = dispatcher.tryLoadFrom(b, className);
+                if (item.isPresent()) {
+                    return item;
+                }
+            } catch (Exception e) {
+                // silently ignore
+                log.debug("Skipping bundle "+b+" for search of "+className+" due to: "+e);
+                if (log.isTraceEnabled()) log.trace("Stack trace details", e);
+                errors.put(b, e);
             }
         }
-        return Maybe.absentNull();
+        return Maybe.absent(() -> {
+            if (errors.isEmpty()) return new IllegalStateException("Unable to find class '"+className+"' in whitelisted bundles");
+            return Exceptions.propagate("Unable to find class '"+className+"' in whitelisted bundles, with errors in bundles "+errors.keySet(), errors.values());
+        });
     }
 
     protected WhiteListBundlePredicate createBundleMatchingPredicate() {
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java
index 1a6da26..db90666 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java
@@ -108,7 +108,7 @@ public class ClassLoaderUtilsTest {
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), bundlePath);
 
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
-        Bundle bundle = installBundle(mgmt, bundleUrl);
+        Bundle bundle = installBundle(mgmt, bundleUrl, false /* this works without starting it */);
         @SuppressWarnings("unchecked")
         Class<? extends Entity> clazz = (Class<? extends Entity>) bundle.loadClass(classname);
         Entity entity = createSimpleEntity(bundleUrl, clazz);
@@ -129,153 +129,154 @@ public class ClassLoaderUtilsTest {
         String bundlePath = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
         String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
         String classname = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY;
-        
+
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), bundlePath);
 
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
-        Bundle bundle = installBundle(mgmt, bundleUrl);
+        Bundle bundle = installBundle(mgmt, bundleUrl, false /* this works without starting it */);
         Class<?> clazz = bundle.loadClass(classname);
         Entity entity = createSimpleEntity(bundleUrl, clazz);
-        
+
         String whiteList = bundle.getSymbolicName()+":"+bundle.getVersion();
         System.setProperty(ClassLoaderUtils.WHITE_LIST_KEY, whiteList);
-        
+
         ClassLoaderUtils cluEntity = new ClassLoaderUtils(getClass(), entity);
 
         BundledName resource = new BundledName(classname).toResource();
         BundledName bn = new BundledName(resource.bundle, resource.version, "/" + resource.name);
         Asserts.assertSize(cluEntity.getResources(bn.toString()), 1);
     }
-    
+
 
     @Test
     public void testVariousLoadersLoadClassInOsgiWhiteList() throws Exception {
         String bundlePath = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
         String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
         String classname = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY;
-        
+
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), bundlePath);
 
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
-        Bundle bundle = installBundle(mgmt, bundleUrl);
+        Bundle bundle = installBundle(mgmt, bundleUrl, true);
+
         Class<?> clazz = bundle.loadClass(classname);
         Entity entity = createSimpleEntity(bundleUrl, clazz);
-        
+
         String whiteList = bundle.getSymbolicName()+":"+bundle.getVersion();
         System.setProperty(ClassLoaderUtils.WHITE_LIST_KEY, whiteList);
-        
+
         ClassLoaderUtils cluMgmt = new ClassLoaderUtils(getClass(), mgmt);
         ClassLoaderUtils cluClass = new ClassLoaderUtils(clazz);
         ClassLoaderUtils cluEntity = new ClassLoaderUtils(getClass(), entity);
-        
+
         assertLoadSucceeds(classname, clazz, cluMgmt, cluClass, cluEntity);
         assertLoadSucceeds(bundle.getSymbolicName() + ":" + classname, clazz, cluMgmt, cluClass, cluEntity);
     }
-    
+
     @Test
     public void testLoadClassInOsgiWhiteListWithInvalidBundlePresent() throws Exception {
         String bundlePath = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
         String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
         String classname = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY;
-        
+
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), bundlePath);
 
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
-        Bundle bundle = installBundle(mgmt, bundleUrl);
-        
+        Bundle bundle = installBundle(mgmt, bundleUrl, true);
+
         Manifest manifest = new Manifest();
         manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
         JarOutputStream target = new JarOutputStream(buffer, manifest);
         target.close();
-        
+
         OsgiManager osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager().get();
         Framework framework = osgiManager.getFramework();
         Bundle installedBundle = framework.getBundleContext().installBundle("stream://invalid", new ByteArrayInputStream(buffer.toByteArray()));
         assertNotNull(installedBundle);
-        
+
         Class<?> clazz = bundle.loadClass(classname);
         Entity entity = createSimpleEntity(bundleUrl, clazz);
-        
+
         String whileList = bundle.getSymbolicName()+":"+bundle.getVersion();
         System.setProperty(ClassLoaderUtils.WHITE_LIST_KEY, whileList);
-        
+
         ClassLoaderUtils cluMgmt = new ClassLoaderUtils(getClass(), mgmt);
         ClassLoaderUtils cluClass = new ClassLoaderUtils(clazz);
         ClassLoaderUtils cluEntity = new ClassLoaderUtils(getClass(), entity);
-        
+
         assertLoadSucceeds(classname, clazz, cluMgmt, cluClass, cluEntity);
         assertLoadSucceeds(bundle.getSymbolicName() + ":" + classname, clazz, cluMgmt, cluClass, cluEntity);
     }
-    
+
     @Test
     public void testLoadClassInOsgiCore() throws Exception {
         Class<?> clazz = BasicEntity.class;
         String classname = clazz.getName();
-        
+
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
         Bundle bundle = getBundle(mgmt, "org.apache.brooklyn.core");
         String url = bundle.getLocation();
         // NB: the above will be a system:file: url when running tests against target/classes/ -- but
         // OSGi manager will accept that if running in dev mode
         Entity entity = createSimpleEntity(url, clazz);
-        
+
         ClassLoaderUtils cluMgmt = new ClassLoaderUtils(getClass(), mgmt);
         ClassLoaderUtils cluClass = new ClassLoaderUtils(clazz);
         ClassLoaderUtils cluNone = new ClassLoaderUtils(getClass());
         ClassLoaderUtils cluEntity = new ClassLoaderUtils(getClass(), entity);
-        
+
         assertLoadSucceeds(classname, clazz, cluMgmt, cluClass, cluNone, cluEntity);
         assertLoadSucceeds(classname, clazz, cluMgmt, cluClass, cluNone, cluEntity);
         assertLoadSucceeds(bundle.getSymbolicName() + ":" + classname, clazz, cluMgmt, cluClass, cluNone, cluEntity);
         assertLoadSucceeds(bundle.getSymbolicName() + ":" + bundle.getVersion() + ":" + classname, clazz, cluMgmt, cluClass, cluNone, cluEntity);
     }
-    
+
     @Test
     public void testLoadClassInOsgiApi() throws Exception {
         Class<?> clazz = Entity.class;
         String classname = clazz.getName();
-        
+
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
         Bundle bundle = getBundle(mgmt, "org.apache.brooklyn.api");
-        
+
         ClassLoaderUtils cluMgmt = new ClassLoaderUtils(getClass(), mgmt);
         ClassLoaderUtils cluClass = new ClassLoaderUtils(clazz);
         ClassLoaderUtils cluNone = new ClassLoaderUtils(getClass());
-        
+
         assertLoadSucceeds(classname, clazz, cluMgmt, cluClass, cluNone);
         assertLoadSucceeds(classname, clazz, cluMgmt, cluClass, cluNone);
         assertLoadSucceeds(bundle.getSymbolicName() + ":" + classname, clazz, cluMgmt, cluClass, cluNone);
         assertLoadSucceeds(bundle.getSymbolicName() + ":" + bundle.getVersion() + ":" + classname, clazz, cluMgmt, cluClass, cluNone);
     }
-    
+
     @Test
     public void testIsBundleWhiteListed() throws Exception {
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
         ClassLoaderUtils clu = new ClassLoaderUtils(getClass(), mgmt);
-        
+
         assertTrue(clu.isBundleWhiteListed(getBundle(mgmt, "org.apache.brooklyn.core")));
         assertTrue(clu.isBundleWhiteListed(getBundle(mgmt, "org.apache.brooklyn.api")));
         assertFalse(clu.isBundleWhiteListed(getBundle(mgmt, "com.google.guava")));
     }
-    
+
     /**
-     * When two guava versions installed, want us to load from the *brooklyn* version rather than 
+     * When two guava versions installed, want us to load from the *brooklyn* version rather than
      * a newer version that happens to be in Karaf.
      */
     @Test(groups={"Integration"})
     public void testLoadsFromRightGuavaVersion() throws Exception {
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
         ClassLoaderUtils clu = new ClassLoaderUtils(getClass(), mgmt);
-        
+
         String bundleUrl = MavenRetriever.localUrl(MavenArtifact.fromCoordinate("com.google.guava:guava:jar:18.0"));
-        Bundle bundle = installBundle(mgmt, bundleUrl);
+        Bundle bundle = installBundle(mgmt, bundleUrl, false /* this works without starting */);
         String bundleName = bundle.getSymbolicName();
-        
+
         String classname = bundleName + ":" + ImmutableList.class.getName();
         assertLoadSucceeds(clu, classname, ImmutableList.class);
     }
-    
+
     @Test
     public void testLoadBrooklynClass() throws Exception {
         mgmt = LocalManagementContextForTests.builder(true).enableOsgiReusable().build();
@@ -310,11 +311,13 @@ public class ClassLoaderUtilsTest {
             Asserts.expectedFailureContains(nested, "not found to load");
         }
     }
-    
-    private Bundle installBundle(ManagementContext mgmt, String bundleUrl) throws Exception {
+
+    private Bundle installBundle(ManagementContext mgmt, String bundleUrl, boolean start) throws Exception {
         OsgiManager osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager().get();
         Framework framework = osgiManager.getFramework();
-        return Osgis.install(framework, bundleUrl);
+        Bundle result = Osgis.install(framework, bundleUrl);
+        if (start) result.start();
+        return result;
     }
 
     private Bundle getBundle(ManagementContext mgmt, final String symbolicName) throws Exception {