Skip to content
Merged
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
7 changes: 4 additions & 3 deletions src/Docker.DotNet.Handler.Abstractions/ClientOptions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Docker.DotNet.Handler.Abstractions;

/// <summary>
/// Represents options used to configure a Docker client connection.
/// Represents the options used to configure a Docker client builder.
/// </summary>
public sealed record ClientOptions
{
Expand All @@ -11,9 +11,10 @@ public sealed record ClientOptions
public Version? ApiVersion { get; init; }

/// <summary>
/// Gets the endpoint URI to connect to.
/// Gets the endpoint URI to connect to, or <see langword="null"/> to resolve the
/// default Docker endpoint when the client is built.
/// </summary>
public Uri Endpoint { get; init; } = null!;
public Uri? Endpoint { get; init; }

/// <summary>
/// Gets the authentication provider used to configure the HTTP handler.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ public interface IDockerHandlerFactory : IStreamHijacker
/// <param name="clientOptions">The client options.</param>
/// <param name="logger">The logger instance.</param>
/// <returns>The resolved transport.</returns>
ResolvedTransport CreateHandler(ClientOptions clientOptions, ILogger logger);
ResolvedTransport CreateHandler(ResolvedClientOptions clientOptions, ILogger logger);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ public interface IDockerHandlerFactory<in TTransportOptions> : IDockerHandlerFac
/// <param name="clientOptions">The client options.</param>
/// <param name="logger">The logger instance.</param>
/// <returns>The resolved transport.</returns>
ResolvedTransport CreateHandler(TTransportOptions transportOptions, ClientOptions clientOptions, ILogger logger);
ResolvedTransport CreateHandler(TTransportOptions transportOptions, ResolvedClientOptions clientOptions, ILogger logger);
}
32 changes: 32 additions & 0 deletions src/Docker.DotNet.Handler.Abstractions/ResolvedClientOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace Docker.DotNet.Handler.Abstractions;

/// <summary>
/// Represents the resolved options used to configure a Docker client connection.
/// </summary>
public sealed record ResolvedClientOptions
{
/// <summary>
/// Gets the Docker Engine API version to request.
/// </summary>
public Version? ApiVersion { get; init; }

/// <summary>
/// Gets the resolved endpoint URI to connect to.
/// </summary>
public Uri Endpoint { get; init; } = null!;

/// <summary>
/// Gets the authentication provider used to configure the HTTP handler.
/// </summary>
public IAuthProvider AuthProvider { get; init; } = NoopAuthProvider.Instance;

/// <summary>
/// Gets default HTTP headers applied to each request.
/// </summary>
public IReadOnlyDictionary<string, string> Headers { get; init; } = new Dictionary<string, string>();

/// <summary>
/// Gets the maximum time to wait for an HTTP request to complete.
/// </summary>
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(100);
}
25 changes: 13 additions & 12 deletions src/Docker.DotNet.LegacyHttp/DockerHandlerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,25 @@ private DockerHandlerFactory()
public static IDockerHandlerFactory<LegacyHttpTransportOptions> Instance { get; }
= new DockerHandlerFactory();

