Browse Source

Resolve base docker images correctly for .NET 5.0+ projects (#702)

* Resolve base docker images correctly for .NET 5.0+ projects
pull/705/head
John Luo 6 years ago
committed by GitHub
parent
commit
b923d360f7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 42
      src/Microsoft.Tye.Core/DockerfileGenerator.cs
  2. 15
      src/Microsoft.Tye.Hosting/TransformProjectsIntoContainers.cs
  3. 37
      test/E2ETest/TyeRunTests.cs
  4. 34
      test/E2ETest/testassets/projects/single-project-5.0/single-project.sln
  5. 30
      test/E2ETest/testassets/projects/single-project-5.0/test-project/Program.cs
  6. 44
      test/E2ETest/testassets/projects/single-project-5.0/test-project/Startup.cs
  7. 9
      test/E2ETest/testassets/projects/single-project-5.0/test-project/appsettings.Development.json
  8. 10
      test/E2ETest/testassets/projects/single-project-5.0/test-project/appsettings.json
  9. 8
      test/E2ETest/testassets/projects/single-project-5.0/test-project/test-project.csproj
  10. 6
      test/E2ETest/testassets/projects/single-project-5.0/tye.yaml

42
src/Microsoft.Tye.Core/DockerfileGenerator.cs

@ -92,15 +92,6 @@ namespace Microsoft.Tye
throw new ArgumentNullException(nameof(container));
}
if (string.IsNullOrEmpty(container.BaseImageName) && project.IsAspNet)
{
container.BaseImageName = "mcr.microsoft.com/dotnet/core/aspnet";
}
else if (string.IsNullOrEmpty(container.BaseImageName))
{
container.BaseImageName = "mcr.microsoft.com/dotnet/core/runtime";
}
if (string.IsNullOrEmpty(container.BaseImageTag) && (project.TargetFrameworkName == "netcoreapp" || project.TargetFrameworkName == "net"))
{
container.BaseImageTag = project.TargetFrameworkVersion;
@ -111,9 +102,25 @@ namespace Microsoft.Tye
throw new CommandException($"Unsupported TFM {project.TargetFramework}.");
}
container.BuildImageName ??= "mcr.microsoft.com/dotnet/core/sdk";
if (string.IsNullOrEmpty(container.BaseImageName))
{
if (TagIs50OrNewer(container.BaseImageTag))
{
container.BaseImageName = project.IsAspNet ? "mcr.microsoft.com/dotnet/aspnet" : "mcr.microsoft.com/dotnet/runtime";
}
else
{
container.BaseImageName = project.IsAspNet ? "mcr.microsoft.com/dotnet/core/aspnet" : "mcr.microsoft.com/dotnet/core/runtime";
}
}
container.BuildImageTag ??= project.TargetFrameworkVersion;
if (string.IsNullOrEmpty(container.BuildImageName))
{
container.BuildImageName = TagIs50OrNewer(container.BuildImageTag) ? "mcr.microsoft.com/dotnet/sdk" : "mcr.microsoft.com/dotnet/core/sdk";
}
if (container.ImageName == null && application.Registry?.Hostname == null)
{
container.ImageName ??= project.Name.ToLowerInvariant();
@ -142,5 +149,20 @@ namespace Microsoft.Tye
container.ImageTag ??= "latest";
}
public static bool TagIs50OrNewer(string tag)
{
if (string.Equals("latest", tag))
{
return true;
}
if (!Version.TryParse(tag, out var version))
{
throw new CommandException($"Could not determine version of docker image for tag: {tag}.");
}
return version.Major >= 5;
}
}
}

15
src/Microsoft.Tye.Hosting/TransformProjectsIntoContainers.cs

