Client Update: Support Terminate client and ChefClient_Name in cscfg.
This commit is contained in:
Родитель
1492ac10bd
Коммит
4237ca716c
|
@ -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>
|
Загрузка…
Ссылка в новой задаче