Update IISDeployer and its base class

This commit is contained in:
Troy Dai 2016-01-11 00:58:40 -08:00
parent 48451bdabc
commit ccde330978
6 changed files with 135 additions and 200 deletions

View File

@ -42,11 +42,11 @@ namespace Microsoft.AspNet.Server.Testing
EnvironmentVariables.Add(new KeyValuePair<string, string>("ASPNET_DETAILEDERRORS", "true"));
}
public ServerType ServerType { get; private set; }
public ServerType ServerType { get; }
public RuntimeFlavor RuntimeFlavor { get; private set; }
public RuntimeFlavor RuntimeFlavor { get; }
public RuntimeArchitecture RuntimeArchitecture { get; private set; }
public RuntimeArchitecture RuntimeArchitecture { get; }
/// <summary>
/// Suggested base url for the deployed application. The final deployed url could be
@ -77,8 +77,6 @@ namespace Microsoft.AspNet.Server.Testing
/// </summary>
public bool PublishWithNoSource { get; set; }
public string DnxRuntime { get; set; }
/// <summary>
/// Environment variables to be set before starting the host.
/// Not applicable for IIS Scenarios.

View File

@ -5,8 +5,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.AspNet.Testing;
using Microsoft.Extensions.Logging;
@ -19,128 +17,78 @@ namespace Microsoft.AspNet.Server.Testing
/// </summary>
public abstract class ApplicationDeployer : IApplicationDeployer
{
/// <summary>
/// Example: runtimes/dnx-coreclr-win-x64.1.0.0-rc1-15844/bin
/// </summary>
protected string ChosenRuntimePath { get; set; }
private readonly Stopwatch _stopwatch = new Stopwatch();
/// <summary>
/// Examples: dnx-coreclr-win-x64.1.0.0-rc1-15844, dnx-mono.1.0.0-rc1-15844
/// </summary>
protected string ChosenRuntimeName { get; set; }
protected DeploymentParameters DeploymentParameters { get; private set; }
protected ILogger Logger { get; private set; }
protected Stopwatch StopWatch { get; private set; } = new Stopwatch();
protected string OSPrefix
{
get
{
if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Linux)
{
return "linux";
}
else if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Darwin)
{
return "darwin";
}
else if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows)
{
return "win";
}
else
{
throw new InvalidOperationException("Unrecognized operating system");
}
}
}
protected string DnuCommandName
{
get
{
if (TestPlatformHelper.IsWindows)
{
return "dnu.cmd";
}
else
{
return "dnu";
}
}
}
protected string DnxCommandName
{
get
{
if (TestPlatformHelper.IsWindows)
{
return "dnx.exe";
}
else
{
return "dnx";
}
}
}
public abstract DeploymentResult Deploy();
public ApplicationDeployer(
DeploymentParameters deploymentParameters,
ILogger logger)
public ApplicationDeployer(DeploymentParameters deploymentParameters, ILogger logger)
{
DeploymentParameters = deploymentParameters;
Logger = logger;
DnuCommandName = TestPlatformHelper.IsWindows ? "dnu.cmd" : "dnu";
DnxCommandName = TestPlatformHelper.IsWindows ? "dnx.exe" : "dnx";
}
protected string PopulateChosenRuntimeInformation()
protected DeploymentParameters DeploymentParameters { get; }
protected ILogger Logger { get; }
protected string DnuCommandName { get; }
protected string DnxCommandName { get; }
protected string TargetRuntimeName { get; private set; }
protected string TargetRuntimeBinPath { get; private set; }
protected string ToolingRuntimeBinPath { get; private set; }
public abstract DeploymentResult Deploy();
protected void PickRuntime()
{
string currentRuntimeBinPath = PlatformServices.Default.Runtime.RuntimePath;
var currentRuntimeBinPath = PlatformServices.Default.Runtime.RuntimePath;
Logger.LogInformation($"Current runtime path is : {currentRuntimeBinPath}");
string targetRuntimeName;
var currentRuntimeFullName = new DirectoryInfo(currentRuntimeBinPath).Parent.Name;
var currentRuntimeVersionParts = currentRuntimeFullName.Split(new char[] { '.' }, 2);
if (currentRuntimeVersionParts.Length < 2)
{
throw new ArgumentNullException($"The current runtime bin path points to a runtime name doesn't indicate a version: {currentRuntimeBinPath}.");
}
var currentRuntimeVersion = currentRuntimeVersionParts[1];
var runtimeHome = new DirectoryInfo(currentRuntimeBinPath).Parent.Parent.FullName;
Logger.LogInformation($"Runtime home folder: {runtimeHome}");
if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Mono)
{
targetRuntimeName = "dnx-mono";
// TODO: review on mono
TargetRuntimeName = $"dnx-mono.{currentRuntimeVersion}";
TargetRuntimeBinPath = Path.Combine(runtimeHome, TargetRuntimeName, "bin");
ToolingRuntimeBinPath = TargetRuntimeBinPath;
}
else
{
targetRuntimeName = new StringBuilder()
.Append("dnx")
.Append((DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr) ? "-coreclr" : "-clr")
.Append($"-{OSPrefix}")
.Append((DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x86) ? "-x86" : "-x64")
.ToString();
var flavor = DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr ? "coreclr" : "clr";
var architecture = DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x86 ? "x86" : "x64";
// tooling runtime will stick to coreclr so as to prevent long path issue during publishing
ToolingRuntimeBinPath = Path.Combine(runtimeHome, $"dnx-coreclr-{GetOSPrefix()}-{architecture}.{currentRuntimeVersion}", "bin");
TargetRuntimeName = $"dnx-{flavor}-{GetOSPrefix()}-{architecture}.{currentRuntimeVersion}";
TargetRuntimeBinPath = Path.Combine(runtimeHome, TargetRuntimeName, "bin");
}
var targetRuntimeBinPath = Regex.Replace(
currentRuntimeBinPath,
"dnx-(mono|((clr|coreclr)-(win|linux|darwin)-(x86|x64)))",
targetRuntimeName,
RegexOptions.IgnoreCase);
var targetRuntimeBinDir = new DirectoryInfo(targetRuntimeBinPath);
if (targetRuntimeBinDir == null || !targetRuntimeBinDir.Exists)
if (!Directory.Exists(ToolingRuntimeBinPath) || !Directory.Exists(TargetRuntimeBinPath))
{
throw new Exception($"Requested runtime at location '{targetRuntimeBinPath}' does not exist.Please make sure it is installed before running test.");
throw new Exception($"Requested runtime '{ToolingRuntimeBinPath}' or '{TargetRuntimeBinPath}; does not exist. Please make sure it is installed before running test.");
}
ChosenRuntimePath = targetRuntimeBinDir.FullName;
ChosenRuntimeName = targetRuntimeBinDir.Parent.Name;
DeploymentParameters.DnxRuntime = ChosenRuntimeName;
Logger.LogInformation($"Chosen runtime path is {ChosenRuntimePath}");
Logger.LogInformation($"Pick target runtime {TargetRuntimeBinPath}");
Logger.LogInformation($"Pick tooling runtime {ToolingRuntimeBinPath}");
// Work around win7 search path issues.
var newPath = ChosenRuntimePath + Path.PathSeparator + Environment.GetEnvironmentVariable("PATH");
var newPath = TargetRuntimeBinPath + Path.PathSeparator + Environment.GetEnvironmentVariable("PATH");
DeploymentParameters.EnvironmentVariables.Add(new KeyValuePair<string, string>("PATH", newPath));
return ChosenRuntimeName;
}
protected void DnuPublish(string publishRoot = null)
@ -150,9 +98,9 @@ namespace Microsoft.AspNet.Server.Testing
var noSource = DeploymentParameters.PublishWithNoSource ? "--no-source" : string.Empty;
var command = DeploymentParameters.Command ?? "web";
var parameters = $"publish {DeploymentParameters.ApplicationPath} -o {DeploymentParameters.PublishedApplicationRootPath}"
+ $" --runtime {DeploymentParameters.DnxRuntime} {noSource} --iis-command {command}";
+ $" --runtime {TargetRuntimeName} {noSource} --iis-command {command}";
var dnuPath = Path.Combine(ChosenRuntimePath, DnuCommandName);
var dnuPath = Path.Combine(ToolingRuntimeBinPath, DnuCommandName);
Logger.LogInformation($"Executing command {dnuPath} {parameters}");
var startInfo = new ProcessStartInfo
@ -166,8 +114,8 @@ namespace Microsoft.AspNet.Server.Testing
};
var hostProcess = new Process() { StartInfo = startInfo };
hostProcess.ErrorDataReceived += (sender, dataArgs) => { Logger.LogError(dataArgs.Data ?? string.Empty); };
hostProcess.OutputDataReceived += (sender, dataArgs) => { Logger.LogInformation(dataArgs.Data ?? string.Empty); };
hostProcess.ErrorDataReceived += (sender, dataArgs) => { Logger.LogWarning(dataArgs.Data ?? string.Empty); };
hostProcess.OutputDataReceived += (sender, dataArgs) => { Logger.LogTrace(dataArgs.Data ?? string.Empty); };
hostProcess.Start();
hostProcess.BeginErrorReadLine();
hostProcess.BeginOutputReadLine();
@ -180,10 +128,9 @@ namespace Microsoft.AspNet.Server.Testing
DeploymentParameters.ApplicationPath =
(DeploymentParameters.ServerType == ServerType.IISExpress ||
DeploymentParameters.ServerType == ServerType.IIS) ?
DeploymentParameters.ServerType == ServerType.IIS) ?
Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "wwwroot") :
Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "approot", "src",
new DirectoryInfo(DeploymentParameters.ApplicationPath).Name);
Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "approot", "src", new DirectoryInfo(DeploymentParameters.ApplicationPath).Name);
Logger.LogInformation($"dnu publish finished with exit code : {hostProcess.ExitCode}");
}
@ -299,15 +246,27 @@ namespace Microsoft.AspNet.Server.Testing
protected void StartTimer()
{
Logger.LogInformation($"Deploying {DeploymentParameters.ToString()}");
StopWatch.Start();
_stopwatch.Start();
}
protected void StopTimer()
{
StopWatch.Stop();
Logger.LogInformation("[Time]: Total time taken for this test variation '{t}' seconds", StopWatch.Elapsed.TotalSeconds);
_stopwatch.Stop();
Logger.LogInformation("[Time]: Total time taken for this test variation '{t}' seconds", _stopwatch.Elapsed.TotalSeconds);
}
public abstract void Dispose();
protected static string GetOSPrefix()
{
switch (PlatformServices.Default.Runtime.OperatingSystemPlatform)
{
case Platform.Linux: return "linux";
case Platform.Darwin: return "darwin";
case Platform.Windows: return "win";
default:
throw new InvalidOperationException("Unrecognized operating system");
}
}
}
}

