-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(attach): implement basic dynamic attach #234
Conversation
66441c2
to
b08711f
Compare
9fa7ae6
to
9d3409f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a suggested way to run this after #311? As expected, when running with the plain jar, I get:
$ java -jar target/cryostat-agent-0.4.0-SNAPSHOT.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
at io.cryostat.agent.Agent.<clinit>(Agent.java:73)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
... 1 more
With the shaded jar, I get:
$ java -jar target/cryostat-agent-0.4.0-SNAPSHOT-shaded.jar
2024-02-26 15:59:23:538 -0500 [main] INFO io.cryostat.agent.Agent - Attaching to VM: io.cryostat.Cryostat 19841
2024-02-26 15:59:23:542 -0500 [main] INFO io.cryostat.agent.Agent - Injecting agent into PID 19841
2024-02-26 15:59:23:542 -0500 [main] INFO io.cryostat.agent.Agent - /home/ebaron/git/cryostat-agent/target/cryostat-agent-0.4.0-SNAPSHOT-shaded.jar
com.sun.tools.attach.AgentLoadException: Agent JAR not found or no Agent-Class attribute
at jdk.attach/sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java:160)
at io.cryostat.agent.Agent.call(Agent.java:136)
at io.cryostat.agent.Agent.call(Agent.java:63)
at io.cryostat.agent.shaded.picocli.CommandLine.executeUserObject(CommandLine.java:2041)
at io.cryostat.agent.shaded.picocli.CommandLine.access$1500(CommandLine.java:148)
at io.cryostat.agent.shaded.picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2461)
at io.cryostat.agent.shaded.picocli.CommandLine$RunLast.handle(CommandLine.java:2453)
at io.cryostat.agent.shaded.picocli.CommandLine$RunLast.handle(CommandLine.java:2415)
at io.cryostat.agent.shaded.picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2273)
at io.cryostat.agent.shaded.picocli.CommandLine$RunLast.execute(CommandLine.java:2417)
at io.cryostat.agent.shaded.picocli.CommandLine.execute(CommandLine.java:2170)
at io.cryostat.agent.Agent.main(Agent.java:109)
I expected the shaded jar to work. It appears to find the correct path to the shaded jar, and the manifest contains the correct Agent-Class
attribute, yet the VM still fails to load it.
Hmm, I'll have to take a look. |
9d3409f
to
5afbcbc
Compare
and
Not sure what's going on - from my end it looks like it's just about working as intended. I haven't tried supplying the injected Agent with its required configuration options yet, but it's at least getting to that point. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can reproduce a working setup with those instructions. Sorry for the delay (again)
5afbcbc
to
037d748
Compare
Based on #224
Related to #233
This implements basic dynamic attach. The Agent can be launched as a standalone Java process like:
$ java -jar target/cryostat-agent-0.4.0-SNAPSHOT.jar 1234 # 1234 is another JVM's pid
This will cause the Agent process to look up PID
1234
using its Attach providers. If1234
is found as a valid PID then the Agent process will attach to PID1234
and attempt to load the Agent's own JAR into that running JVM, which will then bootstrap into the normal Agent launch process. If1234
is not found then nothing is bootstrapped. Instead of1234
the wildcard*
can also be specified, which will lead to the Agent JAR attempting to bootstrap itself into every JVM it finds. Finally, if the PID is not specified or is0
, then the Agent will check if exactly one candidate JVM is available and attempt to bootstrap into that, failing if there are too many JVM candidates or none.In this mode the Agent still tries to load its configuration entirely from the JVM it is bootstrapping into, which does not really make sense for a late-attaching Agent - the host application probably does not have Cryostat Agent-specific configuration properties if it was not launched with the Cryostat Agent to begin with. This will be addressed some time later in a follow-up PR.Additional late-binding configuration options can be specified to the Agent launcher with command line options:
$ java -jar target/cryostat-agent-0.4.0-SNAPSHOT.jar \ -Dcryostat.agent.baseuri=http://cryostat.local \ --smartTrigger=[ProcessCpuLoad>0.2]~profile \ @/deployment/app/moreAgentArgs \ 1234
Try
$ java -jar target/cryostat-agent-0.4.0-SNAPSHOT.jar -h
and see picocli for a more complete explanation of the available options and their behaviour. These late-binding configuration options are picked up by the Agent launcher process and serialized into a singleString
argument that is passed into the injected Agent instances, which they receive on theiragentmain(String arg)
and then deserialize again. System properties specified with-D
are set onto the host JVM before the injected Agent attempts to read its configuration values, so from the Agent implementation POV this is identical to setting the-D
or equivalent environment variable on the host JVM process itself. This mechanism does allow the user who controls the agent injection to override other arbitrary system properties of the host JVM at runtime, however if the user has enough access and ability to inject an agent then they can already exploit this without using the Cryostat Agent specifically.To test:
Things to investigate:
ByteArrayInputStream
or something so we can send it the JAR contents directly?*
PID wildcard, it might also be useful to have a--watch
option where the agent launcher becomes a daemon, injecting agent instances into new JVMs as they appear.