mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
[EG-3461] removed dependency from tools.jar (#6631)
* removed dependency from tools.jar I removed the log line in /node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt because I felt it was not so important and I modified the checkpoint agent detection simply using a static field (I tested both with and without the checkpoint agent running and detection works correctly) * move method to node-api to address review comments Co-authored-by: Walter Oggioni <walter.oggioni@r3.com>
This commit is contained in:
parent
bf53e47f0d
commit
205ce84033
@ -0,0 +1,26 @@
|
||||
package net.corda.nodeapi.internal
|
||||
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
|
||||
class JVMAgentUtilities {
|
||||
|
||||
companion object {
|
||||
@VisibleForTesting
|
||||
@Suppress("NestedBlockDepth")
|
||||
fun parseDebugPort(args: Iterable<String>): Short? {
|
||||
val debugArgumentPrefix = "-agentlib:jdwp="
|
||||
for (arg in args) {
|
||||
if (arg.startsWith(debugArgumentPrefix)) {
|
||||
for (keyValuePair in arg.substring(debugArgumentPrefix.length + 1).split(",")) {
|
||||
val equal = keyValuePair.indexOf('=')
|
||||
if (equal >= 0 && keyValuePair.startsWith("address")) {
|
||||
val portBegin = (keyValuePair.lastIndexOf(':').takeUnless { it < 0 } ?: equal) + 1
|
||||
return keyValuePair.substring(portBegin).toShort()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.corda.nodeapi.internal
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class ParseDebugPortTest(private val args: Iterable<String>,
|
||||
private val expectedPort: Short?,
|
||||
@Suppress("unused_parameter") description : String) {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters(name = "{2}")
|
||||
fun load() = arrayOf(
|
||||
arrayOf(emptyList<String>(), null, "No arguments"),
|
||||
arrayOf(listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=1234"), 1234.toShort(), "Debug argument"),
|
||||
arrayOf(listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=0.0.0.0:7777"), 7777.toShort(), "Debug argument with bind address"),
|
||||
arrayOf(listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y"), null, "Debug argument without port"),
|
||||
arrayOf(listOf("-version", "-Dmy.jvm.property=someValue"), null, "Unrelated arguments"),
|
||||
arrayOf(listOf("-Dcapsule.jvm.args=\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=4321",
|
||||
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=1234"), 1234.toShort(), "Debug argument and capsule arguments")
|
||||
)
|
||||
}
|
||||
|
||||
@Test(timeout = 10_000)
|
||||
fun test() {
|
||||
val port = JVMAgentUtilities.parseDebugPort(args)
|
||||
Assert.assertEquals(expectedPort, port)
|
||||
}
|
||||
}
|
@ -226,9 +226,6 @@ dependencies {
|
||||
// Adding native SSL library to allow using native SSL with Artemis and AMQP
|
||||
compile "io.netty:netty-tcnative-boringssl-static:$tcnative_version"
|
||||
|
||||
// Required by JVMAgentUtil (x-compatible java 8 & 11 agent lookup mechanism)
|
||||
compile files("${System.properties['java.home']}/../lib/tools.jar")
|
||||
|
||||
// Byteman for runtime (termination) rules injection on the running node
|
||||
// Submission tool allowing to install rules on running nodes
|
||||
slowIntegrationTestCompile "org.jboss.byteman:byteman-submit:4.0.11"
|
||||
|
@ -28,8 +28,8 @@ import net.corda.node.internal.subcommands.ValidateConfigurationCli.Companion.lo
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.config.shouldStartLocalShell
|
||||
import net.corda.node.services.config.shouldStartSSHDaemon
|
||||
import net.corda.node.utilities.JVMAgentUtil.getJvmAgentProperties
|
||||
import net.corda.node.utilities.registration.NodeRegistrationException
|
||||
import net.corda.nodeapi.internal.JVMAgentUtilities
|
||||
import net.corda.nodeapi.internal.addShutdownHook
|
||||
import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseIncompatibleException
|
||||
@ -154,6 +154,8 @@ open class NodeStartup : NodeStartupLogging {
|
||||
const val LOGS_DIRECTORY_NAME = "logs"
|
||||
const val LOGS_CAN_BE_FOUND_IN_STRING = "Logs can be found in"
|
||||
const val ERROR_CODE_RESOURCE_LOCATION = "error-codes"
|
||||
|
||||
|
||||
}
|
||||
|
||||
lateinit var cmdLineOptions: SharedNodeCmdLineOptions
|
||||
@ -270,10 +272,10 @@ open class NodeStartup : NodeStartupLogging {
|
||||
logger.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}")
|
||||
logger.info("Machine: ${lookupMachineNameAndMaybeWarn()}")
|
||||
logger.info("Working Directory: ${cmdLineOptions.baseDirectory}")
|
||||
val agentProperties = getJvmAgentProperties(logger)
|
||||
if (agentProperties.containsKey("sun.jdwp.listenerAddress")) {
|
||||
logger.info("Debug port: ${agentProperties.getProperty("sun.jdwp.listenerAddress")}")
|
||||
JVMAgentUtilities.parseDebugPort(info.inputArguments) ?.let {
|
||||
logger.info("Debug port: $it")
|
||||
}
|
||||
|
||||
var nodeStartedMessage = "Starting as node on ${conf.p2pAddress}"
|
||||
if (conf.extraNetworkMapKeys.isNotEmpty()) {
|
||||
nodeStartedMessage = "$nodeStartedMessage with additional Network Map keys ${conf.extraNetworkMapKeys.joinToString(prefix = "[", postfix = "]", separator = ", ")}"
|
||||
|
@ -33,7 +33,6 @@ import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.AppServiceHub.Companion.SERVICE_PRIORITY_NORMAL
|
||||
import net.corda.core.internal.FlowAsyncOperation
|
||||
import net.corda.core.internal.FlowIORequest
|
||||
import net.corda.core.internal.WaitForStateConsumption
|
||||
@ -43,6 +42,7 @@ import net.corda.core.internal.exists
|
||||
import net.corda.core.internal.objectOrNewInstance
|
||||
import net.corda.core.internal.outputStream
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.node.AppServiceHub.Companion.SERVICE_PRIORITY_NORMAL
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
@ -54,9 +54,6 @@ import net.corda.core.utilities.NonEmptySet
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.Try
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleEvent
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleObserver
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleObserver.Companion.reportSuccess
|
||||
import net.corda.node.internal.NodeStartup
|
||||
import net.corda.node.services.api.CheckpointStorage
|
||||
import net.corda.node.services.statemachine.Checkpoint
|
||||
@ -68,7 +65,9 @@ import net.corda.node.services.statemachine.FlowStateMachineImpl
|
||||
import net.corda.node.services.statemachine.SessionId
|
||||
import net.corda.node.services.statemachine.SessionState
|
||||
import net.corda.node.services.statemachine.SubFlow
|
||||
import net.corda.node.utilities.JVMAgentUtil.getJvmAgentProperties
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleEvent
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleObserver
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleObserver.Companion.reportSuccess
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.serialization.internal.CheckpointSerializeAsTokenContextImpl
|
||||
import net.corda.serialization.internal.withTokenContext
|
||||
@ -77,21 +76,24 @@ import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.time.ZoneOffset.UTC
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.companionObject
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, private val database: CordaPersistence,
|
||||
private val serviceHub: ServiceHub, val baseDirectory: Path) : NodeLifecycleObserver {
|
||||
private val serviceHub: ServiceHub, val baseDirectory: Path) : NodeLifecycleObserver {
|
||||
companion object {
|
||||
internal val TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss").withZone(UTC)
|
||||
private val log = contextLogger()
|
||||
private val DUMPABLE_CHECKPOINTS = setOf(
|
||||
Checkpoint.FlowStatus.RUNNABLE,
|
||||
Checkpoint.FlowStatus.HOSPITALIZED,
|
||||
Checkpoint.FlowStatus.PAUSED
|
||||
Checkpoint.FlowStatus.RUNNABLE,
|
||||
Checkpoint.FlowStatus.HOSPITALIZED,
|
||||
Checkpoint.FlowStatus.PAUSED
|
||||
)
|
||||
}
|
||||
|
||||
@ -102,12 +104,10 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri
|
||||
private lateinit var checkpointSerializationContext: CheckpointSerializationContext
|
||||
private lateinit var writer: ObjectWriter
|
||||
|
||||
private val isCheckpointAgentRunning by lazy {
|
||||
checkpointAgentRunning()
|
||||
}
|
||||
private val isCheckpointAgentRunning by lazy(::checkpointAgentRunning)
|
||||
|
||||
override fun update(nodeLifecycleEvent: NodeLifecycleEvent): Try<String> {
|
||||
return when(nodeLifecycleEvent) {
|
||||
return when (nodeLifecycleEvent) {
|
||||
is NodeLifecycleEvent.AfterNodeStart<*> -> Try.on {
|
||||
checkpointSerializationContext = CheckpointSerializationDefaults.CHECKPOINT_CONTEXT.withTokenContext(
|
||||
CheckpointSerializeAsTokenContextImpl(
|
||||
@ -190,13 +190,20 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkpointAgentRunning(): Boolean {
|
||||
val agentProperties = getJvmAgentProperties(log)
|
||||
val pattern = "(.+)?checkpoint-agent(-.+)?\\.jar.*".toRegex()
|
||||
return agentProperties.values.any { value ->
|
||||
value is String && value.contains(pattern)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Note that this method dynamically uses [net.corda.tools.CheckpointAgent.running], make sure to keep it up to date with
|
||||
* the checkpoint agent source code
|
||||
*/
|
||||
private fun checkpointAgentRunning() = try {
|
||||
javaClass.classLoader.loadClass("net.corda.tools.CheckpointAgent").kotlin.companionObject
|
||||
} catch (e: ClassNotFoundException) {
|
||||
null
|
||||
}?.let { cls ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
cls.memberProperties.find { it.name == "running"}
|
||||
?.let {it as KProperty1<Any, Boolean>}
|
||||
?.get(cls.objectInstance!!)
|
||||
} ?: false
|
||||
|
||||
private fun Checkpoint.toJson(id: UUID, now: Instant): CheckpointJson {
|
||||
val (fiber, flowLogic) = when (flowState) {
|
||||
@ -402,6 +409,7 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri
|
||||
private interface FlowAsyncOperationMixin {
|
||||
@get:JsonIgnore
|
||||
val serviceHub: ServiceHub
|
||||
|
||||
// [Any] used so this single mixin can serialize [FlowExternalOperation] and [FlowExternalAsyncOperation]
|
||||
@get:JsonUnwrapped
|
||||
val operation: Any
|
||||
|
@ -1,25 +0,0 @@
|
||||
package net.corda.node.utilities
|
||||
|
||||
import com.sun.tools.attach.VirtualMachine
|
||||
import org.slf4j.Logger
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.util.*
|
||||
|
||||
object JVMAgentUtil {
|
||||
/**
|
||||
* Utility to attach to own VM at run-time and obtain agent details.
|
||||
* In Java 9 this requires setting the following run-time jvm flag: -Djdk.attach.allowAttachSelf=true
|
||||
* This mechanism supersedes the usage of VMSupport which is not available from Java 9 onwards.
|
||||
*/
|
||||
fun getJvmAgentProperties(log: Logger): Properties {
|
||||
val jvmPid = ManagementFactory.getRuntimeMXBean().name.substringBefore('@')
|
||||
return try {
|
||||
val vm = VirtualMachine.attach(jvmPid)
|
||||
return vm.agentProperties
|
||||
} catch (e: Throwable) {
|
||||
log.warn("Unable to determine whether agent is running: ${e.message}.\n" +
|
||||
"You may need to pass in -Djdk.attach.allowAttachSelf=true if running on a Java 9 or later VM")
|
||||
Properties()
|
||||
}
|
||||
}
|
||||
}
|
@ -31,23 +31,22 @@ apply plugin: 'com.jfrog.artifactory'
|
||||
description 'A javaagent to allow hooking into Kryo checkpoints'
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
compile "javassist:javassist:$javaassist_version"
|
||||
compile "com.esotericsoftware:kryo:$kryo_version"
|
||||
compile "co.paralleluniverse:quasar-core:$quasar_version"
|
||||
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
compileOnly "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
compileOnly "javassist:javassist:$javaassist_version"
|
||||
compileOnly "com.esotericsoftware:kryo:$kryo_version"
|
||||
compileOnly "co.paralleluniverse:quasar-core:$quasar_version"
|
||||
|
||||
compile (project(':core')) {
|
||||
compileOnly (project(':core')) {
|
||||
transitive = false
|
||||
}
|
||||
|
||||
// Unit testing helpers.
|
||||
compile "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||
compile "junit:junit:$junit_version"
|
||||
testCompile "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||
testCompile "junit:junit:$junit_version"
|
||||
|
||||
// SLF4J: commons-logging bindings for a SLF4J back end
|
||||
compile "org.slf4j:jcl-over-slf4j:$slf4j_version"
|
||||
compile "org.slf4j:slf4j-api:$slf4j_version"
|
||||
compileOnly "org.slf4j:slf4j-api:$slf4j_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
|
@ -51,8 +51,14 @@ class CheckpointAgent {
|
||||
LoggerFactory.getLogger("CheckpointAgent")
|
||||
}
|
||||
|
||||
val running by lazy {
|
||||
premainExecuted
|
||||
}
|
||||
private var premainExecuted = false
|
||||
|
||||
@JvmStatic
|
||||
fun premain(argumentsString: String?, instrumentation: Instrumentation) {
|
||||
premainExecuted = true
|
||||
parseArguments(argumentsString)
|
||||
instrumentation.addTransformer(CheckpointHook)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user