ansibleで変数に入れたyes/noの扱いに苦しんだ
タイトルをどうつければ伝わるか悩んだ結果こうなった・・・
背景
Ansibleを使っていると、ある1つの環境だけ特別に実行したいとかあると思います。
(雲行きが怪しいぞ・・・という反応がうかがえます。)
例えば3台立っているアプリケーションサーバに、cronを仕込みたいけど、3台で動かしたくないなーといった場合を考えてみます。
(ちゃんとグループを分けなさい、ケチらずバッチサーバを用意して分けなさいという意見が聞こえてきます。)
こんな感じにインベントリ内に変数is_main
を持たせました。
[app]
foo-app-01 is_main=yes
foo-app-02 is_main=no
foo-app-03 is_main=no
このyes/noはansibleを書いているとよく出てくる値です。
serviceなら自動実行を開始させるためにenabled: yes
みたいに使います。今回はcronのdisabled
の値として使うイメージです。
次にタスクの内容です。is_main=yes
なところだけが有効になってほしかったのでタスクはこんな感じにした。
cron:
# ...
disabled: "{{ is_main == False }}" # NG!!
今回の条件では disabledに入る値は常にFalse になるため、全部の環境でcronが有効になります。ちなみに、{{ not is_main }}
でも同じです。
やりたい事と違う!
原因の推測
何度かdebugタスクで表示して確認した上での推測です。全然裏が取れてないです。
- まずinventoryで定義した変数
is_main
は文字列として扱っている - ファイル自体はYAMLなので、まず最初にYAMLとして処理される。YAMLではYes,No等の値はBool値として解釈される。なので
disabled: no
等の記載なら、期待通り動く。 - 今回の場合、
disabled: "{{ is_main == False }}"
はYAML的にはただの文字列。 - しかし、テンプレート構文なのでJinja2で解釈した結果になる
- Jinja2的には変数
is_main
の値は文字列と解釈して「1文字以上の文字列だからTrue
」と判断している - なのでこの式は、
disabled: "{{ is_main == False }}"
→disabled: "{{ True == False }}"
→disabled: False
となる
あっているでしょうか・・・?
対応
自然な感じで書きたいのだけど、どうしたら良いか調べたところ bool フィルターを使うと良さそうとのことだった。boolフィルターは良くあるポジティブな値はTrueにしてくれます。今回求めてたやつですね!
cron:
# ...
disabled: "{{ is_main | bool == False }}"
しかしこの見た目は不吉な匂いを感じます。
これなら文字列が入ってくる前提で考えて {{ is_main == 'no' }}
とかの方がまだ良い気がしないでもない・・・。
やはりグループを分けるべきだったか・・・。
Ansibleはこういうミスは忘れたころに何度も踏んでる気がする・・・頭の悪さを感じてとても辛い。
追記: インベントリファイル(INI形式)の変数の扱い
コメントにて、インベントリファイルの変数で対処する方法等を教えていただきました。
また、インベントリファイルのbooleanの扱いについてBlogでまとめておられます。ありがたし。
Author And Source
この問題について(ansibleで変数に入れたyes/noの扱いに苦しんだ), 我々は、より多くの情報をここで見つけました https://qiita.com/fukasawah/items/ad4dad3e2bee7e1c5001著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .