From 339a9c0fbd2f465aa3042c654495d81fef6d5491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlastimil=20Kalu=C5=BEa?= Date: Wed, 3 Aug 2022 13:34:41 +0200 Subject: [PATCH] feat(#370): Used env variables from new custom configurations --- .../MTlsEndpointAuthenticationProvider.cs | 18 ++-- .../TlsEndpointAuthenticationProvider.cs | 18 ++-- .../Configurations/CustomConfiguration.cs | 47 ++++++++++ .../EnvironmentConfiguration.cs | 38 +++++++- .../Configurations/ICustomConfiguration.cs | 22 +++++ .../PropertiesFileConfiguration.cs | 23 ++++- .../Configurations/CustomConfigurationTest.cs | 86 +++++++++++++++++++ 7 files changed, 233 insertions(+), 19 deletions(-) diff --git a/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs index 49a6edd0f..fba9356f2 100644 --- a/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs +++ b/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs @@ -27,7 +27,7 @@ internal sealed class MTlsEndpointAuthenticationProvider : DockerEndpointAuthent private static readonly Regex PemData = new Regex("-----BEGIN (.*)-----(.*)-----END (.*)-----", RegexOptions.Multiline); private readonly Uri dockerEngine; - private readonly bool dockerTlsVerifyEnabled; + private readonly bool? dockerTlsVerifyEnabled; private readonly string dockerCaCertFile; private readonly string dockerClientCertFile; private readonly string dockerClientKeyFile; @@ -36,13 +36,15 @@ internal sealed class MTlsEndpointAuthenticationProvider : DockerEndpointAuthent public MTlsEndpointAuthenticationProvider() { - var dockerHostValue = Environment.GetEnvironmentVariable("DOCKER_HOST"); - var dockerTlsVerifyValue = Environment.GetEnvironmentVariable("DOCKER_TLS_VERIFY"); - var dockerCertPathValue = Environment.GetEnvironmentVariable("DOCKER_CERT_PATH"); - var dockerCertPath = dockerCertPathValue ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), DefaultCertPath); + ICustomConfiguration propertiesFileConfiguration = new PropertiesFileConfiguration(); + ICustomConfiguration environmentConfiguration = new EnvironmentConfiguration(); - this.dockerEngine = Uri.TryCreate(dockerHostValue, UriKind.RelativeOrAbsolute, out var dockerHost) ? dockerHost : DefaultTlsDockerEndpoint; - this.dockerTlsVerifyEnabled = int.TryParse(dockerTlsVerifyValue, out var dockerTlsVerify) && dockerTlsVerify == 1; + var dockerCertPath = propertiesFileConfiguration.GetDockerCertPath() + ?? environmentConfiguration.GetDockerCertPath() + ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), DefaultCertPath); + + this.dockerEngine = propertiesFileConfiguration.GetDockerHost() ?? environmentConfiguration.GetDockerHost() ?? DefaultTlsDockerEndpoint; + this.dockerTlsVerifyEnabled = propertiesFileConfiguration.GetDockerTlsVerify() ?? environmentConfiguration.GetDockerTlsVerify(); this.dockerCaCertFile = Path.Combine(dockerCertPath, DefaultCaCertFileName); this.dockerClientCertFile = Path.Combine(dockerCertPath, DefaultClientCertFileName); this.dockerClientKeyFile = Path.Combine(dockerCertPath, DefaultClientKeyFileName); @@ -53,7 +55,7 @@ public MTlsEndpointAuthenticationProvider() /// public override bool IsApplicable() { - return this.dockerTlsVerifyEnabled && File.Exists(this.dockerClientCertFile) && File.Exists(this.dockerClientKeyFile); + return this.dockerTlsVerifyEnabled.HasValue && this.dockerTlsVerifyEnabled.Value && File.Exists(this.dockerClientCertFile) && File.Exists(this.dockerClientKeyFile); } /// diff --git a/src/Testcontainers/Builders/TlsEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/TlsEndpointAuthenticationProvider.cs index 6b8fabbed..6e576eedc 100644 --- a/src/Testcontainers/Builders/TlsEndpointAuthenticationProvider.cs +++ b/src/Testcontainers/Builders/TlsEndpointAuthenticationProvider.cs @@ -16,19 +16,21 @@ internal sealed class TlsEndpointAuthenticationProvider : DockerEndpointAuthenti private static readonly Uri DefaultTlsDockerEndpoint = new Uri("tcp://localhost:2376"); private readonly Uri dockerEngine; - private readonly bool dockerTlsEnabled; + private readonly bool? dockerTlsEnabled; private readonly string dockerCaCertFile; private readonly Lazy caCertificate; public TlsEndpointAuthenticationProvider() { - var dockerHostValue = Environment.GetEnvironmentVariable("DOCKER_HOST"); - var dockerTlsValue = Environment.GetEnvironmentVariable("DOCKER_TLS"); - var dockerCertPathValue = Environment.GetEnvironmentVariable("DOCKER_CERT_PATH"); - var dockerCertPath = dockerCertPathValue ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), DefaultCertPath); + ICustomConfiguration propertiesFileConfiguration = new PropertiesFileConfiguration(); + ICustomConfiguration environmentConfiguration = new EnvironmentConfiguration(); - this.dockerEngine = Uri.TryCreate(dockerHostValue, UriKind.RelativeOrAbsolute, out var dockerHost) ? dockerHost : DefaultTlsDockerEndpoint; - this.dockerTlsEnabled = int.TryParse(dockerTlsValue, out var dockerTls) && dockerTls == 1; + var dockerCertPath = propertiesFileConfiguration.GetDockerCertPath() + ?? environmentConfiguration.GetDockerCertPath() + ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), DefaultCertPath); + + this.dockerEngine = propertiesFileConfiguration.GetDockerHost() ?? environmentConfiguration.GetDockerHost() ?? DefaultTlsDockerEndpoint; + this.dockerTlsEnabled = propertiesFileConfiguration.GetDockerTls() ?? environmentConfiguration.GetDockerTls(); this.dockerCaCertFile = Path.Combine(dockerCertPath, DefaultCaCertFileName); this.caCertificate = new Lazy(() => new X509Certificate2(this.dockerCaCertFile)); } @@ -36,7 +38,7 @@ public TlsEndpointAuthenticationProvider() /// public override bool IsApplicable() { - return this.dockerTlsEnabled; + return this.dockerTlsEnabled.HasValue && this.dockerTlsEnabled.Value; } /// diff --git a/src/Testcontainers/Configurations/CustomConfiguration.cs b/src/Testcontainers/Configurations/CustomConfiguration.cs index 38a8a99a6..98f15316e 100644 --- a/src/Testcontainers/Configurations/CustomConfiguration.cs +++ b/src/Testcontainers/Configurations/CustomConfiguration.cs @@ -2,6 +2,7 @@ { using System; using System.Collections.Generic; + using System.Globalization; using DotNet.Testcontainers.Images; internal abstract class CustomConfiguration @@ -18,6 +19,52 @@ protected Uri GetDockerHost(string propertyName) return this.properties.TryGetValue(propertyName, out var propertyValue) && Uri.TryCreate(propertyValue, UriKind.RelativeOrAbsolute, out var dockerHost) ? dockerHost : null; } + protected bool? GetDockerTls(string propertyName) + { + if (!this.properties.TryGetValue(propertyName, out var propertyValue) || string.IsNullOrWhiteSpace(propertyValue)) + { + return null; + } + + propertyValue = propertyValue.Trim().ToLower(CultureInfo.InvariantCulture); + + if (bool.TryParse(propertyValue, out var dockerTls)) + { + return dockerTls; + } + + return propertyValue == "1"; + } + + protected bool? GetDockerTlsVerify(string propertyName) + { + if (!this.properties.TryGetValue(propertyName, out var propertyValue) || string.IsNullOrWhiteSpace(propertyValue)) + { + return null; + } + + propertyValue = propertyValue.Trim().ToLower(CultureInfo.InvariantCulture); + + if (bool.TryParse(propertyValue, out var dockerTlsVerify)) + { + return dockerTlsVerify; + } + + return propertyValue == "1"; + } + + protected string GetDockerCertPath(string propertyName) + { + _ = this.properties.TryGetValue(propertyName, out var propertyValue); + + if (string.IsNullOrWhiteSpace(propertyValue)) + { + return null; + } + + return propertyValue; + } + protected bool GetRyukDisabled(string propertyName) { return this.properties.TryGetValue(propertyName, out var propertyValue) && bool.TryParse(propertyValue, out var ryukDisabled) && ryukDisabled; diff --git a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs index 52522f765..1da19c770 100644 --- a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs +++ b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs @@ -1,4 +1,4 @@ -namespace DotNet.Testcontainers.Configurations +namespace DotNet.Testcontainers.Configurations { using System; using System.Linq; @@ -13,6 +13,12 @@ internal sealed class EnvironmentConfiguration : CustomConfiguration, ICustomCon private const string DockerHost = "DOCKER_HOST"; + private const string DockerTls = "DOCKER_TLS"; + + private const string DockerTlsVerify = "DOCKER_TLS_VERIFY"; + + private const string DockerCertPath = "DOCKER_CERT_PATH"; + private const string RyukDisabled = "TESTCONTAINERS_RYUK_DISABLED"; private const string RyukContainerImage = "TESTCONTAINERS_RYUK_CONTAINER_IMAGE"; @@ -23,7 +29,17 @@ internal sealed class EnvironmentConfiguration : CustomConfiguration, ICustomCon /// Initializes a new instance of the class. /// public EnvironmentConfiguration() - : base(new[] { DockerConfig, DockerHost, RyukDisabled, RyukContainerImage, HubImageNamePrefix } + : base(new[] + { + DockerConfig, + DockerHost, + DockerTls, + DockerTlsVerify, + DockerCertPath, + RyukDisabled, + RyukContainerImage, + HubImageNamePrefix, + } .ToDictionary(key => key, Environment.GetEnvironmentVariable)) { } @@ -34,6 +50,24 @@ public Uri GetDockerHost() return this.GetDockerHost(DockerHost); } + /// + public bool? GetDockerTls() + { + return this.GetDockerTls(DockerTls); + } + + /// + public bool? GetDockerTlsVerify() + { + return this.GetDockerTlsVerify(DockerTlsVerify); + } + + /// + public string GetDockerCertPath() + { + return this.GetDockerCertPath(DockerCertPath); + } + /// public bool GetRyukDisabled() { diff --git a/src/Testcontainers/Configurations/ICustomConfiguration.cs b/src/Testcontainers/Configurations/ICustomConfiguration.cs index f39a7d318..a128c6a3e 100644 --- a/src/Testcontainers/Configurations/ICustomConfiguration.cs +++ b/src/Testcontainers/Configurations/ICustomConfiguration.cs @@ -17,6 +17,28 @@ internal interface ICustomConfiguration [CanBeNull] Uri GetDockerHost(); + /// + /// Gets the Docker uses TLS. + /// + /// The Docker uses TLS. + /// https://www.testcontainers.org/features/configuration/#customizing-docker-host-detection. + bool? GetDockerTls(); + + /// + /// Gets the Docker uses TLS and verifies the remote. + /// + /// The Docker uses TLS and verifies the remote. + /// https://www.testcontainers.org/features/configuration/#customizing-docker-host-detection. + bool? GetDockerTlsVerify(); + + /// + /// Gets the Docker location of your authentication keys and host certificate. + /// + /// The Docker location of your authentication keys and host certificate. + /// https://www.testcontainers.org/features/configuration/#customizing-docker-host-detection. + [CanBeNull] + string GetDockerCertPath(); + /// /// Gets the Ryuk disabled custom configuration. /// diff --git a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs index 96de11eb0..aba5bb19e 100644 --- a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs +++ b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs @@ -1,4 +1,4 @@ -namespace DotNet.Testcontainers.Configurations +namespace DotNet.Testcontainers.Configurations { using System; using System.IO; @@ -48,6 +48,27 @@ public Uri GetDockerHost() return this.GetDockerHost(propertyName); } + /// + public bool? GetDockerTls() + { + const string propertyName = "docker.tls"; + return this.GetDockerTls(propertyName); + } + + /// + public bool? GetDockerTlsVerify() + { + const string propertyName = "docker.tls.verify"; + return this.GetDockerTlsVerify(propertyName); + } + + /// + public string GetDockerCertPath() + { + const string propertyName = "docker.cert.path"; + return this.GetDockerCertPath(propertyName); + } + /// public bool GetRyukDisabled() { diff --git a/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs index bd16988b6..57e5e1f09 100644 --- a/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs +++ b/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs @@ -16,6 +16,9 @@ public sealed class EnvironmentConfigurationTest : IDisposable static EnvironmentConfigurationTest() { EnvironmentVariables.Add("DOCKER_HOST"); + EnvironmentVariables.Add("DOCKER_TLS"); + EnvironmentVariables.Add("DOCKER_TLS_VERIFY"); + EnvironmentVariables.Add("DOCKER_CERT_PATH"); EnvironmentVariables.Add("TESTCONTAINERS_RYUK_DISABLED"); EnvironmentVariables.Add("TESTCONTAINERS_RYUK_CONTAINER_IMAGE"); EnvironmentVariables.Add("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX"); @@ -32,6 +35,49 @@ public void GetDockerHostCustomConfiguration(string propertyName, string propert Assert.Equal(expected, customConfiguration.GetDockerHost()?.ToString()); } + [Theory] + [InlineData("", "", null)] + [InlineData("DOCKER_TLS", "", null)] + [InlineData("DOCKER_TLS", "0", false)] + [InlineData("DOCKER_TLS", "false", false)] + [InlineData("DOCKER_TLS", "FALSE", false)] + [InlineData("DOCKER_TLS", "1", true)] + [InlineData("DOCKER_TLS", "TRUE", true)] + [InlineData("DOCKER_TLS", "true", true)] + public void GetDockerTlsCustomConfiguration(string propertyName, string propertyValue, bool? expected) + { + SetEnvironmentVariable(propertyName, propertyValue); + ICustomConfiguration customConfiguration = new EnvironmentConfiguration(); + Assert.Equal(expected, customConfiguration.GetDockerTls()); + } + + [Theory] + [InlineData("", "", null)] + [InlineData("DOCKER_TLS_VERIFY", "", null)] + [InlineData("DOCKER_TLS_VERIFY", "0", false)] + [InlineData("DOCKER_TLS_VERIFY", "false", false)] + [InlineData("DOCKER_TLS_VERIFY", "FALSE", false)] + [InlineData("DOCKER_TLS_VERIFY", "1", true)] + [InlineData("DOCKER_TLS_VERIFY", "TRUE", true)] + [InlineData("DOCKER_TLS_VERIFY", "true", true)] + public void GetDockerTlsVerifyCustomConfiguration(string propertyName, string propertyValue, bool? expected) + { + SetEnvironmentVariable(propertyName, propertyValue); + ICustomConfiguration customConfiguration = new EnvironmentConfiguration(); + Assert.Equal(expected, customConfiguration.GetDockerTlsVerify()); + } + + [Theory] + [InlineData("", "", null)] + [InlineData("DOCKER_CERT_PATH", "", null)] + [InlineData("DOCKER_CERT_PATH", "/home/docker/.docker/certs", "/home/docker/.docker/certs")] + public void GetDockerCertPathCustomConfiguration(string propertyName, string propertyValue, string expected) + { + SetEnvironmentVariable(propertyName, propertyValue); + ICustomConfiguration customConfiguration = new EnvironmentConfiguration(); + Assert.Equal(expected, customConfiguration.GetDockerCertPath()); + } + [Theory] [InlineData("", "", false)] [InlineData("TESTCONTAINERS_RYUK_DISABLED", "", false)] @@ -95,6 +141,46 @@ public void GetDockerHostCustomConfiguration(string configuration, string expect Assert.Equal(expected, customConfiguration.GetDockerHost()?.ToString()); } + [Theory] + [InlineData("", null)] + [InlineData("docker.tls=", null)] + [InlineData("docker.tls=0", false)] + [InlineData("docker.tls=false", false)] + [InlineData("docker.tls=FALSE", false)] + [InlineData("docker.tls=1", true)] + [InlineData("docker.tls=TRUE", true)] + [InlineData("docker.tls=true", true)] + public void GetDockerTlsCustomConfiguration(string configuration, bool? expected) + { + ICustomConfiguration customConfiguration = new PropertiesFileConfiguration(new[] { configuration }); + Assert.Equal(expected, customConfiguration.GetDockerTls()); + } + + [Theory] + [InlineData("", null)] + [InlineData("docker.tls.verify=", null)] + [InlineData("docker.tls.verify=0", false)] + [InlineData("docker.tls.verify=false", false)] + [InlineData("docker.tls.verify=FALSE", false)] + [InlineData("docker.tls.verify=1", true)] + [InlineData("docker.tls.verify=TRUE", true)] + [InlineData("docker.tls.verify=true", true)] + public void GetDockerTlsVerifyCustomConfiguration(string configuration, bool? expected) + { + ICustomConfiguration customConfiguration = new PropertiesFileConfiguration(new[] { configuration }); + Assert.Equal(expected, customConfiguration.GetDockerTlsVerify()); + } + + [Theory] + [InlineData("", null)] + [InlineData("docker.cert.path=", null)] + [InlineData("docker.cert.path=/home/docker/.docker/certs", "/home/docker/.docker/certs")] + public void GetDockerCertPathCustomConfiguration(string configuration, string expected) + { + ICustomConfiguration customConfiguration = new PropertiesFileConfiguration(new[] { configuration }); + Assert.Equal(expected, customConfiguration.GetDockerCertPath()); + } + [Theory] [InlineData("", false)] [InlineData("ryuk.disabled=", false)]