PR #867: bundle persistence blacklist/whitelist configurable
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/03f254fd Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/03f254fd Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/03f254fd Branch: refs/heads/master Commit: 03f254fd2812580e343993afaddd69a630841d81 Parents: 5d13ebf Author: Aled Sage <[email protected]> Authored: Fri Oct 27 12:09:48 2017 +0100 Committer: Aled Sage <[email protected]> Committed: Fri Oct 27 13:50:15 2017 +0100 ---------------------------------------------------------------------- .../core/mgmt/ha/OsgiArchiveInstaller.java | 43 +++++++++- .../brooklyn/core/mgmt/ha/OsgiManager.java | 4 + .../core/server/BrooklynServerConfig.java | 13 +++ .../core/mgmt/ha/OsgiArchiveInstallerTest.java | 83 ++++++++++++++++++++ .../core/mgmt/rebind/RebindTestFixture.java | 13 ++- 5 files changed, 150 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/03f254fd/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java index e3b91fa..e41ec74 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java @@ -31,15 +31,18 @@ import java.util.Map; import java.util.TreeMap; import java.util.jar.Attributes; import java.util.jar.Manifest; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.brooklyn.api.typereg.ManagedBundle; import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.BrooklynVersion; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult.ResultCode; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; +import org.apache.brooklyn.core.server.BrooklynServerConfig; import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry; import org.apache.brooklyn.core.typereg.BasicManagedBundle; import org.apache.brooklyn.core.typereg.RegisteredTypePredicates; @@ -64,9 +67,11 @@ import org.osgi.framework.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; import com.google.common.collect.Iterables; // package-private so we can move this one if/when we move OsgiManager @@ -74,6 +79,10 @@ class OsgiArchiveInstaller { private static final Logger log = LoggerFactory.getLogger(OsgiArchiveInstaller.class); + public static final ConfigKey<String> PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX = BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX; + + public static final ConfigKey<String> PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX = BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX; + final private OsgiManager osgiManager; private ManagedBundle suppliedKnownBundleMetadata; private InputStream zipIn; @@ -93,6 +102,8 @@ class OsgiArchiveInstaller { private ManagedBundle inferredMetadata; private final boolean inputStreamSupplied; + private volatile Predicate<ManagedBundle> blacklistBundlePersistencePredicate; + OsgiArchiveInstaller(OsgiManager osgiManager, ManagedBundle knownBundleMetadata, InputStream zipIn) { this.osgiManager = osgiManager; this.suppliedKnownBundleMetadata = knownBundleMetadata; @@ -121,7 +132,7 @@ class OsgiArchiveInstaller { } private ManagementContextInternal mgmt() { - return (ManagementContextInternal) osgiManager.mgmt; + return (ManagementContextInternal) osgiManager.getManagementContext(); } private synchronized void init() { @@ -681,15 +692,39 @@ class OsgiArchiveInstaller { } } - private static boolean isBlacklistedForPersistence(ManagedBundle managedBundle) { - // Specifically, we treat as "managed bundles" (to extract their catalog.bom) the contents of: + @VisibleForTesting + boolean isBlacklistedForPersistence(ManagedBundle managedBundle) { + // We treat as "managed bundles" (to extract their catalog.bom) the contents of: // - org.apache.brooklyn.core // - org.apache.brooklyn.policy // - org.apache.brooklyn.test-framework // - org.apache.brooklyn.software-* // - org.apache.brooklyn.library-catalog // - org.apache.brooklyn.karaf-init (not sure why this one could end up in persisted state!) - return managedBundle.getSymbolicName().startsWith("org.apache.brooklyn."); + // We don't want to persist the entire brooklyn distro! Therefore default is to blacklist those. + + if (blacklistBundlePersistencePredicate == null) { + String whitelistRegex = mgmt().getConfig().getConfig(PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX); + String blacklistRegex = mgmt().getConfig().getConfig(PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX); + + final Pattern whitelistPattern = (whitelistRegex != null) ? Pattern.compile(whitelistRegex) : null; + final Pattern blacklistPattern = (blacklistRegex != null) ? Pattern.compile(blacklistRegex) : null; + + blacklistBundlePersistencePredicate = new Predicate<ManagedBundle>() { + @Override public boolean apply(ManagedBundle input) { + String bundleName = input.getSymbolicName(); + if (whitelistPattern != null && whitelistPattern.matcher(bundleName).matches()) { + return false; + } + if (blacklistPattern != null && blacklistPattern.matcher(bundleName).matches()) { + return true; + } + return false; + } + }; + } + + return blacklistBundlePersistencePredicate.apply(managedBundle); } private static List<Bundle> findBundlesByVersion(OsgiManager osgiManager, ManagedBundle desired) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/03f254fd/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java index e7bd75e..e3c0e82 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java @@ -344,6 +344,10 @@ public class OsgiManager { return Maybe.absent(); } + ManagementContext getManagementContext() { + return mgmt; + } + /** * Clears all record of the managed bundles (use with care!). * http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/03f254fd/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java b/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java index 530095d..9bcd409 100644 --- a/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java +++ b/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java @@ -131,6 +131,19 @@ public class BrooklynServerConfig { public static final ConfigKey<Boolean> OSGI_CACHE_CLEAN = ConfigKeys.newBooleanConfigKey("brooklyn.osgi.cache.clean", "Whether to delete the OSGi directory before and after use; if unset, it will delete if the node ID forms part of the cache dir path (which by default it does) to avoid file leaks"); + public static final ConfigKey<String> PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX = ConfigKeys.newStringConfigKey( + "brooklyn.persistence.bundle.whitelist", + "Regex for bundle symbolic names explicitly allowed to be persisted (taking precedence over blacklist); " + + "managed bundles will by default be peristed if not blacklisted; " + + "they do not need to be explicitly whitelisted.", + null); + + public static final ConfigKey<String> PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX = ConfigKeys.newStringConfigKey( + "brooklyn.persistence.bundle.blacklist", + "Regex for bundle symbolic names explicitly excluded from persistence (but whitelist takes precedence); " + + "if not explicitly blacklisted, managed bundles will by default be peristed", + "org\\.apache\\.brooklyn\\..*"); + /** @see BrooklynServerPaths#getMgmtBaseDir(ManagementContext) */ public static String getMgmtBaseDir(ManagementContext mgmt) { return BrooklynServerPaths.getMgmtBaseDir(mgmt); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/03f254fd/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstallerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstallerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstallerTest.java new file mode 100644 index 0000000..3a86a3d --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstallerTest.java @@ -0,0 +1,83 @@ +/* + * 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.core.mgmt.ha; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.ByteArrayInputStream; + +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.typereg.ManagedBundle; +import org.apache.brooklyn.core.server.BrooklynServerConfig; +import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport; +import org.apache.brooklyn.util.osgi.VersionedName; +import org.mockito.Mockito; +import org.testng.annotations.Test; + +public class OsgiArchiveInstallerTest extends BrooklynMgmtUnitTestSupport { + + // The tests here will so far not need an actual OSGi Framework! Therefore we're using the simple + // BrooklynMgmtUnitTestSupport, which does not expose `useOsgi` or `osgiReuse` + + @Test + public void testBlacklistPersistingOrgApacheBrooklyn() throws Exception { + OsgiManager osgiManager = newMockOsgiManager(mgmt); + OsgiArchiveInstaller installer = new OsgiArchiveInstaller(osgiManager, Mockito.mock(ManagedBundle.class), new ByteArrayInputStream(new byte[0])); + + assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.core", "1.0.0"))); + assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.mybundle", "1.0.0"))); + assertFalse(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.different", "1.0.0"))); + } + + @Test + public void testWhitelistPersistingBundle() throws Exception { + mgmt.getBrooklynProperties().put(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX, "org\\.apache\\.brooklyn\\.mywhitelistedbundle"); + OsgiManager osgiManager = newMockOsgiManager(mgmt); + OsgiArchiveInstaller installer = new OsgiArchiveInstaller(osgiManager, Mockito.mock(ManagedBundle.class), new ByteArrayInputStream(new byte[0])); + + assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.core", "1.0.0"))); + assertFalse(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.mywhitelistedbundle", "1.0.0"))); + } + + @Test + public void testCustomBlacklistPersistingBundle() throws Exception { + mgmt.getBrooklynProperties().put(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX, "org\\.example\\.myblacklistprefix.*"); + OsgiManager osgiManager = newMockOsgiManager(mgmt); + OsgiArchiveInstaller installer = new OsgiArchiveInstaller(osgiManager, Mockito.mock(ManagedBundle.class), new ByteArrayInputStream(new byte[0])); + + assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.example.myblacklistprefix.mysuffix", "1.0.0"))); + assertFalse(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.core", "1.0.0"))); + } + + public OsgiManager newMockOsgiManager(ManagementContext mgmt) throws Exception { + OsgiManager result = Mockito.mock(OsgiManager.class); + Mockito.when(result.getManagementContext()).thenReturn(mgmt); + return result; + } + + private ManagedBundle newMockManagedBundle(String symbolicName, String version) { + VersionedName versioneName = new VersionedName(symbolicName, version); + ManagedBundle result = Mockito.mock(ManagedBundle.class); + Mockito.when(result.getSymbolicName()).thenReturn(symbolicName); + Mockito.when(result.getOsgiVersionString()).thenReturn(versioneName.getOsgiVersionString()); + Mockito.when(result.getVersionedName()).thenReturn(versioneName); + return result; + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/03f254fd/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java index efe7d28..b80d857 100644 --- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java @@ -39,8 +39,10 @@ import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore; import org.apache.brooklyn.core.mgmt.persist.FileBasedObjectStore; import org.apache.brooklyn.core.mgmt.persist.PersistMode; +import org.apache.brooklyn.core.server.BrooklynServerConfig; import org.apache.brooklyn.util.core.task.BasicExecutionManager; import org.apache.brooklyn.util.os.Os; +import org.apache.brooklyn.util.osgi.OsgiTestResources; import org.apache.brooklyn.util.repeat.Repeater; import org.apache.brooklyn.util.text.Identifiers; import org.apache.brooklyn.util.time.Duration; @@ -82,11 +84,18 @@ public abstract class RebindTestFixture<T extends StartableApplication> { } protected BrooklynProperties createBrooklynProperties() { + BrooklynProperties result; if (useLiveManagementContext()) { - return BrooklynProperties.Factory.newDefault(); + result = BrooklynProperties.Factory.newDefault(); } else { - return BrooklynProperties.Factory.newEmpty(); + result = BrooklynProperties.Factory.newEmpty(); } + // By default, will not persist "org.apache.brooklyn.*" bundles; therefore explicitly whitelist + // such things commonly used in tests. + String whitelistRegex = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL + + "|" + OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL; + result.put(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX, whitelistRegex); + return result; } /** @return A started management context */
