Skip to content

Commit

Permalink
Linux - Support for container restart trigger (projectkudu#2529)
Browse files Browse the repository at this point in the history
Linux - Support for container restart trigger

Linux App Service now supports a generic file-based communication mechanism
for requesting a restart of the app container. This was previously implemented
in a limited fashion only for the "Docker CI" webhook. This generalizes the
implementation and also requests a restart after a git deployment by default,
in addition to receipt of a Docker webhook request.
  • Loading branch information
nickwalkmsft authored Aug 25, 2017
1 parent 0cd9814 commit 7429a14
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 15 deletions.
5 changes: 4 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.gitattributes text=auto

*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
Expand Down Expand Up @@ -47,4 +49,5 @@
*.fsproj text=auto
*.dbproj text=auto
*.sln text=auto eol=crlf
*.sh text eol=lf
*.sh text eol=lf
*.resx text=auto
14 changes: 14 additions & 0 deletions Kudu.Contracts/Settings/DeploymentSettingsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,19 @@ public static bool TouchWebConfigAfterDeployment(this IDeploymentSettingsManager
{
return settings.GetValue(SettingsKeys.TouchWebConfigAfterDeployment) != "0";
}

public static bool IsDockerCiEnabled(this IDeploymentSettingsManager settings)
{
string value = settings.GetValue(SettingsKeys.DockerCiEnabled);
return StringUtils.IsTrueLike(value);
}

public static bool RestartAppContainerOnGitDeploy(this IDeploymentSettingsManager settings)
{
string value = settings.GetValue(SettingsKeys.LinuxRestartAppContainerAfterDeployment);

// Default is true
return value == null || StringUtils.IsTrueLike(value);
}
}
}
2 changes: 2 additions & 0 deletions Kudu.Contracts/Settings/SettingsKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,7 @@ public static class SettingsKeys
public const string DisableDeploymentOnPush = "SCM_DISABLE_DEPLOY_ON_PUSH";
public const string TouchWebConfigAfterDeployment = "SCM_TOUCH_WEBCONFIG_AFTER_DEPLOYMENT";
public const string MaxRandomDelayInSec = "SCM_MAX_RANDOM_START_DELAY";
public const string DockerCiEnabled = "DOCKER_ENABLE_CI";
public const string LinuxRestartAppContainerAfterDeployment = "SCM_RESTART_APP_CONTAINER_AFTER_DEPLOYMENT";
}
}
7 changes: 7 additions & 0 deletions Kudu.Core/Deployment/DeploymentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class DeploymentManager : IDeploymentManager
private readonly IDeploymentStatusManager _status;
private readonly IWebHooksManager _hooksManager;

