Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 51 additions & 8 deletions src/main/java/io/cryostat/diagnostic/DiagnosticsHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import io.cryostat.libcryostat.sys.Clock;
import io.cryostat.targets.Target;
import io.cryostat.targets.TargetConnectionManager;
import io.cryostat.ws.MessagingServer;
import io.cryostat.ws.Notification;

import io.quarkus.runtime.StartupEvent;
import io.smallrye.common.annotation.Identifier;
Expand All @@ -52,6 +54,12 @@
@ApplicationScoped
public class DiagnosticsHelper {

static final String THREAD_DUMP_DELETED = "ThreadDumpDeleted";
static final String THREAD_DUMP_REQUESTED = "ThreadDumpRequested";
static final String DUMP_THREADS = "threadPrint";
static final String DUMP_THREADS_TO_FIlE = "threadDumpToFile";
private static final String DIAGNOSTIC_BEAN_NAME = "com.sun.management:type=DiagnosticCommand";

@ConfigProperty(name = ConfigProperties.AWS_BUCKET_NAME_THREAD_DUMPS)
String bucket;

Expand All @@ -63,12 +71,6 @@ public class DiagnosticsHelper {
@Inject Logger log;
@Inject Clock clock;

static final String DUMP_THREADS = "threadPrint";
static final String DUMP_THREADS_TO_FIlE = "threadDumpToFile";
private static final String DIAGNOSTIC_BEAN_NAME = "com.sun.management:type=DiagnosticCommand";
static final String THREAD_DUMP_REQUESTED = "ThreadDumpRequested";
static final String THREAD_DUMP_DELETED = "ThreadDumpDeleted";

@Inject EventBus bus;
@Inject TargetConnectionManager targetConnectionManager;
@Inject StorageBuckets buckets;
Expand Down Expand Up @@ -99,14 +101,21 @@ public ThreadDump dumpThreads(Target target, String format) {
String.class)));
}

public void deleteThreadDump(Target target, String threadDumpID) {
public void deleteThreadDump(Target target, String threadDumpId) {
if (Objects.isNull(target.jvmId)) {
log.errorv("TargetId {0} failed to resolve to a jvmId", target.id);
throw new IllegalArgumentException();
} else {
String key = threadDumpKey(target.jvmId, threadDumpID);
String key = threadDumpKey(target.jvmId, threadDumpId);
storage.headObject(HeadObjectRequest.builder().bucket(bucket).key(key).build());
storage.deleteObject(DeleteObjectRequest.builder().bucket(bucket).key(key).build());
var event =
new ThreadDumpEvent(
EventCategory.DELETED,
ThreadDumpEvent.Payload.of(target, threadDumpId));
bus.publish(
MessagingServer.class.getName(),
new Notification(event.category().category(), event.payload()));
}
}

Expand Down Expand Up @@ -204,4 +213,38 @@ public List<S3Object> listThreadDumps(Target target) {
var req = ListObjectsV2Request.builder().bucket(bucket).prefix(jvmId).build();
return storage.listObjectsV2(req).contents();
}

public enum EventCategory {
// ThreadDumpSuccess ("CREATED") events are emitted by LongRunningRequestGenerator
DELETED(THREAD_DUMP_DELETED),
;

private final String category;

private EventCategory(String category) {
this.category = category;
}

public String category() {
return category;
}
}

public record ThreadDumpEvent(EventCategory category, Payload payload) {
public ThreadDumpEvent {
Objects.requireNonNull(category);
Objects.requireNonNull(payload);
}

public record Payload(String jvmId, String threadDumpId) {
public Payload {
Objects.requireNonNull(jvmId);
Objects.requireNonNull(threadDumpId);
}

public static Payload of(Target target, String threadDumpId) {
return new Payload(target.jvmId, threadDumpId);
}
}
}
}
37 changes: 25 additions & 12 deletions src/test/java/io/cryostat/diagnostics/ThreadDumpsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -245,18 +245,31 @@ public void testCreateAndDelete()

var threadDumpId = listResponseJson.getString("[0].threadDumpId");

given().log()
.all()
.when()
.pathParam("targetId", id)
.pathParam("threadDumpId", threadDumpId)
.delete("targets/{targetId}/threaddump/{threadDumpId}")
.then()
.log()
.all()
.and()
.assertThat()
.statusCode(204);
Executors.newSingleThreadScheduledExecutor()
.schedule(
() -> {
given().log()
.all()
.when()
.pathParam("targetId", id)
.pathParam("threadDumpId", threadDumpId)
.delete("targets/{targetId}/threaddump/{threadDumpId}")
.then()
.log()
.all()
.and()
.assertThat()
.statusCode(204);
},
1,
TimeUnit.SECONDS);

expectWebSocketNotification(
"ThreadDumpDeleted",
json ->
Objects.equals(
json.getJsonObject("message").getString("threadDumpId"),
threadDumpId));
}

@Test
Expand Down
Loading