Posted at
AnsibleDay 2

Ansible の Template 機能の紹介

More than 3 years have passed since last update.

 __________________

< template について書くよ >
------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||

Ansible というかほぼ Jinja2 なのだけれども、ちょいちょいググってしまうものをまとめてみます(これをまとめるまで知らなかったものもあります、たまにはドキュメントを見直すのが良いです)。

template module だけでなく task 定義で使う YAML 内でも使われています。

(Qiita の syntax highlight は Jinja にも対応しているのですね)


Ansible Managed

まずはこれ、つい使いたくなるけど罠があるので私は使わない。(Subversion の $Id$ は便利なのに)

http://docs.ansible.com/ansible/intro_configuration.html#ansible-managed

テンプレートファイルに

{{ ansible_managed }}

と書いておけば実行時に ansible.cfg などで設定したフォーマットにしたがって置換してくれます。いつ誰が更新したかとかを入れられます。

ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}

が、この機能は曲者で、ファイルに変更があったかどうかを比べるのにこの行まで含んでしまうから timestamp なんかを入れてしまった日には本来何も変更してないはずなのにファイルが入れ替えられてしまい。毎回 notify handler が発動してしまうという悲劇を産みます。気をつけましょう。


default

ansible のいつしかの version からデフォルトでは未定義の変数を参照するとエラーで終了してしまいますが、指定しない場合のデフォルト値を指定しておけば大丈夫ということで、特に何も指定がなければこの値ですよというのを指定します。

roledefault/main.yml を使うという手もありますが、参照すべきファイルが増えるのは嬉しくないので単純な値ならこれで。

{{ some_variable | default('foo bar') }}

task の中で便利に使えるのが 1.8 で登場した default(ommit) ですね(と言ってもこれ書いてて知った)。

http://docs.ansible.com/ansible/playbooks_filters.html#omitting-undefined-variables-and-parameters に例がありますが、ファイルのパーミッションやオーナーなど、with_items でループ処理したい時、殆どは指定が不要なのにひとつだけ指定したいといった場合、それまでは全部の item に値をもたせるか、default でデフォルト値を設定する必要がありましたが、ommit を使えば未定義の場合はその項目の指定自体がないことにできます。便利(実は今知った...)


リスト操作


min, max

http://docs.ansible.com/ansible/playbooks_filters.html#list-filters

リストの中の最小値、最大値を取り出してくれます


unique, union,...

http://docs.ansible.com/ansible/playbooks_filters.html#set-theory-filters

2つのリストの和とか差とか


random

http://docs.ansible.com/ansible/playbooks_filters.html#random-number-filter

リストの中からランダムに選択されます。 数字内のランダムな値、ステップ数を指定したランダムな値(100のうち10刻みでのランダムな値)とかを取り出せます。

cron モジュールとセットで、複数台のサーバーで同時に実行されるのを避ける場合に便利そうです。ドキュメントにも cron の例があります。

{{ 60 | random(step=5) }} * * * * /some/command


shuffle

http://docs.ansible.com/ansible/playbooks_filters.html#shuffle-filter

シャッフル


動作確認


test.yml

- hosts: all

gather_facts: no
vars:
aaa:
- A
- B
- C
bbb:
- A
- B
- C
- X
- Y
- Z
ccc: [1,2,3,4,5]
ddd: [1,1,2,2,3,3,4,4,5,5]
eee: [1,2,3]
fff: [3,4,5]
tasks:
- debug: msg="[aaa] {{ aaa }}"
- debug: msg="[bbb] {{ bbb }}"
- debug: msg="[ccc] {{ ccc }}"
- debug: msg="[ddd] {{ ddd }}"
- debug: msg="[random] {{ aaa | random }}"
- debug: msg="[unique] {{ ddd | unique }}"
- debug: msg="[union1] {{ aaa | union(bbb) }}"
- debug: msg="[union2] {{ aaa | union(ccc) }}"
- debug: msg="[intersect] {{ bbb | intersect(aaa) }}"
- debug: msg="[difference] {{ bbb | difference(aaa) }}"
- debug: msg="[symmetric_difference] {{ eee | symmetric_difference(fff) }}"
- debug: msg="[max] {{ ccc | max}}"
- debug: msg="[min] {{ ccc | min}}"
- debug: msg="[shuffle] {{ bbb | shuffle}}"

を用意して

ansible-playbook -i localhost, test.yml

とすれば動作確認ができます。


計算

http://docs.ansible.com/ansible/playbooks_filters.html#math

べき乗や平方根、対数が使えるようです


その他のフィルター

IPアドレス関連やコメント用、ハッシュ処理などあるので確認してみてください。

http://docs.ansible.com/ansible/playbooks_filters.html

join は使う場面ありますよね

{{ list | join(" ") }}

この join するリストがシンプルなリストならこれで良いのですが

ハッシュ/ディクショナリのリストだった場合にどうするかというと

aaa:

- en: apple
ja: ringo
- en: orange
ja: mikan
- en: grape
ja: budou

という変数があって、en だけや ja だけを join したい場合は次のようにします

2つ繋げることもできるんです

{{ aaa | map(attribute='en') | join(',') }}

{{ aaa | map(attribute='ja') | join(',') }}

結果

apple,orange,grape

ringo,mikan,budou

map() については http://jinja.pocoo.org/docs/dev/templates/#map を。


Loop 処理

最後にループ処理です

task での Loop はこちらにいろいろ載ってます、ヘぇ、そんなのもあったんだぁという感じなので読んでみましょう。taskwith_xxx には沢山の種類があって、whenwith_xxx のそれぞれの値に対しても使えます。

http://docs.ansible.com/ansible/playbooks_loops.html

テンプレートファイル内での Loop 処理についてはこちら

http://jinja.pocoo.org/docs/dev/templates/

{% for item in items %}

{% if item.key1 == 'AAA' %}
{{ item.key1 }} {{ item.key2 }}
{% elif item.key1 == 'BBB' %}
...
{% else %}
...
{% endif %}
{% endfor %}

が基本でしょうか。if, elif, else, endif です。(いろんな言語使ってるといつも悩みますね、elif のところ。あれどれだっけ?と)

Loop のアイテムごとに番号を振りたいと思ったら loop.index (1から始まる), loop.index0 (0から始まる) という変数が使えます

最初と最後を示す loop.first, loop.last という Boolean 変数もあります

{% for item in items %}

{% if loop.first %}Begin{% endif %}
{{ loop.index }}: {{ item }}
{% if loop.last %}End{% endif %}
{% endfor %}

詳細はこちら

http://jinja.pocoo.org/docs/dev/templates/#list-of-control-structures


エスケープ

template ファイル内に {{ とか {% が含まれる場合は raw を使います

{% raw %}

...
{% endraw %}


まとめ

とりとめもなく書いてしまいましたが、また思いついたら書くことにします。

まだカレンダーに空きがあるようなので。