private const string RestartTriggerReason = "App deployment";
private const string XmlLogFile = "log.xml";
public const string TextLogFile = "log.log";
private const string TemporaryDeploymentIdPrefix = "temp-";
Expand Down Expand Up @@ -225,6 +226,12 @@ public async Task DeployAsync(IRepository repository, ChangeSet changeSet, strin

// Perform the build deployment of this changeset
await Build(changeSet, tracer, deployStep, repository, deploymentAnalytics);

if (!OSDetector.IsOnWindows() && _settings.RestartAppContainerOnGitDeploy())
{
logger.Log(Resources.Log_TriggeringContainerRestart);
LinuxContainerRestartTrigger.RequestContainerRestart(_environment, RestartTriggerReason);
}
}
catch (Exception ex)
{
Expand Down
42 changes: 42 additions & 0 deletions Kudu.Core/Infrastructure/LinuxContainerRestartTrigger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Globalization;
using System.IO;
using Kudu.Core.Helpers;

namespace Kudu.Core.Infrastructure
{
// Utility for touching the restart trigger file on Linux, which will restart the
// site container.
// Contents of the trigger file are irrelevant but this leaves a small explanation for
// users who stumble on it.
public static class LinuxContainerRestartTrigger
{
private const string CONFIG_DIR_NAME = "config";
private const string TRIGGER_FILENAME = "restartTrigger.txt";

private static readonly string FILE_CONTENTS_FORMAT = String.Concat(
"Modifying this file will trigger a restart of the app container.",
System.Environment.NewLine, System.Environment.NewLine,
"The last modification Kudu made to this file was at {0}, for the following reason: {1}.",
System.Environment.NewLine);

public static void RequestContainerRestart(IEnvironment environment, string reason)
{
if (OSDetector.IsOnWindows())
{
throw new NotSupportedException("RequestContainerRestart not supported on Windows");
}

var restartTriggerPath = Path.Combine(environment.SiteRootPath, CONFIG_DIR_NAME, TRIGGER_FILENAME);

FileSystemHelpers.CreateDirectory(Path.GetDirectoryName(restartTriggerPath));

var fileContents = String.Format(
FILE_CONTENTS_FORMAT,
DateTimeOffset.UtcNow.ToString("o", CultureInfo.InvariantCulture),
reason);

FileSystemHelpers.WriteAllText(restartTriggerPath, fileContents);
}
}
}
1 change: 1 addition & 0 deletions Kudu.Core/Kudu.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@
<Compile Include="Infrastructure\IFileSystemWatcher.cs" />
<Compile Include="Infrastructure\InstanceIdUtility.cs" />
<Compile Include="Infrastructure\IServerConfiguration.cs" />
<Compile Include="Infrastructure\LinuxContainerRestartTrigger.cs" />
<Compile Include="Infrastructure\NaiveFileSystemWatcher.cs" />
<Compile Include="Infrastructure\SecurityUtility.cs" />
<Compile Include="Infrastructure\PathUtils\PathLinuxUtility.cs" />
Expand Down
9 changes: 9 additions & 0 deletions Kudu.Core/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Kudu.Core/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,7 @@
<data name="Error_FailedToLocateBash" xml:space="preserve">
<value>Unable to locate 'bash.exe'. Make sure it is installed.</value>
</data>
<data name="Log_TriggeringContainerRestart" xml:space="preserve">
<value>App container will begin restart within 10 seconds.</value>
</data>
</root>
35 changes: 21 additions & 14 deletions Kudu.Services/Docker/DockerController.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
using Kudu.Core.Helpers;
using Kudu.Core.Tracing;
using System;
using System.IO;
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Kudu.Core.Helpers;
using Kudu.Core.Tracing;
using Kudu.Contracts.Settings;
using Kudu.Core.Infrastructure;
using Kudu.Core;

namespace Kudu.Services.Docker
{
public class DockerController : ApiController
{
const string TimestampDirectory = "/home/site/config";
ITraceFactory _traceFactory;
private const string RESTART_REASON = "Docker CI webhook";
private readonly ITraceFactory _traceFactory;
private readonly IDeploymentSettingsManager _settings;
private readonly IEnvironment _environment;

public DockerController(ITraceFactory traceFactory)
public DockerController(ITraceFactory traceFactory, IDeploymentSettingsManager settings, IEnvironment environment)
{
_traceFactory = traceFactory;
_settings = settings;
_environment = environment;
}

[HttpPost]
Expand All @@ -27,21 +33,22 @@ public HttpResponseMessage ReceiveHook()
}

var tracer = _traceFactory.GetTracer();
using (tracer.Step("Docker.SetDockerTimestamp"))
using (tracer.Step("Docker.ReceiveWebhook"))
{
string timestampPath = Path.Combine(TimestampDirectory, "dockerTimestamp.txt");
try
{
Directory.CreateDirectory(Path.GetDirectoryName((timestampPath)));
File.WriteAllText(timestampPath, DateTime.UtcNow.ToString());
if (_settings.IsDockerCiEnabled())
{
LinuxContainerRestartTrigger.RequestContainerRestart(_environment, RESTART_REASON);
}
}
catch (Exception e)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, e.Message);
return Request.CreateResponse(HttpStatusCode.InternalServerError, e.Message);
}

return Request.CreateResponse(HttpStatusCode.OK);
}

return Request.CreateResponse(HttpStatusCode.OK);
}
}
}

0 comments on commit 7429a14

Please sign in to comment.