diff --git a/src/Runner.Common/Constants.cs b/src/Runner.Common/Constants.cs index 0a8261c5525..c1ad8a61dfd 100644 --- a/src/Runner.Common/Constants.cs +++ b/src/Runner.Common/Constants.cs @@ -118,6 +118,7 @@ public static class Commands //validFlags array as well present in the CommandSettings.cs public static class Flags { + public static readonly string AllowDockerInDocker = "allow-docker-in-docker"; public static readonly string Commit = "commit"; public static readonly string Help = "help"; public static readonly string Replace = "replace"; diff --git a/src/Runner.Common/HostContext.cs b/src/Runner.Common/HostContext.cs index 99e152b1d6f..9e2a13284c2 100644 --- a/src/Runner.Common/HostContext.cs +++ b/src/Runner.Common/HostContext.cs @@ -36,6 +36,7 @@ public interface IHostContext : IDisposable event EventHandler Unloading; void ShutdownRunner(ShutdownReason reason); void WritePerfCounter(string counter); + bool AllowDockerInDocker { get; set; } } public enum StartupType @@ -65,6 +66,7 @@ public sealed class HostContext : EventListener, IObserver, private IDisposable _httpTraceSubscription; private IDisposable _diagListenerSubscription; private StartupType _startupType; + private bool _allowDockerInDocker; private string _perfFile; private RunnerWebProxy _webProxy = new RunnerWebProxy(); @@ -440,6 +442,18 @@ public StartupType StartupType } } + public bool AllowDockerInDocker + { + get + { + return _allowDockerInDocker; + } + set + { + _allowDockerInDocker = value; + } + } + public void WritePerfCounter(string counter) { if (!string.IsNullOrEmpty(_perfFile)) diff --git a/src/Runner.Listener/CommandSettings.cs b/src/Runner.Listener/CommandSettings.cs index 07a6c334ba9..4a134936783 100644 --- a/src/Runner.Listener/CommandSettings.cs +++ b/src/Runner.Listener/CommandSettings.cs @@ -27,6 +27,7 @@ public sealed class CommandSettings private readonly string[] validFlags = { + Constants.Runner.CommandLine.Flags.AllowDockerInDocker, Constants.Runner.CommandLine.Flags.Commit, Constants.Runner.CommandLine.Flags.Help, Constants.Runner.CommandLine.Flags.Replace, @@ -65,6 +66,8 @@ public sealed class CommandSettings public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once); + public bool AllowDockerInDocker => TestFlag(Constants.Runner.CommandLine.Flags.AllowDockerInDocker); + // Constructor. public CommandSettings(IHostContext context, string[] args) { diff --git a/src/Runner.Listener/Runner.cs b/src/Runner.Listener/Runner.cs index 5ca2ef21c32..66d117e91de 100644 --- a/src/Runner.Listener/Runner.cs +++ b/src/Runner.Listener/Runner.cs @@ -192,6 +192,9 @@ public async Task ExecuteCommand(CommandSettings command) Trace.Info($"Set runner startup type - {startType}"); HostContext.StartupType = startType; + Trace.Info($"Set runner allowDockerInDocker - {command.AllowDockerInDocker}"); + HostContext.AllowDockerInDocker = command.AllowDockerInDocker; + // Run the runner interactively or as service return await RunAsync(settings, command.RunOnce); } diff --git a/src/Runner.Worker/ContainerOperationProvider.cs b/src/Runner.Worker/ContainerOperationProvider.cs index a476b54646b..0566ed42b33 100644 --- a/src/Runner.Worker/ContainerOperationProvider.cs +++ b/src/Runner.Worker/ContainerOperationProvider.cs @@ -25,10 +25,12 @@ public interface IContainerOperationProvider : IRunnerService public class ContainerOperationProvider : RunnerService, IContainerOperationProvider { private IDockerCommandManager _dockerManger; + private bool _allowDockerInDocker; public override void Initialize(IHostContext hostContext) { base.Initialize(hostContext); + _allowDockerInDocker = hostContext.AllowDockerInDocker; _dockerManger = HostContext.GetService(); } @@ -57,13 +59,13 @@ public async Task StartContainersAsync(IExecutionContext executionContext, objec #if OS_WINDOWS // service CExecSvc is Container Execution Agent. ServiceController[] scServices = ServiceController.GetServices(); - if (scServices.Any(x => String.Equals(x.ServiceName, "cexecsvc", StringComparison.OrdinalIgnoreCase) && x.Status == ServiceControllerStatus.Running)) + if (!_allowDockerInDocker && scServices.Any(x => String.Equals(x.ServiceName, "cexecsvc", StringComparison.OrdinalIgnoreCase) && x.Status == ServiceControllerStatus.Running)) { throw new NotSupportedException("Container feature is not supported when runner is already running inside container."); } #else var initProcessCgroup = File.ReadLines("/proc/1/cgroup"); - if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0)) + if (!_allowDockerInDocker && initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0)) { throw new NotSupportedException("Container feature is not supported when runner is already running inside container."); } diff --git a/src/Test/L0/TestHostContext.cs b/src/Test/L0/TestHostContext.cs index 3d3c99c736b..43b03d0779a 100644 --- a/src/Test/L0/TestHostContext.cs +++ b/src/Test/L0/TestHostContext.cs @@ -29,6 +29,7 @@ public sealed class TestHostContext : IHostContext, IDisposable private AssemblyLoadContext _loadContext; private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D")); private StartupType _startupType; + private bool _allowDockerInDocker; public event EventHandler Unloading; public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token; public ShutdownReason RunnerShutdownReason { get; private set; } @@ -86,6 +87,18 @@ public StartupType StartupType } } + public bool AllowDockerInDocker + { + get + { + return _allowDockerInDocker; + } + set + { + _allowDockerInDocker = value; + } + } + public ProductInfoHeaderValue UserAgent => new ProductInfoHeaderValue("L0Test", "0.0"); public RunnerWebProxy WebProxy => new RunnerWebProxy();