cryostatio / cryostat-legacy

OUTDATED - See the new repository below! -- Secure JDK Flight Recorder management for containerized JVMs
https://github.com/cryostatio/cryostat
Other
224 stars 31 forks source link

[Bug] Unable to interact with short form custom target #1867

Open cmah88 opened 9 months ago

cmah88 commented 9 months ago

Current Behavior

java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost: caused by URISyntaxException: Expected scheme-specific part at index 10: localhost:

image

image

Expected Behavior

No response

Steps To Reproduce

No response

Environment

- OS: 
- Environment: 
- Version:

Anything else?

No response

andrewazores commented 9 months ago

Creating a custom target with localhost:0 results in a target discovery notification, but also immediately an error notification with the 500 response.

It may actually be that the 500 response is occurring in response to the request to list event templates, not the target creation. So perhaps the exception is really happening when Cryostat tries to use this custom target definition to open a JMX connection - is it no longer looking at these "short form" connection URLs and trying to format them into service:jmx:rmi: JMX URLs?

andrewazores commented 9 months ago

@Josh-Matsuoka @aali309 @mwangggg could one of you take a look at this next week?

aali309 commented 9 months ago

Creating a custom target with localhost:0 results in a target discovery notification, but also immediately an error notification with the 500 response.

It may actually be that the 500 response is occurring in response to the request to list event templates, not the target creation. So perhaps the exception is really happening when Cryostat tries to use this custom target definition to open a JMX connection - is it no longer looking at these "short form" connection URLs and trying to format them into service:jmx:rmi: JMX URLs?

Yes, that could be the reason. Target is being created and discovered but listing event templates produces Failed to load resource: the server responded with a status of 500 (Internal Server Error) https://localhost:8181/api/v1/targets/localhost%3A0/templates

andrewazores commented 9 months ago

https://github.com/cryostatio/cryostat/blob/050e03f5390e44adaeae6161ec5e4b7afc476437/src/main/java/io/cryostat/net/TargetConnectionManager.java#L215

Looks like the root cause is here. This should catch URISyntaxException, not only MalformedURLException. This way if the connection attempt using the raw short-form string fails for that reason it will try to create the full service:jmx:rmi URL using the short form.

andrewazores commented 9 months ago

Here's the server stack trace from when this happens:

SEVERE: HTTP 500: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:
io.vertx.ext.web.handler.HttpException: Internal Server Error
Caused by: java.lang.IllegalStateException: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:
    at io.cryostat.configuration.CredentialsManager.getCredentialsByTargetId(CredentialsManager.java:186)
    at io.cryostat.net.web.http.AbstractAuthenticatedRequestHandler.getConnectionDescriptorFromContext(AbstractAuthenticatedRequestHandler.java:142)
    at io.cryostat.net.web.http.api.v1.TargetRecordingsGetHandler.handleAuthenticated(TargetRecordingsGetHandler.java:103)
    at io.cryostat.net.web.http.AbstractAuthenticatedRequestHandler.handle(AbstractAuthenticatedRequestHandler.java:81)
    at io.cryostat.net.web.http.AbstractAuthenticatedRequestHandler.handle(AbstractAuthenticatedRequestHandler.java:51)
    at io.vertx.ext.web.impl.BlockingHandlerDecorator.lambda$handle$0(BlockingHandlerDecorator.java:48)
    at io.vertx.core.impl.ContextBase.lambda$null$0(ContextBase.java:137)
    at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:264)
    at io.vertx.core.impl.ContextBase.lambda$executeBlocking$1(ContextBase.java:135)
    at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:
    at java.base/java.net.URI$Parser.fail(URI.java:2976)
    at java.base/java.net.URI$Parser.failExpecting(URI.java:2982)
    at java.base/java.net.URI$Parser.parse(URI.java:3182)
    at java.base/java.net.URI.<init>(URI.java:623)
    at org.apache.http.client.utils.URIBuilder.build(URIBuilder.java:146)
    at io.cryostat.configuration.CredentialsManager.getCredentialsByTargetId(CredentialsManager.java:177)
    ... 13 more
