Browse Source

Remove reading of launch settings (#203)

* Remove reading of launch settings
- If bindings are specified, add an http and https binding with autodetect port to true.
- Prefer HTTP over HTTPS for ingress
pull/209/head
David Fowler 6 years ago
committed by GitHub
parent
commit
6a592c01e0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      samples/voting/tye.yaml
  2. 52
      src/Microsoft.Tye.Core/ApplicationFactory.cs
  3. 99
      src/Microsoft.Tye.Core/ConfigModel/ConfigFactory.cs
  4. 29
      src/Microsoft.Tye.Hosting/HttpProxyService.cs

2
samples/voting/tye.yaml

@ -8,8 +8,6 @@ services:
- port: 6379
- name: worker
project: worker/worker.csproj
bindings:
- autoAssignPort: true
- name: postgres
image: postgres
env:

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

@ -96,26 +96,48 @@ namespace Microsoft.Tye
builder.Services.Add(service);
foreach (var configBinding in configService.Bindings)
// If there are no bindings and we're in ASP.NET Core project then add an HTTP and HTTPS binding
if (configService.Bindings.Count == 0 &&
service is ProjectServiceBuilder project2 &&
project2.Frameworks.Any(f => f.Name == "Microsoft.AspNetCore.App"))
{
var binding = new BindingBuilder()
// HTTP is the default binding
service.Bindings.Add(new BindingBuilder()
{
Name = configBinding.Name,
AutoAssignPort = configBinding.AutoAssignPort,
ConnectionString = configBinding.ConnectionString,
Host = configBinding.Host,
ContainerPort = configBinding.ContainerPort,
Port = configBinding.Port,
Protocol = configBinding.Protocol,
};
AutoAssignPort = true,
Protocol = "http"
});
// Assume HTTP for projects only (containers may be different)
if (binding.ConnectionString == null && configService.Project != null)
service.Bindings.Add(new BindingBuilder()
{
binding.Protocol ??= "http";
}
Name = "https",
AutoAssignPort = true,
Protocol = "https"
});
}
else
{
foreach (var configBinding in configService.Bindings)
{
var binding = new BindingBuilder()
{
Name = configBinding.Name,
AutoAssignPort = configBinding.AutoAssignPort,
ConnectionString = configBinding.ConnectionString,
Host = configBinding.Host,
ContainerPort = configBinding.ContainerPort,
Port = configBinding.Port,
Protocol = configBinding.Protocol,
};
service.Bindings.Add(binding);
// Assume HTTP for projects only (containers may be different)
if (binding.ConnectionString == null && configService.Project != null)
{
binding.Protocol ??= "http";
}
service.Bindings.Add(binding);
}
}
foreach (var configEnvVar in configService.Configuration)

99
src/Microsoft.Tye.Core/ConfigModel/ConfigFactory.cs

