Chef メモ

provider 内で attribute を設定する事の是非

provider の中で attribute を設定し、別の template でそのattributeを使うというのは、良くない方法だと思う。
良くない理由というのはいくつか考えられる。

  • resource / provider は、自己完結的であるべき
    • カプセル化
    • できない場合は、あえて固有の resource / provider にせず、生の attribute と template で実現したほうが、まだ筋がいいと思う
      • why-run モードの動作を見ていて思った
  • resource / provider は、attributeを定義する側ではなく使う側
    • というのは言い過ぎ?
    • ランダム生成した値を保存したい場合などは使わざるを得ない
    • resource/provider の外で生成するようにする?それもそれで微妙

attributeに使えるデータ型

chefでは内部的にjsonに変換したりして扱っているので、jsonで使用可能なデータ型以外使うべきではない。
でないと、どこかのタイミングで文字列化 (to_s) されてしまい、想定外の結果になりうる。
実装依存なところがあるので、内部処理を詳しく理解していないと予測が難しいし、今後のアップデートで挙動が変わる可能性もある。

具体的には normal attribute が危ない。
空であれば設定する、という方法だと

  • 1回目の chef-client 実行では ruby のオブジェクトとして扱われ、終了時にjsonで保存される (ここで to_s されてしまう)
  • 2周目の chef-client 実行では json からデコードされ、想定外の動作

attribute の使い分け、パターン

あまりに多くの方法が提供されているため、コーディング規約的なものを作らないと滅茶苦茶になってしまう。
この辺は通常のソフトウェア開発と似た状況。
規約についても(相容れない)複数のパターンが考えられるので、それぞれのメリット・デメリットを見極めて統一したい。

これだけは確定だと思うもの

  • normal(set) attribute は、nodeごとの固有の値を「chef-client 実行とは別の方法で」設定するためのもの。cookbook 内で設定される定数値や、mysqlの buffer pool size のような automatic attribute から導出可能な値は基本的に default attribute で十分。
  • node ごとに別々の値を設定したい場合
  • 乱数生成される

normal attribute を安易にrecipeの中で設定すると、Chefの「冪等性」の考え方に反する事になりがち。
normal(set) attribute は基本的にはrecipeの中で使うべきではない。node毎の設定をカスタマイズする際のデフォルト値のような意味合いでセットするパターンも考えられるけど、その辺は後日掘り下げる。

node.set_unless['foo']['bar'] = 'baz'