View File

@ -33,7 +33,7 @@ namespace Microsoft.AspNet.Server.Testing
{
case ServerType.IISExpress:
return new IISExpressDeployer(deploymentParameters, logger);
#if NET451
#if DNX451
case ServerType.IIS:
return new IISDeployer(deploymentParameters, logger);
#endif
@ -48,4 +48,4 @@ namespace Microsoft.AspNet.Server.Testing
}
}
}
}
}

View File

@ -1,12 +1,13 @@
// 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.
#if NET451
#if DNX451
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Xml;
using Microsoft.Extensions.Logging;
using Microsoft.Web.Administration;
@ -36,10 +37,10 @@ namespace Microsoft.AspNet.Server.Testing
_application = new IISApplication(DeploymentParameters, Logger);
DeploymentParameters.DnxRuntime = PopulateChosenRuntimeInformation();
PickRuntime();
// Publish to IIS root\application folder.
DnuPublish(publishRoot: _application.WebSiteRootFolder);
DnuPublish();
// Drop a json file instead of setting environment variable.
SetAspEnvironmentWithJson();
@ -59,19 +60,11 @@ namespace Microsoft.AspNet.Server.Testing
WebRootLocation = DeploymentParameters.ApplicationPath,
DeploymentParameters = DeploymentParameters,
// Accomodate the vdir name.
ApplicationBaseUri = new UriBuilder(Uri.UriSchemeHttp, "localhost", IISApplication.Port, _application.VirtualDirectoryName).Uri.AbsoluteUri + "/",
ApplicationBaseUri = new UriBuilder(Uri.UriSchemeHttp, "localhost", _application.Port).Uri.AbsoluteUri + "/",
HostShutdownToken = _hostShutdownToken.Token
};
}
private void SetAspEnvironmentWithJson()
{
// Drop a hosting.json with Hosting:Environment information.
Logger.LogInformation("Creating hosting.json file with Hosting:Environment.");
var jsonFile = Path.Combine(DeploymentParameters.ApplicationPath, "hosting.json");
File.WriteAllText(jsonFile, string.Format("{ \"Hosting:Environment\":\"{0}\" }", DeploymentParameters.EnvironmentName));
}
public override void Dispose()
{
if (_application != null)
@ -83,6 +76,8 @@ namespace Microsoft.AspNet.Server.Testing
}
TriggerHostShutdown(_hostShutdownToken);
Thread.Sleep(TimeSpan.FromSeconds(3));
}
CleanPublishedOutput();
@ -91,94 +86,79 @@ namespace Microsoft.AspNet.Server.Testing
StopTimer();
}
private void SetAspEnvironmentWithJson()
{
////S Drop a hosting.json with Hosting:Environment information.
// Logger.LogInformation("Creating hosting.json file with Hosting:Environment.");
// var jsonFile = Path.Combine(DeploymentParameters.ApplicationPath, "hosting.json");
// File.WriteAllText(jsonFile, string.Format("{ \"Hosting:Environment\":\"{0}\" }", DeploymentParameters.EnvironmentName));
}
private class IISApplication
{
private const string WebSiteName = "ASPNETTESTRUNS";
private readonly ServerManager _serverManager = new ServerManager();
private readonly DeploymentParameters _deploymentParameters;
private readonly ILogger _logger;
private ApplicationPool _applicationPool;
private Application _application;
private Site _website;
public string VirtualDirectoryName { get; set; }
// Always create website with the same port.
public const int Port = 5100;
public string WebSiteRootFolder
{
get
{
return Path.Combine(
Environment.GetEnvironmentVariable("SystemDrive") + @"\",
"inetpub",
WebSiteName);
}
}
public IISApplication(DeploymentParameters deploymentParameters, ILogger logger)
{
_deploymentParameters = deploymentParameters;
_logger = logger;
WebSiteName = CreateTestSiteName();
Port = FindFreePort();
}
public int Port { get; }
public string WebSiteName { get; }
public string WebSiteRootFolder => $"{Environment.GetEnvironmentVariable("SystemDrive")}\\inetpub\\{WebSiteName}";
public void Deploy()
{
VirtualDirectoryName = new DirectoryInfo(_deploymentParameters.ApplicationPath).Parent.Name;
_applicationPool = CreateAppPool(VirtualDirectoryName);
_application = Website.Applications.Add("/" + VirtualDirectoryName, _deploymentParameters.ApplicationPath);
_application.ApplicationPoolName = _applicationPool.Name;
_serverManager.Sites.Add(WebSiteName, _deploymentParameters.ApplicationPath, Port);
_serverManager.CommitChanges();
}
private Site Website
{
get
{
_website = _serverManager.Sites.Where(s => s.Name == WebSiteName).FirstOrDefault();
if (_website == null)
{
_website = _serverManager.Sites.Add(WebSiteName, WebSiteRootFolder, Port);
}
return _website;
}
}
private ApplicationPool CreateAppPool(string appPoolName)
{
var applicationPool = _serverManager.ApplicationPools.Add(appPoolName);
applicationPool.ManagedRuntimeVersion = string.Empty;
applicationPool.Enable32BitAppOnWin64 = (_deploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x86);
_logger.LogInformation("Created {bit} application pool '{name}' with runtime version {runtime}.",
_deploymentParameters.RuntimeArchitecture, applicationPool.Name,
string.IsNullOrEmpty(applicationPool.ManagedRuntimeVersion) ? "that is default" : applicationPool.ManagedRuntimeVersion);
return applicationPool;
}
public void StopAndDeleteAppPool()
{
_logger.LogInformation("Stopping application pool '{name}' and deleting application.", _applicationPool.Name);
if (_applicationPool != null)
if (string.IsNullOrEmpty(WebSiteName))
{
_applicationPool.Stop();
return;
}
// Remove the application from website.
if (_application != null)
var siteToRemove = _serverManager.Sites.FirstOrDefault(site => site.Name == WebSiteName);
if (siteToRemove != null)
{
_application = Website.Applications.Where(a => a.Path == _application.Path).FirstOrDefault();
Website.Applications.Remove(_application);
_serverManager.ApplicationPools.Remove(_serverManager.ApplicationPools[_applicationPool.Name]);
siteToRemove.Stop();
_serverManager.Sites.Remove(siteToRemove);
_serverManager.CommitChanges();
_logger.LogInformation("Successfully stopped application pool '{name}' and deleted application from IIS.", _applicationPool.Name);
}
}
private static int FindFreePort()
{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
return ((IPEndPoint)socket.LocalEndPoint).Port;
}
}
private string CreateTestSiteName()
{
if (!string.IsNullOrEmpty(_deploymentParameters.SiteName))
{
return $"{_deploymentParameters.SiteName}{DateTime.Now.ToString("yyyyMMddHHmmss")}";
}
else
{
return $"testsite{DateTime.Now.ToString("yyyyMMddHHmmss")}";
}
}
}
}
}
#endif
#endif

