Skip to content

Commit

Permalink
feat(management): avoid self-referencing JMX operations (#280)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewazores authored Dec 11, 2023
1 parent 7956fc4 commit 5a13941
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 271 deletions.
36 changes: 33 additions & 3 deletions src/main/java/io/cryostat/agent/FlightRecorderHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@
*/
package io.cryostat.agent;

import java.io.IOException;
import java.io.StringReader;
import java.text.ParseException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
Expand All @@ -32,7 +36,25 @@ public class FlightRecorderHelper {

private final Logger log = LoggerFactory.getLogger(getClass());

public Optional<TemplatedRecording> createRecording(String templateNameOrLabel) {
public Optional<Recording> createSnapshot() {
Recording snapshot = FlightRecorder.getFlightRecorder().takeSnapshot();
if (snapshot.getSize() == 0) {
log.warn("No active recordings");
snapshot.close();
return Optional.empty();
}
return Optional.of(snapshot);
}

public Recording createRecordingWithCustomTemplate(String template)
throws IOException, ParseException {
Recording recording = new Recording(Configuration.create(new StringReader(template)));
recording.setToDisk(true);
return recording;
}

public Optional<TemplatedRecording> createRecordingWithPredefinedTemplate(
String templateNameOrLabel) {
Optional<Configuration> opt = getTemplate(templateNameOrLabel);
if (opt.isEmpty()) {
log.error(
Expand All @@ -58,16 +80,24 @@ public boolean isValidTemplate(String nameOrLabel) {
return getTemplate(nameOrLabel).isPresent();
}

public List<RecordingInfo> getRecordings() {
public List<Recording> getRecordings() {
return getRecordings(r -> true);
}

public List<Recording> getRecordings(Predicate<Recording> predicate) {
if (!FlightRecorder.isAvailable()) {
log.error("FlightRecorder is unavailable");
return List.of();
}
return FlightRecorder.getFlightRecorder().getRecordings().stream()
.map(RecordingInfo::new)
.filter(predicate)
.collect(Collectors.toList());
}

public Optional<Recording> getRecording(long id) {
return getRecordings(r -> r.getId() == id).stream().findFirst();
}

@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
public static class TemplatedRecording {
private final Configuration configuration;
Expand Down
79 changes: 5 additions & 74 deletions src/main/java/io/cryostat/agent/MainModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
*/
package io.cryostat.agent;

import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
Expand All @@ -38,12 +36,8 @@
import io.cryostat.agent.remote.RemoteContext;
import io.cryostat.agent.remote.RemoteModule;
import io.cryostat.agent.triggers.TriggerModule;
import io.cryostat.core.net.JFRConnection;
import io.cryostat.core.net.JFRConnectionToolkit;
import io.cryostat.core.sys.Environment;
import io.cryostat.core.sys.FileSystem;
import io.cryostat.core.templates.LocalStorageTemplateService;
import io.cryostat.core.tui.ClientWriter;
import io.cryostat.core.JvmIdentifier;
import io.cryostat.core.net.IDException;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down Expand Up @@ -71,7 +65,6 @@ public abstract class MainModule {
// one for outbound HTTP requests, one for incoming HTTP requests, and one as a general worker
private static final int NUM_WORKER_THREADS = 3;
private static final String JVM_ID = "JVM_ID";
private static final String TEMPLATES_PATH = "TEMPLATES_PATH";

@Provides
@Singleton
Expand Down Expand Up @@ -242,76 +235,14 @@ public static FlightRecorderHelper provideFlightRecorderHelper() {
return new FlightRecorderHelper();
}

@Provides
@Singleton
public static FileSystem provideFileSystem() {
return new FileSystem();
}

@Provides
@Singleton
@Named(TEMPLATES_PATH)
public static Path provideTemplatesTmpPath(FileSystem fs) {
try {
return fs.createTempDirectory(null);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Provides
@Singleton
public static Environment provideEnvironment(@Named(TEMPLATES_PATH) Path templatesTmp) {
return new Environment() {
@Override
public String getEnv(String key) {
if (LocalStorageTemplateService.TEMPLATE_PATH.equals(key)) {
return templatesTmp.toString();
}
return super.getEnv(key);
}
};
}

@Provides
@Singleton
public static ClientWriter provideClientWriter() {
Logger log = LoggerFactory.getLogger(JFRConnectionToolkit.class);
return new ClientWriter() {
@Override
public void print(String msg) {
log.info(msg);
}
};
}

@Provides
@Singleton
public static JFRConnectionToolkit provideJfrConnectionToolkit(
ClientWriter cw, FileSystem fs, Environment env) {
return new JFRConnectionToolkit(cw, fs, env);
}

@Provides
@Singleton
@Named(JVM_ID)
public static String provideJvmId(JFRConnectionToolkit tk) {
Logger log = LoggerFactory.getLogger(JFRConnectionToolkit.class);
public static String provideJvmId() {
try {
try (JFRConnection connection = tk.connect(tk.createServiceURL("localhost", 0))) {
String id = connection.getJvmId();
log.info("Computed self JVM ID: {}", id);
return id;
}
} catch (Exception e) {
return JvmIdentifier.getLocal().getHash();
} catch (IDException e) {
throw new RuntimeException(e);
}
}

@Provides
@Singleton
public static LocalStorageTemplateService provideLocalStorageTemplateService(
FileSystem fs, Environment env) {
return new LocalStorageTemplateService(fs, env);
}
}
2 changes: 1 addition & 1 deletion src/main/java/io/cryostat/agent/harvest/Harvester.java
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ private void startRecording(boolean restart) {
return;
}
flightRecorderHelper
.createRecording(template)
.createRecordingWithPredefinedTemplate(template)
.ifPresent(
recording -> {
recording
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@

import java.io.IOException;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.stream.Collectors;

import javax.inject.Inject;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.net.httpserver.HttpExchange;
import jdk.management.jfr.ConfigurationInfo;
import jdk.management.jfr.FlightRecorderMXBean;
import jdk.jfr.Configuration;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -53,11 +51,9 @@ public void handle(HttpExchange exchange) throws IOException {
switch (mtd) {
case "GET":
try {
FlightRecorderMXBean bean =
ManagementFactory.getPlatformMXBean(FlightRecorderMXBean.class);
List<String> xmlTexts =
bean.getConfigurations().stream()
.map(ConfigurationInfo::getContents)
Configuration.getConfigurations().stream()
.map(Configuration::getContents)
.collect(Collectors.toList());
exchange.sendResponseHeaders(HttpStatus.SC_OK, BODY_LENGTH_UNKNOWN);
try (OutputStream response = exchange.getResponseBody()) {
Expand Down
Loading

0 comments on commit 5a13941

Please sign in to comment.