This commit is contained in:
Logan Bussell 2023-09-21 13:01:14 -07:00
Родитель 6275d2fad4
Коммит f720e6e038
7 изменённых файлов: 148 добавлений и 101 удалений

Просмотреть файл

@ -10,7 +10,8 @@ namespace Microsoft.DotNet.Docker.Tests
public enum DotNetImageVariant
{
None = 0,
Composite = 1 << 0,
Extra = 1 << 1
AOT = 1 << 0,
Composite = 1 << 1,
Extra = 1 << 2,
}
}

Просмотреть файл

@ -134,9 +134,9 @@ namespace Microsoft.DotNet.Docker.Tests
public static string GetRepoNameModifier() => $"{(Config.IsNightlyRepo ? "/nightly" : string.Empty)}";
public static string GetImageName(string tag, string variantName, string repoNameModifier = null)
public static string GetImageName(string tag, string repoName, string repoNameModifier = null)
{
string repo = $"dotnet{repoNameModifier ?? GetRepoNameModifier()}/{variantName}";
string repo = $"dotnet{repoNameModifier ?? GetRepoNameModifier()}/{repoName}";
string registry = GetRegistryName(repo, tag);
return $"{registry}{repo}:{tag}";

Просмотреть файл

@ -26,6 +26,7 @@ namespace Microsoft.DotNet.Docker.Tests
private readonly string _adminUser = DockerHelper.IsLinuxContainerModeEnabled ? "root" : "ContainerAdministrator";
private readonly string _nonRootUser = DockerHelper.IsLinuxContainerModeEnabled ? "app" : "ContainerUser";
private readonly bool _nonRootUserSupported;
private readonly bool _isAot;
public ImageScenarioVerifier(
ProductImageData imageData,
@ -38,11 +39,18 @@ namespace Microsoft.DotNet.Docker.Tests
_isWeb = isWeb;
_outputHelper = outputHelper;
_nonRootUserSupported = DockerHelper.IsLinuxContainerModeEnabled && _imageData.Version.Major > 7;
_isAot = _imageData.ImageVariant.HasFlag(DotNetImageVariant.AOT);
}
public async Task Execute()
{
string solutionDir = CreateTestSolutionWithSdkImage(_isWeb ? "web" : "console");
string appType = _isAot && _isWeb
? "webapiaot"
: _isWeb
? "web"
: "console";
string solutionDir = CreateTestSolutionWithSdkImage(appType);
List<string> tags = new List<string>();
InjectCustomTestCode(Path.Combine(solutionDir, "app"));
@ -55,10 +63,13 @@ namespace Microsoft.DotNet.Docker.Tests
// the password isn't necessarily provided in that stage.
string customBuildArgs = $"rid={_imageData.Rid}";
string buildStageTarget = _isAot ? "publish_aot" : "build";
string appStageTarget = _isAot ? "aot_app" : "self_contained_app";
if (!_imageData.HasCustomSdk)
{
// Use `sdk` image to build and run test app
string buildTag = BuildTestAppImage("build", solutionDir, customBuildArgs);
string buildTag = BuildTestAppImage(buildStageTarget, solutionDir, customBuildArgs);
tags.Add(buildTag);
string dotnetRunArgs = _isWeb && _imageData.Version.Major <= 7 ? $" --urls http://0.0.0.0:{_imageData.DefaultPort}" : string.Empty;
await RunTestAppImage(buildTag, command: $"dotnet run ${dotnetRunArgs}");
@ -73,32 +84,36 @@ namespace Microsoft.DotNet.Docker.Tests
await RunTestAppImage(unitTestTag);
}
// Use `sdk` image to publish FX dependent app and run with `runtime` or `aspnet` image
string fxDepTag = BuildTestAppImage("fx_dependent_app", solutionDir, customBuildArgs);
tags.Add(fxDepTag);
// If we're a web app on Windows, use the ContainerAdministrator account
string fxDepUser = (_isWeb && !DockerHelper.IsLinuxContainerModeEnabled) ? _adminUser : null;
await RunTestAppImage(fxDepTag, user: fxDepUser);
// AOT compiled apps don't need the .NET runtime.
if (!_isAot)
{
// Use `sdk` image to publish FX dependent app and run with `runtime` or `aspnet` image
string fxDepTag = BuildTestAppImage("fx_dependent_app", solutionDir, customBuildArgs);
tags.Add(fxDepTag);
// If we're a web app on Windows, use the ContainerAdministrator account
string fxDepUser = (_isWeb && !DockerHelper.IsLinuxContainerModeEnabled) ? _adminUser : null;
await RunTestAppImage(fxDepTag, user: fxDepUser);
// For distroless, run another test that explicitly runs the container as a root user to verify
// the root user is defined.
if (!_isWeb && DockerHelper.IsLinuxContainerModeEnabled && _imageData.IsDistroless &&
(!_imageData.OS.StartsWith(OS.Mariner) || _imageData.Version.Major > 6))
{
await RunTestAppImage(fxDepTag, user: _adminUser);
}
// For non-distroless, which uses the root user by default, run the test as the non-root user
else if (_nonRootUserSupported && !_imageData.IsDistroless)
{
await RunTestAppImage(fxDepTag, user: _nonRootUser);
// For distroless, run another test that explicitly runs the container as a root user to verify
// the root user is defined.
if (!_isWeb && DockerHelper.IsLinuxContainerModeEnabled && _imageData.IsDistroless &&
(!_imageData.OS.StartsWith(OS.Mariner) || _imageData.Version.Major > 6))
{
await RunTestAppImage(fxDepTag, user: _adminUser);
}
// For non-distroless, which uses the root user by default, run the test as the non-root user
else if (_nonRootUserSupported && !_imageData.IsDistroless)
{
await RunTestAppImage(fxDepTag, user: _nonRootUser);
}
}
// There is no point in testing composite images here because there are no composite-specific
// runtime-deps or SDK images
if (DockerHelper.IsLinuxContainerModeEnabled && _imageData.ImageVariant != DotNetImageVariant.Composite)
if (DockerHelper.IsLinuxContainerModeEnabled && !_imageData.ImageVariant.HasFlag(DotNetImageVariant.Composite))
{
// Use `sdk` image to publish self contained app and run with `runtime-deps` image
string selfContainedTag = BuildTestAppImage("self_contained_app", solutionDir, customBuildArgs);
string selfContainedTag = BuildTestAppImage(appStageTarget, solutionDir, customBuildArgs);
tags.Add(selfContainedTag);
await RunTestAppImage(selfContainedTag, user: _adminUser);
@ -197,7 +212,12 @@ namespace Microsoft.DotNet.Docker.Tests
{
string tag = _imageData.GetIdentifier(stageTarget);
DotNetImageRepo runtimeImageRepo = _isWeb ? DotNetImageRepo.Aspnet : DotNetImageRepo.Runtime;
DotNetImageRepo runtimeImageRepo = _isAot
? DotNetImageRepo.Runtime_Deps
: _isWeb
? DotNetImageRepo.Aspnet
: DotNetImageRepo.Runtime;
List<string> buildArgs = new()
{
$"sdk_image={_imageData.GetImage(DotNetImageRepo.SDK, _dockerHelper)}",
@ -298,7 +318,7 @@ namespace Microsoft.DotNet.Docker.Tests
"--no-restore"
};
if (templateName == "web")
if (templateName.Contains("web"))
{
args = args.Append("--exclude-launch-settings");
}
@ -331,7 +351,12 @@ namespace Microsoft.DotNet.Docker.Tests
if (_isWeb && !Config.IsHttpVerificationDisabled)
{
await VerifyHttpResponseFromContainerAsync(containerName, _dockerHelper, _outputHelper, _imageData.DefaultPort);
await VerifyHttpResponseFromContainerAsync(
containerName,
_dockerHelper,
_outputHelper,
_imageData.DefaultPort,
pathAndQuery: _isAot ? "todos" : null);
}
}
finally

Просмотреть файл

@ -13,14 +13,9 @@ namespace Microsoft.DotNet.Docker.Tests
private string _sdkOS;
private string _osTag;
private ImageVersion? _versionFamily;
private DotNetImageVariant _imageVariant = DotNetImageVariant.None;
private DotNetImageRepo _supportedImageRepos =
DotNetImageRepo.Runtime_Deps
| DotNetImageRepo.Runtime
| DotNetImageRepo.Aspnet
| DotNetImageRepo.SDK;
public bool HasCustomSdk => _sdkOS != null;
public bool GlobalizationInvariantMode => (!ImageVariant.HasFlag(DotNetImageVariant.Extra)
|| Version.Major == 6
|| Version.Major == 7)
@ -28,51 +23,32 @@ namespace Microsoft.DotNet.Docker.Tests
public string SdkOS
{
get
{
if (_sdkOS != null)
{
return _sdkOS;
}
return OS;
}
set { _sdkOS = value; }
get => HasCustomSdk ? _sdkOS : OS;
init => _sdkOS = value;
}
public DotNetImageVariant SdkImageVariant { get; init; } = DotNetImageVariant.None;
public string OSTag
{
get
{
if (_osTag is not null)
{
return _osTag;
}
return OS;
}
set { _osTag = value; }
get => _osTag != null ? _osTag : OS;
init => _osTag = value;
}
public ImageVersion Version { get; set; }
public ImageVersion Version { get; init; }
public ImageVersion VersionFamily
{
get { return _versionFamily.GetValueOrDefault(Version); }
set { _versionFamily = value; }
init { _versionFamily = value; }
}
public DotNetImageVariant ImageVariant
{
get => _imageVariant;
set => _imageVariant = value;
}
public DotNetImageVariant ImageVariant { get; init;}
public DotNetImageRepo SupportedImageRepos
{
get => _supportedImageRepos;
set => _supportedImageRepos = value;
}
public DotNetImageRepo SupportedImageRepos { get; init; } = DotNetImageRepo.Runtime_Deps
| DotNetImageRepo.Runtime
| DotNetImageRepo.Aspnet
| DotNetImageRepo.SDK;
public string VersionString => Version.ToString();
@ -97,12 +73,18 @@ namespace Microsoft.DotNet.Docker.Tests
public string GetImage(DotNetImageRepo imageRepo, DockerHelper dockerHelper)
{
// ASP.NET composite includes its own runtime that we want to test
if (ImageVariant == DotNetImageVariant.Composite && imageRepo == DotNetImageRepo.Runtime)
// ASP.NET composite includes its own runtime that we want to test.
if (ImageVariant.HasFlag(DotNetImageVariant.Composite) && imageRepo == DotNetImageRepo.Runtime)
{
imageRepo = DotNetImageRepo.Aspnet;
}
if (imageRepo != DotNetImageRepo.SDK && !SupportedImageRepos.HasFlag(imageRepo))
{
throw new ArgumentOutOfRangeException(nameof(imageRepo),
$"Unsupported image type '{imageRepo}' for Image Variant '{ImageVariant}'");
}
string tag = GetTagName(imageRepo);
string imageName = GetImageName(tag, GetImageRepoName(imageRepo));
@ -170,6 +152,7 @@ namespace Microsoft.DotNet.Docker.Tests
case DotNetImageRepo.SDK:
imageVersion = Version;
os = SdkOS;
variant = GetImageVariantName(SdkImageVariant);
break;
default:
throw new NotSupportedException($"Unsupported image type '{imageRepo}'");

Просмотреть файл

@ -8,6 +8,7 @@ using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
@ -25,6 +26,28 @@ namespace Microsoft.DotNet.Docker.Tests
public static IEnumerable<object[]> GetImageData() => GetImageData(DotNetImageRepo.Runtime_Deps);
[LinuxImageTheory]
[MemberData(nameof(GetImageData))]
public async Task VerifyAotAppScenario(ProductImageData imageData)
{
if (!imageData.ImageVariant.HasFlag(DotNetImageVariant.AOT))
{
OutputHelper.WriteLine("Test is only relevant to AOT images.");
return;
}
if (imageData.Arch == Arch.Arm)
{
OutputHelper.WriteLine("Skipping test due to https://github.com/dotnet/docker-tools/issues/1177. "
+ "ImageBuilder is unable to queue arm32 AOT images together with the arm64 AOT SDKs. "
+ "Re-enable once fixed.");
return;
}
ImageScenarioVerifier verifier = new(imageData, DockerHelper, OutputHelper, isWeb: true);
await verifier.Execute();
}
[LinuxImageTheory]
[MemberData(nameof(GetImageData))]
public void VerifyEnvironmentVariables(ProductImageData imageData)
@ -189,7 +212,9 @@ namespace Microsoft.DotNet.Docker.Tests
private static IEnumerable<string> GetExpectedPackages(ProductImageData imageData, DotNetImageRepo imageRepo)
{
IEnumerable<string> expectedPackages = GetRuntimeDepsPackages(imageData);
IEnumerable<string> expectedPackages = imageData.ImageVariant.HasFlag(DotNetImageVariant.AOT)
? GetAotDepsPackages(imageData)
: GetRuntimeDepsPackages(imageData);
if (imageData.IsDistroless)
{
@ -220,7 +245,7 @@ namespace Microsoft.DotNet.Docker.Tests
_ => throw new NotSupportedException()
};
private static IEnumerable<string> GetRuntimeDepsPackages(ProductImageData imageData) => imageData switch
private static IEnumerable<string> GetAotDepsPackages(ProductImageData imageData) => imageData switch
{
{ OS: OS.Mariner20Distroless, Version: ImageVersion version }
when version.Major == 6 || version.Major == 7 => new[]
@ -229,7 +254,6 @@ namespace Microsoft.DotNet.Docker.Tests
"glibc",
"krb5",
"libgcc",
"libstdc++",
"openssl",
"openssl-libs",
"prebuilt-ca-certificates",
@ -242,7 +266,6 @@ namespace Microsoft.DotNet.Docker.Tests
"icu",
"krb5",
"libgcc",
"libstdc++",
"openssl-libs",
"zlib"
},
@ -250,7 +273,6 @@ namespace Microsoft.DotNet.Docker.Tests
{
"glibc",
"libgcc",
"libstdc++",
"openssl-libs",
"zlib"
},
@ -260,7 +282,6 @@ namespace Microsoft.DotNet.Docker.Tests
"libc6",
"libgcc-s1",
"libssl3",
"libstdc++6",
"zlib1g"
},
{ OS: OS.Focal } => new[]
@ -271,7 +292,6 @@ namespace Microsoft.DotNet.Docker.Tests
"libgssapi-krb5-2",
"libicu66",
"libssl1.1",
"libstdc++6",
"zlib1g"
},
{ OS: string os } when os.Contains(OS.Alpine) => new[]
@ -279,7 +299,6 @@ namespace Microsoft.DotNet.Docker.Tests
"ca-certificates-bundle",
"libgcc",
"libssl3",
"libstdc++",
"zlib"
},
{ OS: OS.BookwormSlim } => new[]
@ -289,7 +308,6 @@ namespace Microsoft.DotNet.Docker.Tests
"libgcc-s1",
"libicu72",
"libssl3",
"libstdc++6",
"tzdata",
"zlib1g"
},
@ -301,12 +319,18 @@ namespace Microsoft.DotNet.Docker.Tests
"libgssapi-krb5-2",
"libicu67",
"libssl1.1",
"libstdc++6",
"zlib1g"
},
_ => throw new NotSupportedException()
};
private static IEnumerable<string> GetRuntimeDepsPackages(ProductImageData imageData) {
string libstdcppPkgName = imageData.OS.Contains(OS.Mariner) || imageData.OS.Contains(OS.Alpine)
? "libstdc++"
: "libstdc++6";
return GetAotDepsPackages(imageData).Append(libstdcppPkgName);
}
internal static IEnumerable<string> GetExtraPackages(ProductImageData imageData) => imageData switch
{
{ IsDistroless: true, OS: string os } when os.Contains(OS.Mariner) => new[]

Просмотреть файл

@ -2,6 +2,7 @@ ARG sdk_image
ARG runtime_image
ARG runtime_deps_image
FROM $sdk_image as build
ARG rid
@ -61,3 +62,16 @@ EXPOSE $port
WORKDIR /app
COPY --from=publish_self_contained /source/app/out ./
ENTRYPOINT ["./app"]
FROM build as publish_aot
RUN dotnet publish -r $rid --no-restore -o /app
FROM $runtime_deps_image AS aot_app
WORKDIR /app
COPY --from=publish_aot /app .
USER $APP_UID
ENTRYPOINT ["./app"]

Просмотреть файл

@ -165,28 +165,28 @@ namespace Microsoft.DotNet.Docker.Tests
private static readonly ProductImageData[] s_linuxMonitorTestData =
{
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Amd64 },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Arm64 },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Amd64 },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Arm64 },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64 },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64 },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Amd64 },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Arm64 },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Amd64 },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Arm64 },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64 },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64 },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Amd64 },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Arm64 },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Amd64 },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Arm64 },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64 },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64 },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.JammyChiseled, OSTag = OS.UbuntuChiseled, Arch = Arch.Amd64 },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.JammyChiseled, OSTag = OS.UbuntuChiseled, Arch = Arch.Arm64 },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64 },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64 },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V6_3, VersionFamily = V6_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_2, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Alpine318, OSTag = OS.Alpine, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20, OSTag = OS.Mariner, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V7_3, VersionFamily = V7_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.JammyChiseled, OSTag = OS.UbuntuChiseled, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.JammyChiseled, OSTag = OS.UbuntuChiseled, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Amd64, SupportedImageRepos = DotNetImageRepo.Monitor },
new ProductImageData { Version = V8_0, VersionFamily = V8_0, OS = OS.Mariner20Distroless, OSTag = OS.MarinerDistroless, Arch = Arch.Arm64, SupportedImageRepos = DotNetImageRepo.Monitor }
};
private static readonly ProductImageData[] s_windowsMonitorTestData =