Skip to content

Commit

Permalink
refactor to use test containers
Browse files Browse the repository at this point in the history
  • Loading branch information
SylvainJuge committed Sep 18, 2024
1 parent 966aee6 commit 91976c0
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 221 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.jmxscraper;

import static org.assertj.core.api.Assertions.assertThat;

import java.time.Duration;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.MountableFile;

/** Test container that allows to execute {@link JmxScraper} in an isolated container */
public class JmxScraperContainer extends GenericContainer<JmxScraperContainer> {

private final String endpoint;
private final Set<String> targetSystems;
private String serviceUrl;
private int intervalMillis;
private final Set<String> customYaml;

public JmxScraperContainer(String otlpEndpoint) {
super("openjdk:8u272-jre-slim");

String scraperJarPath = System.getProperty("shadow.jar.path");
assertThat(scraperJarPath).isNotNull();

this.withCopyFileToContainer(MountableFile.forHostPath(scraperJarPath), "/scraper.jar")
.waitingFor(
Wait.forLogMessage(".*JMX scraping started.*", 1)
.withStartupTimeout(Duration.ofSeconds(10)));

this.endpoint = otlpEndpoint;
this.targetSystems = new HashSet<>();
this.customYaml = new HashSet<>();
this.intervalMillis = 1000;
}

public JmxScraperContainer withTargetSystem(String targetSystem) {
targetSystems.add(targetSystem);
return this;
}

public JmxScraperContainer withIntervalMillis(int intervalMillis) {
this.intervalMillis = intervalMillis;
return this;
}

public JmxScraperContainer withService(String host, int port) {
// TODO: adding a way to provide 'host:port' syntax would make this easier for end users
this.serviceUrl =
String.format(
Locale.getDefault(), "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi", host, port);
return this;
}

public JmxScraperContainer withCustomYaml(String yamlPath) {
this.customYaml.add(yamlPath);
return this;
}

@Override
public void start() {
// for now only configure through JVM args
List<String> arguments = new ArrayList<>();
arguments.add("java");
arguments.add("-Dotel.exporter.otlp.endpoint=" + endpoint);

if (!targetSystems.isEmpty()) {
arguments.add("-Dotel.jmx.target.system=" + String.join(",", targetSystems));
}

if (serviceUrl == null) {
throw new IllegalStateException("Missing service URL");
}
arguments.add("-Dotel.jmx.service.url=" + serviceUrl);
arguments.add("-Dotel.jmx.interval.milliseconds=" + intervalMillis);

if (!customYaml.isEmpty()) {
int i = 0;
StringBuilder sb = new StringBuilder("-Dotel.jmx.config=");
for (String yaml : customYaml) {
String containerPath = "/custom_" + i + ".yaml";
this.withCopyFileToContainer(MountableFile.forClasspathResource(yaml), containerPath);
if (i > 0) {
sb.append(",");
}
sb.append(containerPath);
i++;
}
arguments.add(sb.toString());
}

arguments.add("-jar");
arguments.add("/scraper.jar");

this.withCommand(arguments.toArray(new String[0]));

super.start();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.jmxscraper;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.shaded.com.google.errorprone.annotations.CanIgnoreReturnValue;
import org.testcontainers.utility.MountableFile;

/** Test container that allows to execute {@link TestApp} in an isolated container */
public class TestAppContainer extends GenericContainer<TestAppContainer> {

private static final Logger logger = LoggerFactory.getLogger(TestAppContainer.class);

private final Map<String, String> properties;
private int port;
private String login;
private String pwd;

public TestAppContainer() {
super("openjdk:8u272-jre-slim");

this.properties = new HashMap<>();

String appJar = System.getProperty("app.jar.path");
assertThat(Paths.get(appJar)).isNotEmptyFile().isReadable();

this.withCopyFileToContainer(MountableFile.forHostPath(appJar), "/app.jar")
.waitingFor(
Wait.forLogMessage(TestApp.APP_STARTED_MSG + "\\n", 1)
.withStartupTimeout(Duration.ofSeconds(5)))
.withCommand("java", "-jar", "/app.jar");
}

@CanIgnoreReturnValue
public TestAppContainer withJmxPort(int port) {
this.port = port;
properties.put("com.sun.management.jmxremote.port", Integer.toString(port));
return this.withExposedPorts(port);
}

@CanIgnoreReturnValue
public TestAppContainer withUserAuth(String login, String pwd) {
this.login = login;
this.pwd = pwd;
return this;
}

public int getPort() {
return getMappedPort(port);
}

@Override
protected void doStart() {
super.doStart();
}

@Override
public void start() {

// TODO: add support for ssl
properties.put("com.sun.management.jmxremote.ssl", "false");

if (pwd == null) {
properties.put("com.sun.management.jmxremote.authenticate", "false");
} else {
properties.put("com.sun.management.jmxremote.authenticate", "true");

Path pwdFile = createPwdFile(login, pwd);
this.withCopyFileToContainer(MountableFile.forHostPath(pwdFile), "/jmx.password");
properties.put("com.sun.management.jmxremote.password.file", "/jmx.password");

Path accessFile = createAccessFile(login);
this.withCopyFileToContainer(MountableFile.forHostPath(accessFile), "/jmx.access");
properties.put("com.sun.management.jmxremote.access.file", "/jmx.access");
}

String confArgs =
properties.entrySet().stream()
.map(
e -> {
String s = "-D" + e.getKey();
if (!e.getValue().isEmpty()) {
s += "=" + e.getValue();
}
return s;
})
.collect(Collectors.joining(" "));

this.withEnv("JAVA_TOOL_OPTIONS", confArgs);

logger.info("Test application JAVA_TOOL_OPTIONS = " + confArgs);

super.start();

logger.info("Test application JMX port mapped to {}:{}", getHost(), getMappedPort(port));
}

private static Path createPwdFile(String login, String pwd) {
try {
Path path = Files.createTempFile("test", ".pwd");
writeLine(path, String.format("%s %s", login, pwd));
return path;
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private static Path createAccessFile(String login) {
try {
Path path = Files.createTempFile("test", ".pwd");
writeLine(path, String.format("%s %s", login, "readwrite"));
return path;
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private static void writeLine(Path path, String line) throws IOException {
line = line + "\n";
Files.write(path, line.getBytes(StandardCharsets.UTF_8));
}
}
Loading

0 comments on commit 91976c0

Please sign in to comment.