tl;dr

Windows 上で起動しているプロセスを Serverspec でテストする際に調べたので自分メモ。

参考

serverspec - RSpec tests for your servers configured by CFEngine, Puppet, Chef, Ansible, Itamae or anything else even by hand

github.com


serverspec.org

specinfra - Command Execution Framework for serverspec, itamae and so on

github.com

メモ

やりたかったこと

対象の Windows ホスト上で自分で作った Python スクリプトが引数も含めて正常に動いているかについてチェックしたかった

オレオレスクリプト

以下のようにオレオレスクリプトを起動する。

PS C:pathtoscripts> start python.exe .o-re-no-service02.py

実行すると以下のようにコマンドプロンプトが立ち上がって、その中でスクリプトが起動する。

20160320190357

Serverspec on Windows ではどんな風にプロセスの情報を取得しているのか(超ザックリと)

こちらのドキュメントに書かれているように、Serverspec の command については全て PowerShell スクリプトを実行するようになっているので、プロセスの情報を取得する場合には以下のようなスクリプトが実行される(Cmdlet が実行される)。

例えば…

describe process("python.exe") do
  it { should be_running }
end

というテストがある場合には、Serverspec の process.rb から以下のメソッドが呼ばれる。

  def running?
      pid = @runner.get_process(@name, :format => "pid=").stdout
      not pid.empty?
    end

次に Specinfra の process.rb 内の以下のメソッドが呼ばる。

def get(process, opts)
      column = opts[:format].chomp '='

      case column
      when 'pid'
        # map 'pid' to its windows equivalent
        get_process_property(process, 'processid')
      when 'user'
        %Q!gwmi win32_process -filter "name = '#{process}'" | select -first 1 | %{$_.getowner().user}!
      when 'group'
        # no concept of process group on Windows
        raise NotImplementedError.new('Unable to get process group on Windows')
      else
        get_process_property(process, column)
      end
    end

そして、マッチャが should be_running の場合には、opts[:format] には pid が指定されているので、同じ process.rb 内の以下の privateメソッドを get_process_property(process, processid) で呼び出す。

def get_process_property(process, property)
      %Q!Get-WmiObject Win32_Process -Filter "name = '#{process}'" | select -First 1 #{property} -ExpandProperty #{property}!
    end

試しに上記のメソッド内で実行される PowerShell スクリプトを実行してみる。

PS C:pathtoscripts> Get-WmiObject Win32_Process -Filter "name = 'python.exe'" | select -First 1 processid -ExpandProperty processid

以下のようにプロセス ID が返ってくる。

PS C:pathtoscripts> Get-WmiObject Win32_Process -Filter "name = 'python.exe'" | select -First 1 processid -ExpandProperty processid
764

ということで…

引数も含めてプロセスが起動していることを確認したい場合にどうするか。

先ほどの PowerShell スクリプトをもう一度実行してみる。但し、以下のように絞込は行わず、全てのプロパティを出力してみる。

PS C:pathtoscripts> Get-WmiObject Win32_Process -Filter "name = 'python.exe'" | select -First 1

以下のように出力される。

__GENUS                    : 2
__CLASS                    : Win32_Process
__SUPERCLASS               : CIM_Process
__DYNASTY                  : CIM_ManagedSystemElement
__RELPATH                  : Win32_Process.Handle="764"
__PROPERTY_COUNT           : 45
__DERIVATION               : {CIM_Process, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER                   : WIN-LLA3FAS3UBE
__NAMESPACE                : rootcimv2
__PATH                     : \WIN-LLA3FAS3UBErootcimv2:Win32_Process.Handle="764"
Caption                    : python.exe
CommandLine                : "C:Python27python.exe" .o-re-no-service02.py
CreationClassName          : Win32_Process
CreationDate               : 20160320094741.949928+000
CSCreationClassName        : Win32_ComputerSystem
CSName                     : WIN-LLA3FAS3UBE
Description                : python.exe
ExecutablePath             : C:Python27python.exe
ExecutionState             :
Handle                     : 764
HandleCount                : 68
InstallDate                :
KernelModeTime             : 156001
MaximumWorkingSetSize      : 1380
MinimumWorkingSetSize      : 200
Name                       : python.exe
OSCreationClassName        : Win32_OperatingSystem
OSName                     : Microsoft Windows Server 2012 Standard|C:Windows|DeviceHarddisk0Partition2
OtherOperationCount        : 2233
OtherTransferCount         : 36862
PageFaults                 : 1731
PageFileUsage              : 3292
ParentProcessId            : 1032
PeakPageFileUsage          : 3292
PeakVirtualSize            : 68542464
PeakWorkingSetSize         : 6712
Priority                   : 8
PrivatePageCount           : 3371008
ProcessId                  : 764
QuotaNonPagedPoolUsage     : 7
QuotaPagedPoolUsage        : 124
QuotaPeakNonPagedPoolUsage : 7
QuotaPeakPagedPoolUsage    : 124
ReadOperationCount         : 118
ReadTransferCount          : 493182
SessionId                  : 2
Status                     :
TerminationDate            :
ThreadCount                : 1
UserModeTime               : 624004
VirtualSize                : 68542464
WindowsVersion             : 6.2.9200
WorkingSetSize             : 6873088
WriteOperationCount        : 1797
WriteTransferCount         : 83834
PSComputerName             : WIN-LLA3FAS3UBE
ProcessName                : python.exe
Handles                    : 68
VM                         : 68542464
WS                         : 6873088
Path                       : C:Python27python.exe

上記を見ると、CommandLine というプロパティにスクリプトを実行した際の引数も出力されているので、この CommandLine を利用すれば良さそうということで、以下のようにテストを書いた。

describe process("python.exe") do
  it { should be_running }
  its(:CommandLine) { should match /o-re-no-service02.py/ }
end

そして、テスト

以下のようにテストは無事に通った。

20160320194736

良かった。

ということで

process リソースについては

Cmdlet の Get-WmiObject Win32_Process を利用していることが解ったので、必要に応じて Get-WmiObject Win32_Process の出力結果からチェックしたいプロパティをピックアップしてテストを書けば良いと思う。

以上

メモでした! 間違ってたらごめんなさい!

元記事はこちら

Serverspec on Windows の process リソースの使い方メモ