PowerShell DSCのConifgurationを引いて監視を効率化する
第3回PoewrShell勉強会でLTやってきたのでスライドとコードを掲載。
始めてのLTだったので優しくしてください><
技術評論社のChef本に、Nodeオブジェクト上に監視用のattributeを起こして、監視を自動化する実装が書いてあって、それにインスパイアを受けました。PowerShell DSCでも似たようなことができないかと思い、挑戦してみました。
コンフィグ実行時に-ConfigurationDataで渡すオブジェクトを利用すれば、同じようなことができます。
[Configuration] -ConfigurationData $ConfigurationData
こんな書き方をしますが、この$ConfigurationDataオブジェクトがChefでいうNodeオブジェクトにあたるので、よしなに必要な情報をリストに入れてあげて(オブジェクト名や中の要素等、すべてが自由書式)、このオブジェクトを流用する形になりますね。
監視用のモジュールというか関数というか別スクリプトを起こす気がなかったのと、二番煎じになるので今回は別のやり方にしました。(近いうちに書いてみます)
PowerShell DSCとChefで大きく違う点は、Nodeオブジェクトもレシピも一緒くたに書けてしまう点です。そのため、複数名で運用する想定なら、ある程度書き方の規約を決める必要があると思います。…とりあえずChefのファイル郡構成を模す形にするのがいいかもですね。
話がそれました。今回は$ConfigurationDataを作り込んで監視情報を引くというより、その情報自体がDSCサーバーに記録されて引けるので、そちらを利用するものを書きました。
[ノード名].mofファイルのbasenameや、Service Resourceの記述が引ければ、それだけでも手堅い監視ができちゃいますよね。
ということで下記が監視スクリプトです。
$ConfPath = ".mofファイル格納ディレクトリのパス" (Get-ChildItem $ConfPath).Fullname | ForEach-Object { $NodeName = (Split-Path $_ -Leaf).Replace(".mof","") $Session = New-CimSession -ComputerName $NodeName $DscConfig = Get-DscConfiguration -CimSession $Session if (!$?){ if(!(Test-Connection $NodeName)) { . Error-Action; echo "$NodeName is Node Down!" } continue } $DscConfig | Where-Object {$_.CimClass.CimClassName -eq "MSFT_ServiceResource" } | ForEach-Object { $ServiceName = $_.Name if ($_.State -eq "Stopped") { . Error-Action; echo "$NodeName : $ServiceName is Stopping!" } } } function Error-Action { echo "Danger!!" }
Cimの認証(-credentialオプション)は省略してます。よしなに実装です。
エラー時のアクションは例示です。メール送信とか書く気力がなかったんです。こんな書き方をした奴の頭がそもそもデンジャー。
DSCサーバーから実行することを想定しています。DSCサーバーの外から実行する場合は.mofファイルを嘗める実装になります。
PULLする構成の場合、.mofはPULLノードから引ける必要があるので、監視サーバーもPULLノードにして、SMBなりで見に行けばスマートですかね。
.mofファイルを嘗める実装、スライドに書いていませんでしたが、実は書いてありました。(むしろ最初は.mofファイルを嘗めて「ハイ、完成」でしたが、Get-DscConfigurationが現状のステータスを拾ってくれるのに気付いて書き直した次第。)
で、下記の通りです。
# Param $ConfPath = ".mofファイル格納ディレクトリのパス" [bool]$Flag = $False $AllNodes = @() # Get .mof file information (Get-ChildItem $ConfPath).Fullname | ForEach-Object { $NodeName = (Split-Path $_ -Leaf).Replace(".mof","") $Services = @() get-content $_ | ForEach-Object { if ($_ -like '*`[Service`]*') { $Flag = $True } if ($_ -like ' Name =*' -and $Flag ) { $Flag = $False $Services += $_.split('`"')[1] } } $Node = @(@{"NodeName"=$NodeName;"Services"=$Services}) $AllNodes += $Node } # Monitoring $AllNodes | ForEach-Object { $NodeName = $_.NodeName if(Test-Connection $NodeName) { $_.Services | ForEach-Object { if ((Get-Service -ComputerName $NodeName -Name $_).Status -ne "Running") { . Error-Action; echo "$NodeName : $_ is Stopping!" } } } else { . Error-Action; echo "$NodeName is Node Down!" } } # Alert or Start-DSCConfiguration. function Error-Action { echo "Danger!!" }
あとは例示で出したコンフィグを記念に。SNMPとBitLockerの機能を入れて、関連サービスを「自動起動」にして、開始するだけのものです。実際にこんなConfiguration書く人はおらんでしょう。どないサーバーやねん、て。
$ConfigurationData = @{ AllNodes = @( @{NodeName = "192.168.100.150"}, @{NodeName = "192.168.100.151"} ) } Configuration EXConfig2 { Node $AllNodes.NodeName { WindowsFeature SNMP { Ensure = "Present" Name = "SNMP-Service" } WindowsFeature BL { Ensure = "Present" Name = "BitLocker" } Service SNMP { Name = "SNMP" StartupType = "Automatic" State = "Running" } Service SNMPTRAP { Name = "SNMPTRAP" StartupType = "Automatic" State = "Running" } Service BDESVC { Name = "BDESVC" StartupType = "Automatic" State = "Running" } } } EXConfig2 -ConfigurationData $ConfigurationData
近日中にSyntaxHighLight処理しときます。