@ -2,11 +2,8 @@
// 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.Text.Json;
using Microsoft.Build.Construction;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
@ -42,11 +39,13 @@ namespace Microsoft.Tye.ConfigModel
Source = file,
};
var service = CreateService(file);
if (service is object)
var service = new ConfigService()
{
application.Services.Add(service);
}
Name = Path.GetFileNameWithoutExtension(file.Name).ToLowerInvariant(),
Project = file.FullName.Replace('\\', '/'),
};
application.Services.Add(service);
return application;
}
@ -62,11 +61,13 @@ namespace Microsoft.Tye.ConfigModel
// throughout the code, because we load them dynamically.
foreach (var projectFile in ProjectReader.EnumerateProjects(file))
{
var description = CreateService(projectFile);
if (description != null)
var service = new ConfigService()
{
application.Services.Add(description);
}
Name = Path.GetFileNameWithoutExtension(projectFile.Name).ToLowerInvariant(),
Project = projectFile.FullName.Replace('\\', '/'),
};
application.Services.Add(service);
}
return application;
@ -82,82 +83,22 @@ namespace Microsoft.Tye.ConfigModel
var application = deserializer.Deserialize<ConfigApplication>(reader);
application.Source = file;
// Deserialization makes all collection properties null so make sure they are non-null so
// other code doesn't need to react
foreach (var service in application.Services)
{
if (service.Project == null)
{
continue;
}
if (!TryGetLaunchProfile(new FileInfo(Path.Combine(file.DirectoryName, service.Project)), out var launchProfile))
{
continue;
}
// Bindings can be null here from deserialization.
service.Bindings ??= new List<ConfigServiceBinding>();
PopulateFromLaunchProfile(service, launchProfile);
service.Configuration ??= new List<ConfigConfigurationSource>();
service.Volumes ??= new List<ConfigVolume>();
}
return application;
}
private static bool TryGetLaunchProfile(FileInfo file, out JsonElement launchProfile)
{
var launchSettingsPath = Path.Combine(file.DirectoryName, "Properties", "launchSettings.json");
if (!File.Exists(launchSettingsPath))
foreach (var ingress in application.Ingress)
{
launchProfile = default;
return false;
ingress.Bindings ??= new List<ConfigIngressBinding>();
ingress.Rules ??= new List<ConfigIngressRule>();
}
// If there's a launchSettings.json, then use it to get addresses
var root = JsonSerializer.Deserialize<JsonElement>(File.ReadAllText(launchSettingsPath));
var key = NameSanitizer.SanitizeToIdentifier(Path.GetFileNameWithoutExtension(file.Name));
var profiles = root.GetProperty("profiles");
return profiles.TryGetProperty(key, out launchProfile);
}
private static ConfigService? CreateService(FileInfo file)
{
if (!TryGetLaunchProfile(file, out var launchProfile))
{
return null;
}
var service = new ConfigService()
{
Name = Path.GetFileNameWithoutExtension(file.Name).ToLowerInvariant(),
Project = file.FullName.Replace('\\', '/'),
};
PopulateFromLaunchProfile(service, launchProfile);
return service;
}
private static void PopulateFromLaunchProfile(ConfigService service, JsonElement launchProfile)
{
if (service.Bindings.Count == 0 && launchProfile.TryGetProperty("applicationUrl", out var applicationUrls))
{
var addresses = applicationUrls.GetString().Split(';', StringSplitOptions.RemoveEmptyEntries);
foreach (var address in addresses)
{
var uri = new Uri(address);
service.Bindings.Add(new ConfigServiceBinding()
{
// Don't use ports from launch profiles. These are very likely to be the same defaults (5000, 5001)
// that were generated when the project was created, and so they will almost always conflict
// between multiple apps.
AutoAssignPort = true,
Protocol = uri.Scheme
});
}
}
// Don't apply environment variables here. We don't want to carry forward settings from
// development into production.
return application;
}
}
}

29
src/Microsoft.Tye.Hosting/HttpProxyService.cs

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
@ -72,7 +73,7 @@ namespace Microsoft.Tye.Hosting
var port = service.PortMap[binding.Port.Value][i];
ports.Add(port);
var url = $"{binding.Protocol ?? "http"}://localhost:{port}";
var url = $"{binding.Protocol}://localhost:{port}";
addresses.Add(url);
}
@ -100,23 +101,27 @@ namespace Microsoft.Tye.Hosting
var uris = new List<Uri>();
// HTTP before HTTPS (this might change once we figure out certs...)
var targetBinding = targetServiceDescription.Bindings.FirstOrDefault(b => b.Protocol == "http") ??
targetServiceDescription.Bindings.FirstOrDefault(b => b.Protocol == "https");
if (targetBinding == null)
{
_logger.LogInformation("Service {ServiceName} does not have any HTTP or HTTPs bindings", targetServiceDescription.Name);
continue;
}
// For each of the target service replicas, get the base URL
// based on the replica port
for (int i = 0; i < targetServiceDescription.Replicas; i++)
{
foreach (var binding in targetServiceDescription.Bindings)
{
if (binding.Port == null)
{
continue;
}
var port = target.PortMap[binding.Port.Value][i];
var url = $"{binding.Protocol ?? "http"}://localhost:{port}";
uris.Add(new Uri(url));
}
var port = target.PortMap[targetBinding.Port!.Value][i];
var url = $"{targetBinding.Protocol}://localhost:{port}";
uris.Add(new Uri(url));
}
_logger.LogInformation("Service {ServiceName} is using {Urls}", targetServiceDescription.Name, string.Join(",", uris.Select(u => u.ToString())));
// The only load balancing strategy here is round robin
long count = 0;
RequestDelegate del = context =>

Loading…
Cancel
Save