cryostatio / cryostat-legacy Goto Github PK
View Code? Open in Web Editor NEWOUTDATED - See the new repository below! -- Secure JDK Flight Recorder management for containerized JVMs
Home Page: https://github.com/cryostatio/cryostat
License: Other
OUTDATED - See the new repository below! -- Secure JDK Flight Recorder management for containerized JVMs
Home Page: https://github.com/cryostatio/cryostat
License: Other
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList.forEach(ArrayList.java:1542)
at com.redhat.rhjmc.containerjfr.tui.ws.MessagingServer.flush(MessagingServer.java:131)
at com.redhat.rhjmc.containerjfr.tui.ws.WsCommandExecutor.flush(WsCommandExecutor.java:113)
at com.redhat.rhjmc.containerjfr.tui.ws.WsCommandExecutor.run(WsCommandExecutor.java:79)
at com.redhat.rhjmc.containerjfr.ContainerJfr.main(ContainerJfr.java:69)
See cryostatio/cryostat-web#32
The in-memory recording should not be closed after uploading to Grafana.
Using websockat to connect to ws://localhost:8181/command if I press enter, inputting an empty string (I assume), there is an uncaught exception that makes the Websocket stuff die and no further action can be taken without restarting the server.
Exception in thread "main" java.lang.NullPointerException
at com.redhat.rhjmc.containerjfr.tui.ws.WsCommandExecutor.run(WsCommandExecutor.java:50)
at com.redhat.rhjmc.containerjfr.ContainerJfr.main(ContainerJfr.java:69)
If incorrect input like "hi" is provided, the server continues after responding over the websocket with error details. That should also occur for an empty message.
The README or some other documentation should be included that describes the requirements of Java applications in containers to be visible by this project, with sample commands for Docker/Podman or even specific to OpenShift. E.g. the RJMX exposure.
See previous discussion during review of #57 .
The current implementation for streaming of in-memory recordings relies on using an intermediate buffer in container-jfr, which reads data out of the target JVM into a buffer, then asks the Vert.x webserver to copy the contents of that buffer into its internal write queue. Once all of the data has thus been copied out of the remote JVM and into the response write queue, the response begins to be flushed out the network stack. There should be some better way to stream the data through container-jfr and the Vert.x webserver so that less time is spend building up the intermediate copy of the flight recording, perhaps using a Vert.x Pump.
The WWW-Authenticate header should be included with 401 responses, so that clients can determine what form of authentication is expected.
SSIA
Users should be able to (re-)upload existing JFR files from their local machine into ContainerJFR's storage (archive).
In case their ContainerJFR instance goes away and storage is lost (ex. OpenShift Operator is deleted and restored)
To allow ContainerJFR to be used as a desktop application for analysis, but with the Flight Recorder options set by JVM flags and dumped to local file directly by the JVM or another external tool (ex. jcmd)
To allow migration between different local environments, for example a user using ContainerJFR as a desktop application with a workstation and a laptop
For simply restoring accidentally deleted recordings from ContainerJFR archives
ContainerJFR should do some validation that the received file is a valid JFR file, that the specified name for the file is acceptable (ie. compatible with file-relating commands), etc. The file name should also be automatically updated if the specified name conflicts with a pre-existing file name, so that the upload doesn't overwrite previous data.
When trying to visit the Trello board link via README.md, I see "board not found, this board may be private and you may be able to view it by logging in".
A minimal container-jfr image, without the -web client assets or any other additional resources beyond what is needed for connecting to container-jfr and starting/stopping/retrieving a recording, should be made available.
As documented here: cryostatio/cryostat-operator#24
When running in Minishift (or perhaps more generally, OpenShift 3.x), requesting container-jfr to connect to itself as a target results in the connection hanging on the container-jfr side, and becoming unresponsive to connected websocket clients or their connections being closed. This doesn't seem to occur with CodeReady Containers/OpenShift 4.x, nor does it occur when running container-jfr with the Docker daemon locally or running it as a JVM process directly on a host machine.
Whatever causes the connection to hang to begin with should be addressed, if possible. A timeout should also be implemented in case the connection does hang, so that the container-jfr instance can remain alive and responsive (perhaps this also implies liveness/readiness probes should be implemented).
[ERROR] Failures:
[ERROR] MessagingServerTest.shouldHandleRemovedConnections:160
Expected: "another message"
but: was "hello world"
This test seems to intermittently fail. Possibly related to Maven parallel execution configuration, since I don't recall ever seeing this failure before with the Gradle build setup.
When running in minimal mode and with the Grafana and jfr-datasource environment variables unset, the endpoints /grafana_dashboard_url and /grafana_datasource_url respond 200 and with an empty string in the JSON response value. Should this instead be a 404 or other error status?
This Content-Type
response header for /reports/<recording>
endpoint has incorrect value: text/plain
.
This problem is reproducible by running kube-setup.sh
against a fresh Openshift installation. Looking at the script content, it's fetching the latest
of quay.io/rh-jmc-team/container-jfr
, which is currently v0.4.3
Interestingly, it appears the response content type is explicitly set to NanoHTTPD.MIME_HTML
since v0.3.2
.
It's possible that Openshift's reverse proxy somehow overwrote this header field.
$ curl --head -H "Accept: text/html" http://container-jfr-container-jfr.10.15.17.89.nip.io/reports/test
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Wed, 2 Oct 2019 19:33:32 GMT
Access-Control-Allow-Origin: *
Content-Length: 122387
Set-Cookie: 98c81825faae9a2f4c5de3ce34beb5a5=160b9b5980b10c3e9837d7d18ffece6b; path=/; HttpOnly
Cache-control: private
I attempted to request a recording via the container-jfr-operator CR API and found this in the container-jfr logs:
[INFO] (10.128.0.1:56640): GET /clienturl 200 0ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:56766): GET /clienturl 200 0ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:56894): GET /clienturl 200 1ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:57020): GET /clienturl 200 1ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:57392): GET /clienturl 200 0ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:57856): GET /clienturl 200 0ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:58252): GET /clienturl 200 0ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:58378): GET /clienturl 200 0ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:58504): GET /clienturl 200 1ms
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.1.99:35886): GET /clienturl 200 0ms
[INFO] Connected remote client 10.128.0.1:58582
[INFO] (10.128.0.1:58582): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:58582): CMD {"command":"connect","args":["172.30.181.199:9091"]}
[INFO] No active connection
[INFO] (10.128.0.1:58582): CMD {"command":"dump","args":["apimade","30","ALL"]}
[INFO] (10.128.0.1:56504): CMD {"command":"list-event-types","args":[]}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58582): CMD {"command":"list","args":null}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58582): CMD {"command":"disconnect","args":null}
[INFO] (10.128.1.99:35886): GET /clienturl 200 0ms
[INFO] Disconnected remote client 10.128.0.1:58582
[INFO] Connected remote client 10.128.0.1:58644
[INFO] (10.128.0.1:58644): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:58644): CMD {"command":"disconnect","args":null}
[INFO] (10.128.0.1:58644): CMD {"command":"connect","args":["172.30.181.199:9091"]}
[INFO] No active connection
[INFO] (10.128.0.1:58644): CMD {"command":"dump","args":["apimade","30","ALL"]}
[INFO] (10.128.0.1:56504): CMD {"command":"list-event-types","args":[]}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:56504): CMD {"command":"list-event-types","args":[]}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] Disconnected remote client 10.128.0.1:58644
[INFO] (10.128.0.1:58684): GET /clienturl 200 0ms
[INFO] (10.128.1.99:35886): GET /clienturl 200 2ms
[INFO] Connected remote client 10.128.0.1:58690
[INFO] (10.128.0.1:58690): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58690): CMD {"command":"disconnect","args":null}
[INFO] Disconnected remote client 10.128.0.1:58690
[INFO] (10.128.1.99:35886): GET /clienturl 200 3ms
[INFO] Connected remote client 10.128.0.1:58722
[INFO] (10.128.0.1:58722): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:56504): CMD {"command":"ping","args":[]}
[INFO] (10.128.0.1:58722): CMD {"command":"connect","args":["172.30.181.199:9091"]}
[INFO] No active connection
[INFO] (10.128.0.1:58722): CMD {"command":"dump","args":["apimade","30","ALL"]}
[INFO] (10.128.0.1:56504): CMD {"command":"list-event-types","args":[]}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58722): CMD {"command":"list","args":null}
[INFO] Disconnected remote client 10.128.0.1:58722
[INFO] (10.128.1.99:35886): GET /clienturl 200 0ms
[INFO] Connected remote client 10.128.0.1:58772
[INFO] (10.128.0.1:58772): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58772): CMD {"command":"disconnect","args":null}
[INFO] Disconnected remote client 10.128.0.1:58772
[INFO] (10.128.1.99:35886): GET /clienturl 200 1ms
[INFO] Connected remote client 10.128.0.1:58802
[INFO] (10.128.0.1:58802): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:58802): CMD {"command":"connect","args":["172.30.181.199:9091"]}
[INFO] No active connection
[INFO] (10.128.0.1:56504): CMD {"command":"list-event-types","args":[]}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58802): CMD {"command":"dump","args":["apimade","30","ALL"]}
[INFO] Disconnected remote client 10.128.0.1:58802
[INFO] (10.128.1.99:35886): GET /clienturl 200 0ms
[INFO] Connected remote client 10.128.0.1:58848
[INFO] (10.128.0.1:58848): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58848): CMD {"command":"disconnect","args":null}
[INFO] Disconnected remote client 10.128.0.1:58848
[INFO] (10.128.1.99:35886): GET /clienturl 200 0ms
[INFO] Connected remote client 10.128.0.1:58872
[INFO] (10.128.0.1:58872): CMD {"command":"is-connected","args":null}
[INFO] (10.128.0.1:58872): CMD {"command":"connect","args":["172.30.181.199:9091"]}
[INFO] No active connection
[INFO] (10.128.0.1:56504): CMD {"command":"list-event-types","args":[]}
[INFO] (10.128.0.1:56504): CMD {"command":"list","args":[]}
[INFO] (10.128.0.1:58872): CMD {"command":"dump","args":["apimade","30","ALL"]}
[INFO] Disconnected remote client 10.128.0.1:58872
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList.forEach(ArrayList.java:1542)
at com.redhat.rhjmc.containerjfr.tui.ws.MessagingServer.flush(MessagingServer.java:115)
at com.redhat.rhjmc.containerjfr.tui.ws.WsCommandExecutor.flush(WsCommandExecutor.java:119)
at com.redhat.rhjmc.containerjfr.tui.ws.WsCommandExecutor.run(WsCommandExecutor.java:85)
at com.redhat.rhjmc.containerjfr.ContainerJfr.main(ContainerJfr.java:69)
[INFO] (10.128.1.99:35886): GET /clienturl 200 0ms
The requested recording was observed to be created in the -web UI, but container-jfr seemed to be broken after this exception was thrown. For example, analysis summaries for the recording could be retrieved, but targets could not be scanned (infinite spinner).
HTTPS and WSS should be used, not plain HTTP and WS.
JMCConnection and JMCConnectionToolkit are misnomers. These classes represent connections to a remote target JVM's Flight Recorder, not anything specific to JMC.
Auth management should be somehow configurable (ex. by env var), and platform detection used to determine the auth manager to use only if no configuration exists (or is invalid?). Currently the only working scenario this enables is for noop auth in an OpenShift deployment, but for future auth managers it will make more sense to allow this flexibility.
An authentication manager (or rather, managers for each of TUI, TCP, and WS connections) should be implemented which blocks user interaction until successfully authenticated. Ideally this should also have hooks for connection to some external authz mechanism (SSO) so that users can reuse their existing infrastructure.
PR rh-jmc-team#43 modified error strings in implementations, but not in tests.
com.redhat.rhjmc.containerjfr.commands.internal.ConnectCommandTest > shouldNotValidateNull() FAILED
org.mockito.exceptions.verification.ArgumentsAreDifferent at ConnectCommandTest.java:84
com.redhat.rhjmc.containerjfr.commands.internal.ConnectCommandTest > shouldNotValidateEmptyString() FAILED
org.mockito.exceptions.verification.ArgumentsAreDifferent at ConnectCommandTest.java:90
com.redhat.rhjmc.containerjfr.commands.internal.ConnectCommandTest > shouldExpectOneArg() FAILED
org.mockito.exceptions.verification.ArgumentsAreDifferent at ConnectCommandTest.java:67
com.redhat.rhjmc.containerjfr.commands.internal.ConnectCommandTest > shouldNotValidateInvalidIdentifiers(String)[1] FAILED
org.mockito.exceptions.verification.ArgumentsAreDifferent at ConnectCommandTest.java:78
com.redhat.rhjmc.containerjfr.commands.internal.ConnectCommandTest > shouldNotValidateInvalidIdentifiers(String)[2] FAILED
org.mockito.exceptions.verification.ArgumentsAreDifferent at ConnectCommandTest.java:78
com.redhat.rhjmc.containerjfr.commands.internal.ConnectCommandTest > shouldNotValidateInvalidIdentifiers(String)[3] FAILED
org.mockito.exceptions.verification.ArgumentsAreDifferent at ConnectCommandTest.java:78
417 tests completed, 6 failed
testsuite com.redhat.rhjmc.containerjfr.commands.internal.SaveRecordingCommandTest:
testcase com.redhat.rhjmc.containerjfr.commands.internal.ConnectCommandTest > shouldNotValidateNull(): Argument(s) are different! Wanted:
cw.println(
"Expected one argument: host name/URL"
);
-> at com.redhat.rhjmc.containerjfr.core.tui.ClientWriter.println(ClientWriter.java:11)
> Task :test FAILED
This is really trivial though.
The HTML report generation API exposed by the JMC core libraries does not seem to offer any sort of streaming interface, so the entire recording must be loaded out of the target JVM and into memory, and then the HTML report built in-memory along with all required data structures. All of this intermediate data can add up to quite a large size, and when running container-jfr in a resource-constrained environment ex. a typical Kubernetes or Openshift scenario, can easily trigger OOMs and crash the process.
Ideally there would be a pipelined streaming API for remote JVM Flight Recording -> container-jfr -> JMC HTML Report API -> HTML report stream
, so that container-jfr can then acts as an intermediate pipe between the end user's client web browser and the target JVM's Flight Recorder, reducing the amount of memory required for the report building operation. This at the very least depends upon the target JVM supporting streaming JFR events (https://openjdk.java.net/jeps/349).
As an interim measure, if a reliable way can be found to measure the size of the recording within the target JVM without first loading it into container-jfr memory, then some heuristic can be applied and the decision to produce a report cancelled early if the expected resource consumption is too high. Ex. if generating the HTML report typically requires 2x as much memory as the recording size itself, and container-jfr has less than 3x (report plus recording) recording size of memory available to it, then the report should not be attempted.
Currently there are several classes which create TCP sockets or HTTP client connections (some examples: RecordingExporter, UploadSavedRecordingsCommand, SocketClientReaderWriter, SocketInteractiveShellExecutor, JMCConnection), and which are partly or entirely missing unit tests since the networking codepaths can not be exercised in unit testing without actually producing network connections. We need some enhanced mocking utilities, or a test harness to intercept connections, in order to properly test and verify these classes.
There is probably a cheap performance win to be had by buffering reads of archived recordings.
See discussion in #114 . Currently, messages do not explicitly contain any identifying information about the sending client (though the server can of course tell which socket connection received a message), and all responses to such messages are multicast out to all clients, with no indication for the clients whether they are receiving a broadcast or a direct response to one of their messages. Due to the overall design and architecture it does not make sense at this time to move to only using unicast responses, so including some kind of client/message identifier on client messages which is included in the corresponding broadcast response will allow clients to selectively react to responses.
As title says. Some actions in the project require these to be installed, generally with an exact or minimal major version.
Despite the existence of container-jfr-core, container-jfr itself still contains some direct dependencies on upstream JMC, mostly in the way of service interfaces, recording option definitions, recording descriptors, and exception types. These should be abstracted away behind -core, so that the coupling to upstream JMC is restricted to -core as a thin wrapper, allowing the possibility to remove the dependency on upstream JMC in the future with minimal additional refactoring work.
container-jfr
must handle scenarios where the target JVMs require authentication for RMI/JMX connections, and scenarios where SSL is enabled on the communication socket.
I'm not sure what caused this to happen, but I noticed that there was no access control for my deployed Container JFR (v0.13.0) on CodeReady Containers. Looking in the logs I saw this:
$ oc logs containerjfr-58f689b7b4-skrjl -c containerjfr
[INFO] Logger level: INFO
[INFO] container-jfr started. args: []
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[WARN] No available SSL certificates. Fallback to plain HTTP.
[INFO] Selecting platform default AuthManager
[INFO] io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://172.30.0.1/apis/route.openshift.io/v1/namespaces/default/routes. Message: service unavailable
.
at io.fabric8.kubernetes.client.dsl.base.OperationSupport.requestFailure(OperationSupport.java:510)
at io.fabric8.kubernetes.client.dsl.base.OperationSupport.assertResponseCode(OperationSupport.java:449)
at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:413)
at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:372)
at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:354)
at io.fabric8.kubernetes.client.dsl.base.BaseOperation.listRequestHelper(BaseOperation.java:153)
at io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:620)
at io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:69)
at com.redhat.rhjmc.containerjfr.platform.internal.OpenShiftPlatformStrategy.isAvailable(OpenShiftPlatformStrategy.java:53)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176)
at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:361)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:503)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543)
at com.redhat.rhjmc.containerjfr.platform.PlatformModule.providePlatformClient(PlatformModule.java:24)
at com.redhat.rhjmc.containerjfr.platform.PlatformModule_ProvidePlatformClientFactory.proxyProvidePlatformClient(PlatformModule_ProvidePlatformClientFactory.java:35)
at com.redhat.rhjmc.containerjfr.platform.PlatformModule_ProvidePlatformClientFactory.get(PlatformModule_ProvidePlatformClientFactory.java:24)
at com.redhat.rhjmc.containerjfr.platform.PlatformModule_ProvidePlatformClientFactory.get(PlatformModule_ProvidePlatformClientFactory.java:10)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.redhat.rhjmc.containerjfr.net.web.WebModule_ProvideAuthManagerFactory.get(WebModule_ProvideAuthManagerFactory.java:23)
at com.redhat.rhjmc.containerjfr.net.web.WebModule_ProvideAuthManagerFactory.get(WebModule_ProvideAuthManagerFactory.java:10)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.redhat.rhjmc.containerjfr.net.NetworkModule.provideAuthManager(NetworkModule.java:132)
at com.redhat.rhjmc.containerjfr.net.NetworkModule_ProvideAuthManagerFactory.proxyProvideAuthManager(NetworkModule_ProvideAuthManagerFactory.java:69)
at com.redhat.rhjmc.containerjfr.net.NetworkModule_ProvideAuthManagerFactory.get(NetworkModule_ProvideAuthManagerFactory.java:44)
at com.redhat.rhjmc.containerjfr.net.NetworkModule_ProvideAuthManagerFactory.get(NetworkModule_ProvideAuthManagerFactory.java:14)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.redhat.rhjmc.containerjfr.net.web.WebModule_ProvideWebServerFactory.get(WebModule_ProvideWebServerFactory.java:70)
at com.redhat.rhjmc.containerjfr.net.web.WebModule_ProvideWebServerFactory.get(WebModule_ProvideWebServerFactory.java:17)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.redhat.rhjmc.containerjfr.DaggerContainerJfr_Client.webServer(DaggerContainerJfr_Client.java:660)
at com.redhat.rhjmc.containerjfr.ContainerJfr.main(ContainerJfr.java:67)
[INFO] Selected KubeApi Platform Strategy
[INFO] low memory pressure streaming disabled for web server
[INFO] HTTPS service running on https://containerjfr-default.apps-crc.testing:443
This was an instance of CRC that was stopped previously and restarted without redeploying anything, FWIW.
We should consider using Maven to build rather than Gradle.
Things to consider:
-web
needs to be built by invoking npm
The HTML Reports should be modified such that rule result descriptions contain links to Grafana views - if a Grafana dashboard and datasource are configured - so that the end user can quickly and easily jump from the container-jfr overview into a more detailed analysis from the automated report, without resorting to downloading the flight recording and analysing the recording using traditional desktop JMC.
When SSL is enabled, recording downloads and reports do not work due to "mixed active content"-type errors - ie, the client is loaded over HTTPS but the download and reports requests are made over HTTP.
Currently, the only auth manager implementations are "noop" (permissive) and "OpenShift" (delegates to the OpenShift API). There should be an auth manager implementation that instead allows some configuration of basic key-value pairs for usernames and password hashes. Ideally this should allow for more than one such user account to be configured. This could be via some environment variables following some predefined naming convention, or by some config file. Combined with #102 , this would allow a scenario like basic auth in OpenShift, and enabling auth for the desktop app or simple Docker deployment scenarios.
See #141
Remote target VMs have their own internally defined event templates. These should be included in the set of event templates that users can specify for a recording.
Build tooling should be switched from jib
to s2i
.
In addition to the magic string ALL
or the current event.foo:setting=value,event.bar:setting=value
event specifier strings, users should be able to list and then select from sets of event templates/presets.
Example scenario:
User has ongoing in-memory recording named foo from target app.svc.local. Saving this recording to archive produces a file on disk named "app-svc-local_foo.jfr". Currently, saving the recording again will overwrite "app-svc-local_foo.jfr". This should not be the case.
A timestamp should be attached to saved filenames, ex. "app-svc-local_foo_20191105T090738.jfr"
If two recordings happen to have the same filename, whether from rapid repeated saving of the same active recording or re-upload or any other reason, then some differentiating suffix should be applied to the filename such as an incrementing count of the number of copies ("local_foo_20191105T090738_1.jfr")
The documentation and all demos/examples currently state this list of JVM flags as required for container-jfr
to be able to connect and manage targets:
'-Dcom.sun.management.jmxremote.rmi.port=9091',
'-Dcom.sun.management.jmxremote=true',
'-Dcom.sun.management.jmxremote.port=9091',
'-Dcom.sun.management.jmxremote.ssl=false',
'-Dcom.sun.management.jmxremote.authenticate=false',
'-Dcom.sun.management.jmxremote.local.only=false',
'-Djava.rmi.server.hostname=$TARGET_HOSTNAME'
This set of flags should be examined to see if any are unnecessary or redundant.
See #141
A user should be able to create a custom event template (ex. by uploading an XML .jfc
file), which would subsequently be included in the set of event templates that can be applied to a recording. This should be stored in ContainerJFR's own local storage, and available as a template for any and all target JVMs. The template may not then be applicable to every target in case it specifies events/options not known to the target, but that's up to the users to determine compatibility when they're uploading custom templates.
When running mvn clean verify
, or something like it, the build sometimes gets stuck and seems to hang on a pre-integration-test step. The issue appears to be with the exec plugin when attempting to start the container using podman. This uses a synchronous exec plugin configuration but gives the --detach
flag to podman, so the podman process should be exiting after the container has been spun up. It seems that sometimes either podman doesn't exit, or somehow the exec plugin doesn't see that it has. When this happens, podman ps -a
can be used to observe that the container does in fact exist and is running. However, podman kill container-jfr-itest
typically complains about a "device or resource busy", although it still seems to succeed in killing and removing the container anyway.
In order to avoid the auth token being entered into logs etc., it should be supplied by the client on WebSocket connection request via a websocket subprotocol (ex. https://docs.openshift.com/container-platform/4.1/authentication/understanding-authentication.html : Sent as a websocket subprotocol header in the form base64url.bearer.authorization.k8s.io.<base64url-encoded-token> for websocket requests
) rather than the current query parameter.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.