Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ public class Configuration {
private final String name;
private final TracingConfigurationSettings tracing;
private final AppHttpPipeline appHttpPipeline;
private final MtlsConfigurationSettings mtls;

// @TODO: add secrets https://github.com/dapr/java-sdk/issues/1280
// @TODO: add metrics https://github.com/dapr/java-sdk/issues/1281
// @TODO: add logging https://github.com/dapr/java-sdk/issues/1282
// @TODO: add middleware httpPipeline https://github.com/dapr/java-sdk/issues/1283
// @TODO: add nameResolution https://github.com/dapr/java-sdk/issues/1284
// @TODO: add disallow components https://github.com/dapr/java-sdk/issues/1285
// @TODO: add mtls https://github.com/dapr/java-sdk/issues/1286

/**
* Creates a new configuration.
Expand All @@ -38,9 +38,28 @@ public class Configuration {
* @param appHttpPipeline AppHttpPipeline middleware configuration.
*/
public Configuration(String name, TracingConfigurationSettings tracing, AppHttpPipeline appHttpPipeline) {
this(name, tracing, appHttpPipeline, null);
}

/**
* Creates a new configuration.
*
* @param name Configuration name.
* @param tracing TracingConfigParameters tracing configuration
* parameters.
* @param appHttpPipeline AppHttpPipeline middleware configuration.
* @param mtls MtlsConfigurationSettings mTLS configuration.
*/
public Configuration(
String name,
TracingConfigurationSettings tracing,
AppHttpPipeline appHttpPipeline,
MtlsConfigurationSettings mtls
) {
this.name = name;
this.tracing = tracing;
this.appHttpPipeline = appHttpPipeline;
this.mtls = mtls;
}

public String getName() {
Expand All @@ -54,4 +73,8 @@ public TracingConfigurationSettings getTracing() {
public AppHttpPipeline getAppHttpPipeline() {
return appHttpPipeline;
}

public MtlsConfigurationSettings getMtls() {
return mtls;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_PLACEMENT_IMAGE_TAG;
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_SCHEDULER_IMAGE_TAG;
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_SENTRY_IMAGE_TAG;

public class DaprContainer extends GenericContainer<DaprContainer> {
private static final Logger LOGGER = LoggerFactory.getLogger(DaprContainer.class);
Expand All @@ -67,12 +68,15 @@ public class DaprContainer extends GenericContainer<DaprContainer> {
private String appChannelAddress = "localhost";
private String placementService = "placement";
private String schedulerService = "scheduler";
private String sentryService = "sentry";
private DockerImageName placementDockerImageName = DockerImageName.parse(DAPR_PLACEMENT_IMAGE_TAG);
private DockerImageName schedulerDockerImageName = DockerImageName.parse(DAPR_SCHEDULER_IMAGE_TAG);
private DockerImageName sentryDockerImageName = DockerImageName.parse(DAPR_SENTRY_IMAGE_TAG);

private Configuration configuration;
private DaprPlacementContainer placementContainer;
private DaprSchedulerContainer schedulerContainer;
private DaprSentryContainer sentryContainer;
private String appName;
private Integer appPort;
private DaprProtocol appProtocol = DaprProtocol.HTTP; // default from docs
Expand All @@ -82,6 +86,7 @@ public class DaprContainer extends GenericContainer<DaprContainer> {
private Integer appHealthCheckThreshold = 3; //default from docs
private boolean shouldReusePlacement;
private boolean shouldReuseScheduler;
private boolean shouldReuseSentry;

/**
* Creates a new Dapr container.
Expand Down Expand Up @@ -171,6 +176,11 @@ public DaprContainer withSchedulerService(String schedulerService) {
return this;
}

public DaprContainer withSentryService(String sentryService) {
this.sentryService = sentryService;
return this;
}

public DaprContainer withAppName(String appName) {
this.appName = appName;
return this;
Expand Down Expand Up @@ -221,6 +231,21 @@ public DaprContainer withReusableScheduler(boolean shouldReuseScheduler) {
return this;
}

public DaprContainer withSentryImage(DockerImageName sentryDockerImageName) {
this.sentryDockerImageName = sentryDockerImageName;
return this;
}

public DaprContainer withSentryImage(String sentryDockerImageName) {
this.sentryDockerImageName = DockerImageName.parse(sentryDockerImageName);
return this;
}

public DaprContainer withReusableSentry(boolean shouldReuseSentry) {
this.shouldReuseSentry = shouldReuseSentry;
return this;
}

public DaprContainer withPlacementContainer(DaprPlacementContainer placementContainer) {
this.placementContainer = placementContainer;
return this;
Expand All @@ -231,6 +256,29 @@ public DaprContainer withSchedulerContainer(DaprSchedulerContainer schedulerCont
return this;
}

/**
* Sets the Sentry container used as certificate authority when mTLS is enabled in the {@link Configuration}.
* When not set, a Sentry container is created automatically with the same configuration.
* @param sentryContainer Sentry container.
* @return this container.
*/
public DaprContainer withSentryContainer(DaprSentryContainer sentryContainer) {
this.sentryContainer = sentryContainer;
return this;
}

/**
* Returns true when the {@link Configuration} enables mTLS. In that case a Sentry container is used as
* certificate authority, the placement and scheduler services are started with TLS enabled, and daprd is
* started with {@code --enable-mtls}.
* @return whether mTLS is enabled.
*/
public boolean isMtlsEnabled() {
return configuration != null
&& configuration.getMtls() != null
&& Boolean.TRUE.equals(configuration.getMtls().getEnabled());
}

public DaprContainer withComponent(Component component) {
components.add(component);
return this;
Expand Down Expand Up @@ -292,11 +340,50 @@ protected void configure() {
withNetwork(Network.newNetwork());
}

boolean mtlsEnabled = isMtlsEnabled();
String sentryAddress = null;
String trustDomain = null;
String trustAnchors = null;

if (mtlsEnabled) {
MtlsConfigurationSettings mtls = configuration.getMtls();
trustDomain = mtls.getControlPlaneTrustDomain() != null
? mtls.getControlPlaneTrustDomain()
: DaprSentryContainer.DEFAULT_TRUST_DOMAIN;

if (this.sentryContainer == null) {
this.sentryContainer = new DaprSentryContainer(this.sentryDockerImageName)
.withNetwork(getNetwork())
.withNetworkAliases(sentryService)
.withConfiguration(configuration)
.withTrustDomain(trustDomain)
.withDaprLogLevel(daprLogLevel)
.withReuse(this.shouldReuseSentry);
}

// Sentry must be running before the other services start, as they need the trust anchors it issues.
this.sentryContainer.start();

sentryAddress = mtls.getSentryAddress() != null
? mtls.getSentryAddress()
: sentryService + ":" + this.sentryContainer.getPort();
trustAnchors = this.sentryContainer.getTrustAnchors();
}

if (this.placementContainer == null) {
this.placementContainer = new DaprPlacementContainer(this.placementDockerImageName)
.withNetwork(getNetwork())
.withNetworkAliases(placementService)
.withReuse(this.shouldReusePlacement);

if (mtlsEnabled) {
this.placementContainer
.withTlsEnabled(true)
.withSentryAddress(sentryAddress)
.withTrustDomain(trustDomain)
.withTrustAnchors(trustAnchors);
}

this.placementContainer.start();
}

Expand All @@ -305,6 +392,15 @@ protected void configure() {
.withNetwork(getNetwork())
.withNetworkAliases(schedulerService)
.withReuse(this.shouldReuseScheduler);

if (mtlsEnabled) {
this.schedulerContainer
.withTlsEnabled(true)
.withSentryAddress(sentryAddress)
.withTrustDomain(trustDomain)
.withTrustAnchors(trustAnchors);
}

this.schedulerContainer.start();
}

Expand Down Expand Up @@ -354,6 +450,15 @@ protected void configure() {
cmds.add("/dapr-resources/" + configuration.getName() + ".yaml");
}

if (mtlsEnabled) {
cmds.add("--enable-mtls");
cmds.add("--sentry-address");
cmds.add(sentryAddress);
cmds.add("--control-plane-trust-domain");
cmds.add(trustDomain);
withEnv("DAPR_TRUST_ANCHORS", trustAnchors);
}

cmds.add("--log-level");
cmds.add(daprLogLevel.toString());
cmds.add("--resources-path");
Expand Down Expand Up @@ -410,7 +515,11 @@ protected void configure() {
withCopyToContainer(Transferable.of(endpointYaml), "/dapr-resources/" + endpoint.getName() + ".yaml");
}

dependsOn(placementContainer, schedulerContainer);
if (sentryContainer != null) {
dependsOn(placementContainer, schedulerContainer, sentryContainer);
} else {
dependsOn(placementContainer, schedulerContainer);
}
}

public String getAppName() {
Expand Down Expand Up @@ -449,6 +558,18 @@ public String getPlacementService() {
return placementService;
}

public String getSchedulerService() {
return schedulerService;
}

public String getSentryService() {
return sentryService;
}

public DaprSentryContainer getSentryContainer() {
return sentryContainer;
}

public static DockerImageName getDefaultImageName() {
return DEFAULT_IMAGE_NAME;
}
Expand All @@ -461,6 +582,10 @@ public DockerImageName getSchedulerDockerImageName() {
return schedulerDockerImageName;
}

public DockerImageName getSentryDockerImageName() {
return sentryDockerImageName;
}

// Required by spotbugs plugin
@Override
public boolean equals(Object o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ public interface DaprContainerConstants {
String DAPR_RUNTIME_IMAGE_TAG = "daprio/daprd:" + DAPR_VERSION;
String DAPR_PLACEMENT_IMAGE_TAG = "daprio/placement:" + DAPR_VERSION;
String DAPR_SCHEDULER_IMAGE_TAG = "daprio/scheduler:" + DAPR_VERSION;
String DAPR_SENTRY_IMAGE_TAG = "daprio/sentry:" + DAPR_VERSION;
String DAPR_WORKFLOWS_DASHBOARD = "ghcr.io/diagridio/diagrid-dashboard:" + DAPR_WORKFLOWS_DASHBOARD_VERSION;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,24 @@
package io.dapr.testcontainers;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.images.builder.Transferable;
import org.testcontainers.utility.DockerImageName;

import java.util.ArrayList;
import java.util.List;

/**
* Test container for Dapr placement service.
*/
public class DaprPlacementContainer extends GenericContainer<DaprPlacementContainer> {

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("daprio/placement");
private static final String TRUST_ANCHORS_FILE = "/var/run/secrets/dapr.io/tls/ca.crt";
private int placementPort = 50005;
private boolean tlsEnabled;
private String sentryAddress;
private String trustDomain;
private String trustAnchors;

/**
* Creates a new Dapr placement container.
Expand All @@ -46,7 +55,41 @@ public DaprPlacementContainer(String image) {
@Override
protected void configure() {
super.configure();
withCommand("./placement", "-port", Integer.toString(placementPort));
List<String> cmds = new ArrayList<>();
cmds.add("./placement");
cmds.add("-port");
cmds.add(Integer.toString(placementPort));
cmds.addAll(tlsCommandArguments());

withCommand(cmds.toArray(new String[]{}));
}

private List<String> tlsCommandArguments() {
List<String> cmds = new ArrayList<>();

if (!tlsEnabled) {
return cmds;
}

cmds.add("--tls-enabled");

if (sentryAddress != null) {
cmds.add("--sentry-address");
cmds.add(sentryAddress);
}

if (trustDomain != null) {
cmds.add("--trust-domain");
cmds.add(trustDomain);
}

if (trustAnchors != null) {
withCopyToContainer(Transferable.of(trustAnchors), TRUST_ANCHORS_FILE);
cmds.add("--trust-anchors-file");
cmds.add(TRUST_ANCHORS_FILE);
}

return cmds;
}

public static DockerImageName getDefaultImageName() {
Expand All @@ -62,6 +105,48 @@ public int getPort() {
return placementPort;
}

/**
* Enables TLS on the placement gRPC server. Requires a Sentry address and the trust anchors issued by Sentry.
* @param tlsEnabled whether TLS is enabled.
* @return this container.
*/
public DaprPlacementContainer withTlsEnabled(boolean tlsEnabled) {
this.tlsEnabled = tlsEnabled;
return this;
}

public DaprPlacementContainer withSentryAddress(String sentryAddress) {
this.sentryAddress = sentryAddress;
return this;
}

public DaprPlacementContainer withTrustDomain(String trustDomain) {
this.trustDomain = trustDomain;
return this;
}

/**
* Sets the PEM encoded trust anchors (root CA certificate) issued by Sentry.
* @param trustAnchors PEM encoded trust anchors.
* @return this container.
*/
public DaprPlacementContainer withTrustAnchors(String trustAnchors) {
this.trustAnchors = trustAnchors;
return this;
}

public boolean isTlsEnabled() {
return tlsEnabled;
}

public String getSentryAddress() {
return sentryAddress;
}

public String getTrustDomain() {
return trustDomain;
}

// Required by spotbugs plugin
@Override
public boolean equals(Object o) {
Expand Down
Loading
Loading