From 0158189ca4d245bd61f1e33296d7e94a9d250e4c Mon Sep 17 00:00:00 2001 From: Matthias Maeller Date: Tue, 28 May 2024 15:00:30 +0200 Subject: [PATCH 1/2] GH-8558 Make Ryuk shutdown hook configurable. --- .../utility/RyukResourceReaper.java | 26 ++++++++++--------- .../utility/TestcontainersConfiguration.java | 4 +++ .../TestcontainersConfigurationTest.java | 25 ++++++++++++++++++ docs/features/configuration.md | 5 +++- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java index 7e1b7802fb0..a9be4dc371c 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/RyukResourceReaper.java @@ -77,18 +77,20 @@ private synchronized void maybeStart() { ryukContainer.start(); - Runtime - .getRuntime() - .addShutdownHook( - new Thread( - DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, - () -> { - this.dockerClient.killContainerCmd(this.ryukContainer.getContainerId()) - .withSignal("SIGTERM") - .exec(); - } - ) - ); + if (TestcontainersConfiguration.getInstance().isRyukShutdownHookEnabled()) { + Runtime + .getRuntime() + .addShutdownHook( + new Thread( + DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, + () -> { + this.dockerClient.killContainerCmd(this.ryukContainer.getContainerId()) + .withSignal("SIGTERM") + .exec(); + } + ) + ); + } CountDownLatch ryukScheduledLatch = new CountDownLatch(1); diff --git a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java index 921e36f80cd..37c887950ba 100644 --- a/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java +++ b/core/src/main/java/org/testcontainers/utility/TestcontainersConfiguration.java @@ -179,6 +179,10 @@ public boolean isDisableChecks() { return Boolean.parseBoolean(getEnvVarOrUserProperty("checks.disable", "false")); } + public boolean isRyukShutdownHookEnabled() { + return Boolean.parseBoolean(getEnvVarOrUserProperty("ryuk.container.shutdownhook", "false")); + } + @UnstableAPI public boolean environmentSupportsReuse() { // specifically not supported as an environment variable or classpath property diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index fcc0a654ef5..32984482d4e 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -225,6 +225,31 @@ public void shouldTrimImageNames() { .isEqualTo("testcontainers/ryuk:0.3.2"); } + @Test + public void shouldNotReadRyukShutdownHookClasspathProperties() { + assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook disabled by default").isFalse(); + + classpathProperties.setProperty("ryuk.container.shutdownhook", "true"); + assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook is not affected by classpath properties").isFalse(); + } + + @Test + public void shouldReadRyukShutdownHookFromUserProperties() { + assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook disabled by default").isFalse(); + + userProperties.setProperty("ryuk.container.shutdownhook", "true"); + assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook enabled via user properties").isTrue(); + } + + @Test + public void shouldReadRyukShutdownHookFromEnvironment() { + assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook disabled by default").isFalse(); + + userProperties.remove("ryuk.container.shutdownhook"); + environment.put("TESTCONTAINERS_RYUK_CONTAINER_SHUTDOWNHOOK", "true"); + assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook enabled via env var").isTrue(); + } + private TestcontainersConfiguration newConfig() { return new TestcontainersConfiguration(userProperties, classpathProperties, environment); } diff --git a/docs/features/configuration.md b/docs/features/configuration.md index d874b16ad7b..55dad090969 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -79,13 +79,16 @@ 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.shutdownhook = true** +> In order to improve the termination process you may configure a shutdown hook which will send a SIGTERM to the Ryuk container causing it to finish sooner. + ### Disabling Ryuk Ryuk must be started as a privileged container. If your environment already implements automatic cleanup of containers after the execution, but does not allow starting privileged containers, you can turn off the Ryuk container by setting `TESTCONTAINERS_RYUK_DISABLED` **environment variable** to `true`. -!!!tip +!!! tip Note that Testcontainers will continue doing the cleanup at JVM's shutdown, unless you `kill -9` your JVM process. ## Customizing image pull behaviour From d320f631575a502ee7d03bb697976e014c3d2734 Mon Sep 17 00:00:00 2001 From: Matthias Maeller Date: Tue, 28 May 2024 15:49:45 +0200 Subject: [PATCH 2/2] GH-8558 Format. --- .../utility/TestcontainersConfigurationTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java index 32984482d4e..80163859b82 100644 --- a/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java +++ b/core/src/test/java/org/testcontainers/utility/TestcontainersConfigurationTest.java @@ -230,7 +230,9 @@ public void shouldNotReadRyukShutdownHookClasspathProperties() { assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook disabled by default").isFalse(); classpathProperties.setProperty("ryuk.container.shutdownhook", "true"); - assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook is not affected by classpath properties").isFalse(); + assertThat(newConfig().isRyukShutdownHookEnabled()) + .as("Ryuk shutdown hook is not affected by classpath properties") + .isFalse(); } @Test @@ -238,7 +240,9 @@ public void shouldReadRyukShutdownHookFromUserProperties() { assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook disabled by default").isFalse(); userProperties.setProperty("ryuk.container.shutdownhook", "true"); - assertThat(newConfig().isRyukShutdownHookEnabled()).as("Ryuk shutdown hook enabled via user properties").isTrue(); + assertThat(newConfig().isRyukShutdownHookEnabled()) + .as("Ryuk shutdown hook enabled via user properties") + .isTrue(); } @Test