From 8db93b2eb28bc2bc7d579981da1651cd41ec03f8 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Mon, 12 Dec 2022 08:41:08 +0100 Subject: [PATCH] feat(#694): Add Ryuk container privileged custom configuration (#709) --- docs/custom_configuration/index.md | 27 ++++++------ .../Configurations/CustomConfiguration.cs | 43 +++++++++++++------ .../EnvironmentConfiguration.cs | 9 ++++ .../Configurations/ICustomConfiguration.cs | 7 +++ .../PropertiesFileConfiguration.cs | 7 +++ .../Containers/ResourceReaper.cs | 4 -- .../Configurations/CustomConfigurationTest.cs | 24 +++++++++++ 7 files changed, 91 insertions(+), 30 deletions(-) diff --git a/docs/custom_configuration/index.md b/docs/custom_configuration/index.md index 1d83715bb..de20133f3 100644 --- a/docs/custom_configuration/index.md +++ b/docs/custom_configuration/index.md @@ -2,19 +2,20 @@ Testcontainers supports various configurations to set up your test environment. It automatically discovers the Docker environment and applies the configuration. You can set or override the default values either with the Testcontainers [properties file][properties-file-format] (`~/testcontainers.properties`) or with environment variables. If you prefer to configure your test environment at runtime, you can set or override the configuration through the `TestcontainersSettings` class. The following configurations are available: -| Properties File | Environment Variable | Description | Default | -|--------------------------|-----------------------------------------|---------------------------------------------------------------------------------------------------------------------------|-----------------------------| -| `docker.config` | `DOCKER_CONFIG` | The directory path that contains the Docker configuration (`config.json`) file. | `~/.docker/` | -| `docker.host` | `DOCKER_HOST` | The Docker daemon socket to connect to. | - | -| `docker.auth.config` | `DOCKER_AUTH_CONFIG` | The Docker configuration file content (GitLab: [Use statically-defined credentials][use-statically-defined-credentials]). | - | -| `docker.cert.path` | `DOCKER_CERT_PATH` | The directory path that contains the client certificate (`{ca,cert,key}.pem`) files. | `~/.docker/` | -| `docker.tls` | `DOCKER_TLS` | Enables TLS. | `false` | -| `docker.tls.verify` | `DOCKER_TLS_VERIFY` | Enables TLS verify. | `false` | -| `host.override` | `TESTCONTAINERS_HOST_OVERRIDE` | The host that exposes Docker's ports. | - | -| `docker.socket.override` | `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE` | The file path to the Docker daemon socket that is used by Ryuk (resource reaper). | `/var/run/docker.sock` | -| `ryuk.disabled` | `TESTCONTAINERS_RYUK_DISABLED` | Disables Ryuk (resource reaper). | `false` | -| `ryuk.container.image` | `TESTCONTAINERS_RYUK_CONTAINER_IMAGE` | The Ryuk (resource reaper) Docker image. | `testcontainers/ryuk:0.3.4` | -| `hub.image.name.prefix` | `TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX` | The name to use for substituting the Docker Hub registry part of the image name. | - | +| Properties File | Environment Variable | Description | Default | +|-----------------------------|--------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|-----------------------------| +| `docker.config` | `DOCKER_CONFIG` | The directory path that contains the Docker configuration (`config.json`) file. | `~/.docker/` | +| `docker.host` | `DOCKER_HOST` | The Docker daemon socket to connect to. | - | +| `docker.auth.config` | `DOCKER_AUTH_CONFIG` | The Docker configuration file content (GitLab: [Use statically-defined credentials][use-statically-defined-credentials]). | - | +| `docker.cert.path` | `DOCKER_CERT_PATH` | The directory path that contains the client certificate (`{ca,cert,key}.pem`) files. | `~/.docker/` | +| `docker.tls` | `DOCKER_TLS` | Enables TLS. | `false` | +| `docker.tls.verify` | `DOCKER_TLS_VERIFY` | Enables TLS verify. | `false` | +| `host.override` | `TESTCONTAINERS_HOST_OVERRIDE` | The host that exposes Docker's ports. | - | +| `docker.socket.override` | `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE` | The file path to the Docker daemon socket that is used by Ryuk (resource reaper). | `/var/run/docker.sock` | +| `ryuk.disabled` | `TESTCONTAINERS_RYUK_DISABLED` | Disables Ryuk (resource reaper). | `false` | +| `ryuk.container.privileged` | `TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED` | Runs Ryuk (resource reaper) in privileged mode. | `false` | +| `ryuk.container.image` | `TESTCONTAINERS_RYUK_CONTAINER_IMAGE` | The Ryuk (resource reaper) Docker image. | `testcontainers/ryuk:0.3.4` | +| `hub.image.name.prefix` | `TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX` | The name to use for substituting the Docker Hub registry part of the image name. | - | ## Enable logging diff --git a/src/Testcontainers/Configurations/CustomConfiguration.cs b/src/Testcontainers/Configurations/CustomConfiguration.cs index 86a754d43..fe61e96b3 100644 --- a/src/Testcontainers/Configurations/CustomConfiguration.cs +++ b/src/Testcontainers/Configurations/CustomConfiguration.cs @@ -16,7 +16,7 @@ protected CustomConfiguration(IReadOnlyDictionary properties) protected string GetDockerConfig(string propertyName) { - return this.GetPropertyValue(propertyName); + return this.GetPropertyValue(propertyName); } protected Uri GetDockerHost(string propertyName) @@ -26,12 +26,12 @@ protected Uri GetDockerHost(string propertyName) protected string GetDockerHostOverride(string propertyName) { - return this.GetPropertyValue(propertyName); + return this.GetPropertyValue(propertyName); } protected string GetDockerSocketOverride(string propertyName) { - return this.GetPropertyValue(propertyName); + return this.GetPropertyValue(propertyName); } protected JsonDocument GetDockerAuthConfig(string propertyName) @@ -55,24 +55,27 @@ protected JsonDocument GetDockerAuthConfig(string propertyName) protected string GetDockerCertPath(string propertyName) { - return this.GetPropertyValue(propertyName); + return this.GetPropertyValue(propertyName); } protected bool GetDockerTls(string propertyName) { - _ = this.properties.TryGetValue(propertyName, out var propertyValue); - return "1".Equals(propertyValue, StringComparison.Ordinal) || (bool.TryParse(propertyValue, out var tlsEnabled) && tlsEnabled); + return this.GetPropertyValue(propertyName); } protected bool GetDockerTlsVerify(string propertyName) { - _ = this.properties.TryGetValue(propertyName, out var propertyValue); - return "1".Equals(propertyValue, StringComparison.Ordinal) || (bool.TryParse(propertyValue, out var tlsVerifyEnabled) && tlsVerifyEnabled); + return this.GetPropertyValue(propertyName); } protected bool GetRyukDisabled(string propertyName) { - return this.properties.TryGetValue(propertyName, out var propertyValue) && bool.TryParse(propertyValue, out var ryukDisabled) && ryukDisabled; + return this.GetPropertyValue(propertyName); + } + + protected bool GetRyukContainerPrivileged(string propertyName) + { + return this.GetPropertyValue(propertyName); } protected IDockerImage GetRyukContainerImage(string propertyName) @@ -96,13 +99,27 @@ protected IDockerImage GetRyukContainerImage(string propertyName) protected string GetHubImageNamePrefix(string propertyName) { - return this.GetPropertyValue(propertyName); + return this.GetPropertyValue(propertyName); } - private string GetPropertyValue(string propertyName) + private T GetPropertyValue(string propertyName) { - _ = this.properties.TryGetValue(propertyName, out var propertyValue); - return propertyValue; + switch (Type.GetTypeCode(typeof(T))) + { + case TypeCode.Boolean: + { + return (T)(object)(this.properties.TryGetValue(propertyName, out var propertyValue) && ("1".Equals(propertyValue, StringComparison.Ordinal) || (bool.TryParse(propertyValue, out var result) && result))); + } + + case TypeCode.String: + { + _ = this.properties.TryGetValue(propertyName, out var propertyValue); + return (T)(object)propertyValue; + } + + default: + throw new ArgumentOutOfRangeException(typeof(T).Name); + } } } } diff --git a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs index ef2f84456..f5441a8c9 100644 --- a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs +++ b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs @@ -28,6 +28,8 @@ internal sealed class EnvironmentConfiguration : CustomConfiguration, ICustomCon private const string RyukDisabled = "TESTCONTAINERS_RYUK_DISABLED"; + private const string RyukContainerPrivileged = "TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED"; + private const string RyukContainerImage = "TESTCONTAINERS_RYUK_CONTAINER_IMAGE"; private const string HubImageNamePrefix = "TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX"; @@ -51,6 +53,7 @@ public EnvironmentConfiguration() DockerHostOverride, DockerSocketOverride, RyukDisabled, + RyukContainerPrivileged, RyukContainerImage, HubImageNamePrefix, } @@ -118,6 +121,12 @@ public bool GetRyukDisabled() return this.GetRyukDisabled(RyukDisabled); } + /// + public bool GetRyukContainerPrivileged() + { + return this.GetRyukContainerPrivileged(RyukContainerPrivileged); + } + /// public IDockerImage GetRyukContainerImage() { diff --git a/src/Testcontainers/Configurations/ICustomConfiguration.cs b/src/Testcontainers/Configurations/ICustomConfiguration.cs index 32edee2d5..d907ea30e 100644 --- a/src/Testcontainers/Configurations/ICustomConfiguration.cs +++ b/src/Testcontainers/Configurations/ICustomConfiguration.cs @@ -79,6 +79,13 @@ internal interface ICustomConfiguration /// https://dotnet.testcontainers.org/custom_configuration/. bool GetRyukDisabled(); + /// + /// Gets the Ryuk container privileged custom configuration. + /// + /// The Ryuk container privileged custom configuration. + /// https://dotnet.testcontainers.org/custom_configuration/. + bool GetRyukContainerPrivileged(); + /// /// Gets the Ryuk container image custom configuration. /// diff --git a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs index 81f9f3e2c..b22a94682 100644 --- a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs +++ b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs @@ -119,6 +119,13 @@ public bool GetRyukDisabled() return this.GetRyukDisabled(propertyName); } + /// + public bool GetRyukContainerPrivileged() + { + const string propertyName = "ryuk.container.privileged"; + return this.GetRyukContainerPrivileged(propertyName); + } + /// public IDockerImage GetRyukContainerImage() { diff --git a/src/Testcontainers/Containers/ResourceReaper.cs b/src/Testcontainers/Containers/ResourceReaper.cs index 522591ec7..60600e4be 100644 --- a/src/Testcontainers/Containers/ResourceReaper.cs +++ b/src/Testcontainers/Containers/ResourceReaper.cs @@ -230,10 +230,6 @@ public async ValueTask DisposeAsync() await this.maintainConnectionTask .ConfigureAwait(false); } - catch (Exception) - { - // Ignore - } finally { this.maintainConnectionCts.Dispose(); diff --git a/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs index 5f259234b..c30508a30 100644 --- a/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs +++ b/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs @@ -24,6 +24,7 @@ static EnvironmentConfigurationTest() EnvironmentVariables.Add("TESTCONTAINERS_HOST_OVERRIDE"); EnvironmentVariables.Add("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); EnvironmentVariables.Add("TESTCONTAINERS_RYUK_DISABLED"); + EnvironmentVariables.Add("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED"); EnvironmentVariables.Add("TESTCONTAINERS_RYUK_CONTAINER_IMAGE"); EnvironmentVariables.Add("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX"); } @@ -142,6 +143,18 @@ public void GetRyukDisabledCustomConfiguration(string propertyName, string prope Assert.Equal(expected, customConfiguration.GetRyukDisabled()); } + [Theory] + [InlineData("", "", false)] + [InlineData("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED", "", false)] + [InlineData("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED", "false", false)] + [InlineData("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED", "true", true)] + public void GetRyukContainerPrivilegedCustomConfiguration(string propertyName, string propertyValue, bool expected) + { + SetEnvironmentVariable(propertyName, propertyValue); + ICustomConfiguration customConfiguration = new EnvironmentConfiguration(); + Assert.Equal(expected, customConfiguration.GetRyukContainerPrivileged()); + } + [Theory] [InlineData("", "", null)] [InlineData("TESTCONTAINERS_RYUK_CONTAINER_IMAGE", "", null)] @@ -288,6 +301,17 @@ public void GetRyukDisabledCustomConfiguration(string configuration, bool expect Assert.Equal(expected, customConfiguration.GetRyukDisabled()); } + [Theory] + [InlineData("", false)] + [InlineData("ryuk.container.privileged=", false)] + [InlineData("ryuk.container.privileged=false", false)] + [InlineData("ryuk.container.privileged=true", true)] + public void GetRyukContainerPrivilegedCustomConfiguration(string configuration, bool expected) + { + ICustomConfiguration customConfiguration = new PropertiesFileConfiguration(new[] { configuration }); + Assert.Equal(expected, customConfiguration.GetRyukContainerPrivileged()); + } + [Theory] [InlineData("", null)] [InlineData("ryuk.container.image=", null)]