Browse Source

Network configuration for Docker services and usage of existing networks (#287)

* Add configuration option to enable the containers usage of an existing network

* Use IsNullOrEmpty instead IsNullOrWhiteSpace to check the value of Application.Network

* Add tests for network assignment

* Remove network-test assent and use frontend-backend for network tests

* Improve logs in DockerRunner

* Fix whitespaces

* Fix whitespace formatting

* Fix format with dotnet format

* Add assertions to make sure the app working on network tests
davidfowl/build-earlier
Igr Alexánder Fernández Saúco 7 years ago
committed by GitHub
parent
commit
69070743e8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Microsoft.Tye.Core/ApplicationBuilder.cs
  2. 2
      src/Microsoft.Tye.Core/ApplicationFactory.cs
  3. 2
      src/Microsoft.Tye.Core/ConfigModel/ConfigApplication.cs
  4. 28
      src/Microsoft.Tye.Hosting/DockerRunner.cs
  5. 2
      src/Microsoft.Tye.Hosting/Model/Application.cs
  6. 2
      src/tye/ApplicationBuilderExtensions.cs
  7. 112
      test/E2ETest/TyeRunTests.cs

2
src/Microsoft.Tye.Core/ApplicationBuilder.cs

@ -26,5 +26,7 @@ namespace Microsoft.Tye
public List<ServiceBuilder> Services { get; } = new List<ServiceBuilder>();
public List<IngressBuilder> Ingress { get; } = new List<IngressBuilder>();
public string? Network { get; set; }
}
}

2
src/Microsoft.Tye.Core/ApplicationFactory.cs

