From 8da92ba9c8dc600ccfb581edf60eed1aec19b77a Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 29 Mar 2020 21:47:14 -0700 Subject: [PATCH] Add support for named docker volumes (#253) * Add support for named docker volumes - Added tests --- src/Microsoft.Tye.Core/ApplicationFactory.cs | 2 +- .../ConfigModel/ConfigVolume.cs | 3 +- src/Microsoft.Tye.Core/ProjectReader.cs | 16 +- src/Microsoft.Tye.Core/VolumeBuilder.cs | 7 +- src/Microsoft.Tye.Hosting/DockerRunner.cs | 15 +- .../Model/DockerRunInfo.cs | 2 +- .../Model/DockerVolume.cs | 21 +++ .../Model/ProjectRunInfo.cs | 2 +- .../Model/V1/V1DockerVolume.cs | 14 ++ .../Model/V1/V1RunInfo.cs | 2 +- .../TransformProjectsIntoContainers.cs | 7 +- src/Microsoft.Tye.Hosting/TyeDashboardApi.cs | 8 +- src/tye/ApplicationBuilderExtensions.cs | 4 +- test/E2ETest/TyeRunTests.cs | 148 +++++++++++++++++- .../projects/volume-test/Program.cs | 26 +++ .../Properties/launchSettings.json | 27 ++++ .../projects/volume-test/Startup.cs | 54 +++++++ .../volume-test/appsettings.Development.json | 9 ++ .../projects/volume-test/appsettings.json | 10 ++ .../testassets/projects/volume-test/tye.yaml | 13 ++ .../projects/volume-test/volume-test.csproj | 8 + 21 files changed, 370 insertions(+), 28 deletions(-) create mode 100644 src/Microsoft.Tye.Hosting/Model/DockerVolume.cs create mode 100644 src/Microsoft.Tye.Hosting/Model/V1/V1DockerVolume.cs create mode 100644 test/E2ETest/testassets/projects/volume-test/Program.cs create mode 100644 test/E2ETest/testassets/projects/volume-test/Properties/launchSettings.json create mode 100644 test/E2ETest/testassets/projects/volume-test/Startup.cs create mode 100644 test/E2ETest/testassets/projects/volume-test/appsettings.Development.json create mode 100644 test/E2ETest/testassets/projects/volume-test/appsettings.json create mode 100644 test/E2ETest/testassets/projects/volume-test/tye.yaml create mode 100644 test/E2ETest/testassets/projects/volume-test/volume-test.csproj diff --git a/src/Microsoft.Tye.Core/ApplicationFactory.cs b/src/Microsoft.Tye.Core/ApplicationFactory.cs index 46b07dba..8aa12188 100644 --- a/src/Microsoft.Tye.Core/ApplicationFactory.cs +++ b/src/Microsoft.Tye.Core/ApplicationFactory.cs @@ -167,7 +167,7 @@ namespace Microsoft.Tye foreach (var configVolume in configService.Volumes) { - var volume = new VolumeBuilder(configVolume.Source, configVolume.Target); + var volume = new VolumeBuilder(configVolume.Source, configVolume.Name, configVolume.Target); if (service is ProjectServiceBuilder project) { project.Volumes.Add(volume); diff --git a/src/Microsoft.Tye.Core/ConfigModel/ConfigVolume.cs b/src/Microsoft.Tye.Core/ConfigModel/ConfigVolume.cs index 964e71d6..1f0e421e 100644 --- a/src/Microsoft.Tye.Core/ConfigModel/ConfigVolume.cs +++ b/src/Microsoft.Tye.Core/ConfigModel/ConfigVolume.cs @@ -8,9 +8,10 @@ namespace Microsoft.Tye.ConfigModel { public class ConfigVolume { - [Required] public string Source { get; set; } = default!; + public string Name { get; set; } = default!; + [Required] public string Target { get; set; } = default!; } diff --git a/src/Microsoft.Tye.Core/ProjectReader.cs b/src/Microsoft.Tye.Core/ProjectReader.cs index 47f90213..b90ea633 100644 --- a/src/Microsoft.Tye.Core/ProjectReader.cs +++ b/src/Microsoft.Tye.Core/ProjectReader.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Loader; using System.Threading.Tasks; using Microsoft.Build.Construction; @@ -211,9 +212,9 @@ namespace Microsoft.Tye output.WriteDebugLine($"IntermediateOutputPath={project.IntermediateOutputPath}"); // Normalize directories to their absolute paths - project.IntermediateOutputPath = Path.Combine(project.ProjectFile.DirectoryName, project.IntermediateOutputPath); - project.TargetPath = Path.Combine(project.ProjectFile.DirectoryName, project.TargetPath); - project.PublishDir = Path.Combine(project.ProjectFile.DirectoryName, project.PublishDir); + project.IntermediateOutputPath = Path.Combine(project.ProjectFile.DirectoryName, NormalizePath(project.IntermediateOutputPath)); + project.TargetPath = Path.Combine(project.ProjectFile.DirectoryName, NormalizePath(project.TargetPath)); + project.PublishDir = Path.Combine(project.ProjectFile.DirectoryName, NormalizePath(project.PublishDir)); var targetFramework = projectInstance.GetPropertyValue("TargetFramework"); project.TargetFramework = targetFramework; @@ -258,5 +259,14 @@ namespace Microsoft.Tye return default; } } + + private static string NormalizePath(string path) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return path.Replace('/', '\\'); + } + return path.Replace('\\', '/'); + } } } diff --git a/src/Microsoft.Tye.Core/VolumeBuilder.cs b/src/Microsoft.Tye.Core/VolumeBuilder.cs index 2641f087..4335d84f 100644 --- a/src/Microsoft.Tye.Core/VolumeBuilder.cs +++ b/src/Microsoft.Tye.Core/VolumeBuilder.cs @@ -6,13 +6,16 @@ namespace Microsoft.Tye { public sealed class VolumeBuilder { - public VolumeBuilder(string source, string target) + public VolumeBuilder(string? source, string? name, string target) { Source = source; + Name = name; Target = target; } - public string Source { get; set; } + public string? Source { get; set; } + + public string? Name { get; set; } public string Target { get; set; } } diff --git a/src/Microsoft.Tye.Hosting/DockerRunner.cs b/src/Microsoft.Tye.Hosting/DockerRunner.cs index f5124c17..553ac96c 100644 --- a/src/Microsoft.Tye.Hosting/DockerRunner.cs +++ b/src/Microsoft.Tye.Hosting/DockerRunner.cs @@ -86,7 +86,7 @@ namespace Microsoft.Tye.Hosting if (!string.IsNullOrEmpty(userSecretStore)) { // Map the user secrets on this drive to user secrets - docker.VolumeMappings[userSecretStore] = "/root/.microsoft/usersecrets:ro"; + docker.VolumeMappings.Add(new DockerVolume(source: userSecretStore, name: null, target: "/root/.microsoft/usersecrets:ro")); } var dockerInfo = new DockerInformation(new Task[service.Description.Replicas]); @@ -151,10 +151,17 @@ namespace Microsoft.Tye.Hosting environmentArguments += $"-e {pair.Key}={pair.Value} "; } - foreach (var pair in docker.VolumeMappings) + foreach (var volumeMapping in docker.VolumeMappings) { - var sourcePath = Path.GetFullPath(Path.Combine(application.ContextDirectory, pair.Key.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))); - volumes += $"-v {sourcePath}:{pair.Value} "; + if (volumeMapping.Source != null) + { + var sourcePath = Path.GetFullPath(Path.Combine(application.ContextDirectory, volumeMapping.Source)); + volumes += $"-v {sourcePath}:{volumeMapping.Target} "; + } + else if (volumeMapping.Name != null) + { + volumes += $"-v {volumeMapping.Name}:{volumeMapping.Target} "; + } } var command = $"run -d {workingDirectory} {volumes} {environmentArguments} {portString} --name {replica} --restart=unless-stopped {docker.Image} {docker.Args ?? ""}"; diff --git a/src/Microsoft.Tye.Hosting/Model/DockerRunInfo.cs b/src/Microsoft.Tye.Hosting/Model/DockerRunInfo.cs index e9ca5d1e..91f8cec5 100644 --- a/src/Microsoft.Tye.Hosting/Model/DockerRunInfo.cs +++ b/src/Microsoft.Tye.Hosting/Model/DockerRunInfo.cs @@ -16,7 +16,7 @@ namespace Microsoft.Tye.Hosting.Model public string? WorkingDirectory { get; set; } - public Dictionary VolumeMappings { get; } = new Dictionary(); + public List VolumeMappings { get; } = new List(); public string? Args { get; } diff --git a/src/Microsoft.Tye.Hosting/Model/DockerVolume.cs b/src/Microsoft.Tye.Hosting/Model/DockerVolume.cs new file mode 100644 index 00000000..532678ca --- /dev/null +++ b/src/Microsoft.Tye.Hosting/Model/DockerVolume.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Tye.Hosting.Model +{ + public class DockerVolume + { + public DockerVolume(string? source, string? name, string target) + { + Source = source; + Name = name; + Target = target; + } + + public string? Name { get; } + public string? Source { get; } + public string Target { get; } + } +} diff --git a/src/Microsoft.Tye.Hosting/Model/ProjectRunInfo.cs b/src/Microsoft.Tye.Hosting/Model/ProjectRunInfo.cs index 50534b5d..18b2b6a6 100644 --- a/src/Microsoft.Tye.Hosting/Model/ProjectRunInfo.cs +++ b/src/Microsoft.Tye.Hosting/Model/ProjectRunInfo.cs @@ -44,6 +44,6 @@ namespace Microsoft.Tye.Hosting.Model public string RunArguments { get; } // This exists for running projects as containers - public Dictionary VolumeMappings { get; } = new Dictionary(); + public List VolumeMappings { get; } = new List(); } } diff --git a/src/Microsoft.Tye.Hosting/Model/V1/V1DockerVolume.cs b/src/Microsoft.Tye.Hosting/Model/V1/V1DockerVolume.cs new file mode 100644 index 00000000..e4a0dc77 --- /dev/null +++ b/src/Microsoft.Tye.Hosting/Model/V1/V1DockerVolume.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Tye.Hosting.Model.V1 +{ + public class V1DockerVolume + { + public string? Name { get; set; } + public string? Source { get; set; } + public string? Target { get; set; } + } +} diff --git a/src/Microsoft.Tye.Hosting/Model/V1/V1RunInfo.cs b/src/Microsoft.Tye.Hosting/Model/V1/V1RunInfo.cs index c47cb566..7d65e02b 100644 --- a/src/Microsoft.Tye.Hosting/Model/V1/V1RunInfo.cs +++ b/src/Microsoft.Tye.Hosting/Model/V1/V1RunInfo.cs @@ -13,7 +13,7 @@ namespace Microsoft.Tye.Hosting.Model.V1 public bool Build { get; set; } public string? Project { get; set; } public string? WorkingDirectory { get; set; } - public Dictionary? VolumeMappings { get; set; } + public List? VolumeMappings { get; set; } public string? Image { get; set; } public string? Executable { get; set; } } diff --git a/src/Microsoft.Tye.Hosting/TransformProjectsIntoContainers.cs b/src/Microsoft.Tye.Hosting/TransformProjectsIntoContainers.cs index a723cb26..fda8213b 100644 --- a/src/Microsoft.Tye.Hosting/TransformProjectsIntoContainers.cs +++ b/src/Microsoft.Tye.Hosting/TransformProjectsIntoContainers.cs @@ -71,13 +71,10 @@ namespace Microsoft.Tye.Hosting WorkingDirectory = "/app" }; - dockerRunInfo.VolumeMappings[project.PublishOutputPath] = "/app"; + dockerRunInfo.VolumeMappings.Add(new DockerVolume(source: project.PublishOutputPath, name: null, target: "/app")); // Make volume mapping works when running as a container - foreach (var mapping in project.VolumeMappings) - { - dockerRunInfo.VolumeMappings[mapping.Key] = mapping.Value; - } + dockerRunInfo.VolumeMappings.AddRange(project.VolumeMappings); // Change the project into a container info serviceDescription.RunInfo = dockerRunInfo; diff --git a/src/Microsoft.Tye.Hosting/TyeDashboardApi.cs b/src/Microsoft.Tye.Hosting/TyeDashboardApi.cs index 454b7a1f..113c8377 100644 --- a/src/Microsoft.Tye.Hosting/TyeDashboardApi.cs +++ b/src/Microsoft.Tye.Hosting/TyeDashboardApi.cs @@ -133,7 +133,13 @@ namespace Microsoft.Tye.Hosting { v1RunInfo.Type = V1RunInfoType.Docker; v1RunInfo.Image = dockerRunInfo.Image; - v1RunInfo.VolumeMappings = dockerRunInfo.VolumeMappings; + v1RunInfo.VolumeMappings = dockerRunInfo.VolumeMappings.Select(v => new V1DockerVolume + { + Name = v.Name, + Source = v.Source, + Target = v.Target + }).ToList(); + v1RunInfo.WorkingDirectory = dockerRunInfo.WorkingDirectory; v1RunInfo.Args = dockerRunInfo.Args; } diff --git a/src/tye/ApplicationBuilderExtensions.cs b/src/tye/ApplicationBuilderExtensions.cs index 46d9f13b..f2c3e9bc 100644 --- a/src/tye/ApplicationBuilderExtensions.cs +++ b/src/tye/ApplicationBuilderExtensions.cs @@ -29,7 +29,7 @@ namespace Microsoft.Tye.ConfigModel foreach (var mapping in container.Volumes) { - dockerRunInfo.VolumeMappings[mapping.Source!] = mapping.Target!; + dockerRunInfo.VolumeMappings.Add(new DockerVolume(mapping.Source, mapping.Name, mapping.Target)); } runInfo = dockerRunInfo; @@ -66,7 +66,7 @@ namespace Microsoft.Tye.ConfigModel foreach (var mapping in project.Volumes) { - projectInfo.VolumeMappings[mapping.Source!] = mapping.Target!; + projectInfo.VolumeMappings.Add(new DockerVolume(mapping.Source, mapping.Name, mapping.Target)); } runInfo = projectInfo; diff --git a/test/E2ETest/TyeRunTests.cs b/test/E2ETest/TyeRunTests.cs index f2eeb912..5f90cccb 100644 --- a/test/E2ETest/TyeRunTests.cs +++ b/test/E2ETest/TyeRunTests.cs @@ -17,6 +17,7 @@ using Microsoft.Tye.Hosting.Model; using Microsoft.Tye.Hosting.Model.V1; using Xunit; using Xunit.Abstractions; +using static E2ETest.TestHelpers; namespace E2ETest { @@ -138,6 +139,101 @@ namespace E2ETest } } + [ConditionalFact] + [SkipIfDockerNotRunning] + public async Task DockerNamedVolumeTest() + { + using var projectDirectory = CopyTestProjectDirectory("volume-test"); + var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml")); + + var outputContext = new OutputContext(_sink, Verbosity.Debug); + var application = await ApplicationFactory.CreateAsync(outputContext, projectFile); + + // Add a volume + var project = ((ProjectServiceBuilder)application.Services[0]); + // Remove the existing volume so we can generate a random one for this test to avoid conflicts + var volumeName = "tye_docker_volumes_test" + Guid.NewGuid().ToString().Substring(0, 10); + project.Volumes.Clear(); + project.Volumes.Add(new VolumeBuilder(source: null, name: volumeName, "/data")); + + var handler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (a, b, c, d) => true, + AllowAutoRedirect = false + }; + + var client = new HttpClient(new RetryHandler(handler)); + var args = new[] { "--docker" }; + + await RunHostingApplication(application, args, _sink, async serviceApi => + { + var serviceUri = await GetServiceUrl(client, serviceApi, "volume-test"); + + Assert.NotNull(serviceUri); + + var response = await client.GetAsync(serviceUri); + + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + + await client.PostAsync(serviceUri, new StringContent("Things saved to the volume!")); + + Assert.Equal("Things saved to the volume!", await client.GetStringAsync(serviceUri)); + }); + + await RunHostingApplication(application, args, _sink, async serviceApi => + { + var serviceUri = await GetServiceUrl(client, serviceApi, "volume-test"); + + Assert.NotNull(serviceUri); + + // The volume has data persisted + Assert.Equal("Things saved to the volume!", await client.GetStringAsync(serviceUri)); + }); + + // Delete the volume + await ProcessUtil.RunAsync("docker", $"volume rm {volumeName}"); + } + + [ConditionalFact] + [SkipIfDockerNotRunning] + public async Task DockerHostVolumeTest() + { + using var projectDirectory = CopyTestProjectDirectory("volume-test"); + var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml")); + + var outputContext = new OutputContext(_sink, Verbosity.Debug); + var application = await ApplicationFactory.CreateAsync(outputContext, projectFile); + + // Add a volume + var project = ((ProjectServiceBuilder)application.Services[0]); + + using var tempDir = TempDirectory.Create(); + + project.Volumes.Clear(); + project.Volumes.Add(new VolumeBuilder(source: tempDir.DirectoryPath, name: null, target: "/data")); + + var handler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (a, b, c, d) => true, + AllowAutoRedirect = false + }; + + File.WriteAllText(Path.Combine(tempDir.DirectoryPath, "file.txt"), "This content came from the host"); + + var client = new HttpClient(new RetryHandler(handler)); + var args = new[] { "--docker" }; + + await RunHostingApplication(application, args, _sink, async serviceApi => + { + var serviceUri = await GetServiceUrl(client, serviceApi, "volume-test"); + + Assert.NotNull(serviceUri); + + // The volume has data the host mapped data + Assert.Equal("This content came from the host", await client.GetStringAsync(serviceUri)); + }); + } + [Fact] public async Task IngressRunTest() { @@ -165,11 +261,7 @@ namespace E2ETest try { - var ingressService = await client.GetStringAsync($"{serviceApi}api/v1/services/ingress"); - - var service = JsonSerializer.Deserialize(ingressService, _options); - var binding = service.Description!.Bindings.Single(); - var ingressUri = $"http://localhost:{binding.Port}"; + var ingressUri = await GetServiceUrl(client, serviceApi, "ingress"); var responseA = await client.GetAsync(ingressUri + "/A"); var responseB = await client.GetAsync(ingressUri + "/B"); @@ -270,7 +362,51 @@ namespace E2ETest await host.StopAsync(); } - private async Task CheckServiceIsUp(Microsoft.Tye.Hosting.Model.Application application, HttpClient client, string serviceName, Uri dashboardUri, TimeSpan? timeout = default) + private async Task GetServiceUrl(HttpClient client, Uri serviceApi, string serviceName) + { + var serviceResult = await client.GetStringAsync($"{serviceApi}api/v1/services/{serviceName}"); + var service = JsonSerializer.Deserialize(serviceResult, _options); + var binding = service.Description!.Bindings.Where(b => b.Protocol == "http").Single(); + return $"{binding.Protocol ?? "http"}://localhost:{binding.Port}"; + } + + private async Task RunHostingApplication(ApplicationBuilder application, string[] args, TestOutputLogEventSink sink, Func execute) + { + using var host = new TyeHost(application.ToHostingApplication(), args) + { + Sink = sink, + }; + + await StartHostAndWaitForReplicasToStart(host); + + var serviceApi = new Uri(host.DashboardWebApplication!.Addresses.First()); + + try + { + await execute(serviceApi!); + } + finally + { + using (var client = new HttpClient()) + { + // If we failed, there's a good chance the service isn't running. Let's get the logs either way and put + // them in the output. + foreach (var s in host.Application.Services.Values) + { + var request = new HttpRequestMessage(HttpMethod.Get, new Uri(serviceApi, $"/api/v1/logs/{s.Description.Name}")); + var response = await client.SendAsync(request); + var text = await response.Content.ReadAsStringAsync(); + + _output.WriteLine($"Logs for service: {s.Description.Name}"); + _output.WriteLine(text); + } + } + + await host.StopAsync(); + } + } + + private async Task CheckServiceIsUp(Application application, HttpClient client, string serviceName, Uri dashboardUri, TimeSpan? timeout = default) { // make sure backend is up before frontend var dashboardString = await client.GetStringAsync($"{dashboardUri}api/v1/services/{serviceName}"); diff --git a/test/E2ETest/testassets/projects/volume-test/Program.cs b/test/E2ETest/testassets/projects/volume-test/Program.cs new file mode 100644 index 00000000..6ccaa111 --- /dev/null +++ b/test/E2ETest/testassets/projects/volume-test/Program.cs @@ -0,0 +1,26 @@ +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 volume_test +{ + 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(); + }); + } +} diff --git a/test/E2ETest/testassets/projects/volume-test/Properties/launchSettings.json b/test/E2ETest/testassets/projects/volume-test/Properties/launchSettings.json new file mode 100644 index 00000000..4cb64d88 --- /dev/null +++ b/test/E2ETest/testassets/projects/volume-test/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:27607", + "sslPort": 44301 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "volume_test": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/test/E2ETest/testassets/projects/volume-test/Startup.cs b/test/E2ETest/testassets/projects/volume-test/Startup.cs new file mode 100644 index 00000000..4548e6f5 --- /dev/null +++ b/test/E2ETest/testassets/projects/volume-test/Startup.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.IO; +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 volume_test +{ + 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 => + { + if (!File.Exists("/data/file.txt")) + { + context.Response.StatusCode = 404; + return; + } + var data = await File.ReadAllTextAsync("/data/file.txt"); + await context.Response.WriteAsync(data); + }); + + endpoints.MapPost("/", async context => + { + await File.WriteAllTextAsync("/data/file.txt", await new StreamReader(context.Request.Body).ReadToEndAsync()); + + context.Response.StatusCode = 202; + }); + }); + } + } +} diff --git a/test/E2ETest/testassets/projects/volume-test/appsettings.Development.json b/test/E2ETest/testassets/projects/volume-test/appsettings.Development.json new file mode 100644 index 00000000..8983e0fc --- /dev/null +++ b/test/E2ETest/testassets/projects/volume-test/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/test/E2ETest/testassets/projects/volume-test/appsettings.json b/test/E2ETest/testassets/projects/volume-test/appsettings.json new file mode 100644 index 00000000..d9d9a9bf --- /dev/null +++ b/test/E2ETest/testassets/projects/volume-test/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/test/E2ETest/testassets/projects/volume-test/tye.yaml b/test/E2ETest/testassets/projects/volume-test/tye.yaml new file mode 100644 index 00000000..30912f6e --- /dev/null +++ b/test/E2ETest/testassets/projects/volume-test/tye.yaml @@ -0,0 +1,13 @@ +# tye application configuration file +# read all about it at https://github.com/dotnet/tye +# +# when you've given us a try, we'd love to know what you think: +# https://aka.ms/AA7q20u +# +name: volume-test +services: +- name: volume-test + project: volume-test.csproj + volumes: + - name: data-vol + target: /data \ No newline at end of file diff --git a/test/E2ETest/testassets/projects/volume-test/volume-test.csproj b/test/E2ETest/testassets/projects/volume-test/volume-test.csproj new file mode 100644 index 00000000..50570be1 --- /dev/null +++ b/test/E2ETest/testassets/projects/volume-test/volume-test.csproj @@ -0,0 +1,8 @@ + + + + netcoreapp3.1 + volume_test + + +