andrewazores commented 9 months ago

That was after defining a custom target with the short-form localhost:0 and then clicking on the Recordings navigation item in the UI. When clicking on Events it's similar:

SEVERE: HTTP 500: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:
io.vertx.ext.web.handler.HttpException: Internal Server Error
Caused by: io.cryostat.net.web.http.api.v2.ApiException: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:
    at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.handle(AbstractV2RequestHandler.java:99)
    at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.handle(AbstractV2RequestHandler.java:49)
    at io.vertx.ext.web.impl.BlockingHandlerDecorator.lambda$handle$0(BlockingHandlerDecorator.java:48)
    at io.vertx.core.impl.ContextBase.lambda$null$0(ContextBase.java:137)
    at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:264)
    at io.vertx.core.impl.ContextBase.lambda$executeBlocking$1(ContextBase.java:135)
    at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.IllegalStateException: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:
    at io.cryostat.configuration.CredentialsManager.getCredentialsByTargetId(CredentialsManager.java:186)
    at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.getConnectionDescriptorFromParams(AbstractV2RequestHandler.java:151)
    at io.cryostat.net.web.http.api.v2.TargetProbesGetHandler.handle(TargetProbesGetHandler.java:93)
    at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.handle(AbstractV2RequestHandler.java:86)
    ... 10 more
Caused by: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:
    at java.base/java.net.URI$Parser.fail(URI.java:2976)
    at java.base/java.net.URI$Parser.failExpecting(URI.java:2982)
    at java.base/java.net.URI$Parser.parse(URI.java:3182)
    at java.base/java.net.URI.<init>(URI.java:623)
    at org.apache.http.client.utils.URIBuilder.build(URIBuilder.java:146)
    at io.cryostat.configuration.CredentialsManager.getCredentialsByTargetId(CredentialsManager.java:177)
    ... 13 more
andrewazores commented 9 months ago

Here is where the exception originates:

https://github.com/cryostatio/cryostat/blob/2374132e18818e4b20fe99a31d59505c8d90beb4/src/main/java/io/cryostat/configuration/CredentialsManager.java#L177

                boolean isJmx = URIUtil.isJmxUrl(uri);
                if (isJmx) {
                    match = Objects.equals(uri.toString(), targetId);
                } else {
                    URI in = new URI(targetId);
                    match = Objects.equals(uri, in);
                    URI userless = new URIBuilder(uri).setUserInfo(null).build();
                    match |= Objects.equals(userless, in);
                }

URIUtil.isJmxUrl() is for checking whether the given URI is a valid JMX Service URL, ex. a service:jmx:rmi: one. The implicit assumption in this code block is that the given URI is either of that form, or it is an Agent http:// URL. It does not account for the possibility of localhost:0 or other "short-form" target identifier.

Immediately apparent options:

  1. Check if the targetId looks like a short-form (with a regex?) in this block and if it is, convert it to a JMX Service URL
  2. Catch the URISyntaxException and assume that when caught this means, or might mean, that the targetId was a short-form. Then do the same thing as option 1.
  3. Catch the IllegalStateException somewhere higher up in the stack, do the short-form-to-JMX conversion, and retry
  4. Add logic like below:
boolean isJmx = URIUtil.isJmxUrl(targetId);
boolean isHttp = URIUtil.isHttpUrl(targetId);
if (isJmx) {
  ...
} else if (isHttp) {
  ...
} else {
  // assume it is a short form
  var u = connectionToolkit.createServiceUrl(targetId);
  ... // do the same thing as in the isJmx branch
}

Options 1 and 4 are probably the best since they aren't relying on exception throwing/catching for control flow. Option 4 is probably simpler since it first checks whether the targetId looks like an http:// URL, which is better-defined than the "short-form" and therefore easier to check for.