Skip to content

Commit 1545a84

Browse files
authored
Accept User as new Docker argument to set UID/GID (#905)
Signed-off-by: Victor Chang <vicchang@nvidia.com>
1 parent b4e3a47 commit 1545a84

File tree

4 files changed

+92
-3
lines changed

4 files changed

+92
-3
lines changed

src/TaskManager/Plug-ins/Docker/DockerPlugin.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
using System.Diagnostics;
1718
using System.Globalization;
18-
using Amazon.Runtime.Internal.Transform;
1919
using Ardalis.GuardClauses;
2020
using Docker.DotNet;
2121
using Docker.DotNet.Models;
@@ -364,9 +364,14 @@ private CreateContainerParameters BuildContainerSpecification(IList<ContainerVol
364364
{
365365
Runtime = Strings.RuntimeNvidia,
366366
Mounts = volumeMounts,
367-
}
367+
},
368368
};
369369

370+
if (Event.TaskPluginArguments.ContainsKey(Keys.User))
371+
{
372+
parameters.User = Event.TaskPluginArguments[Keys.User];
373+
}
374+
370375
return parameters;
371376
}
372377

@@ -406,6 +411,7 @@ private async Task<List<ContainerVolumeMount>> SetupInputs(CancellationToken can
406411
// eg: /monai/input
407412
var volumeMount = new ContainerVolumeMount(input, Event.TaskPluginArguments[input.Name], inputHostDirRoot, inputContainerDirRoot);
408413
volumeMounts.Add(volumeMount);
414+
_logger.InputVolumeMountAdded(inputHostDirRoot, inputContainerDirRoot);
409415

410416
// For each file, download from bucket and store in Task Manager Container.
411417
foreach (var obj in objects)
@@ -424,6 +430,8 @@ private async Task<List<ContainerVolumeMount>> SetupInputs(CancellationToken can
424430
}
425431
}
426432

433+
SetPermission(containerPath);
434+
427435
return volumeMounts;
428436
}
429437

@@ -436,7 +444,10 @@ private ContainerVolumeMount SetupIntermediateVolume()
436444

437445
Directory.CreateDirectory(containerPath);
438446

439-
return new ContainerVolumeMount(Event.IntermediateStorage, Event.TaskPluginArguments[Keys.WorkingDirectory], hostPath, containerPath);
447+
var volumeMount = new ContainerVolumeMount(Event.IntermediateStorage, Event.TaskPluginArguments[Keys.WorkingDirectory], hostPath, containerPath);
448+
_logger.IntermediateVolumeMountAdded(hostPath, containerPath);
449+
SetPermission(containerPath);
450+
return volumeMount;
440451
}
441452

442453
return default!;
@@ -465,11 +476,32 @@ private List<ContainerVolumeMount> SetupOutputs()
465476
Directory.CreateDirectory(containerPath);
466477

467478
volumeMounts.Add(new ContainerVolumeMount(output, Event.TaskPluginArguments[output.Name], hostPath, containerPath));
479+
_logger.OutputVolumeMountAdded(hostPath, containerPath);
468480
}
469481

482+
SetPermission(containerRootPath);
483+
470484
return volumeMounts;
471485
}
472486

487+
private void SetPermission(string path)
488+
{
489+
if (Event.TaskPluginArguments.ContainsKey(Keys.User))
490+
{
491+
if (!System.OperatingSystem.IsWindows())
492+
{
493+
var process = Process.Start("chown", $"-R {Event.TaskPluginArguments[Keys.User]} {path}");
494+
process.WaitForExit();
495+
496+
if (process.ExitCode != 0)
497+
{
498+
_logger.ErrorSettingDirectoryPermission(path, Event.TaskPluginArguments[Keys.User]);
499+
throw new SetPermissionException($"chown command exited with code {process.ExitCode}");
500+
}
501+
}
502+
}
503+
}
504+
473505
protected override void Dispose(bool disposing)
474506
{
475507
if (!DisposedValue && disposing)

src/TaskManager/Plug-ins/Docker/Keys.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ internal static class Keys
3333
/// </summary>
3434
public static readonly string EntryPoint = "entrypoint";
3535

36+
/// <summary>
37+
/// Key for specifying the user to the container. Same as -u argument for docker run.
38+
/// </summary>
39+
public static readonly string User = "user";
40+
3641
/// <summary>
3742
/// Key for the command to execute by the container.
3843
/// </summary>

src/TaskManager/Plug-ins/Docker/Logging/Log.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,17 @@ public static partial class Log
103103

104104
[LoggerMessage(EventId = 1027, Level = LogLevel.Information, Message = "Image does not exist '{image}' locally, attempting to pull.")]
105105
public static partial void ImageDoesNotExist(this ILogger logger, string image);
106+
107+
[LoggerMessage(EventId = 1028, Level = LogLevel.Information, Message = "Input volume added {hostPath} = {containerPath}.")]
108+
public static partial void InputVolumeMountAdded(this ILogger logger, string hostPath, string containerPath);
109+
110+
[LoggerMessage(EventId = 1029, Level = LogLevel.Information, Message = "Output volume added {hostPath} = {containerPath}.")]
111+
public static partial void OutputVolumeMountAdded(this ILogger logger, string hostPath, string containerPath);
112+
113+
[LoggerMessage(EventId = 1030, Level = LogLevel.Information, Message = "Intermediate volume added {hostPath} = {containerPath}.")]
114+
public static partial void IntermediateVolumeMountAdded(this ILogger logger, string hostPath, string containerPath);
115+
116+
[LoggerMessage(EventId = 1031, Level = LogLevel.Error, Message = "Error setting directory {path} with permission {user}.")]
117+
public static partial void ErrorSettingDirectoryPermission(this ILogger logger, string path, string user);
106118
}
107119
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2022 MONAI Consortium
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using System.Runtime.Serialization;
18+
19+
namespace Monai.Deploy.WorkflowManager.TaskManager.Docker
20+
{
21+
[Serializable]
22+
internal class SetPermissionException : Exception
23+
{
24+
public SetPermissionException()
25+
{
26+
}
27+
28+
public SetPermissionException(string? message) : base(message)
29+
{
30+
}
31+
32+
public SetPermissionException(string? message, Exception? innerException) : base(message, innerException)
33+
{
34+
}
35+
36+
protected SetPermissionException(SerializationInfo info, StreamingContext context) : base(info, context)
37+
{
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)