diff --git a/src/main/java/io/cryostat/net/AgentClient.java b/src/main/java/io/cryostat/net/AgentClient.java index 3807264cf9..f5841b1ae6 100644 --- a/src/main/java/io/cryostat/net/AgentClient.java +++ b/src/main/java/io/cryostat/net/AgentClient.java @@ -129,6 +129,22 @@ Future startRecording(StartRecordingRequest req) { }); } + Future openStream(long id) { + Future> f = + invoke(HttpMethod.GET, "/recordings/" + id, BodyCodec.buffer()); + return f.map( + resp -> { + int statusCode = resp.statusCode(); + if (HttpStatusCodeIdentifier.isSuccessCode(statusCode)) { + return resp.body(); + } else if (statusCode == 403) { + throw new UnsupportedOperationException(); + } else { + throw new RuntimeException("Unknown failure"); + } + }); + } + Future stopRecording(long id) { Future> f = invoke( diff --git a/src/main/java/io/cryostat/net/AgentJFRService.java b/src/main/java/io/cryostat/net/AgentJFRService.java index 9345f2c719..4eca953b8b 100644 --- a/src/main/java/io/cryostat/net/AgentJFRService.java +++ b/src/main/java/io/cryostat/net/AgentJFRService.java @@ -15,6 +15,8 @@ */ package io.cryostat.net; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; @@ -51,6 +53,8 @@ import io.cryostat.core.templates.Template; import io.cryostat.core.templates.TemplateType; +import io.vertx.core.Future; +import io.vertx.core.buffer.Buffer; import org.jsoup.nodes.Document; class AgentJFRService implements CryostatFlightRecorderService { @@ -186,20 +190,31 @@ public boolean isEnabled() { } @Override - public InputStream openStream(IRecordingDescriptor arg0, boolean arg1) + public InputStream openStream(IRecordingDescriptor descriptor, boolean removeOnClose) throws FlightRecorderException { - throw new UnimplementedException(); + Future f = client.openStream(descriptor.getId()); + try { + Buffer b = f.toCompletionStage().toCompletableFuture().get(); + return new BufferedInputStream(new ByteArrayInputStream(b.getBytes())); + } catch (ExecutionException | InterruptedException e) { + logger.warn(e); + throw new FlightRecorderException("Failed to open remote recording stream", e); + } } @Override - public InputStream openStream(IRecordingDescriptor arg0, IQuantity arg1, boolean arg2) + public InputStream openStream( + IRecordingDescriptor descriptor, IQuantity lastPartDuration, boolean removeOnClose) throws FlightRecorderException { throw new UnimplementedException(); } @Override public InputStream openStream( - IRecordingDescriptor arg0, IQuantity arg1, IQuantity arg2, boolean arg3) + IRecordingDescriptor descriptor, + IQuantity startTime, + IQuantity endTime, + boolean removeOnClose) throws FlightRecorderException { throw new UnimplementedException(); } diff --git a/src/main/java/io/cryostat/net/web/WebServer.java b/src/main/java/io/cryostat/net/web/WebServer.java index 278ad84e18..1346904500 100644 --- a/src/main/java/io/cryostat/net/web/WebServer.java +++ b/src/main/java/io/cryostat/net/web/WebServer.java @@ -38,7 +38,6 @@ import io.cryostat.MainModule; import io.cryostat.core.log.Logger; import io.cryostat.core.net.JFRConnection; -import io.cryostat.net.AgentConnection; import io.cryostat.net.AuthManager; import io.cryostat.net.HttpServer; import io.cryostat.net.NetworkConfiguration; @@ -50,6 +49,7 @@ import io.cryostat.net.web.http.api.ApiVersion; import io.cryostat.net.web.http.api.v2.ApiException; import io.cryostat.util.HttpStatusCodeIdentifier; +import io.cryostat.util.URIUtil; import com.google.gson.Gson; import io.vertx.core.AbstractVerticle; @@ -296,13 +296,7 @@ public String getAssetDownloadURL(ApiVersion apiVersion, String... pathSegments) } private String getTargetId(JFRConnection conn) throws IOException { - // TODO this is a hack, the JFRConnection interface should be refactored to expose a more - // general connection URL / targetId method since the JMX implementation is now only one - // possible implementation - if (conn instanceof AgentConnection) { - return ((AgentConnection) conn).getUri().toString(); - } - return conn.getJMXURL().toString(); + return URIUtil.getConnectionUri(conn).toString(); } public FileUpload getTempFileUpload( diff --git a/src/main/java/io/cryostat/recordings/RecordingArchiveHelper.java b/src/main/java/io/cryostat/recordings/RecordingArchiveHelper.java index 5ca7130d5f..c5d45fab29 100644 --- a/src/main/java/io/cryostat/recordings/RecordingArchiveHelper.java +++ b/src/main/java/io/cryostat/recordings/RecordingArchiveHelper.java @@ -916,7 +916,7 @@ private void validateRecordingPath( Path writeRecordingToDestination(JFRConnection connection, IRecordingDescriptor descriptor) throws IOException, URISyntaxException, FlightRecorderException, Exception { - URI serviceUri = URIUtil.convert(connection.getJMXURL()); + URI serviceUri = URIUtil.getConnectionUri(connection); String jvmId = jvmIdHelper.getJvmId(serviceUri.toString()); Path specificRecordingsPath = getRecordingSubdirectoryPath(jvmId); if (!fs.exists(specificRecordingsPath)) { diff --git a/src/main/java/io/cryostat/util/URIUtil.java b/src/main/java/io/cryostat/util/URIUtil.java index 30a76c39a5..d794d325a9 100644 --- a/src/main/java/io/cryostat/util/URIUtil.java +++ b/src/main/java/io/cryostat/util/URIUtil.java @@ -15,11 +15,15 @@ */ package io.cryostat.util; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import javax.management.remote.JMXServiceURL; +import io.cryostat.core.net.JFRConnection; +import io.cryostat.net.AgentConnection; + public class URIUtil { private URIUtil() {} @@ -48,4 +52,14 @@ public static URI getRmiTarget(JMXServiceURL serviceUrl) throws URISyntaxExcepti } return new URI(pathPart.substring("/jndi/".length(), pathPart.length())); } + + public static URI getConnectionUri(JFRConnection connection) throws IOException { + // TODO this is a hack, the JFRConnection interface should be refactored to expose a more + // general connection URL / targetId method since the JMX implementation is now only one + // possible implementation + if (connection instanceof AgentConnection) { + return ((AgentConnection) connection).getUri(); + } + return URI.create(connection.getJMXURL().toString()); + } }