mirror of https://github.com/dotnet/tye.git
Browse Source
* Add support for running local containers - This support builds the application locally then volume mounts the application into the container when the --docker flag is specified. Added support for volume mounts and working directory to the DockerRunner. - Add simple test for tye run --dockerpull/147/head
committed by
GitHub
7 changed files with 179 additions and 7 deletions
@ -0,0 +1,100 @@ |
|||||
|
// 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.IO; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Tye.Hosting.Model; |
||||
|
|
||||
|
namespace Microsoft.Tye.Hosting |
||||
|
{ |
||||
|
public class TransformProjectsIntoContainers : IApplicationProcessor |
||||
|
{ |
||||
|
private readonly ILogger _logger; |
||||
|
|
||||
|
public TransformProjectsIntoContainers(ILogger logger) |
||||
|
{ |
||||
|
_logger = logger; |
||||
|
} |
||||
|
|
||||
|
public Task StartAsync(Model.Application application) |
||||
|
{ |
||||
|
// This transforms a ProjectRunInfo into
|
||||
|
var tasks = new List<Task>(); |
||||
|
foreach (var s in application.Services.Values) |
||||
|
{ |
||||
|
if (s.Description.RunInfo is ProjectRunInfo project) |
||||
|
{ |
||||
|
tasks.Add(TransformProjectToContainer(application, s, project)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Task.WhenAll(tasks); |
||||
|
} |
||||
|
|
||||
|
private async Task TransformProjectToContainer(Model.Application application, Model.Service service, ProjectRunInfo project) |
||||
|
{ |
||||
|
var serviceDescription = service.Description; |
||||
|
var serviceName = serviceDescription.Name; |
||||
|
|
||||
|
var expandedProject = Environment.ExpandEnvironmentVariables(project.Project); |
||||
|
var fullProjectPath = Path.GetFullPath(Path.Combine(application.ContextDirectory, expandedProject)); |
||||
|
service.Status.ProjectFilePath = fullProjectPath; |
||||
|
|
||||
|
// Sometimes building can fail because of file locking (like files being open in VS)
|
||||
|
_logger.LogInformation("Building project {ProjectFile}", service.Status.ProjectFilePath); |
||||
|
|
||||
|
service.Logs.OnNext($"dotnet build \"{service.Status.ProjectFilePath}\" /nologo"); |
||||
|
|
||||
|
var buildResult = await ProcessUtil.RunAsync("dotnet", $"build \"{service.Status.ProjectFilePath}\" /nologo", |
||||
|
outputDataReceived: data => service.Logs.OnNext(data), |
||||
|
throwOnError: false); |
||||
|
|
||||
|
if (buildResult.ExitCode != 0) |
||||
|
{ |
||||
|
_logger.LogInformation("Building {ProjectFile} failed with exit code {ExitCode}: " + buildResult.StandardOutput + buildResult.StandardError, service.Status.ProjectFilePath, buildResult.ExitCode); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var targetFramework = GetTargetFramework(service.Status.ProjectFilePath); |
||||
|
|
||||
|
// We transform the project information into the following docker command:
|
||||
|
// docker run -w /app -v {projectDir}:/app -it {image} dotnet /app/bin/Debug/{tfm}/{outputfile}.dll
|
||||
|
var containerImage = DetermineContainerImage(targetFramework); |
||||
|
var outputFileName = Path.GetFileNameWithoutExtension(service.Status.ProjectFilePath) + ".dll"; |
||||
|
var dockerRunInfo = new DockerRunInfo(containerImage, $"dotnet /app/bin/Debug/{targetFramework}/{outputFileName} {project.Args}") |
||||
|
{ |
||||
|
WorkingDirectory = "/app" |
||||
|
}; |
||||
|
dockerRunInfo.VolumeMappings[Path.GetDirectoryName(service.Status.ProjectFilePath)!] = "/app"; |
||||
|
|
||||
|
// Change the project into a container info
|
||||
|
serviceDescription.RunInfo = dockerRunInfo; |
||||
|
} |
||||
|
|
||||
|
private static string DetermineContainerImage(string targetFramework) |
||||
|
{ |
||||
|
// TODO: Determine the base iamge from the tfm
|
||||
|
return "mcr.microsoft.com/dotnet/core/sdk:3.1-buster"; |
||||
|
} |
||||
|
|
||||
|
private static string GetTargetFramework(string? projectFilePath) |
||||
|
{ |
||||
|
// TODO: Use msbuild to get the target path
|
||||
|
var debugOutputPath = Path.Combine(Path.GetDirectoryName(projectFilePath)!, "bin", "Debug"); |
||||
|
|
||||
|
var tfms = Directory.Exists(debugOutputPath) ? Directory.GetDirectories(debugOutputPath) : Array.Empty<string>(); |
||||
|
|
||||
|
return tfms.Select(tfm => new DirectoryInfo(tfm).Name).FirstOrDefault() ?? "netcoreapp3.1"; |
||||
|
} |
||||
|
|
||||
|
public Task StopAsync(Model.Application application) |
||||
|
{ |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue