public void VerifyImage_InsecureFilesCheck(ImageData imageData) { if (imageData.Version < new Version("3.1") || !DockerHelper.IsLinuxContainerModeEnabled || (imageData.OS.Contains("alpine") && imageData.IsArm)) { return; } string worldWritableDirectoriesWithoutStickyBitCmd = @"find / -xdev -type d \( -perm -0002 -a ! -perm -1000 \)"; string worldWritableFilesCmd = "find / -xdev -type f -perm -o+w"; string noUserOrGroupFilesCmd; if (imageData.OS.Contains("alpine")) { // BusyBox in Alpine doesn't support the more convenient -nouser and -nogroup options for the find command noUserOrGroupFilesCmd = @"find / -xdev -exec stat -c %U-%n {} \+ | { grep ^UNKNOWN || true; }"; } else { noUserOrGroupFilesCmd = @"find / -xdev \( -nouser -o -nogroup \)"; } string command = $"/bin/sh -c \"{worldWritableDirectoriesWithoutStickyBitCmd} && {worldWritableFilesCmd} && {noUserOrGroupFilesCmd}\""; foreach (DotNetImageType imageType in Enum.GetValues(typeof(DotNetImageType))) { string output = _dockerHelper.Run( image: imageData.GetImage(imageType, _dockerHelper), name: imageData.GetIdentifier($"InsecureFiles-{imageType}"), command: command ); Assert.Empty(output); } }
public void VerifySdkImage_PackageCache(ImageData imageData) { string verifyCacheCommand = null; if (imageData.Version.Major == 2) { if (DockerHelper.IsLinuxContainerModeEnabled) { verifyCacheCommand = "test -d /usr/share/dotnet/sdk/NuGetFallbackFolder"; } else { verifyCacheCommand = "CMD /S /C PUSHD \"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder\""; } } else { _outputHelper.WriteLine(".NET Core SDK images >= 3.0 don't include a package cache."); } if (verifyCacheCommand != null) { // Simple check to verify the NuGet package cache was created _dockerHelper.Run( image: imageData.GetImage(DotNetImageType.SDK, _dockerHelper), command: verifyCacheCommand, name: imageData.GetIdentifier("PackageCache")); } }
private string CreateTestAppWithSdkImage(string appType) { string appDir = Path.Combine(Directory.GetCurrentDirectory(), $"{appType}App{DateTime.Now.ToFileTime()}"); string containerName = _imageData.GetIdentifier($"create-{appType}"); try { string targetFramework; // TODO: Until https://github.com/dotnet/aspnetcore/pull/19860 is fixed, 5.0 web projects need to // continue to use the old TFM. if (_imageData.Version.Major < 5 || appType == "web") { targetFramework = $"netcoreapp{_imageData.Version}"; } else { targetFramework = $"net{_imageData.Version}"; } _dockerHelper.Run( image: _imageData.GetImage(DotNetImageType.SDK, _dockerHelper), name: containerName, command: $"dotnet new {appType} --framework {targetFramework} --no-restore", workdir: "/app", skipAutoCleanup: true); _dockerHelper.Copy($"{containerName}:/app", appDir); string sourceDockerfileName = $"Dockerfile.{DockerHelper.DockerOS.ToLower()}"; File.Copy( Path.Combine(_testArtifactsDir, sourceDockerfileName), Path.Combine(appDir, "Dockerfile")); string nuGetConfigFileName = "NuGet.config"; if (Config.IsNightlyRepo) { nuGetConfigFileName += ".nightly"; } File.Copy(Path.Combine(_testArtifactsDir, nuGetConfigFileName), Path.Combine(appDir, "NuGet.config")); File.Copy(Path.Combine(_testArtifactsDir, ".dockerignore"), Path.Combine(appDir, ".dockerignore")); } catch (Exception) { if (Directory.Exists(appDir)) { Directory.Delete(appDir, true); } throw; } finally { _dockerHelper.DeleteContainer(containerName); } return(appDir); }
private string CreateTestAppWithSdkImage(string appType) { string appDir = Path.Combine(Directory.GetCurrentDirectory(), $"{appType}App{DateTime.Now.ToFileTime()}"); string containerName = _imageData.GetIdentifier($"create-{appType}"); try { _dockerHelper.Run( image: _imageData.GetImage(DotNetImageType.SDK, _dockerHelper), name: containerName, command: $"dotnet new {appType} --framework netcoreapp{_imageData.Version}", workdir: "/app", skipAutoCleanup: true); _dockerHelper.Copy($"{containerName}:/app", appDir); ApplyProjectCustomizations(_imageData, Path.Combine(appDir, "app.csproj")); string sourceDockerfileName = $"Dockerfile.{DockerHelper.DockerOS.ToLower()}"; // TODO: Remove Windows arm workaround once underlying Windows/Docker issue is resolved // https://github.com/dotnet/dotnet-docker/issues/1054 if (!DockerHelper.IsLinuxContainerModeEnabled && _imageData.Arch == Arch.Arm) { sourceDockerfileName += $".{Enum.GetName(typeof(Arch), _imageData.Arch).ToLowerInvariant()}"; } File.Copy( Path.Combine(_testArtifactsDir, sourceDockerfileName), Path.Combine(appDir, "Dockerfile")); string nuGetConfigFileName = "NuGet.config"; if (Config.IsNightlyRepo) { nuGetConfigFileName += ".nightly"; } File.Copy(Path.Combine(_testArtifactsDir, nuGetConfigFileName), Path.Combine(appDir, "NuGet.config")); File.Copy(Path.Combine(_testArtifactsDir, ".dockerignore"), Path.Combine(appDir, ".dockerignore")); } catch (Exception) { if (Directory.Exists(appDir)) { Directory.Delete(appDir, true); } throw; } finally { _dockerHelper.DeleteContainer(containerName); } return(appDir); }
private void PowerShellScenario_Execute(ProductImageData imageData, string optionalArgs) { if (imageData.Version.Major < 3) { OutputHelper.WriteLine("PowerShell does not exist in pre-3.0 images, skip testing"); return; } // Disable this test for Arm-based Alpine on 6.0 until PowerShell has support (https://github.com/PowerShell/PowerShell/issues/14667, https://github.com/PowerShell/PowerShell/issues/12937) if (imageData.Version.Major == 6 && imageData.OS.Contains("alpine") && imageData.IsArm) { OutputHelper.WriteLine("PowerShell does not have Alpine arm images, skip testing"); return; } // A basic test which executes an arbitrary command to validate PS is functional string output = DockerHelper.Run( image: imageData.GetImage(DotNetImageType.SDK, DockerHelper), name: imageData.GetIdentifier($"pwsh"), optionalRunArgs: optionalArgs, command: $"pwsh -c (Get-Childitem env:DOTNET_RUNNING_IN_CONTAINER).Value" ); Assert.Equal(output, bool.TrueString, ignoreCase: true); }
public async Task VerifyAspnetSample(SampleImageData imageData) { if (imageData.OS == OS.Bionic && imageData.DockerfileSuffix != "ubuntu-x64") { return; } await VerifySampleAsync(imageData, SampleImageType.Aspnetapp, async (image, containerName) => { try { DockerHelper.Run( image: image, name: containerName, detach: true, optionalRunArgs: "-p 80"); if (!Config.IsHttpVerificationDisabled) { await ImageScenarioVerifier.VerifyHttpResponseFromContainerAsync(containerName, DockerHelper, OutputHelper); } ValidateEnvironmentVariables(imageData, image, SampleImageType.Aspnetapp); } finally { DockerHelper.DeleteContainer(containerName); } }); }
public string GetProductVersion(DotNetImageType imageType, DockerHelper dockerHelper) { string version; string imageName = GetImage(imageType, dockerHelper); string containerName = GetIdentifier($"GetProductVersion-{imageType}"); switch (imageType) { case DotNetImageType.SDK: version = dockerHelper.Run(imageName, containerName, "dotnet --version"); break; case DotNetImageType.Runtime: version = GetRuntimeVersion(imageName, containerName, "Microsoft.NETCore.App", dockerHelper); break; case DotNetImageType.Aspnet: version = GetRuntimeVersion(imageName, containerName, "Microsoft.AspNetCore.App", dockerHelper); break; default: throw new NotSupportedException($"Unsupported image type '{imageType}'"); } return(version); }
private string CreateTestAppWithSdkImage(string appType) { string appDir = Path.Combine(Directory.GetCurrentDirectory(), $"{appType}App{DateTime.Now.ToFileTime()}"); string containerName = _imageData.GetIdentifier($"create-{appType}"); try { _dockerHelper.Run( image: _imageData.GetImage(DotNetImageType.SDK, _dockerHelper), name: containerName, command: $"dotnet new {appType} --framework netcoreapp{_imageData.Version}", workdir: "/app", skipAutoCleanup: true); _dockerHelper.Copy($"{containerName}:/app", appDir); ApplyProjectCustomizations(_imageData, Path.Combine(appDir, "app.csproj")); File.Copy( Path.Combine(_testArtifactsDir, $"Dockerfile.{DockerHelper.DockerOS.ToLower()}"), Path.Combine(appDir, "Dockerfile")); string nuGetConfigFileName = "NuGet.config"; if (Config.IsNightlyRepo) { nuGetConfigFileName += ".nightly"; } File.Copy(Path.Combine(_testArtifactsDir, nuGetConfigFileName), Path.Combine(appDir, "NuGet.config")); File.Copy(Path.Combine(_testArtifactsDir, ".dockerignore"), Path.Combine(appDir, ".dockerignore")); } catch (Exception) { if (Directory.Exists(appDir)) { Directory.Delete(appDir, true); } throw; } finally { _dockerHelper.DeleteContainer(containerName); } return(appDir); }
public void VerifyDotnetSample(SampleImageData imageData) { string image = imageData.GetImage(SampleImageType.Dotnetapp, DockerHelper); string containerName = imageData.GetIdentifier("sample-dotnetapp"); string output = DockerHelper.Run(image, containerName); Assert.StartsWith("Hello from .NET Core!", output); }
public static void Validate( IEnumerable <EnvironmentVariableInfo> variables, DotNetImageType imageType, ProductImageData imageData, DockerHelper dockerHelper) { const char delimiter = '|'; IEnumerable <string> echoParts; string invokeCommand; char delimiterEscape; if (DockerHelper.IsLinuxContainerModeEnabled) { echoParts = variables.Select(envVar => $"${envVar.Name}"); invokeCommand = $"/bin/sh -c"; delimiterEscape = '\\'; } else { echoParts = variables.Select(envVar => $"%{envVar.Name}%"); invokeCommand = $"CMD /S /C"; delimiterEscape = '^'; } string combinedValues = dockerHelper.Run( image: imageData.GetImage(imageType, dockerHelper), name: imageData.GetIdentifier($"env"), command: $"{invokeCommand} \"echo {string.Join($"{delimiterEscape}{delimiter}", echoParts)}\""); string[] values = combinedValues.Split(delimiter); Assert.Equal(variables.Count(), values.Count()); for (int i = 0; i < values.Count(); i++) { EnvironmentVariableInfo variable = variables.ElementAt(i); string actualValue; // Process unset variables in Windows if (!DockerHelper.IsLinuxContainerModeEnabled && string.Equals(values[i], $"%{variable.Name}%", StringComparison.Ordinal)) { actualValue = string.Empty; } else { actualValue = values[i]; } if (variable.AllowAnyValue) { Assert.NotEmpty(actualValue); } else { Assert.Equal(variable.ExpectedValue, actualValue); } } }
public async Task VerifyDotnetSample(SampleImageData imageData) { await VerifySampleAsync(imageData, SampleImageType.Dotnetapp, (image, containerName) => { string output = DockerHelper.Run(image, containerName); Assert.StartsWith("Hello from .NET Core!", output); return(Task.CompletedTask); }); }
private string GetRuntimeVersion(string imageName, string containerName, string runtimeName, DockerHelper dockerHelper) { const string versionGroupName = "Version"; string runtimeListing = dockerHelper.Run(imageName, containerName, "dotnet --list-runtimes"); Regex versionRegex = new Regex($"{runtimeName} (?<{versionGroupName}>[^\\s]+) "); Match match = versionRegex.Match(runtimeListing); return(match.Success ? match.Groups[versionGroupName].Value : string.Empty); }
public void VerifyComplexAppSample() { string appTag = SampleImageData.GetImageName("complexapp-local-app"); string testTag = SampleImageData.GetImageName("complexapp-local-test"); string sampleFolder = Path.Combine(s_samplesPath, "complexapp"); string dockerfilePath = $"{sampleFolder}/Dockerfile"; string testContainerName = ImageData.GenerateContainerName("sample-complex-test"); string tempDir = null; try { // Test that the app works DockerHelper.Build(appTag, dockerfilePath, contextDir: sampleFolder, pull: Config.PullImages); string containerName = ImageData.GenerateContainerName("sample-complex"); string output = DockerHelper.Run(appTag, containerName); Assert.StartsWith("string: The quick brown fox jumps over the lazy dog", output); if (!DockerHelper.IsLinuxContainerModeEnabled && DockerHelper.DockerArchitecture.StartsWith("arm", StringComparison.OrdinalIgnoreCase)) { // Skipping run app tests due to a .NET issue: https://github.com/dotnet/runtime/issues/2082 return; } // Run the app's tests DockerHelper.Build(testTag, dockerfilePath, target: "test", contextDir: sampleFolder); DockerHelper.Run(testTag, testContainerName, skipAutoCleanup: true); // Copy the test log from the container to the host tempDir = Directory.CreateDirectory( Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())).FullName; DockerHelper.Copy($"{testContainerName}:/source/tests/TestResults", tempDir); string testLogFile = new DirectoryInfo($"{tempDir}/TestResults").GetFiles("*.trx").First().FullName; // Open the test log file and verify the tests passed XDocument doc = XDocument.Load(testLogFile); XElement summary = doc.Root.Element(XName.Get("ResultSummary", doc.Root.Name.NamespaceName)); Assert.Equal("Completed", summary.Attribute("outcome").Value); XElement counters = summary.Element(XName.Get("Counters", doc.Root.Name.NamespaceName)); Assert.Equal("2", counters.Attribute("total").Value); Assert.Equal("2", counters.Attribute("passed").Value); } finally { if (tempDir != null) { Directory.Delete(tempDir, true); } DockerHelper.DeleteContainer(testContainerName); DockerHelper.DeleteImage(testTag); DockerHelper.DeleteImage(appTag); } }
public string GetProductVersion(DotNetImageType imageType, DockerHelper dockerHelper) { string imageName = GetImage(imageType, dockerHelper); string containerName = GetIdentifier($"GetProductVersion-{imageType}"); return(imageType switch { DotNetImageType.SDK => dockerHelper.Run(imageName, containerName, "dotnet --version"), DotNetImageType.Runtime => GetRuntimeVersion(imageName, containerName, "Microsoft.NETCore.App", dockerHelper), DotNetImageType.Aspnet => GetRuntimeVersion(imageName, containerName, "Microsoft.AspNetCore.App", dockerHelper), _ => throw new NotSupportedException($"Unsupported image type '{imageType}'"), });
private IEnumerable <string> GetInstalledRpmPackages(ProductImageData imageData) { // Get list of installed RPM packages string command = $"bash -c \"rpm -qa | sort\""; string installedPackages = DockerHelper.Run( image: imageData.GetImage(ImageType, DockerHelper), command: command, name: imageData.GetIdentifier("PackageInstallation")); return(installedPackages.Split(Environment.NewLine)); }
public async Task VerifyDotnetSample(SampleImageData imageData) { await VerifySampleAsync(imageData, SampleImageType.Dotnetapp, (image, containerName) => { string output = DockerHelper.Run(image, containerName); Assert.True(output.Contains("42") || output.StartsWith("Hello")); ValidateEnvironmentVariables(imageData, image, SampleImageType.Dotnetapp); return(Task.CompletedTask); }); }
/// <summary> /// Runs a single instance of the dotnet-monitor image. /// </summary> /// <param name="imageData">The image data of the dotnet-monitor image.</param> /// <param name="noAuthentication">Set to true to disable dotnet-monitor authenication.</param> /// <param name="verifyContainerAsync">Callback to test some aspect of the container.</param> /// <param name="runArgsCallback">Allows for modifying the "docker run" args of the container.</param> private async Task VerifyMonitorAsync( MonitorImageData imageData, bool noAuthentication, Func <string, Task> verifyContainerAsync = null, Action <DockerRunArgsBuilder> runArgsCallback = null) { GetNames(imageData, out string monitorImageName, out string monitorContainerName); try { DockerRunArgsBuilder runArgsBuilder = DockerRunArgsBuilder.Create() .ExposePort(DefaultMetricsPort); if (null != runArgsCallback) { runArgsCallback(runArgsBuilder); } DockerHelper.Run( image: monitorImageName, name: monitorContainerName, command: GetMonitorAdditionalArgs(noAuthentication), detach: true, optionalRunArgs: runArgsBuilder.Build()); if (!Config.IsHttpVerificationDisabled) { // Verify metrics endpoint is accessible using HttpResponseMessage metricsMessage = await ImageScenarioVerifier.GetHttpResponseFromContainerAsync( monitorContainerName, DockerHelper, OutputHelper, DefaultMetricsPort, UrlPath_Metrics); string metricsContent = await metricsMessage.Content.ReadAsStringAsync(); // Metrics should not return any content if // no processes are detected. Assert.Equal(string.Empty, metricsContent); } if (null != verifyContainerAsync) { await verifyContainerAsync(monitorContainerName); } } finally { DockerHelper.DeleteContainer(monitorContainerName); } }
private void PowerShellScenario_Execute(ProductImageData imageData, string optionalArgs) { if (imageData.Version.Major < 3) { OutputHelper.WriteLine("PowerShell does not exist in pre-3.0 images, skip testing"); return; } // A basic test which executes an arbitrary command to validate PS is functional string output = DockerHelper.Run( image: imageData.GetImage(DotNetImageType.SDK, DockerHelper), name: imageData.GetIdentifier($"pwsh"), optionalRunArgs: optionalArgs, command: $"pwsh -c (Get-Childitem env:DOTNET_RUNNING_IN_CONTAINER).Value" ); Assert.Equal(output, bool.TrueString, ignoreCase: true); }
public void VerifyDistrolessRunsAsNonRootUser(ProductImageData imageData) { if (!imageData.IsDistroless) { return; } string command = $"bash -c \"echo $EUID\""; string imageTag = DockerHelper.BuildDistrolessHelper(ImageType, imageData, "bash"); string userId = DockerHelper.Run( image: imageTag, command: command, name: imageData.GetIdentifier("NonRootUser")); Assert.NotEqual("0", userId); }
protected void VerifyCommonInsecureFiles(ProductImageData imageData) { if (imageData.Version < new Version("3.1") || (imageData.OS.Contains("alpine") && imageData.IsArm)) { return; } string worldWritableDirectoriesWithoutStickyBitCmd = @"find / -xdev -type d \( -perm -0002 -a ! -perm -1000 \)"; string worldWritableFilesCmd = "find / -xdev -type f -perm -o+w"; string noUserOrGroupFilesCmd; if (imageData.OS.Contains("alpine")) { // BusyBox in Alpine doesn't support the more convenient -nouser and -nogroup options for the find command noUserOrGroupFilesCmd = @"find / -xdev -exec stat -c %U-%n {} \+ | { grep ^UNKNOWN || true; }"; } else { noUserOrGroupFilesCmd = @"find / -xdev \( -nouser -o -nogroup \)"; } string command = $"/bin/sh -c \"{worldWritableDirectoriesWithoutStickyBitCmd} && {worldWritableFilesCmd} && {noUserOrGroupFilesCmd}\""; string imageTag; if (imageData.IsDistroless) { imageTag = DockerHelper.BuildDistrolessHelper(ImageType, imageData, "bash", "findutils"); } else { imageTag = imageData.GetImage(ImageType, DockerHelper); } string output = DockerHelper.Run( image: imageTag, name: imageData.GetIdentifier($"InsecureFiles-{ImageType}"), command: command, runAsUser: "******" ); Assert.Empty(output); }
public void VerifyShellNotInstalledForDistroless(ProductImageData imageData) { if (!imageData.IsDistroless) { OutputHelper.WriteLine("Skipping test for non-distroless platform."); return; } string imageTag = imageData.GetImage(ImageType, DockerHelper); // Attempting to execute the container's shell should result in an exception. // There should be no shell installed in distroless containers. InvalidOperationException ex = Assert.Throws <InvalidOperationException>(() => DockerHelper.Run( image: imageTag, name: imageData.GetIdentifier($"env"), optionalRunArgs: $"--entrypoint /bin/sh") ); Assert.Contains("Exit code: 127", ex.Message); }
private IEnumerable <SdkContentFileInfo> GetActualSdkContents(ProductImageData imageData) { string dotnetPath; if (DockerHelper.IsLinuxContainerModeEnabled) { dotnetPath = "/usr/share/dotnet"; } else { dotnetPath = "Program Files\\dotnet"; } string powerShellCommand = $"Get-ChildItem -File -Force -Recurse '{dotnetPath}' " + "| Get-FileHash -Algorithm SHA512 " + "| select @{name='Value'; expression={$_.Hash + ' ' +$_.Path}} " + "| select -ExpandProperty Value"; string command = $"pwsh -Command \"{powerShellCommand}\""; string containerFileList = DockerHelper.Run( image: imageData.GetImage(ImageType, DockerHelper), command: command, name: imageData.GetIdentifier("DotnetFolder")); IEnumerable <SdkContentFileInfo> actualDotnetFiles = containerFileList .Replace("\r\n", "\n") .Split("\n") .Select(output => { string[] outputParts = output.Split(" "); return(new SdkContentFileInfo(outputParts[1], outputParts[0])); }) .OrderBy(fileInfo => fileInfo.Path) .ToArray(); return(actualDotnetFiles); }
public async Task VerifyAspnetSample(SampleImageData imageData) { string image = imageData.GetImage(SampleImageType.Aspnetapp, DockerHelper); string containerName = imageData.GetIdentifier("sample-aspnetapp"); try { DockerHelper.Run( image: image, name: containerName, detach: true, optionalRunArgs: "-p 80"); if (!Config.IsHttpVerificationDisabled) { await ImageScenarioVerifier.VerifyHttpResponseFromContainerAsync(containerName, DockerHelper, OutputHelper); } } finally { DockerHelper.DeleteContainer(containerName); } }
private IEnumerable <string> GetInstalledRpmPackages(ProductImageData imageData) { // Get list of installed RPM packages string command = $"bash -c \"rpm -qa | sort\""; string imageTag; if (imageData.IsDistroless) { imageTag = DockerHelper.BuildDistrolessHelper(ImageType, imageData, "bash", "rpm"); } else { imageTag = imageData.GetImage(ImageType, DockerHelper); } string installedPackages = DockerHelper.Run( image: imageTag, command: command, name: imageData.GetIdentifier("PackageInstallation")); return(installedPackages.Split(Environment.NewLine)); }
private async Task VerifySdkImage_RunApp(ImageData imageData, string appSdkImage) { try { // dotnet run the new app using the sdk image _dockerHelper.Run( image: appSdkImage, command: "dotnet run --no-launch-profile", detach: imageData.IsWeb, containerName: appSdkImage); if (imageData.IsWeb && !s_isHttpVerificationDisabled) { await VerifyHttpResponseFromContainer(appSdkImage); } } finally { _dockerHelper.DeleteContainer(appSdkImage); } }
/// <summary> /// Runs a single instance of each of the dotnet-monitor and samples images. /// </summary> /// <param name="monitorImageData">The image data of the dotnet-monitor image.</param> /// <param name="shareTmpVolume">Set to true to mount the /tmp directory in both containers.</param> /// <param name="listenDiagPortVolume"> /// Set to true to have the monitor container listen with a diagnostic port listener /// for diagnostic connections from the samples container. /// </param> /// <param name="noAuthentication">Set to true to disable dotnet-monitor authenication.</param> /// <param name="verifyContainerAsync">Callback to test some aspect of the containers.</param> /// <param name="monitorRunArgsCallback">Allows for modifying the "docker run" args of the dotnet-monitor container.</param> /// <param name="sampleRunArgsCallback">Allows for modifying the "docker run" args of the samples container.</param> private async Task VerifyScenarioAsync( MonitorImageData monitorImageData, SampleImageData sampleImageData, bool shareTmpVolume, bool listenDiagPortVolume, bool noAuthentication, Func <string, string, Task> verifyContainerAsync, Action <DockerRunArgsBuilder> monitorRunArgsCallback = null, Action <DockerRunArgsBuilder> sampleRunArgsCallback = null) { GetNames(monitorImageData, out string monitorImageName, out string monitorContainerName); GetNames(sampleImageData, out string sampleImageName, out string sampleContainerName); DockerRunArgsBuilder monitorArgsBuilder = DockerRunArgsBuilder.Create() .MonitorUrl(DefaultArtifactsPort); DockerRunArgsBuilder sampleArgsBuilder = DockerRunArgsBuilder.Create() .ExposePort(DefaultHttpPort); string diagPortVolumeName = null; string tmpVolumeName = null; try { // Create a volume for the two containers to share the /tmp directory. if (shareTmpVolume) { tmpVolumeName = DockerHelper.CreateVolume(UniqueName("tmpvol")); monitorArgsBuilder.VolumeMount(tmpVolumeName, Directory_Tmp); sampleArgsBuilder.VolumeMount(tmpVolumeName, Directory_Tmp); } // Create a volume so that the dotnet-monitor container can provide a // diagnostic listening port to the samples container so that the samples // process can connect to the dotnet-monitor process. if (listenDiagPortVolume) { diagPortVolumeName = DockerHelper.CreateVolume(UniqueName("diagportvol")); monitorArgsBuilder.VolumeMount(diagPortVolumeName, Directory_Diag); monitorArgsBuilder.MonitorListen(File_DiagPort); sampleArgsBuilder.VolumeMount(diagPortVolumeName, Directory_Diag); sampleArgsBuilder.RuntimeSuspend(File_DiagPort); } // Allow modification of the "docker run" args of the monitor container if (null != monitorRunArgsCallback) { monitorRunArgsCallback(monitorArgsBuilder); } // Allow modification of the "docker run" args of the samples container if (null != sampleRunArgsCallback) { sampleRunArgsCallback(sampleArgsBuilder); } // Run the sample container DockerHelper.Run( image: sampleImageName, name: sampleContainerName, detach: true, optionalRunArgs: sampleArgsBuilder.Build()); // Run the dotnet-monitor container DockerHelper.Run( image: monitorImageName, name: monitorContainerName, command: GetMonitorAdditionalArgs(noAuthentication), detach: true, optionalRunArgs: monitorArgsBuilder.Build()); await verifyContainerAsync( monitorContainerName, sampleContainerName); } finally { DockerHelper.DeleteContainer(monitorContainerName); DockerHelper.DeleteContainer(sampleContainerName); if (!string.IsNullOrEmpty(diagPortVolumeName)) { DockerHelper.DeleteVolume(diagPortVolumeName); } if (!string.IsNullOrEmpty(tmpVolumeName)) { DockerHelper.DeleteVolume(tmpVolumeName); } } }