Skip to content

Commit

Permalink
Merge pull request #1277 from michalvavrik/feature/jaeger-tls
Browse files Browse the repository at this point in the history
Support Jaeger TLS communication with Quarkus OTel OTLP collector configured from TLS registry
  • Loading branch information
michalvavrik authored Sep 3, 2024
2 parents 87b6219 + ba45eef commit 614b2ec
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.quarkus.qe;

import static io.quarkus.test.services.containers.JaegerGenericDockerContainerManagedResource.CERTIFICATE_CONTEXT_KEY;
import static io.quarkus.test.services.containers.JaegerGenericDockerContainerManagedResource.JAEGER_CLIENT_CERT_CN;
import static io.restassured.RestAssured.given;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;

import java.util.concurrent.TimeUnit;

import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.JaegerService;
import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.security.certificate.Certificate;
import io.quarkus.test.security.certificate.PemClientCertificate;
import io.quarkus.test.services.JaegerContainer;
import io.quarkus.test.services.QuarkusApplication;

@QuarkusScenario
public class OpenTelemetryJaegerTlsIT {

private static final String SERVICE_NAME = "test-traced-service";
private static final String CLIENT_ENDPOINT = "/client";
private static final String OPERATION = "GET " + CLIENT_ENDPOINT;

@JaegerContainer(tls = true)
static JaegerService jaeger = new JaegerService();

@QuarkusApplication
static RestService app = new RestService()
.withProperty("quarkus.otel.exporter.otlp.traces.tls-configuration-name", "jaeger")
.withProperty("quarkus.otel.exporter.otlp.traces.endpoint", () -> jaeger.getCollectorUrl(Protocol.HTTPS))
.withProperty("quarkus.tls.jaeger.key-store.pem.0.cert", () -> getClientCert().certPath())
.withProperty("quarkus.tls.jaeger.key-store.pem.0.key", () -> getClientCert().keyPath())
.withProperty("quarkus.tls.jaeger.trust-store.pem.certs", () -> getClientCert().truststorePath())
.withProperty("quarkus.tls.jaeger.trust-all", "false"); // it's default, but let's make it clear

private static PemClientCertificate getClientCert() {
return (PemClientCertificate) jaeger.<Certificate.PemCertificate> getPropertyFromContext(CERTIFICATE_CONTEXT_KEY)
.getClientCertificateByCn(JAEGER_CLIENT_CERT_CN);
}

@Test
public void shouldUpdateJaegerAsTracer() {
app.given()
.get(CLIENT_ENDPOINT)
.then()
.statusCode(HttpStatus.SC_OK)
.body(equalTo("I'm a client"));

await().atMost(30, TimeUnit.SECONDS).untilAsserted(() -> given()
.queryParam("service", SERVICE_NAME)
.queryParam("operation", OPERATION)
.get(jaeger.getTraceUrl())
.then()
.statusCode(HttpStatus.SC_OK)
.body("data", hasSize(1))
.body("data[0].spans", hasSize(1))
.body("data[0].spans.operationName", hasItems(OPERATION))
.body("data[0].spans.logs.fields.value.flatten()", hasItems("ClientResource called")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ static Certificate of(String prefix, io.quarkus.test.services.Certificate.Format
null, false, null, false));
}

static Certificate.PemCertificate of(String prefix, io.quarkus.test.services.Certificate.Format format, String password,
boolean tlsRegistryEnabled, String tlsConfigName, ClientCertificateRequest[] clientCertRequests) {
return ofInterchangeable(new CertificateOptions(prefix, format, password, false, false, false,
clientCertRequests, createCertsTempDir(prefix), new DefaultContainerMountStrategy(prefix), false,
null, null, null, null, tlsRegistryEnabled, tlsConfigName, false));
}

static Certificate of(String prefix, io.quarkus.test.services.Certificate.Format format, String password,
boolean tlsRegistryEnabled, String tlsConfigName) {
return ofInterchangeable(new CertificateOptions(prefix, format, password, false, false, false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ public String getRestUrl() {
}

public String getCollectorUrl() {
return getURI(Protocol.HTTP).withPath(JAEGER_API_PATH).toString();
return getCollectorUrl(Protocol.HTTP);
}

public String getCollectorUrl(Protocol protocol) {
return getURI(protocol).withPath(JAEGER_API_PATH).toString();
}

public String getTraceUrl() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,10 @@

String expectedLog() default "server started";

/**
* @return whether communication between Quarkus OTel exporter and Jaeger OTLP collector should be secured
*/
boolean tls() default false;

Class<? extends ManagedResourceBuilder> builder() default JaegerContainerManagedResourceBuilder.class;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class JaegerContainerManagedResourceBuilder extends ContainerManagedResou
private int tracePort;
private String expectedLog;
private boolean useOtlpCollector;
private boolean tlsEnabled;

@Override
protected String getImage() {
Expand Down Expand Up @@ -51,6 +52,10 @@ protected boolean shouldUseOtlpCollector() {
return useOtlpCollector;
}

protected boolean isTlsEnabled() {
return tlsEnabled;
}

@Override
public void init(Annotation annotation) {
JaegerContainer metadata = (JaegerContainer) annotation;
Expand All @@ -59,6 +64,7 @@ public void init(Annotation annotation) {
this.tracePort = metadata.tracePort();
this.expectedLog = metadata.expectedLog();
this.useOtlpCollector = metadata.useOtlpCollector();
this.tlsEnabled = metadata.tls();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package io.quarkus.test.services.containers;

import static io.quarkus.test.bootstrap.JaegerService.JAEGER_TRACE_URL_PROPERTY;
import static io.quarkus.test.services.Certificate.Format.PEM;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.MountableFile;

import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.security.certificate.Certificate;
import io.quarkus.test.security.certificate.ClientCertificateRequest;
import io.quarkus.test.utils.DockerUtils;

public class JaegerGenericDockerContainerManagedResource extends GenericDockerContainerManagedResource {

public static final String CERTIFICATE_CONTEXT_KEY = "io.quarkus.test.services.containers.jaeger.certificate";
public static final String JAEGER_CLIENT_CERT_CN = "jaeger-client";
private static final String COLLECTOR_OTLP_ENABLED = "COLLECTOR_OTLP_ENABLED";
private final JaegerContainerManagedResourceBuilder model;

Expand All @@ -29,6 +35,21 @@ protected GenericContainer<?> initContainer() {
GenericContainer<?> container = super.initContainer();
container.addExposedPort(model.getTracePort());
container.withCreateContainerCmdModifier(cmd -> cmd.withName(DockerUtils.generateDockerContainerName()));
if (model.isTlsEnabled()) {
var clientCertRequest = new ClientCertificateRequest[] {
new ClientCertificateRequest(JAEGER_CLIENT_CERT_CN, false) };
var cert = Certificate.of("jaeger-cert", PEM, "jaeger-password", true, "jaeger-tls-config", clientCertRequest);
model.getContext().put(CERTIFICATE_CONTEXT_KEY, cert);
// I found CLI flags used below here: https://www.jaegertracing.io/docs/1.60/cli/
container.withCreateContainerCmdModifier(cmd -> cmd
.withCmd("--collector.otlp.grpc.tls.enabled=true",
"--collector.otlp.grpc.tls.key=/test-tls/key/tls.key",
"--collector.otlp.grpc.tls.cert=/test-tls/cert/tls.cert",
"--collector.otlp.grpc.tls.client-ca=/test-tls/ca/ca.crt"));
container.withCopyFileToContainer(MountableFile.forHostPath(cert.certPath()), "/test-tls/cert/tls.cert");
container.withCopyFileToContainer(MountableFile.forHostPath(cert.keyPath()), "/test-tls/key/tls.key");
container.withCopyFileToContainer(MountableFile.forHostPath(cert.truststorePath()), "/test-tls/ca/ca.crt");
}

if (model.shouldUseOtlpCollector()) {
container.addEnv(COLLECTOR_OTLP_ENABLED, "true");
Expand Down

0 comments on commit 614b2ec

Please sign in to comment.