diff --git a/core/src/main/java/org/testcontainers/utility/RyukContainer.java b/core/src/main/java/org/testcontainers/utility/RyukContainer.java index a0139420cab..8de50b4571a 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukContainer.java +++ b/core/src/main/java/org/testcontainers/utility/RyukContainer.java @@ -11,6 +11,10 @@ class RyukContainer extends GenericContainer { RyukContainer() { super("testcontainers/ryuk:0.14.0"); withExposedPorts(8080); + String network = TestcontainersConfiguration.getInstance().getRyukNetwork(); + if (network != null) { + withNetworkMode(network); + } withCreateContainerCmdModifier(cmd -> { cmd.withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID); cmd.withHostConfig( diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 5c80b82ba9c..8560d8b36e0 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -155,6 +155,15 @@ public Integer getRyukTimeout() { return Integer.parseInt(getEnvVarOrProperty("ryuk.container.timeout", "30")); } + /** + * @return the name of the network the Ryuk container should be attached to, or {@code null} if Ryuk should use + * the default network. + */ + @Nullable + public String getRyukNetwork() { + return getEnvVarOrProperty("ryuk.container.network", null); + } + @Deprecated public String getKafkaImage() { return getImage(KAFKA_IMAGE).asCanonicalNameString(); diff --git a/core/src/test/java/org/testcontainers/utility/RyukContainerTest.java b/core/src/test/java/org/testcontainers/utility/RyukContainerTest.java new file mode 100644 index 00000000000..a5e96126a1e --- /dev/null +++ b/core/src/test/java/org/testcontainers/utility/RyukContainerTest.java @@ -0,0 +1,28 @@ +package org.testcontainers.utility; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(MockTestcontainersConfigurationExtension.class) +class RyukContainerTest { + + @Test + void shouldNotUseCustomNetworkByDefault() { + assertThat(new RyukContainer().getNetworkMode()).as("no custom network by default").isNull(); + } + + @Test + void shouldApplyConfiguredNetworkBeforeStart() { + Mockito + .doReturn("custom-network") + .when(TestcontainersConfiguration.getInstance()) + .getRyukNetwork(); + + assertThat(new RyukContainer().getNetworkMode()) + .as("configured network is applied before the container is started") + .isEqualTo("custom-network"); + } +} diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index 4e0520af5ba..356c42c6e58 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -217,6 +217,27 @@ void shouldReadReuseFromEnvironment() { assertThat(newConfig().environmentSupportsReuse()).as("reuse enabled via env var").isTrue(); } + @Test + void shouldNotReadRyukNetworkByDefault() { + assertThat(newConfig().getRyukNetwork()).as("no custom network by default").isNull(); + } + + @Test + void shouldReadRyukNetworkFromUserProperties() { + userProperties.setProperty("ryuk.container.network", "custom-network"); + assertThat(newConfig().getRyukNetwork()) + .as("custom network is set via user properties") + .isEqualTo("custom-network"); + } + + @Test + void shouldReadRyukNetworkFromEnvironment() { + environment.put("TESTCONTAINERS_RYUK_CONTAINER_NETWORK", "custom-network"); + assertThat(newConfig().getRyukNetwork()) + .as("custom network is set via an environment variable") + .isEqualTo("custom-network"); + } + @Test void shouldTrimImageNames() { userProperties.setProperty("ryuk.container.image", " testcontainers/ryuk:0.3.2 "); diff --git a/docs/features/configuration.md b/docs/features/configuration.md index 389936cb89f..58455874b75 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -79,6 +79,11 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **ryuk.container.privileged = true** > In some environments ryuk must be started in privileged mode to work properly (--privileged flag) +> **ryuk.container.network** +> If set, ryuk is attached to the given (pre-existing) network instead of the default one. +> Useful in environments such as rootless Podman or devcontainers, where ryuk otherwise cannot reach +> containers running in custom networks. + ### Disabling Ryuk Ryuk must be started as a privileged container. If your environment already implements automatic cleanup of containers after the execution,