Client Update: Support Terminate client and ChefClient_Name in cscfg.

This commit is contained in:
Jack Cragoe 2015-02-27 15:16:13 -08:00
Родитель 1492ac10bd
Коммит 4237ca716c
4 изменённых файлов: 255 добавлений и 59 удалений

Просмотреть файл

@ -25,43 +25,21 @@ namespace Microsoft.OnlinePublishing.Chef
/// <summary>
/// Stop the Chef Client windows service with the default wait time of 1 minute.
/// </summary>
public static void Stop()
/// <param name="terminateOnFailure">Should the process terminate the processes of the Client service if it failes to stop in alloted time.</param>
public static void Stop(bool terminateOnFailure)
{
Stop(new TimeSpan(0, 1, 0));
Stop(new TimeSpan(0, 1, 0), terminateOnFailure);
}
/// <summary>
/// Stop the Chef Client windows service.
/// </summary>
/// <param name="timeToWait">Wait time for operation to complete.</param>
public static void Stop(TimeSpan timeToWait)
/// <param name="terminateOnFailure">Should the process terminate the processes of the Client service if it failes to stop in alloted time.</param>
public static void Stop(TimeSpan timeToWait, bool terminateOnFailure)
{
try
{
// Stop Chef Client
Trace.TraceInformation("Chef Client - attempting to stop the Chef Client windows service.");
using (var chefService = new ServiceController("chef-client"))
{
if (chefService != null && chefService.Status != ServiceControllerStatus.Stopped)
{
chefService.Stop();
chefService.WaitForStatus(ServiceControllerStatus.Stopped, timeToWait);
Trace.TraceInformation("Chef Client - Chef Client windows service Stopped.");
}
else
{
Trace.TraceInformation("Chef Client - Chef Client windows service is not running.");
}
}
}
catch (System.ServiceProcess.TimeoutException)
{
Trace.TraceInformation("Chef Client - failed to stop Chef Client in time allotted [{0}].", timeToWait);
}
catch (InvalidOperationException e)
{
Trace.TraceInformation("Chef Client - Invalid Operation, is the role running with elevated privileges. Ex:{0}.", e.ToString());
}
var service = new WindowsService() { Name = "chef-client", TerminateOnFailure = terminateOnFailure, TimeToWait = timeToWait };
service.Stop();
}
/// <summary>
@ -69,37 +47,21 @@ namespace Microsoft.OnlinePublishing.Chef
/// </summary>
public static void Start()
{
try
{
RoleEnvironment.Changing += ChefConfigChanging;
RoleEnvironment.StatusCheck += Chef_StatusCheck;
Start(new TimeSpan( 0, 1, 0) );
}
// Start Chef Client - wait 30 seconds
Trace.TraceInformation("Chef Client - Attempting to start Chef-Client.");
using (var chefService = new ServiceController("chef-client"))
{
if (chefService != null && chefService.Status != ServiceControllerStatus.Running)
{
chefService.Start();
chefService.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 30));
Trace.TraceInformation("Chef Client - Chef-Client Started.");
}
else
{
Trace.TraceInformation("Chef Client - Chef-Client previously running.");
}
}
/// <summary>
/// Start Chef Client windows service.
/// </summary>
public static void Start(TimeSpan timeToWait)
{
RoleEnvironment.Changing += ChefConfigChanging;
RoleEnvironment.StatusCheck += Chef_StatusCheck;
ClientService.statusCheckFilePath = CloudConfigurationManager.GetSetting("ChefClient_SetBusyCheck");
}
catch (System.ServiceProcess.TimeoutException)
{
Trace.TraceInformation("Chef Client - failed to start Chef Client within time range.");
}
catch (InvalidOperationException e)
{
Trace.TraceInformation("Chef Client - Invalid Operation, is the role running with elevated privileges. Ex:{0}.", e.ToString());
}
// Start Chef Client - wait 30 seconds
var service = new WindowsService() { Name = "chef-client", TimeToWait = timeToWait };
service.Start();
ClientService.statusCheckFilePath = CloudConfigurationManager.GetSetting("ChefClient_SetBusyCheck");
}
/// <summary>
@ -114,6 +76,7 @@ namespace Microsoft.OnlinePublishing.Chef
{
return;
}
e.SetBusy();
}
@ -139,7 +102,7 @@ namespace Microsoft.OnlinePublishing.Chef
c.ConfigurationSettingName == "ChefClient_Role" ||
c.ConfigurationSettingName == "ChefClient_Environment" ))
{
Stop(new TimeSpan(0, 0, 5));
Stop(new TimeSpan(0, 0, 30), true);
e.Cancel = true;
}
}

