@@ -24,12 +24,13 @@ namespace Synapse.Core.Infrastructure.Containers;
24
24
/// </summary>
25
25
/// <param name="logger">The service used to perform logging</param>
26
26
/// <param name="hostEnvironment">The current <see cref="IHostEnvironment"/></param>
27
- /// <param name="dockerClient">The service used to interact with the Docker API</param>
28
27
/// <param name="options">The current <see cref="DockerContainerPlatformOptions"/></param>
29
- public class DockerContainerPlatform ( ILogger < DockerContainerPlatform > logger , IHostEnvironment hostEnvironment , IDockerClient dockerClient , IOptions < DockerContainerPlatformOptions > options )
30
- : IHostedService , IContainerPlatform
28
+ public class DockerContainerPlatform ( ILogger < DockerContainerPlatform > logger , IHostEnvironment hostEnvironment , IOptions < DockerContainerPlatformOptions > options )
29
+ : IHostedService , IContainerPlatform , IDisposable , IAsyncDisposable
31
30
{
32
31
32
+ bool _disposed ;
33
+
33
34
/// <summary>
34
35
/// Gets the service used to perform logging
35
36
/// </summary>
@@ -43,7 +44,7 @@ public class DockerContainerPlatform(ILogger<DockerContainerPlatform> logger, IH
43
44
/// <summary>
44
45
/// Gets the service used to interact with the Docker API
45
46
/// </summary>
46
- protected IDockerClient DockerClient { get ; } = dockerClient ;
47
+ protected IDockerClient ? Docker { get ; set ; }
47
48
48
49
/// <summary>
49
50
/// Gets the current <see cref="DockerContainerPlatformOptions"/>
@@ -53,40 +54,42 @@ public class DockerContainerPlatform(ILogger<DockerContainerPlatform> logger, IH
53
54
/// <inheritdoc/>
54
55
public virtual async Task StartAsync ( CancellationToken cancellationToken )
55
56
{
57
+ var dockerConfiguration = new DockerClientConfiguration ( this . Options . Api . Endpoint ) ;
58
+ this . Docker = dockerConfiguration . CreateClient ( string . IsNullOrWhiteSpace ( this . Options . Api . Version ) ? null : System . Version . Parse ( this . Options . Api . Version ! ) ) ;
56
59
if ( ! this . Environment . RunsInDocker ( ) ) return ;
57
60
var containerShortId = System . Environment . MachineName ;
58
- var containerId = ( await this . DockerClient . Containers . InspectContainerAsync ( containerShortId , cancellationToken ) ) . ID ;
61
+ var containerId = ( await this . Docker . Containers . InspectContainerAsync ( containerShortId , cancellationToken ) ) . ID ;
59
62
var response = null as NetworkResponse ;
60
63
try
61
64
{
62
- response = await this . DockerClient . Networks . InspectNetworkAsync ( this . Options . Network , cancellationToken ) ;
65
+ response = await this . Docker . Networks . InspectNetworkAsync ( this . Options . Network , cancellationToken ) ;
63
66
}
64
67
catch ( DockerNetworkNotFoundException )
65
68
{
66
- await this . DockerClient . Networks . CreateNetworkAsync ( new ( ) { Name = this . Options . Network } , cancellationToken ) ;
69
+ await this . Docker . Networks . CreateNetworkAsync ( new ( ) { Name = this . Options . Network } , cancellationToken ) ;
67
70
}
68
71
finally
69
72
{
70
- if ( response == null || ! response ! . Containers . ContainsKey ( containerId ) )
71
- await this . DockerClient . Networks . ConnectNetworkAsync ( this . Options . Network , new NetworkConnectParameters ( ) { Container = containerId } , cancellationToken ) ;
73
+ if ( response == null || ! response ! . Containers . ContainsKey ( containerId ) ) await this . Docker . Networks . ConnectNetworkAsync ( this . Options . Network , new NetworkConnectParameters ( ) { Container = containerId } , cancellationToken ) ;
72
74
}
73
75
}
74
76
75
77
/// <inheritdoc/>
76
78
public virtual async Task < IContainer > CreateAsync ( ContainerProcessDefinition definition , CancellationToken cancellationToken = default )
77
79
{
78
80
ArgumentNullException . ThrowIfNull ( definition ) ;
81
+ if ( this . Docker == null ) throw new NullReferenceException ( "The DockerContainerPlatform has not been properly initialized" ) ;
79
82
try
80
83
{
81
- await this . DockerClient . Images . InspectImageAsync ( definition . Image , cancellationToken ) . ConfigureAwait ( false ) ;
84
+ await this . Docker . Images . InspectImageAsync ( definition . Image , cancellationToken ) . ConfigureAwait ( false ) ;
82
85
}
83
86
catch ( DockerApiException ex ) when ( ex . StatusCode == HttpStatusCode . NotFound )
84
87
{
85
88
var downloadProgress = new Progress < JSONMessage > ( ) ;
86
89
var imageComponents = definition . Image . Split ( ':' ) ;
87
90
var imageName = imageComponents [ 0 ] ;
88
91
var imageTag = imageComponents . Length > 1 ? imageComponents [ 1 ] : null ;
89
- await this . DockerClient . Images . CreateImageAsync ( new ( ) { FromImage = imageName , Tag = imageTag } , new ( ) , downloadProgress , cancellationToken ) . ConfigureAwait ( false ) ;
92
+ await this . Docker . Images . CreateImageAsync ( new ( ) { FromImage = imageName , Tag = imageTag } , new ( ) , downloadProgress , cancellationToken ) . ConfigureAwait ( false ) ;
90
93
}
91
94
var parameters = new CreateContainerParameters ( )
92
95
{
@@ -99,16 +102,60 @@ public virtual async Task<IContainer> CreateAsync(ContainerProcessDefinition def
99
102
Binds = definition . Volumes ? . Select ( e => $ "{ e . Key } ={ e . Value } ") ? . ToList ( ) ?? [ ]
100
103
}
101
104
} ;
102
- var response = await this . DockerClient . Containers . CreateContainerAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
103
- if ( this . Environment . RunsInDocker ( ) ) await this . DockerClient . Networks . ConnectNetworkAsync ( this . Options . Network , new NetworkConnectParameters ( ) { Container = response . ID } , cancellationToken ) ;
105
+ var response = await this . Docker . Containers . CreateContainerAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
106
+ if ( this . Environment . RunsInDocker ( ) ) await this . Docker . Networks . ConnectNetworkAsync ( this . Options . Network , new NetworkConnectParameters ( ) { Container = response . ID } , cancellationToken ) ;
104
107
foreach ( var warning in response . Warnings )
105
108
{
106
109
this . Logger . LogWarning ( warning ) ;
107
110
}
108
- return new DockerContainer ( response . ID , this . DockerClient ) ;
111
+ return new DockerContainer ( response . ID , this . Docker ) ;
109
112
}
110
113
111
114
/// <inheritdoc/>
112
115
public virtual Task StopAsync ( CancellationToken cancellationToken ) => Task . CompletedTask ;
113
116
117
+ /// <summary>
118
+ /// Disposes of the <see cref="DockerContainerPlatform"/>
119
+ /// </summary>
120
+ /// <param name="disposing">A boolean indicating whether or not the <see cref="DockerContainerPlatform"/> is being disposed of</param>
121
+ /// <returns>A new <see cref="ValueTask"/></returns>
122
+ protected virtual async ValueTask DisposeAsync ( bool disposing )
123
+ {
124
+ if ( this . _disposed ) return ;
125
+ if ( disposing )
126
+ {
127
+ this . Docker ? . Dispose ( ) ;
128
+ }
129
+ this . _disposed = true ;
130
+ await Task . CompletedTask . ConfigureAwait ( false ) ;
131
+ }
132
+
133
+ /// <inheritdoc/>
134
+ public async ValueTask DisposeAsync ( )
135
+ {
136
+ await this . DisposeAsync ( disposing : true ) . ConfigureAwait ( false ) ;
137
+ GC . SuppressFinalize ( this ) ;
138
+ }
139
+
140
+ /// <summary>
141
+ /// Disposes of the <see cref="DockerContainerPlatform"/>
142
+ /// </summary>
143
+ /// <param name="disposing">A boolean indicating whether or not the <see cref="DockerContainerPlatform"/> is being disposed of</param>
144
+ protected virtual void Dispose ( bool disposing )
145
+ {
146
+ if ( this . _disposed ) return ;
147
+ if ( disposing )
148
+ {
149
+ this . Docker ? . Dispose ( ) ;
150
+ }
151
+ this . _disposed = true ;
152
+ }
153
+
154
+ /// <inheritdoc/>
155
+ public void Dispose ( )
156
+ {
157
+ this . Dispose ( disposing : true ) ;
158
+ GC . SuppressFinalize ( this ) ;
159
+ }
160
+
114
161
}
0 commit comments