@ -30,6 +30,8 @@ namespace Microsoft.Tye
builder.Registry = new ContainerRegistry(config.Registry);
}
builder.Network = config.Network;
foreach (var configExtension in config.Extensions)
{
var extension = new ExtensionConfiguration((string)configExtension["name"]);

2
src/Microsoft.Tye.Core/ConfigModel/ConfigApplication.cs

@ -21,6 +21,8 @@ namespace Microsoft.Tye.ConfigModel
public string? Registry { get; set; }
public string? Network { get; set; }
public List<Dictionary<string, object>> Extensions { get; set; } = new List<Dictionary<string, object>>();
public List<ConfigService> Services { get; set; } = new List<ConfigService>();

28
src/Microsoft.Tye.Hosting/DockerRunner.cs

@ -51,8 +51,32 @@ namespace Microsoft.Tye.Hosting
string? dockerNetwork = null;
if (!string.IsNullOrEmpty(application.Network))
{
var dockerNetworkResult = await ProcessUtil.RunAsync("docker", $"network ls --filter \"name={application.Network}\" --format \"{{{{.ID}}}}\"");
if (dockerNetworkResult.ExitCode != 0)
{
_logger.LogError("{Network}: Run docker network ls command failed", application.Network);
throw new CommandException("Run docker network ls command failed");
}
if (!string.IsNullOrWhiteSpace(dockerNetworkResult.StandardOutput))
{
_logger.LogInformation("The specified network {Network} exists", application.Network);
dockerNetwork = application.Network;
}
else
{
_logger.LogWarning("The specified network {Network} doesn't exist.", application.Network);
application.Network = null;
}
}
// We're going to be making containers, only make a network if we have more than one (we assume they'll need to talk)
if (containers.Count > 1)
if (string.IsNullOrEmpty(dockerNetwork) && containers.Count > 1)
{
dockerNetwork = "tye_network_" + Guid.NewGuid().ToString().Substring(0, 10);
@ -94,7 +118,7 @@ namespace Microsoft.Tye.Hosting
await Task.WhenAll(tasks);
if (application.Items.TryGetValue("dockerNetwork", out var dockerNetwork))
if (string.IsNullOrEmpty(application.Network) && application.Items.TryGetValue("dockerNetwork", out var dockerNetwork))
{
_logger.LogInformation("Removing docker network {Network}", dockerNetwork);

2
src/Microsoft.Tye.Hosting/Model/Application.cs

@ -26,6 +26,8 @@ namespace Microsoft.Tye.Hosting.Model
public Dictionary<object, object> Items { get; } = new Dictionary<object, object>();
public string? Network { get; set; }
public void PopulateEnvironment(Service service, Action<string, string> set, string defaultHost = "localhost")
{
if (service.Description.Configuration != null)

2
src/tye/ApplicationBuilderExtensions.cs

@ -152,7 +152,7 @@ namespace Microsoft.Tye
services.Add(ingress.Name, new Service(description));
}
return new Application(application.Source, services);
return new Application(application.Source, services) { Network = application.Network };
}
public static Tye.Hosting.Model.EnvironmentVariable ToHostingEnvironmentVariable(this EnvironmentVariableBuilder builder)

112
test/E2ETest/TyeRunTests.cs

@ -17,10 +17,12 @@ using Microsoft.Tye.Hosting.Model;
using Microsoft.Tye.Hosting.Model.V1;
using Xunit;
using Xunit.Abstractions;
using static E2ETest.TestHelpers;
namespace E2ETest
{
public class TyeRunTests
{
private readonly ITestOutputHelper _output;
@ -276,6 +278,114 @@ namespace E2ETest
await ProcessUtil.RunAsync("docker", $"volume rm {volumeName}");
}
[ConditionalFact]
[SkipIfDockerNotRunning]
public async Task DockerNetworkAssignmentTest()
{
var projectDirectory = new DirectoryInfo(
Path.Combine(GetSolutionRootDirectory("tye"), "samples", "frontend-backend"));
using var tempDirectory = TempDirectory.Create(true);
DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);
var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml"));
var outputContext = new OutputContext(_sink, Verbosity.Debug);
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);
var dockerNetwork = "tye_docker_network_test" + Guid.NewGuid().ToString().Substring(0, 10);
application.Network = dockerNetwork;
// Create the existing network
await ProcessUtil.RunAsync("docker", $"network create {dockerNetwork}");
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
AllowAutoRedirect = false
};
var client = new HttpClient(new RetryHandler(handler));
try
{
await RunHostingApplication(
application,
new[] { "--docker" },
async (app, uri) =>
{
// Make sure we're running containers
Assert.True(app.Services.All(s => s.Value.Description.RunInfo is DockerRunInfo));
foreach (var serviceBuilder in application.Services)
{
var serviceUri = await GetServiceUrl(client, uri, serviceBuilder.Name);
var serviceResponse = await client.GetAsync(serviceUri);
Assert.True(serviceResponse.IsSuccessStatusCode);
var serviceResult =
await client.GetStringAsync($"{uri}api/v1/services/{serviceBuilder.Name}");
var service = JsonSerializer.Deserialize<V1Service>(serviceResult, _options);
Assert.NotNull(service);
Assert.Equal(dockerNetwork, service.Replicas.FirstOrDefault().Value.DockerNetwork);
}
});
}
finally
{
// Delete the network
await ProcessUtil.RunAsync("docker", $"network rm {dockerNetwork}");
}
}
[ConditionalFact]
[SkipIfDockerNotRunning]
public async Task DockerNetworkAssignmentForNonExistingNetworkTest()
{
var projectDirectory = new DirectoryInfo(
Path.Combine(GetSolutionRootDirectory("tye"), "samples", "frontend-backend"));
using var tempDirectory = TempDirectory.Create(true);
DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);
var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml"));
var outputContext = new OutputContext(_sink, Verbosity.Debug);
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);
var dockerNetwork = "tye_docker_network_test" + Guid.NewGuid().ToString().Substring(0, 10);
application.Network = dockerNetwork;
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
AllowAutoRedirect = false
};
var client = new HttpClient(new RetryHandler(handler));
await RunHostingApplication(
application,
new[] { "--docker" },
async (app, uri) =>
{
// Make sure we're running containers
Assert.True(app.Services.All(s => s.Value.Description.RunInfo is DockerRunInfo));
foreach (var serviceBuilder in application.Services)
{
var serviceUri = await GetServiceUrl(client, uri, serviceBuilder.Name);
var serviceResponse = await client.GetAsync(serviceUri);
Assert.True(serviceResponse.IsSuccessStatusCode);
var serviceResult = await client.GetStringAsync($"{uri}api/v1/services/{serviceBuilder.Name}");
var service = JsonSerializer.Deserialize<V1Service>(serviceResult, _options);
Assert.NotNull(service);
Assert.NotEqual(dockerNetwork, service.Replicas.FirstOrDefault().Value.DockerNetwork);
}
});
}
[ConditionalFact]
[SkipIfDockerNotRunning]
public async Task DockerHostVolumeTest()
@ -287,7 +397,7 @@ namespace E2ETest
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);
// Add a volume
var project = ((ProjectServiceBuilder)application.Services[0]);
var project = (ProjectServiceBuilder)application.Services[0];
using var tempDir = TempDirectory.Create(preferUserDirectoryOnMacOS: true);

Loading…
Cancel
Save