Compare commits

...

1 Commits

Author SHA1 Message Date
David Fowler eec0a71371 WIP 6 years ago
  1. 14
      src/Microsoft.Tye.Hosting/HttpProxyService.cs
  2. 1
      src/Microsoft.Tye.Hosting/Microsoft.Tye.Hosting.csproj
  3. 171
      src/Microsoft.Tye.Hosting/TyeHost.cs
  4. 4
      test/E2ETest/ReplicaStoppingTests.cs
  5. 4
      test/E2ETest/TyeRunTests.cs
  6. 2
      test/Test.Infrastructure/TestHelpers.cs

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

@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Proxy;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Tye.Hosting.Model; using Microsoft.Tye.Hosting.Model;
@ -24,7 +25,7 @@ namespace Microsoft.Tye.Hosting
{ {
public partial class HttpProxyService : IApplicationProcessor public partial class HttpProxyService : IApplicationProcessor
{ {
private List<WebApplication> _webApplications = new List<WebApplication>(); private List<IHost> _webApplications = new List<IHost>();
private readonly ILogger _logger; private readonly ILogger _logger;
private ConcurrentDictionary<int, bool> _readyPorts; private ConcurrentDictionary<int, bool> _readyPorts;
@ -50,11 +51,16 @@ namespace Microsoft.Tye.Hosting
if (service.Description.RunInfo is IngressRunInfo runInfo) if (service.Description.RunInfo is IngressRunInfo runInfo)
{ {
var host = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder =>
{
builder.Configure(app =>
{
});
});
var builder = new WebApplicationBuilder(); var builder = new WebApplicationBuilder();
builder.Services.AddSingleton<MatcherPolicy, IngressHostMatcherPolicy>();
builder.Logging.AddProvider(new ServiceLoggerProvider(service.Logs));
var addresses = new List<string>(); var addresses = new List<string>();

1
src/Microsoft.Tye.Hosting/Microsoft.Tye.Hosting.csproj

@ -20,7 +20,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Bedrock.Framework" Version="0.1.38-alpha.gd25d5b37ad" /> <PackageReference Include="Bedrock.Framework" Version="0.1.38-alpha.gd25d5b37ad" />
<PackageReference Include="FeatherHttp" Version="0.1.42-alpha.gf06a8747e7" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="3.0.0" /> <PackageReference Include="Serilog.Extensions.Hosting" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" /> <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />

171
src/Microsoft.Tye.Hosting/TyeHost.cs

@ -5,13 +5,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -32,6 +34,7 @@ namespace Microsoft.Tye.Hosting
private Microsoft.Extensions.Logging.ILogger? _logger; private Microsoft.Extensions.Logging.ILogger? _logger;
private IHostApplicationLifetime? _lifetime; private IHostApplicationLifetime? _lifetime;
private ICollection<string>? _addresses;
private AggregateApplicationProcessor? _processor; private AggregateApplicationProcessor? _processor;
private readonly Application _application; private readonly Application _application;
@ -46,7 +49,11 @@ namespace Microsoft.Tye.Hosting
public Application Application => _application; public Application Application => _application;
public WebApplication? DashboardWebApplication { get; set; } public IHost? DashboardWebApplication { get; set; }
public ICollection<string>? Addresses => _addresses;
public Extensions.Logging.ILogger? Logger => _logger;
// An additional sink that output will be piped to. Useful for testing. // An additional sink that output will be piped to. Useful for testing.
public ILogEventSink? Sink { get; set; } public ILogEventSink? Sink { get; set; }
@ -71,25 +78,24 @@ namespace Microsoft.Tye.Hosting
} }
} }
public async Task<WebApplication> StartAsync() public async Task<IHost> StartAsync()
{ {
var app = BuildWebApplication(_application, _options, Sink); var app = BuildWebApplication(_application, _options, Sink);
DashboardWebApplication = app; DashboardWebApplication = app;
_logger = app.Logger; _addresses = DashboardWebApplication.Services.GetRequiredService<IServer>().Features.Get<IServerAddressesFeature>().Addresses;
_lifetime = app.ApplicationLifetime; _logger = DashboardWebApplication.Services.GetRequiredService<ILogger<TyeHost>>();
_lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
_logger.LogInformation("Executing application from {Source}", _application.Source); _logger.LogInformation("Executing application from {Source}", _application.Source);
ConfigureApplication(app);
_replicaRegistry = new ReplicaRegistry(_application.ContextDirectory, _logger); _replicaRegistry = new ReplicaRegistry(_application.ContextDirectory, _logger);
_processor = CreateApplicationProcessor(_replicaRegistry, _options, _logger); _processor = CreateApplicationProcessor(_replicaRegistry, _options, _logger);
await app.StartAsync(); await app.StartAsync();
_logger.LogInformation("Dashboard running on {Address}", app.Addresses.First()); _logger.LogInformation("Dashboard running on {Address}", _addresses.First());
try try
{ {
@ -103,88 +109,79 @@ namespace Microsoft.Tye.Hosting
if (_options.Dashboard) if (_options.Dashboard)
{ {
OpenDashboard(app.Addresses.First()); OpenDashboard(_addresses.First());
} }
return app; return app;
} }
private static WebApplication BuildWebApplication(Application application, HostOptions options, ILogEventSink? sink) private IHost BuildWebApplication(Application application, HostOptions options, ILogEventSink? sink)
{ {
var args = new List<string>(); return Host.CreateDefaultBuilder()
if (options.Port.HasValue) .UseSerilog((context, configuration) =>
{
args.Add("--port");
args.Add(options.Port.Value.ToString(CultureInfo.InvariantCulture));
}
var builder = WebApplication.CreateBuilder(args.ToArray());
// Logging for this application
builder.Host.UseSerilog((context, configuration) =>
{
var logLevel = options.LogVerbosity switch
{ {
Verbosity.Quiet => LogEventLevel.Warning, var logLevel = options.LogVerbosity switch
Verbosity.Info => LogEventLevel.Information, {
Verbosity.Debug => LogEventLevel.Verbose, Verbosity.Quiet => LogEventLevel.Warning,
_ => default Verbosity.Info => LogEventLevel.Information,
}; Verbosity.Debug => LogEventLevel.Verbose,
_ => default
configuration };
.MinimumLevel.Is(logLevel)
.Filter.ByExcluding(Matching.FromSource("Microsoft.AspNetCore")) configuration
.Filter.ByExcluding(Matching.FromSource("Microsoft.Extensions")) .MinimumLevel.Is(logLevel)
.Filter.ByExcluding(Matching.FromSource("Microsoft.Hosting")) .Filter.ByExcluding(Matching.FromSource("Microsoft.AspNetCore"))
.Enrich .Filter.ByExcluding(Matching.FromSource("Microsoft.Extensions"))
.FromLogContext() .Filter.ByExcluding(Matching.FromSource("Microsoft.Hosting"))
.WriteTo .Enrich
.Console(); .FromLogContext()
.WriteTo
if (sink is object) .Console();
if (sink is object)
{
configuration.WriteTo.Sink(sink, logLevel);
}
})
.ConfigureServices(services =>
{ {
configuration.WriteTo.Sink(sink, logLevel); services.AddRazorPages(o => o.RootDirectory = "/Dashboard/Pages");
} services.AddServerSideBlazor();
}); services.AddOptions<StaticFileOptions>()
.PostConfigure(o =>
builder.Services.AddRazorPages(o => o.RootDirectory = "/Dashboard/Pages"); {
var fileProvider = new ManifestEmbeddedFileProvider(typeof(TyeHost).Assembly, "wwwroot");
builder.Services.AddServerSideBlazor();
// Make sure we don't remove the existing file providers (blazor needs this)
builder.Services.AddOptions<StaticFileOptions>() o.FileProvider = new CompositeFileProvider(o.FileProvider, fileProvider);
.PostConfigure(o => });
services.AddCors(
options =>
{
options.AddPolicy(
"default",
policy =>
{
policy
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddSingleton(application);
})
.ConfigureWebHostDefaults(builder =>
{ {
var fileProvider = new ManifestEmbeddedFileProvider(typeof(TyeHost).Assembly, "wwwroot"); var port = ComputePort(options.Port);
// Make sure we don't remove the existing file providers (blazor needs this)
o.FileProvider = new CompositeFileProvider(o.FileProvider, fileProvider);
});
builder.Services.AddCors( builder.Configure(ConfigureApplication)
options => .UseUrls($"http://127.0.0.1:{port}");
{ })
options.AddPolicy( .Build();
"default",
policy =>
{
policy
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddSingleton(application);
var app = builder.Build();
return app;
} }
private void ConfigureApplication(WebApplication app) private void ConfigureApplication(IApplicationBuilder app)
{ {
var port = ComputePort(app);
app.Listen($"http://127.0.0.1:{port}");
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
app.UseCors("default"); app.UseCors("default");
@ -195,13 +192,16 @@ namespace Microsoft.Tye.Hosting
var api = new TyeDashboardApi(); var api = new TyeDashboardApi();
api.MapRoutes(app); app.UseEndpoints(endpoints =>
{
api.MapRoutes(endpoints);
app.MapBlazorHub(); endpoints.MapBlazorHub();
app.MapFallbackToPage("/_Host"); endpoints.MapFallbackToPage("/_Host");
});
} }
private int ComputePort(WebApplication app) private int ComputePort(int? port)
{ {
// logic for computing the port: // logic for computing the port:
// - we allow the user to specify the port... if they don't // - we allow the user to specify the port... if they don't
@ -210,17 +210,16 @@ namespace Microsoft.Tye.Hosting
// - we don't want to cause conflicts with any of the users known bindings // - we don't want to cause conflicts with any of the users known bindings
// or something else running. // or something else running.
var port = app.Configuration["port"]; if (port.HasValue)
if (!string.IsNullOrEmpty(port))
{ {
// Port was passed in at the command-line, use it! // Port was passed in at the command-line, use it!
return int.Parse(port, NumberStyles.Number, CultureInfo.InvariantCulture); return port.Value;
} }
if (IsPortInUseByBinding(_application, DefaultPort)) if (IsPortInUseByBinding(_application, DefaultPort))
{ {
// Port has been reserved for the app. // Port has been reserved for the app.
app.Logger.LogInformation("Default dashboard port {DefaultPort} has been reserved by the application, choosing random port.", DefaultPort); // app.Logger.LogInformation("Default dashboard port {DefaultPort} has been reserved by the application, choosing random port.", DefaultPort);
return AutodetectPort; return AutodetectPort;
} }
@ -229,7 +228,7 @@ namespace Microsoft.Tye.Hosting
return DefaultPort; return DefaultPort;
} }
// Port is in use by something already running. // Port is in use by something already running.
app.Logger.LogInformation("Default dashboard port {DefaultPort} is in use, choosing random port.", DefaultPort); // app.Logger.LogInformation("Default dashboard port {DefaultPort} is in use, choosing random port.", DefaultPort);
return AutodetectPort; return AutodetectPort;
} }

4
test/E2ETest/ReplicaStoppingTests.cs

@ -112,7 +112,7 @@ namespace E2ETest
{ {
await StartHostAndWaitForReplicasToStart(host); await StartHostAndWaitForReplicasToStart(host);
var uri = new Uri(host.DashboardWebApplication!.Addresses.First()); var uri = new Uri(host.Addresses!.First());
await execute(host, uri!); await execute(host, uri!);
} }
@ -120,7 +120,7 @@ namespace E2ETest
{ {
if (host.DashboardWebApplication != null) if (host.DashboardWebApplication != null)
{ {
var uri = new Uri(host.DashboardWebApplication!.Addresses.First()); var uri = new Uri(host.Addresses!.First());
using var client = new HttpClient(); using var client = new HttpClient();

4
test/E2ETest/TyeRunTests.cs

@ -1105,7 +1105,7 @@ services:
{ {
await StartHostAndWaitForReplicasToStart(host); await StartHostAndWaitForReplicasToStart(host);
var uri = new Uri(host.DashboardWebApplication!.Addresses.First()); var uri = new Uri(host.Addresses!.First());
await execute(host.Application, uri!); await execute(host.Application, uri!);
} }
@ -1113,7 +1113,7 @@ services:
{ {
if (host.DashboardWebApplication != null) if (host.DashboardWebApplication != null)
{ {
var uri = new Uri(host.DashboardWebApplication!.Addresses.First()); var uri = new Uri(host.Addresses!.First());
using var client = new HttpClient(); using var client = new HttpClient();

2
test/Test.Infrastructure/TestHelpers.cs

@ -246,7 +246,7 @@ namespace Test.Infrastructure
{ {
static async Task Purge(TyeHost host) static async Task Purge(TyeHost host)
{ {
var logger = host.DashboardWebApplication!.Logger; var logger = host.Logger;
var replicaRegistry = new ReplicaRegistry(host.Application.ContextDirectory, logger); var replicaRegistry = new ReplicaRegistry(host.Application.ContextDirectory, logger);
var processRunner = new ProcessRunner(logger, replicaRegistry, new ProcessRunnerOptions()); var processRunner = new ProcessRunner(logger, replicaRegistry, new ProcessRunnerOptions());
var dockerRunner = new DockerRunner(logger, replicaRegistry); var dockerRunner = new DockerRunner(logger, replicaRegistry);

Loading…
Cancel
Save