From 217926092d5632f17a8746e0df2329787c556108 Mon Sep 17 00:00:00 2001 From: Joseph Zuniga-Daly <59851625+josephzunigadaly@users.noreply.github.com> Date: Mon, 9 Mar 2020 11:40:51 +0000 Subject: [PATCH] ENT-4334 Configuration option to exclude packages from Quasar instrumentation (#6005) * Add quasarExcludePackages configuration option * Change quasarExcludePackages to quasar.excludePackages * Add doc comment for QuasarConfiguration * Use forEach method * Fix rule violation (TooGenericExceptionThrown) * Mention new configuration option in changelog * Remove outer section from new quasarExcludePackages configuration option --- docs/source/changelog.rst | 2 + docs/source/corda-configuration-file.rst | 14 +++- .../net/corda/node/internal/AbstractNode.kt | 11 ++++ .../node/services/config/NodeConfiguration.kt | 2 + .../services/config/NodeConfigurationImpl.kt | 4 +- .../schema/v1/V1NodeConfigurationSpec.kt | 4 +- .../internal/QuasarExcludePackagesTest.kt | 64 +++++++++++++++++++ .../test-config-quasarexcludepackages.conf | 33 ++++++++++ .../node/internal/InternalMockNetwork.kt | 1 + 9 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 node/src/test/kotlin/net/corda/node/internal/QuasarExcludePackagesTest.kt create mode 100644 node/src/test/resources/test-config-quasarexcludepackages.conf diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index e335464ee0..dfe00c134a 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -109,6 +109,8 @@ Unreleased options, as well as ``extensions.sshd`` configuration entry, have been removed from the standalone shell. Available alternatives are either to use the standalone shell directly, or connect to the node embedded shell via SSH. +* Added new node configuration option to exclude packages from Quasar instrumentation. + .. _changelog_v4.1: Version 4.1 diff --git a/docs/source/corda-configuration-file.rst b/docs/source/corda-configuration-file.rst index c3642f38b2..5a6af7ff2e 100644 --- a/docs/source/corda-configuration-file.rst +++ b/docs/source/corda-configuration-file.rst @@ -558,7 +558,19 @@ p2pAddress *Default:* not defined - + +quasarExcludePackages + A list of packages to exclude from Quasar instrumentation. Wildcards are allowed, for example ``org.xml**``. + + **Important: Do not change unless requested by support.** + + *Default:* empty list + + Example configuration: + + .. parsed-literal:: + quasarExcludePackages=["org.xml**", "org.yaml**"] + rpcAddress (deprecated) The address of the RPC system on which RPC requests can be made to the node. If not provided then the node will run without RPC. diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 496b9c0f7f..22bc371d6f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -1,5 +1,6 @@ package net.corda.node.internal +import co.paralleluniverse.fibers.instrument.Retransform import com.codahale.metrics.MetricRegistry import com.google.common.collect.MutableClassToInstanceMap import com.google.common.util.concurrent.MoreExecutors @@ -227,6 +228,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, MoreExecutors.shutdownAndAwaitTermination(it, 50, SECONDS) } } + + quasarExcludePackages(configuration) } private val notaryLoader = configuration.notary?.let { @@ -420,6 +423,14 @@ abstract class AbstractNode(val configuration: NodeConfiguration, return validateKeyStores() } + private fun quasarExcludePackages(nodeConfiguration: NodeConfiguration) { + val quasarInstrumentor = Retransform.getInstrumentor() + + nodeConfiguration.quasarExcludePackages.forEach { packageExclude -> + quasarInstrumentor.addExcludedPackage(packageExclude) + } + } + open fun generateAndSaveNodeInfo(): NodeInfo { check(started == null) { "Node has already been started" } log.info("Generating nodeInfo ...") diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index 42b55271b6..010e40007f 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -90,6 +90,8 @@ interface NodeConfiguration : ConfigurationWithOptionsContainer { val flowExternalOperationThreadPoolSize: Int + val quasarExcludePackages: List + companion object { // default to at least 8MB and a bit extra for larger heap sizes val defaultTransactionCacheSize: Long = 8.MB + getAdditionalCacheMemory() diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt index 2f00d2eab3..521b98d56c 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt @@ -82,7 +82,8 @@ data class NodeConfigurationImpl( Defaults.networkParameterAcceptanceSettings, override val blacklistedAttachmentSigningKeys: List = Defaults.blacklistedAttachmentSigningKeys, override val configurationWithOptions: ConfigurationWithOptions, - override val flowExternalOperationThreadPoolSize: Int = Defaults.flowExternalOperationThreadPoolSize + override val flowExternalOperationThreadPoolSize: Int = Defaults.flowExternalOperationThreadPoolSize, + override val quasarExcludePackages: List = Defaults.quasarExcludePackages ) : NodeConfiguration { internal object Defaults { val jmxMonitoringHttpPort: Int? = null @@ -119,6 +120,7 @@ data class NodeConfigurationImpl( val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings = NetworkParameterAcceptanceSettings() val blacklistedAttachmentSigningKeys: List = emptyList() const val flowExternalOperationThreadPoolSize: Int = 1 + val quasarExcludePackages: List = emptyList() fun cordappsDirectories(baseDirectory: Path) = listOf(baseDirectory / CORDAPPS_DIR_NAME_DEFAULT) diff --git a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt index e83a23e7c2..7f7b66bc9f 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt @@ -64,6 +64,7 @@ internal object V1NodeConfigurationSpec : Configuration.Specification(), nodeConfiguration.quasarExcludePackages) + } + + + @Test(timeout=300_000) + fun `quasarExcludePackages is read from configuration`() { + + // Arrange + val config = getConfig("test-config-quasarexcludepackages.conf") + + // Act + val nodeConfiguration :NodeConfiguration = V1NodeConfigurationSpec.parse(config).value() + + // Assert + Assert.assertEquals(listOf("net.corda.node.internal.QuasarExcludePackagesTest**"), nodeConfiguration.quasarExcludePackages) + } + + @Test(timeout=300_000) + fun `quasarExcludePackages is passed through to QuasarInstrumentor`() { + + // Arrange + val config = getConfig("test-config-quasarexcludepackages.conf") + val nodeConfiguration :NodeConfiguration = V1NodeConfigurationSpec.parse(config).value() + + // Act + val node = Node(nodeConfiguration, VersionInfo.UNKNOWN) + node.stop() + + // Assert + Assert.assertTrue(Retransform.getInstrumentor().isExcluded("net.corda.node.internal.QuasarExcludePackagesTest.Test")) + } + + class ResourceMissingException(message: String) : Exception(message) + + private fun getConfig(cfgName: String): Config { + val resource = this::class.java.classLoader.getResource(cfgName) ?: throw ResourceMissingException("Resource not found") + val path = resource.toPath() + return ConfigHelper.loadConfig(path.parent, path) + } +} diff --git a/node/src/test/resources/test-config-quasarexcludepackages.conf b/node/src/test/resources/test-config-quasarexcludepackages.conf new file mode 100644 index 0000000000..512a2a228c --- /dev/null +++ b/node/src/test/resources/test-config-quasarexcludepackages.conf @@ -0,0 +1,33 @@ +myLegalName = "O=Alice Corp, L=Madrid, C=ES" +emailAddress = "admin@company.com" +keyStorePassword = "cordacadevpass" +trustStorePassword = "trustpass" +crlCheckSoftFail = true +baseDirectory = "/opt/corda" +cordappDirectories = ["./myCorDapps1", "./myCorDapps2"] +dataSourceProperties = { + dataSourceClassName = org.h2.jdbcx.JdbcDataSource + dataSource.url = "jdbc:h2:file:blah" + dataSource.user = "sa" + dataSource.password = "" +} +database = { + transactionIsolationLevel = "REPEATABLE_READ" + exportHibernateJMXStatistics = "false" +} +p2pAddress = "localhost:2233" +h2port = 0 +useTestClock = false +verifierType = InMemory +rpcSettings = { + address = "locahost:3418" + adminAddress = "localhost:3419" + useSsl = false + standAloneBroker = false +} +flowTimeout { + timeout = 30 seconds + maxRestartCount = 3 + backoffBase = 2.0 +} +quasarExcludePackages = [ "net.corda.node.internal.QuasarExcludePackagesTest**" ] diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt index 1e7e81c2f5..464e08966f 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt @@ -461,6 +461,7 @@ open class InternalMockNetwork(cordappPackages: List = emptyList(), doReturn(makeTestDataSourceProperties("node_${id}_net_$networkId")).whenever(it).dataSourceProperties doReturn(emptyList()).whenever(it).extraNetworkMapKeys doReturn(listOf(baseDirectory / "cordapps")).whenever(it).cordappDirectories + doReturn(emptyList()).whenever(it).quasarExcludePackages parameters.configOverrides(it) }