LoginSignup
1
0

More than 5 years have passed since last update.

ChefからInSpecにattributeをJSON経由で渡したら、シンボルが文字列になっていた

Last updated at Posted at 2018-06-13

問題

ChefレシピからattibuteをJSONでテストに渡していたら、symbolを想定していた変数がstringとして設定されていた。

考えてみれば当たり前だが、JSONの書式にはsymbolに相当するものが無い。
JSON.pretty_generateなどでJSONに変換した時点でstringに置き換えられていた。

recipes/default.rb

node.default['service']['foo']['action'] = [:start, :enable]

...

require 'json'
IO.write('/tmp/node.json', JSON.pretty_generate(node.to_hash))

対応1: 文字列の前提でテストを作る

シンプルに比較対象をシンボルから文字列にする。。。
まあchefのattributeでsymbolが必要なのはactionとnotifies, subscribes くらいの様な気がするので、主にそこだけ気をつければ良いのだが。。。。


hash['service'].each do |s_name, s_attr|
  describe service(s_name) do
    it { should be_enabled }     if s_attr['action'].include?('enable')
    it { should_not be_enabled } if s_attr['action'].include?('disable')
    it { should be_running }     if s_attr['action'].include?('start')
    it { should_not be_running } if s_attr['action'].include?('stop')
  end
end

対応2: symbolのまま渡す方法は無いか。。

レシピ側で、.inspectメソッドでハッシュを文字列として書き出し、

recipes/default.rb

...

hash = node.to_hash
hash['run_list'] = node['run_list'] # ここだけ読み込み時のエラー回避の為に置き換え
IO.write('/tmp/node.hash', hash.inspect)

テストシナリオではevalで読み込ませれば、うまく行きそうに思えた。。。。が、

test/integration/default/default_test.rb
node = {}
eval('node = ' + `cat /tmp/node.hash`)

...

残念

試してみると、Chefはリモート、InSpecはローカルで実行されていて、InSpecのテストから直接はリモートのファイルを参照できなかった。

shell veriferにして $KITCHEN_USERNAME などを使うか、テストスクリプト中で ssh などを行えばできるのだろうが、、、
その様なことを考えなくて良いjson( ).params によるjson渡しが楽すぎて、シンボルをそのまま渡すことはとりあえず断念。

追記:kitchen exec を用いることで1ノードなら対応できた

test/integration/default/default_test.rb
node = {}
eval('node = ' + ` kitchen exec --command='cat /tmp/node.hash' | tail +2 `)

...

kitchenのインスタンス名は渡せていないので、対象が1システムの場合のみ。
やはりshell veriferで素直にローカルにscpかな。。

実はjson( ).paramsはすごかった

InSpecのテストで、jsonからパラメーターを読み込むのに、何気に使っていたjson( ).paramsは、テスト実行ノードがたとえリモートでも、そこのファイルを読み込んでくれる native inspec resource の様子。

test/integration/default/default_test.rb
node = json('/tmp/node.json').params

...

require 'json' も不要

対応3: レシピでノードオブジェクトのvalueとしてsymbol(もしくはsymbolのarray)は使わない様に統一

レシピでactionに渡す値を最初から.to_symや.mapを使って加工すれば良いのでしょうが、。。。本末転倒な感じ。

追記:
そもそもChefだけの場合でもJSONでattributeを渡さなければいけないケースがありうることから、結局はこの対応が必要なのか。
Chefでリソースのactionへの引数を、String(もしくはそのArray)から変換する

参照

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0