View File

@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Server.Testing
// Start timer
StartTimer();
DeploymentParameters.DnxRuntime = PopulateChosenRuntimeInformation();
PickRuntime();
// For now we always auto-publish. Otherwise we'll have to write our own local web.config for the HttpPlatformHandler
DeploymentParameters.PublishApplicationBeforeDeployment = true;

View File

@ -2,11 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Microsoft.AspNet.Testing;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Server.Testing
@ -28,7 +26,7 @@ namespace Microsoft.AspNet.Server.Testing
// Start timer
StartTimer();
DeploymentParameters.DnxRuntime = PopulateChosenRuntimeInformation();
PickRuntime();
if (DeploymentParameters.PublishApplicationBeforeDeployment)
{
@ -55,7 +53,7 @@ namespace Microsoft.AspNet.Server.Testing
commandName = "run";
}
var dnxPath = Path.Combine(ChosenRuntimePath, DnxCommandName);
var dnxPath = Path.Combine(TargetRuntimeBinPath, DnxCommandName);
var dnxArgs = $"-p \"{DeploymentParameters.ApplicationPath}\" {commandName} " +
$"--server.urls {DeploymentParameters.ApplicationBaseUriHint} " +
$"--server {(DeploymentParameters.ServerType == ServerType.WebListener ? "Microsoft.AspNet.Server.WebListener" : "Microsoft.AspNet.Server.Kestrel")}";