Skip to content

Commit 380d8ee

Browse files
authored
Merge pull request #17 from Project-MONAI/vchang/cli_docker
Docker support - CLI to support start/stop/restart with Docker
2 parents 1aeb731 + 7081f49 commit 380d8ee

File tree

83 files changed

+2190
-480
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2190
-480
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
# Created by https://www.toptal.com/developers/gitignore/api/aspnetcore,dotnetcore,visualstudio,visualstudiocode
33
# Edit at https://www.toptal.com/developers/gitignore?templates=aspnetcore,dotnetcore,visualstudio,visualstudiocode
44

5+
# MIG
6+
/cli
7+
58
# Database
69
*.db
710

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"request": "launch",
88
"preLaunchTask": "build-cli",
99
"program": "${workspaceFolder}/src/CLI/bin/Debug/net5.0/linux-x64/mig-cli",
10-
"args": ["aet", "add", "-a", "TEST", "--apps", "1,2,3"],
10+
"args": ["config", "endpoint", "http://localhost:4500"],
1111
"cwd": "${workspaceFolder}/src/CLI/bin/Debug/net5.0/linux-x64",
1212
"stopAtEntry": true,
1313
"console": "internalConsole"

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ RUN echo "Building MONAI Deploy Informatics Gateway $Version ($FileVersion)..."
2626
RUN dotnet publish -c Release -o out --nologo /p:Version=$Version /p:FileVersion=$FileVersion src/InformaticsGateway/Monai.Deploy.InformaticsGateway.csproj
2727

2828
# Build runtime image
29-
FROM mcr.microsoft.com/dotnet/runtime:5.0-focal
29+
FROM mcr.microsoft.com/dotnet/aspnet:5.0-focal
3030

3131
ENV DEBIAN_FRONTEND=noninteractive
3232

src/Api/FileStorageInfo.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// limitations under the License.
1111

1212
using Ardalis.GuardClauses;
13+
using System;
1314
using System.IO.Abstractions;
1415

1516
namespace Monai.Deploy.InformaticsGateway.Api
@@ -21,6 +22,11 @@ public record FileStorageInfo
2122
{
2223
private readonly IFileSystem _fileSystem;
2324

25+
/// <summary>
26+
/// Gets the unique ID of the file.
27+
/// </summary>
28+
public Guid Id { get; init; }
29+
2430
/// <summary>
2531
/// Gets the correlation ID of the file.
2632
/// For SCP received DICOM instances: use internally generated unique association ID.
@@ -44,7 +50,19 @@ public record FileStorageInfo
4450
public string[] Applications { get; private set; }
4551

4652
/// <summary>
47-
/// Gets or set the number of attempts to upload.
53+
/// Gets or sets the DateTime that the file was received.
54+
/// </summary>
55+
/// <value></value>
56+
public DateTime Received { get; set; }
57+
58+
/// <summary>
59+
/// Gets or set database row versioning info.
60+
/// </summary>
61+
/// <value></value>
62+
public byte[] Timestamp { get; set; }
63+
64+
/// <summary>
65+
/// Gets or sets the number of attempts to upload.
4866
/// </summary>
4967
public int TryCount { get; set; } = 0;
5068

@@ -67,8 +85,10 @@ public FileStorageInfo(string correlationId, string storageRootPath, string mess
6785
}
6886

6987
_fileSystem = fileSystem;
88+
Id = Guid.NewGuid();
7089
CorrelationId = correlationId;
7190
StorageRootPath = storageRootPath;
91+
Received = DateTime.UtcNow;
7292
FilePath = GenerateStoragePath(storageRootPath, correlationId, messageId, fileExtension);
7393
}
7494

src/CLI/AssemblyInfo.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2021 MONAI Consortium
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
// Unless required by applicable law or agreed to in writing, software
7+
// distributed under the License is distributed on an "AS IS" BASIS,
8+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
// See the License for the specific language governing permissions and
10+
// limitations under the License.
11+
12+
using System.Runtime.CompilerServices;
13+
14+
[assembly: InternalsVisibleTo("Monai.Deploy.InformaticsGateway.CLI.Test")]

src/CLI/Commands/AetCommand.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ private void SetupAddAetCommand()
8383