Просмотреть файл

@ -0,0 +1,174 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="WindowsService.cs" company="Microsoft Corporation">
// Copyright (C) Microsoft. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Microsoft.OnlinePublishing.Chef
{
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Management;
/// <summary>
/// Windows Service gives the ability to stop a windows service (namely chef-client).
/// If the service failes to stop in a given timespan, then the service and its child processes are terminated.
/// </summary>
class WindowsService
{
/// <summary>
/// Gets or sets the Name of the Windows Service.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the alloted time to wait during shutdown sequence.
/// </summary>
public TimeSpan TimeToWait { get; set; }
/// <summary>
/// Gets or sets whether or not to terminate processes upon failure to stop teh service in the alloted time to wait.
/// </summary>
public bool TerminateOnFailure { get; set; }
/// <summary>
/// Start Chef Client windows service.
/// </summary>
public void Start()
{
try
{
// Start Chef Client - wait 30 seconds
Trace.TraceInformation("{0} - Attempting to start {0}.", Name);
using (var chefService = new ServiceController(Name))
{
if (chefService != null && chefService.Status != ServiceControllerStatus.Running)
{
chefService.Start();
chefService.WaitForStatus(ServiceControllerStatus.Running, TimeToWait);
Trace.TraceInformation("{0} - {0} Started.", Name);
}
else
{
Trace.TraceInformation("{0} - {0} previously running.", Name);
}
}
}
catch (System.ServiceProcess.TimeoutException)
{
Trace.TraceInformation("{0} - failed to start Chef Client within time range.", Name);
}
catch (InvalidOperationException e)
{
Trace.TraceInformation("{0} - Invalid Operation, is the role running with elevated privileges. Ex:{1}.", Name, e.ToString());
}
}
/// <summary>
/// Stop the Windows Service, if Terminate on Failure, then terminate process and all child spawn.
/// </summary>
public void Stop()
{
try
{
// Stop Chef Client
Trace.TraceInformation("{0} - attempting to stop the {0} windows service.", Name);
using (var chefService = new ServiceController(Name))
{
if (chefService != null && chefService.Status != ServiceControllerStatus.Stopped)
{
chefService.Stop();
chefService.WaitForStatus(ServiceControllerStatus.Stopped, TimeToWait);
Trace.TraceInformation("{0} - {0} windows service Stopped.", Name);
}
else
{
Trace.TraceInformation("{0} - {0} windows service is not running.", Name);
}
}
}
catch (System.ServiceProcess.TimeoutException)
{
Trace.TraceInformation("{0} - failed to stop {0} in time allotted [{1}].", Name, TimeToWait);
if (TerminateOnFailure)
{
Trace.TraceInformation("{0} - attempting to terminate service process and its children.", Name);
KillService();
}
}
catch (InvalidOperationException e)
{
Trace.TraceInformation("{0} - Invalid Operation, is the role running with elevated privileges. Ex:{1}.", Name, e.ToString());
}
}
/// <summary>
/// Locate process by service name and kill it and its spawn.
/// </summary>
private void KillService()
{
var searcher = new ManagementObjectSearcher(
"SELECT * " +
"FROM Win32_Service " +
"WHERE Name=\"" + Name + "\"");
var collection = searcher.Get();
foreach (var item in collection)
{
var serviceProcessId = (UInt32)item["ProcessId"];
KillSpawnedProcesses(serviceProcessId);
Trace.TraceInformation("{0} - Killing Service process with Id [{1}].", Name, serviceProcessId);
KillProcess(serviceProcessId);
}
}
/// <summary>
/// Kill process and all spawn. Travers all children for multi generation children.
/// </summary>
/// <param name="parentProcessId">Parent ID</param>
private void KillSpawnedProcesses(UInt32 parentProcessId)
{
Trace.TraceInformation("{0} - Finding processes spawned by process with Id [" + parentProcessId + "]", Name);
var searcher = new ManagementObjectSearcher(
"SELECT * " +
"FROM Win32_Process " +
"WHERE ParentProcessId=" + parentProcessId);
var collection = searcher.Get();
if (collection.Count > 0)
{
Trace.TraceInformation("{0} - Killing [{1}] processes spawned by process with Id [{2}].", Name, collection.Count, parentProcessId);
foreach (var item in collection)
{
var childProcessId = (UInt32)item["ProcessId"];
KillSpawnedProcesses(childProcessId);
KillProcess(childProcessId);
}
}
}
/// <summary>
/// Attempt to kill process. It can ocurr that the process has been killed prior to getting to this statement as the process tree is being killed.
/// </summary>
/// <param name="processId">ID of process to kill.</param>
private void KillProcess(uint processId)
{
try
{
if ((int)processId != Process.GetCurrentProcess().Id)
{
var process = Process.GetProcessById((int)processId);
Trace.TraceInformation("{0} - Killing process [{1}] with Id [{2}]", Name, process.ProcessName, processId);
process.Kill();
}
}
catch (ArgumentException e)
{
Trace.TraceInformation("{0} - failed to find process [{1}]. Process already killed. Ex:{2}", Name, processId, e.ToString());
}
catch (System.ComponentModel.Win32Exception e)
{
Trace.TraceInformation("{0} - failed to kill process [{1}]. Ex:{2}", Name, processId, e.ToString());
}
}
}
}

