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
This commit is contained in:
Joseph Zuniga-Daly 2020-03-09 11:40:51 +00:00 committed by GitHub
parent 2887dd0c88
commit 217926092d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 132 additions and 3 deletions

View File

@ -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

View File

@ -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.

View File

@ -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<S>(val configuration: NodeConfiguration,
MoreExecutors.shutdownAndAwaitTermination(it, 50, SECONDS)
}
}
quasarExcludePackages(configuration)
}
private val notaryLoader = configuration.notary?.let {
@ -420,6 +423,14 @@ abstract class AbstractNode<S>(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 ...")

View File

@ -90,6 +90,8 @@ interface NodeConfiguration : ConfigurationWithOptionsContainer {
val flowExternalOperationThreadPoolSize: Int
val quasarExcludePackages: List<String>
companion object {
// default to at least 8MB and a bit extra for larger heap sizes
val defaultTransactionCacheSize: Long = 8.MB + getAdditionalCacheMemory()

View File

@ -82,7 +82,8 @@ data class NodeConfigurationImpl(
Defaults.networkParameterAcceptanceSettings,
override val blacklistedAttachmentSigningKeys: List<String> = Defaults.blacklistedAttachmentSigningKeys,
override val configurationWithOptions: ConfigurationWithOptions,
override val flowExternalOperationThreadPoolSize: Int = Defaults.flowExternalOperationThreadPoolSize
override val flowExternalOperationThreadPoolSize: Int = Defaults.flowExternalOperationThreadPoolSize,
override val quasarExcludePackages: List<String> = Defaults.quasarExcludePackages
) : NodeConfiguration {
internal object Defaults {
val jmxMonitoringHttpPort: Int? = null
@ -119,6 +120,7 @@ data class NodeConfigurationImpl(
val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings = NetworkParameterAcceptanceSettings()
val blacklistedAttachmentSigningKeys: List<String> = emptyList()
const val flowExternalOperationThreadPoolSize: Int = 1
val quasarExcludePackages: List<String> = emptyList()
fun cordappsDirectories(baseDirectory: Path) = listOf(baseDirectory / CORDAPPS_DIR_NAME_DEFAULT)

View File

@ -64,6 +64,7 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
.optional()
.withDefaultValue(Defaults.networkParameterAcceptanceSettings)
private val flowExternalOperationThreadPoolSize by int().optional().withDefaultValue(Defaults.flowExternalOperationThreadPoolSize)
private val quasarExcludePackages by string().list().optional().withDefaultValue(Defaults.quasarExcludePackages)
@Suppress("unused")
private val custom by nestedObject().optional()
@Suppress("unused")
@ -128,7 +129,8 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
blacklistedAttachmentSigningKeys = configuration[blacklistedAttachmentSigningKeys],
networkParameterAcceptanceSettings = configuration[networkParameterAcceptanceSettings],
configurationWithOptions = ConfigurationWithOptions(configuration, Configuration.Validation.Options.defaults),
flowExternalOperationThreadPoolSize = configuration[flowExternalOperationThreadPoolSize]
flowExternalOperationThreadPoolSize = configuration[flowExternalOperationThreadPoolSize],
quasarExcludePackages = configuration[quasarExcludePackages]
))
} catch (e: Exception) {
return when (e) {

View File

@ -0,0 +1,64 @@
package net.corda.node.internal
import co.paralleluniverse.fibers.instrument.Retransform
import com.typesafe.config.Config
import net.corda.core.internal.toPath
import net.corda.node.VersionInfo
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.schema.v1.V1NodeConfigurationSpec
import org.junit.Assert
import org.junit.Test
class QuasarExcludePackagesTest {
@Test(timeout=300_000)
fun `quasarExcludePackages default is empty list`() {
// Arrange
val config = getConfig("working-config.conf")
// Act
val nodeConfiguration :NodeConfiguration = V1NodeConfigurationSpec.parse(config).value()
// Assert
Assert.assertEquals(emptyList<String>(), 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)
}
}

View File

@ -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**" ]

View File

@ -461,6 +461,7 @@ open class InternalMockNetwork(cordappPackages: List<String> = emptyList(),
doReturn(makeTestDataSourceProperties("node_${id}_net_$networkId")).whenever(it).dataSourceProperties
doReturn(emptyList<SecureHash>()).whenever(it).extraNetworkMapKeys
doReturn(listOf(baseDirectory / "cordapps")).whenever(it).cordappDirectories
doReturn(emptyList<String>()).whenever(it).quasarExcludePackages
parameters.configOverrides(it)
}