Add Nginx Deployer

This commit is contained in:
BrennanConroy 2016-03-17 20:07:12 +00:00
parent b06a84457d
commit 22eab75005
6 changed files with 156 additions and 15 deletions

View File

@ -61,9 +61,9 @@ namespace Microsoft.AspNetCore.Server.Testing
public string EnvironmentName { get; set; }
public string ApplicationHostConfigTemplateContent { get; set; }
public string ServerConfigTemplateContent { get; set; }
public string ApplicationHostConfigLocation { get; set; }
public string ServerConfigLocation { get; set; }
public string SiteName { get; set; }

View File

@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Server.Testing
IISExpress,
IIS,
WebListener,
Kestrel
Kestrel,
Nginx
}
}

View File

@ -40,6 +40,8 @@ namespace Microsoft.AspNetCore.Server.Testing
case ServerType.WebListener:
case ServerType.Kestrel:
return new SelfHostDeployer(deploymentParameters, logger);
case ServerType.Nginx:
return new NginxDeployer(deploymentParameters, logger);
default:
throw new NotSupportedException(
string.Format("Found no deployers suitable for server type '{0}' with the current runtime.",

View File

@ -50,19 +50,19 @@ namespace Microsoft.AspNetCore.Server.Testing
private CancellationToken StartIISExpress(Uri uri)
{
if (!string.IsNullOrWhiteSpace(DeploymentParameters.ApplicationHostConfigTemplateContent))
if (!string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigTemplateContent))
{
// Pass on the applicationhost.config to iis express. With this don't need to pass in the /path /port switches as they are in the applicationHost.config
// We take a copy of the original specified applicationHost.Config to prevent modifying the one in the repo.
DeploymentParameters.ApplicationHostConfigTemplateContent =
DeploymentParameters.ApplicationHostConfigTemplateContent
DeploymentParameters.ServerConfigTemplateContent =
DeploymentParameters.ServerConfigTemplateContent
.Replace("[ApplicationPhysicalPath]", DeploymentParameters.ApplicationPath)
.Replace("[PORT]", uri.Port.ToString());
DeploymentParameters.ApplicationHostConfigLocation = Path.GetTempFileName();
DeploymentParameters.ServerConfigLocation = Path.GetTempFileName();
File.WriteAllText(DeploymentParameters.ApplicationHostConfigLocation, DeploymentParameters.ApplicationHostConfigTemplateContent);
File.WriteAllText(DeploymentParameters.ServerConfigLocation, DeploymentParameters.ServerConfigTemplateContent);
}
var webroot = DeploymentParameters.ApplicationPath;
@ -71,9 +71,9 @@ namespace Microsoft.AspNetCore.Server.Testing
webroot = Path.Combine(webroot, "wwwroot");
}
var parameters = string.IsNullOrWhiteSpace(DeploymentParameters.ApplicationHostConfigLocation) ?
var parameters = string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigLocation) ?
string.Format("/port:{0} /path:\"{1}\" /trace:error", uri.Port, webroot) :
string.Format("/site:{0} /config:{1} /trace:error", DeploymentParameters.SiteName, DeploymentParameters.ApplicationHostConfigLocation);
string.Format("/site:{0} /config:{1} /trace:error", DeploymentParameters.SiteName, DeploymentParameters.ServerConfigLocation);
var iisExpressPath = GetIISExpressPath();
@ -140,18 +140,18 @@ namespace Microsoft.AspNetCore.Server.Testing
{
ShutDownIfAnyHostProcess(_hostProcess);
if (!string.IsNullOrWhiteSpace(DeploymentParameters.ApplicationHostConfigLocation)
&& File.Exists(DeploymentParameters.ApplicationHostConfigLocation))
if (!string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigLocation)
&& File.Exists(DeploymentParameters.ServerConfigLocation))
{
// Delete the temp applicationHostConfig that we created.
try
{
File.Delete(DeploymentParameters.ApplicationHostConfigLocation);
File.Delete(DeploymentParameters.ServerConfigLocation);
}
catch (Exception exception)
{
// Ignore delete failures - just write a log.
Logger.LogWarning("Failed to delete '{config}'. Exception : {exception}", DeploymentParameters.ApplicationHostConfigLocation, exception.Message);
Logger.LogWarning("Failed to delete '{config}'. Exception : {exception}", DeploymentParameters.ServerConfigLocation, exception.Message);
}
}

