例えば、trzファイルをリモートに展開する際、OSの種類により展開元ファイルを変更するとした場合、when:を使うと冗長となるが、jinja2のifなどを用いるとシンプルに書ける。
whenを使用すると冗長
- when: ansible_distribution == 'CentOS'
unarchive:
src: foo.trz
dest: /qux
- when: ansible_distribution == 'Ubuntu'
unarchive:
src: bar.trz
dest: /qux
- when: ansible_distribution not in ['CentOS', 'Ubuntu']
unarchive:
src: baz.trz
dest: /qux
解1: jinja2のifを使用
jinja2のifを使用するとよりシンプルに書ける
- unarchive:
src: >-
{%- if ansible_distribution == 'CentOS' -%} foo.trz
{%- elif ansible_distribution == 'Ubuntu' -%} bar.trz
{%- else -%} baz.trz
{%- endif -%}
dest: /qux
- >- はyamlの構文で、続く節を空白で繋ぎ、最後に改行を付けない。なお、インデントされた全体を""にて囲むならば>-を削除可能。
- {%- -%}はjinja2の構文で、内側ではjinja2の構文を含めることが可能、外側では前後の空白、改行を除去する。
- 従って、もちろんfoo.trzなどを次の行としても可。お好みで。
- jinja2では、if, elif, else, endif, for, endfor, setなどが使用可能。
jinja2をplaybookで使用する場合の考慮事項
- yamlそのものの構文をjinja2にて変更することはできない。
- あくまでも値などyamlの一要素に対しての変更のみ。
この文章はjinja2の紹介の意図だったのですが、他の対応方法も追記しておきます。
解2: Hash|辞書|mapによる対応
- vars:
dist2src:
CentOS: foo.trz
Ubuntu: bar.trz
else: baz.trz
unarchive:
src: '{{ dist2src[ansible_distribution]|default(dist2src.else) }}'
dest: /qux
task varsでHashにて対応を定義し、本文では単に参照。
この例のケースでは一番妥当かもしれません。
解3: python?によるif文対応
- unarchive:
src: >-
{{
'foo.trz' if ansible_distribution == 'CentOS' else
'bar.trz' if ansible_distribution == 'Ubuntu' else
'baz.trz'
}}
dest: /qux
こんな書き方も可能。
リファレンスは何処に。。
解4: ternaryフィルターによる対応
- unarchive:
src: >-
{{
( ansible_distribution == 'CentOS' )|ternary ( 'foo.trz' , (
( ansible_distribution == 'Ubuntu' )|ternary ( 'bar.trz' ,
'baz.trz' )
))
}}
dest: /qux
3項演算子的に使用可能なternaryフィルターを利用する例。
可能ではあるが、読みにくい。
ansible_distribution == xxxx を括弧で括っているのは、フィルターの優先順位が==よりも高い為。
雑感
Ansibleでは色々な方法が使用可能であったりするが、何処を調べれば良いのか分からず、ひたすらググっては試さないといけない?
参考
- プログラマーのための YAML 入門 (初級編)
- jinja2: Template Designer Documentation
- ほげめも: Ansible の Jinja2 を活用する <- リスト(Array)やディレクトリー(Hash)に値を設定する場合には要注意。set _ = は set dummy = などと置き換えると混乱しないか。
- Ansibleのregisterから任意のディクショナリやリストを生成する - Qiita
- Ansibleで条件を使用して変数値を設定する方法を教えてください。 - 答えられる
- Other Useful Filters