public ResolvedTransport CreateHandler(ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(ResolvedClientOptions clientOptions, ILogger logger)
{
var transportOptions = new LegacyHttpTransportOptions();
Validate(transportOptions, clientOptions);
return CreateHandler(transportOptions, clientOptions, logger);
}

public ResolvedTransport CreateHandler(LegacyHttpTransportOptions transportOptions, ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(LegacyHttpTransportOptions transportOptions, ResolvedClientOptions clientOptions, ILogger logger)
{
Validate(transportOptions, clientOptions);
if (clientOptions is null)
{
throw new ArgumentNullException(nameof(clientOptions));
}

var endpoint = clientOptions.Endpoint;

Validate(endpoint);

var scheme = clientOptions.AuthProvider.TlsEnabled ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
var uri = new UriBuilder(clientOptions.Endpoint) { Scheme = scheme }.Uri;
var uri = new UriBuilder(endpoint) { Scheme = scheme }.Uri;
var handler = new ManagedHandler(logger);
transportOptions.ConfigureHandler(handler);

Expand All @@ -38,14 +44,9 @@ public Task<WriteClosableStream> HijackStreamAsync(HttpContent content)
return Task.FromResult(hijackable.HijackStream());
}

private static void Validate(LegacyHttpTransportOptions _, ClientOptions clientOptions)
private static void Validate(Uri endpoint)
{
if (clientOptions.Endpoint is null)
{
throw new ArgumentNullException(nameof(clientOptions), "ClientOptions.Endpoint must be set.");
}

var scheme = clientOptions.Endpoint.Scheme;
var scheme = endpoint.Scheme;

if (!string.Equals(scheme, "tcp", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)
Expand Down
25 changes: 12 additions & 13 deletions src/Docker.DotNet.NPipe/DockerHandlerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,28 @@ private DockerHandlerFactory()
public static IDockerHandlerFactory<NPipeTransportOptions> Instance { get; }
= new DockerHandlerFactory();

public ResolvedTransport CreateHandler(ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(ResolvedClientOptions clientOptions, ILogger logger)
{
var transportOptions = new NPipeTransportOptions();
Validate(transportOptions, clientOptions);
return CreateHandler(transportOptions, clientOptions, logger);
}

public ResolvedTransport CreateHandler(NPipeTransportOptions transportOptions, ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(NPipeTransportOptions transportOptions, ResolvedClientOptions clientOptions, ILogger logger)
{
Validate(transportOptions, clientOptions);
if (clientOptions is null)
{
throw new ArgumentNullException(nameof(clientOptions));
}

var uri = clientOptions.Endpoint;

Validate(uri);

if (clientOptions.AuthProvider.TlsEnabled)
{
throw new NotSupportedException("TLS is not supported over npipe.");
}

var uri = clientOptions.Endpoint;

var segments = uri.Segments;

if (segments.Length != 3 || !"pipe/".Equals(segments[1], StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -73,14 +77,9 @@ public Task<WriteClosableStream> HijackStreamAsync(HttpContent content)
return Task.FromResult(hijackable.HijackStream());
}

private static void Validate(NPipeTransportOptions _, ClientOptions clientOptions)
private static void Validate(Uri endpoint)
{
if (clientOptions.Endpoint is null)
{
throw new ArgumentNullException(nameof(clientOptions), "ClientOptions.Endpoint must be set.");
}

var scheme = clientOptions.Endpoint.Scheme;
var scheme = endpoint.Scheme;

if (!string.Equals(scheme, "npipe", StringComparison.OrdinalIgnoreCase))
{
Expand Down
25 changes: 13 additions & 12 deletions src/Docker.DotNet.NativeHttp/DockerHandlerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,25 @@ private DockerHandlerFactory()
public static IDockerHandlerFactory<NativeHttpTransportOptions> Instance { get; }
= new DockerHandlerFactory();

public ResolvedTransport CreateHandler(ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(ResolvedClientOptions clientOptions, ILogger logger)
{
var transportOptions = new NativeHttpTransportOptions();
Validate(transportOptions, clientOptions);
return CreateHandler(transportOptions, clientOptions, logger);
}

public ResolvedTransport CreateHandler(NativeHttpTransportOptions transportOptions, ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(NativeHttpTransportOptions transportOptions, ResolvedClientOptions clientOptions, ILogger logger)
{
Validate(transportOptions, clientOptions);
if (clientOptions is null)
{
throw new ArgumentNullException(nameof(clientOptions));
}

var endpoint = clientOptions.Endpoint;

Validate(endpoint);

var scheme = clientOptions.AuthProvider.TlsEnabled ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
var uri = new UriBuilder(clientOptions.Endpoint) { Scheme = scheme }.Uri;
var uri = new UriBuilder(endpoint) { Scheme = scheme }.Uri;

#if NET
var handler = new SocketsHttpHandler
Expand All @@ -54,14 +60,9 @@ public async Task<WriteClosableStream> HijackStreamAsync(HttpContent content)
return new WriteClosableStreamWrapper(stream);
}

private static void Validate(NativeHttpTransportOptions _, ClientOptions clientOptions)
private static void Validate(Uri endpoint)
{
if (clientOptions.Endpoint is null)
{
throw new ArgumentNullException(nameof(clientOptions), "ClientOptions.Endpoint must be set.");
}

var scheme = clientOptions.Endpoint.Scheme;
var scheme = endpoint.Scheme;

if (!string.Equals(scheme, "tcp", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)
Expand Down
21 changes: 10 additions & 11 deletions src/Docker.DotNet.Unix/DockerHandlerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@ private DockerHandlerFactory()
public static IDockerHandlerFactory<UnixSocketTransportOptions> Instance { get; }
= new DockerHandlerFactory();

public ResolvedTransport CreateHandler(ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(ResolvedClientOptions clientOptions, ILogger logger)
{
var transportOptions = new UnixSocketTransportOptions();
Validate(transportOptions, clientOptions);
return CreateHandler(transportOptions, clientOptions, logger);
}

public ResolvedTransport CreateHandler(UnixSocketTransportOptions transportOptions, ClientOptions clientOptions, ILogger logger)
public ResolvedTransport CreateHandler(UnixSocketTransportOptions transportOptions, ResolvedClientOptions clientOptions, ILogger logger)
{
Validate(transportOptions, clientOptions);
if (clientOptions is null)
{
throw new ArgumentNullException(nameof(clientOptions));
}

var uri = clientOptions.Endpoint;

Validate(uri);

var socketName = uri.Segments.Last();
var socketPath = uri.LocalPath;
uri = new UriBuilder(Uri.UriSchemeHttp, socketName).Uri;
Expand Down Expand Up @@ -59,14 +63,9 @@ public Task<WriteClosableStream> HijackStreamAsync(HttpContent content)
return Task.FromResult(hijackable.HijackStream());
}

private static void Validate(UnixSocketTransportOptions _, ClientOptions clientOptions)
private static void Validate(Uri endpoint)
{
if (clientOptions.Endpoint is null)
{
throw new ArgumentNullException(nameof(clientOptions), "ClientOptions.Endpoint must be set.");
}

var scheme = clientOptions.Endpoint.Scheme;
var scheme = endpoint.Scheme;

if (!string.Equals(scheme, "unix", StringComparison.OrdinalIgnoreCase))
{
Expand Down
6 changes: 3 additions & 3 deletions src/Docker.DotNet/DockerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ public sealed class DockerClient : IDockerClient

private readonly HttpClient _client;

private readonly ClientOptions _clientOptions;
private readonly ResolvedClientOptions _clientOptions;

private readonly Uri _effectiveEndpoint;

private readonly IStreamHijacker _hijack;

internal DockerClient(
HttpMessageHandler handler,
ClientOptions clientOptions,
ResolvedClientOptions clientOptions,
Uri effectiveEndpoint,
IStreamHijacker hijack)
{
Expand All @@ -42,7 +42,7 @@ internal DockerClient(
Exec = new ExecOperations(this);
}

public ClientOptions Options { get; }
public ResolvedClientOptions Options { get; }

public ISystemOperations System { get; }

Expand Down
30 changes: 25 additions & 5 deletions src/Docker.DotNet/DockerClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public DockerClientBuilder()
/// <param name="dockerConfig">The Docker config to preserve.</param>
public DockerClientBuilder(
DockerConfig dockerConfig)
: this(dockerConfig, new ClientOptions { Endpoint = dockerConfig.GetEndpoint() }, NullLogger.Instance)
: this(dockerConfig, new ClientOptions(), NullLogger.Instance)
{
}

Expand Down Expand Up @@ -255,13 +255,33 @@ public DockerClientBuilder<TTransportOptions> WithTransportOptions<TTransportOpt
/// <returns>A configured <see cref="DockerClient"/> instance.</returns>
public virtual DockerClient Build()
{
var transportFactory = ResolveTransportFactory(ClientOptions.Endpoint.Scheme);
var clientOptions = CreateResolvedClientOptions();

var resolvedTransport = transportFactory.CreateHandler(ClientOptions, Logger);
var transportFactory = ResolveTransportFactory(clientOptions.Endpoint.Scheme);

var authenticatedHandler = ClientOptions.AuthProvider.ConfigureHandler(resolvedTransport.Handler);
var resolvedTransport = transportFactory.CreateHandler(clientOptions, Logger);

return new DockerClient(authenticatedHandler, ClientOptions, resolvedTransport.EffectiveEndpoint, transportFactory);
var authenticatedHandler = clientOptions.AuthProvider.ConfigureHandler(resolvedTransport.Handler);

return new DockerClient(authenticatedHandler, clientOptions, resolvedTransport.EffectiveEndpoint, transportFactory);
}

/// <summary>
/// Resolves the client options, falling back to the default Docker endpoint when none was configured.
/// </summary>
/// <returns>The client options with a resolved endpoint.</returns>
protected ResolvedClientOptions CreateResolvedClientOptions()
{
var endpoint = ClientOptions.Endpoint ?? _dockerConfig.GetEndpoint();

return new ResolvedClientOptions
{
ApiVersion = ClientOptions.ApiVersion,
Endpoint = endpoint,
AuthProvider = ClientOptions.AuthProvider,
Headers = ClientOptions.Headers,
Timeout = ClientOptions.Timeout,
};
}

/// <summary>
Expand Down
8 changes: 5 additions & 3 deletions src/Docker.DotNet/DockerClientBuilder`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,12 @@ public DockerClientBuilder(
/// <returns>A configured <see cref="DockerClient"/> instance.</returns>
public override DockerClient Build()
{
var resolvedTransport = _transportFactory.CreateHandler(_transportOptions, ClientOptions, Logger);
var clientOptions = CreateResolvedClientOptions();

var authenticatedHandler = ClientOptions.AuthProvider.ConfigureHandler(resolvedTransport.Handler);
var resolvedTransport = _transportFactory.CreateHandler(_transportOptions, clientOptions, Logger);

return new DockerClient(authenticatedHandler, ClientOptions, resolvedTransport.EffectiveEndpoint, _transportFactory);
var authenticatedHandler = clientOptions.AuthProvider.ConfigureHandler(resolvedTransport.Handler);

return new DockerClient(authenticatedHandler, clientOptions, resolvedTransport.EffectiveEndpoint, _transportFactory);
}
}
2 changes: 1 addition & 1 deletion src/Docker.DotNet/IDockerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace Docker.DotNet;

public interface IDockerClient : IDisposable
{
ClientOptions Options { get; }
ResolvedClientOptions Options { get; }

ISystemOperations System { get; }

Expand Down
Loading