View File

@ -0,0 +1,138 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using Microsoft.AspNetCore.Server.Testing.Common;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Testing
{
/// <summary>
/// Deployer for Kestrel on Nginx.
/// </summary>
public class NginxDeployer : SelfHostDeployer
{
private string _configFile;
private readonly int _waitTime = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;
public NginxDeployer(DeploymentParameters deploymentParameters, ILogger logger)
: base(deploymentParameters, logger)
{
}
public override DeploymentResult Deploy()
{
_configFile = Path.GetTempFileName();
var uri = new Uri(DeploymentParameters.ApplicationBaseUriHint);
var redirectUri = $"http://localhost:{TestUriHelper.FindFreePort()}";
var exitToken = StartSelfHost(new Uri(redirectUri));
SetupNginx(redirectUri, uri);
// Wait for App to be loaded since Nginx returns 502 instead of 503 when App isn't loaded
// Target actual address to avoid going through Nginx proxy
using (var httpClient = new HttpClient())
{
var response = RetryHelper.RetryRequest(() =>
{
return httpClient.GetAsync(redirectUri);
}, Logger).Result;
if (!response.IsSuccessStatusCode)
{
throw new InvalidOperationException("Deploy failed");
}
}
return new DeploymentResult
{
WebRootLocation = DeploymentParameters.ApplicationPath,
DeploymentParameters = DeploymentParameters,
ApplicationBaseUri = uri.ToString(),
HostShutdownToken = exitToken
};
}
private void SetupNginx(string redirectUri, Uri originalUri)
{
// copy nginx.conf template and replace pertinent information
DeploymentParameters.ServerConfigTemplateContent = DeploymentParameters.ServerConfigTemplateContent
.Replace("[user]", Environment.GetEnvironmentVariable("LOGNAME"))
.Replace("[listenPort]", originalUri.Port.ToString())
.Replace("[redirectUri]", redirectUri)
.Replace("[pidFile]", Path.Combine(DeploymentParameters.ApplicationPath, Guid.NewGuid().ToString()));
File.WriteAllText(_configFile, DeploymentParameters.ServerConfigTemplateContent);
var startInfo = new ProcessStartInfo
{
FileName = "nginx",
Arguments = $"-c {_configFile}",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
// Trying a work around for https://github.com/aspnet/Hosting/issues/140.
RedirectStandardInput = true
};
using (var runNginx = new Process() { StartInfo = startInfo })
{
runNginx.ErrorDataReceived += (sender, dataArgs) =>
{
if (!string.IsNullOrEmpty(dataArgs.Data))
{
Logger.LogWarning("nginx: " + dataArgs.Data);
}
};
runNginx.OutputDataReceived += (sender, dataArgs) =>
{
if (!string.IsNullOrEmpty(dataArgs.Data))
{
Logger.LogInformation("nginx: " + dataArgs.Data);
}
};
runNginx.Start();
runNginx.BeginErrorReadLine();
runNginx.BeginOutputReadLine();
runNginx.WaitForExit(_waitTime);
if (runNginx.ExitCode != 0)
{
throw new Exception("Failed to start Nginx");
}
}
}
public override void Dispose()
{
if (!string.IsNullOrEmpty(_configFile))
{
var startInfo = new ProcessStartInfo
{
FileName = "nginx",
Arguments = $"-s stop -c {_configFile}",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
// Trying a work around for https://github.com/aspnet/Hosting/issues/140.
RedirectStandardInput = true
};
using (var runNginx = new Process() { StartInfo = startInfo })
{
runNginx.Start();
runNginx.WaitForExit(_waitTime);
}
File.Delete(_configFile);
}
base.Dispose();
}
}
}

View File

@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Testing
};
}
private CancellationToken StartSelfHost(Uri uri)
protected CancellationToken StartSelfHost(Uri uri)
{
string executableName;
string executableArgs = string.Empty;