Просмотреть файл

@ -64,6 +64,14 @@ if ($config -and $config.name)
$name = $config.name
}
# Allow to pull from CSCFG allowing for easier targetting of node name prefix, this can only be set on initial deployment
# once the node name is established, the exisitng name will always win.
$cscfgName = Get-CloudServiceConfigurationSettingValue "ChefClient_Name"
if ($cscfgName)
{
$name = $cscfgName
}
# Add Instance number to the node name
Write-Output "Role Instance Name: $($roleInstance.Id)"
$nodeName = $($roleInstance.Id).Replace($roleName, $name)

Просмотреть файл

@ -0,0 +1,51 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Microsoft.OnlinePublishing.InstallationSDK.ChefClientInstaller</id>
<version>0.1.61</version>
<title>Microsoft Online Publishing Installation SDK Chef Client Installer</title>
<authors>ampdmi@microsoft.com</authors>
<owners>ampdmi@microsoft.com</owners>
<projectUrl>http://aka.ms/msompinstallationsdk</projectUrl>
<description>PowerShell scripts for performing installation of Chef Client for Azure Roles.</description>
<tags>Online-Media-Publishing MS-Internal-Only Azure Installation Deployment SDK</tags>
<releaseNotes>
0.1.61:
- Terminate the Chef-Client processes if the service fails to stop in the allotted time.
0.1.5:
- Added Role and Environment to be cscfg configurable. ChefClient_ServerUrl, ChefClient_Role,
and ChefClient_Environment are now configurable from loud service config updates.
- Add a set instance busy check file and configuarable path in ChefClient_SetBusyCheck
0.1.4:
- Added support for deploying the node-based encrypted_data_bag_secret
0.1.3:
- Removed Client MSI from package so it meets size requirements for MS-NuGet and NuGet.
0.1.2:
- Update to client to create base folder structure and PSModulePath.
0.1.1:
- BugFix:Upon OS update, client service is not reinstalled.
0.1.0:
- Initial Release
See http://aka.ms/msompinstallationsdk for complete release history.
Join the ampdmitalk DG to ask questions and take part in the deployment and monitoring community.
</releaseNotes>
<dependencies>
<dependency id="Microsoft.OnlinePublishing.InstallationSDK" version="1.1.0"/>
</dependencies>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System.ServiceProcess"/>
<frameworkAssembly assemblyName="System.Management"/>
</frameworkAssemblies>
</metadata>
<files>
<file src="..\Nuget\Install.ps1" target="tools" />
<!-- InstallationSDK.ChefClientInstaller Module -->
<file src="..\Modules\InstallationSDK.ChefClientInstaller\bin\InstallationSDK.ChefClientInstaller\InstallationSDK.ChefClientInstaller.psm1" target="content\Deployment\Modules\InstallationSDK.ChefClientInstaller" />
<file src="..\Modules\InstallationSDK.ChefClientInstaller\bin\InstallationSDK.ChefClientInstaller\InstallationSDK.ChefClientInstaller.psd1" target="content\Deployment\Modules\InstallationSDK.ChefClientInstaller" />
<file src="..\Modules\InstallationSDK.ChefClientInstaller\bin\InstallationSDK.ChefClientInstaller\resources\Readme.txt" target="content\Deployment\Modules\InstallationSDK.ChefClientInstaller\resources" />
<!-- <file src="..\Modules\InstallationSDK.ChefClientInstaller\bin\InstallationSDK.ChefClientInstaller\resources\*.msi" target="content\Deployment\Modules\InstallationSDK.ChefClientInstaller\resources" /> -->
<file src="..\Modules\InstallationSDK.ChefClientInstaller\bin\InstallationSDK.ChefClientInstaller\code\*.*" target="content" />
<file src="..\Modules\InstallationSDK.ChefClientInstaller\bin\InstallationSDK.ChefClientInstaller\script\*.*" target="content\Deployment" />
</files>
</package>