@ -125,6 +125,8 @@ namespace Microsoft.Tye.Hosting
private static string DetermineContainerImage(ProjectRunInfo project)
{
var baseImageTag = !string.IsNullOrEmpty(project.ContainerBaseTag) ? project.ContainerBaseTag : project.TargetFrameworkVersion;
string baseImage;
if (!string.IsNullOrEmpty(project.ContainerBaseImage))
{
@ -132,11 +134,18 @@ namespace Microsoft.Tye.Hosting
}
else
{
baseImage = project.IsAspNet ? "mcr.microsoft.com/dotnet/core/aspnet" : "mcr.microsoft.com/dotnet/core/runtime";
if (DockerfileGenerator.TagIs50OrNewer(baseImageTag))
{
// .NET 5.0+ does not have the /core in its image name
baseImage = project.IsAspNet ? "mcr.microsoft.com/dotnet/aspnet" : "mcr.microsoft.com/dotnet/runtime";
}
else
{
// .NET Core 2.1/3.1 has the /core in its image name
baseImage = project.IsAspNet ? "mcr.microsoft.com/dotnet/core/aspnet" : "mcr.microsoft.com/dotnet/core/runtime";
}
}
var baseImageTag = !string.IsNullOrEmpty(project.ContainerBaseTag) ? project.ContainerBaseTag : project.TargetFrameworkVersion;
return $"{baseImage}:{baseImageTag}";
}

37
test/E2ETest/TyeRunTests.cs

@ -121,6 +121,43 @@ services:
});
}
[ConditionalTheory]
[SkipIfDockerNotRunning]
[InlineData("single-project", "mcr.microsoft.com/dotnet/core/aspnet:3.1")]
[InlineData("single-project-5.0", "mcr.microsoft.com/dotnet/aspnet:5.0")]
public async Task SingleProjectWithDocker_UsesCorrectBaseImage(string projectName, string baseImage)
{
using var projectDirectory = CopyTestProjectDirectory(projectName);
var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
var outputContext = new OutputContext(_sink, Verbosity.Debug);
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
AllowAutoRedirect = false
};
var client = new HttpClient(new RetryHandler(handler));
await RunHostingApplication(application, new HostOptions() { Docker = true, }, async (app, uri) =>
{
// Make sure we're running containers
Assert.True(app.Services.All(s => s.Value.Description.RunInfo is DockerRunInfo));
// Ensure correct image used
var dockerRunInfo = app.Services.Single().Value.Description.RunInfo as DockerRunInfo;
Assert.Equal(baseImage, dockerRunInfo?.Image);
// Ensure app runs
var testProjectUri = await GetServiceUrl(client, uri, "test-project");
var response = await client.GetAsync(testProjectUri);
Assert.True(response.IsSuccessStatusCode);
});
}
[ConditionalFact]
[SkipIfDockerNotRunning]
public async Task FrontendBackendRunTestWithDocker()

34
test/E2ETest/testassets/projects/single-project-5.0/single-project.sln

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test-project", "test-project\test-project.csproj", "{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Debug|x64.ActiveCfg = Debug|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Debug|x64.Build.0 = Debug|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Debug|x86.ActiveCfg = Debug|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Debug|x86.Build.0 = Debug|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Release|Any CPU.Build.0 = Release|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Release|x64.ActiveCfg = Release|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Release|x64.Build.0 = Release|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Release|x86.ActiveCfg = Release|Any CPU
{7D3606B2-7B8E-4ABB-BE0A-E0B18285D8F5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

30
test/E2ETest/testassets/projects/single-project-5.0/test-project/Program.cs

@ -0,0 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace test_project
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

44
test/E2ETest/testassets/projects/single-project-5.0/test-project/Startup.cs

@ -0,0 +1,44 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace test_project
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}

9
test/E2ETest/testassets/projects/single-project-5.0/test-project/appsettings.Development.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

10
test/E2ETest/testassets/projects/single-project-5.0/test-project/appsettings.json

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

8
test/E2ETest/testassets/projects/single-project-5.0/test-project/test-project.csproj

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp5.0</TargetFramework>
<RootNamespace>test_project</RootNamespace>
</PropertyGroup>
</Project>

6
test/E2ETest/testassets/projects/single-project-5.0/tye.yaml

@ -0,0 +1,6 @@
# tye application configuration file
# read all about it at https://github.com/dotnet/tye
name: single-project
services:
- name: test-project
project: test-project/test-project.csproj
Loading…
Cancel
Save