8484
private async Task<int> ListAeTitlehandlerAsync(IHost host, bool verbose, CancellationToken cancellationToken)
8585
{
86+
Guard.Against.Null(host, nameof(host));
87+
8688
this.LogVerbose(verbose, host, "Configuring services...");
8789

8890
var console = host.Services.GetRequiredService<IConsole>();
@@ -100,8 +102,9 @@ private async Task<int> ListAeTitlehandlerAsync(IHost host, bool verbose, Cancel
100102
IReadOnlyList<MonaiApplicationEntity> items = null;
101103
try
102104
{
103-
ConfigurationOptions config = LoadConfiguration(verbose, configService, client);
104-
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {config.Endpoint}...");
105+
CheckConfiguration(configService);
106+
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
107+
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
105108
this.LogVerbose(verbose, host, $"Retrieving MONAI SCP AE Titles...");
106109
items = await client.MonaiScpAeTitle.List(cancellationToken);
107110
}
@@ -142,6 +145,9 @@ private async Task<int> ListAeTitlehandlerAsync(IHost host, bool verbose, Cancel
142145

143146
private async Task<int> RemoveAeTitlehandlerAsync(string name, IHost host, bool verbose, CancellationToken cancellationToken)
144147
{
148+
Guard.Against.NullOrWhiteSpace(name, nameof(name));
149+
Guard.Against.Null(host, nameof(host));
150+
145151
this.LogVerbose(verbose, host, "Configuring services...");
146152
var configService = host.Services.GetRequiredService<IConfigurationService>();
147153
var client = host.Services.GetRequiredService<IInformaticsGatewayClient>();
@@ -153,8 +159,9 @@ private async Task<int> RemoveAeTitlehandlerAsync(string name, IHost host, bool
153159

154160
try
155161
{
156-
ConfigurationOptions config = LoadConfiguration(verbose, configService, client);
157-
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {config.Endpoint}...");
162+
CheckConfiguration(configService);
163+
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
164+
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
158165
this.LogVerbose(verbose, host, $"Deleting MONAI SCP AE Title {name}...");
159166
_ = await client.MonaiScpAeTitle.Delete(name, cancellationToken);
160167
logger.Log(LogLevel.Information, $"MONAI SCP AE Title '{name}' deleted.");
@@ -174,6 +181,9 @@ private async Task<int> RemoveAeTitlehandlerAsync(string name, IHost host, bool
174181

175182
private async Task<int> AddAeTitlehandlerAsync(MonaiApplicationEntity entity, IHost host, bool verbose, CancellationToken cancellationToken)
176183
{
184+
Guard.Against.Null(entity, nameof(entity));
185+
Guard.Against.Null(host, nameof(host));
186+
177187
this.LogVerbose(verbose, host, "Configuring services...");
178188
var configService = host.Services.GetRequiredService<IConfigurationService>();
179189
var client = host.Services.GetRequiredService<IInformaticsGatewayClient>();
@@ -185,9 +195,10 @@ private async Task<int> AddAeTitlehandlerAsync(MonaiApplicationEntity entity, IH
185195

186196
try
187197
{
188-
ConfigurationOptions config = LoadConfiguration(verbose, configService, client);
198+
CheckConfiguration(configService);
199+
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
189200

190-
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {config.Endpoint}...");
201+
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
191202
var result = await client.MonaiScpAeTitle.Create(entity, cancellationToken);
192203

193204
logger.Log(LogLevel.Information, "New MONAI Deploy SCP Application Entity created:");

src/CLI/Commands/CommandBase.cs

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
using Microsoft.Extensions.DependencyInjection;
1515
using Microsoft.Extensions.Hosting;
1616
using Microsoft.Extensions.Logging;
17-
using Monai.Deploy.InformaticsGateway.Client;
1817
using System;
1918
using System.CommandLine;
2019

@@ -28,12 +27,17 @@ public CommandBase(string name, string description) : base(name, description)
2827

2928
protected ILogger CreateLogger<T>(IHost host)
3029
{
30+
Guard.Against.Null(host, nameof(host));
31+
3132
var loggerFactory = host.Services.GetService<ILoggerFactory>();
3233
return loggerFactory?.CreateLogger<T>();
3334
}
3435

3536
protected void LogVerbose(bool verbose, IHost host, string message)
3637
{
38+
Guard.Against.Null(host, nameof(host));
39+
Guard.Against.NullOrWhiteSpace(message, nameof(message));
40+
3741
if (verbose)
3842
{
3943
var logger = CreateLogger<CommandBase>(host);
@@ -48,33 +52,24 @@ protected void LogVerbose(bool verbose, IHost host, string message)
4852
}
4953
}
5054

51-
protected ConfigurationOptions LoadConfiguration(bool verbose, IConfigurationService configurationService, IInformaticsGatewayClient client)
55+
protected void AddConfirmationOption() => AddConfirmationOption(this);
56+
57+
protected void AddConfirmationOption(Command command)
5258
{
53-
Guard.Against.Null(configurationService, nameof(configurationService));
54-
Guard.Against.Null(client, nameof(client));
59+
Guard.Against.Null(command, nameof(command));
5560

56-
var configuration = LoadConfiguration(verbose, configurationService);
57-
client.ConfigureServiceUris(new Uri(configuration.Endpoint));
58-
return configuration;
61+
var confirmationOption = new Option<bool>(new[] { "-y", "--yes" }, "Automatic yes to prompts");
62+
command.AddOption(confirmationOption);
5963
}
6064

61-
protected ConfigurationOptions LoadConfiguration(bool verbose, IConfigurationService configurationService)
65+
protected void CheckConfiguration(IConfigurationService configService)
6266
{
63-
Guard.Against.Null(configurationService, nameof(configurationService));
64-
65-
if (configurationService.ConfigurationExists())
67+
Guard.Against.Null(configService, nameof(configService));
68+
69+
if (!configService.IsInitialized)
6670
{
67-
var config = configurationService.Load(verbose);
68-
return config;
71+
throw new ConfigurationException($"Please execute `{AppDomain.CurrentDomain.FriendlyName} config init` to intialize Informatics Gateway.");
6972
}
70-
71-
throw new ConfigurationException($"{Strings.ApplicationName} endpoint not configured. Please run 'config` first.");
72-
}
73-
74-
protected void AddConfirmationOption()
75-
{
76-
var confirmationOption = new Option<bool>(new[] { "-y", "--yes" }, "Automatic yes to prompts");
77-
this.AddOption(confirmationOption);
7873
}
7974
}
8075
}

0 commit comments

Comments
 (0)