From c31e284d6648201f42800d8702e7d7884063b948 Mon Sep 17 00:00:00 2001 From: Atif Ali <56743004+aali309@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:35:40 -0400 Subject: [PATCH] feat(agent): implement HTTP JFR snapshot creation (#1627) Co-authored-by: Andrew Azores --- .../java/io/cryostat/net/AgentClient.java | 51 +++++++++++++++++++ .../java/io/cryostat/net/AgentJFRService.java | 19 +++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/cryostat/net/AgentClient.java b/src/main/java/io/cryostat/net/AgentClient.java index f5841b1ae6..c2c9310701 100644 --- a/src/main/java/io/cryostat/net/AgentClient.java +++ b/src/main/java/io/cryostat/net/AgentClient.java @@ -129,6 +129,57 @@ Future startRecording(StartRecordingRequest req) { }); } + Future startSnapshot() { + StartRecordingRequest snapshotReq = new StartRecordingRequest("snapshot", "", "", 0, 0, 0); + + Future> f = + invoke( + HttpMethod.POST, + "/recordings/", + Buffer.buffer(gson.toJson(snapshotReq)), + BodyCodec.string()); + + return f.map( + resp -> { + int statusCode = resp.statusCode(); + if (HttpStatusCodeIdentifier.isSuccessCode(statusCode)) { + String body = resp.body(); + return gson.fromJson(body, SerializableRecordingDescriptor.class) + .toJmcForm(); + } else if (statusCode == 403) { + throw new UnsupportedOperationException(); + } else { + throw new RuntimeException("Unknown failure"); + } + }); + } + + Future updateRecordingOptions(long id, IConstrainedMap newSettings) { + + JsonObject jsonSettings = new JsonObject(); + for (String key : newSettings.keySet()) { + jsonSettings.put(key, newSettings.get(key)); + } + Future> f = + invoke( + HttpMethod.PATCH, + String.format("/recordings/%d", id), + jsonSettings.toBuffer(), + BodyCodec.none()); + + return f.map( + resp -> { + int statusCode = resp.statusCode(); + if (HttpStatusCodeIdentifier.isSuccessCode(statusCode)) { + return null; + } else if (statusCode == 403) { + throw new UnsupportedOperationException(); + } else { + throw new RuntimeException("Unknown failure"); + } + }); + } + Future openStream(long id) { Future> f = invoke(HttpMethod.GET, "/recordings/" + id, BodyCodec.buffer()); diff --git a/src/main/java/io/cryostat/net/AgentJFRService.java b/src/main/java/io/cryostat/net/AgentJFRService.java index 4eca953b8b..1a25e58b9b 100644 --- a/src/main/java/io/cryostat/net/AgentJFRService.java +++ b/src/main/java/io/cryostat/net/AgentJFRService.java @@ -174,7 +174,11 @@ public List getServerTemplates() throws FlightRecorderException { @Override public IRecordingDescriptor getSnapshotRecording() throws FlightRecorderException { - throw new UnimplementedException(); + try { + return client.startSnapshot().toCompletionStage().toCompletableFuture().get(); + } catch (ExecutionException | InterruptedException e) { + throw new FlightRecorderException("Failed to create snapshot recording", e); + } } @Override @@ -245,9 +249,18 @@ public void updateEventOptions(IRecordingDescriptor arg0, IConstrainedMap arg1) + public void updateRecordingOptions( + IRecordingDescriptor recordingDescriptor, IConstrainedMap newSettings) throws FlightRecorderException { - throw new UnimplementedException(); + try { + long recordingId = recordingDescriptor.getId(); + client.updateRecordingOptions(recordingId, newSettings) + .toCompletionStage() + .toCompletableFuture() + .get(); + } catch (ExecutionException | InterruptedException e) { + throw new FlightRecorderException("Failed to update recording options", e); + } } @Override