先日リリースされたChef Client 11.12.0から密かに同梱されているOhaiが7.0系に差し替わったのだが、これが結構な仕様変更を含んでいて、Ohai Pluginなどを自作して使ってる人は気をつけないとハマる模様。
プラグインの仕様変更
いちおう互換性が保持されるようになっていてv6のプラグインもそのまま動くのだけれど、実行するとこんな感じのWARNINGが出る。
[2014-04-16T15:50:02+09:00] WARN: [DEPRECATION] Plugin at /tmp/example/plugins/foo.rb is a version 6 plugin. Version 6 plugins will not be supported in future releases of Ohai. Please upgrade your plugin to version 7 plugin syntax. For more information visit here: docs.opscode.com/ohai_custom.html
細かい点で色々仕様が変わってはいるのだけど、一番大きいのはプラグインの書き方が変わったことと、プラグイン名を指定していた部分がアトリビュート名を指定するように変わったこと。
新しいプラグインの書き方
従来のプラグインはこんな感じだった。
provides "foo"
require_plugin "baz"
foo Mash.new
foo[:data1] = "foo1"
foo[:data2] = "foo2"
Ohai 7からはこんな感じになる。
Ohai.plugin(:Foo) do
provides "foo"
depends "bar/baz"
collect_data do
foo Mash.new
foo[:data1] = "foo1"
foo[:data2] = "foo2"
end
collect_data(:windows) do
foo Mash.new
foo[:data1] = "win_foo1"
foo[:data2] = "win_foo2"
end
end
v6ではベタ書きスクリプトっぽかったのが、v7ではオブジェクトっぽく内容を定義する形になった。
上の例には書いていないが、普通にメソッドを書いたり共通処理用のクラスを別途まとめたりもできるようになっているので、複雑な処理が必要な場合にだいぶ書きやすくなったと思う。
collect_data
がデータを収集する部分なんだけど、引数でプラットフォーム毎の内容に分けて書くことができるようになった。
該当するプラットフォームのcollect_data
があるとそちらが呼ばれて、なければ:default
が指定されているcollect_data
が呼ばれる(指定しない場合は:default)。
また、v6ではrequire_plugin
で依存するプラグインを指定していたが、v7からはdepends
で依存するアトリビュートを指定するようになった。
利用する側はプラグイン名を知る必要はなく、「どのアトリビュートが使いたい」というのを指定すれば、Ohaiの本体が自動的にそのアトリビュートを提供するプラグインを読み込んでくれる。ここ割りと重要。
Rubyプログラムから使用する場合の注意点
プラグインの仕様が変わったことで利用の仕方も少し変わった。
普通に全プラグインを使う場合は従来と同じでOhai::System#all_plugins
を呼び出せば全部実行してくれる。
require "ohai"
ohai = Ohai::System.new
ohai.all_plugins
p ohai.data
自作プラグインなど特定のプラグインだけを実行したい場合は少し変わったのだけど、これがv6用プラグインとv7用プラグインで若干違っていたりしてカオスな感じがする。
require_pluginを使うパターン
v6用とv7用が混在している場合はこのやり方しかないように思う。
require "ohai"
Ohai::Config[:plugin_path] << "/path/to/oreore/plugins"
ohai = Ohai::System.new
ohai.load_plugins
ohai.require_plugin("foo/bar") # v7の場合はアトリビュート名
ohai.require_plugin("hoge_fuga") # v6の場合はプラグイン名
p ohai.data
まずload_plugins
というのが事前に必要になった。これを呼ばないとプラグインがOhaiに認識されない。
ちなみにload_plugins
を呼んでもv6用プラグインは読み込まれない。なぜならv6用プラグインは「読み込まれる=実行される」なので、問答無用で実行されてしまうから。
ただしv6用のプラグインであることは認識される(ソースファイル内の文字列とかで判定してるんだろうか?)。
require_plugin
にはv7用プラグインの場合はアトリビュート名を、v6用の場合はプラグイン名を指定する。
v7用プラグインはload_plugins
によってprovides
などのメタ情報がロードされるので、それを使って解決しているのだろう。
v6は前述のとおり読み込んでしまったら実行されてしまうので、読み込んでない状態では中に書かれているprovides
とかも認識されない。よってプラグイン名を指定することになるようだ。
ちなみにv7用プラグインのプラグインを指定しても動かない。
このへんの仕組みはOhai::ProvidesMap
とかOhai::Loader
がやってるようなので、興味のある人はソースを読んでみるといいかも。
all_pluginsに引数を渡すパターン
このやり方はv6用プラグインが混在している環境では使えない。
というのも、v6用プラグインは指定できず、無条件に実行されてしまうから(この挙動が仕様なのか現バージョンの不具合なのかは不明)。
require "ohai"
Ohai::Config[:plugin_path] << "/path/to/oreore/plugins"
ohai = Ohai::System.new
ohai.all_plugins([
"foo/bar",
"languages/ruby"
])
p ohai.data
all_plugins
の引数にアトリビュート名を指定すると、該当するアトリビュートを提供するプラグインのみが実行される。
ただし、(v6用の)プラグイン名は指定できない。そして指定してないにも関わらず、存在するv6プラグインは全て実行される。
ちなみにload_plugins
は不要。というかall_plugins
が内部で呼び出している。