Ansible: Playbookの実行条件制御 `when` の使い方(1)
Ansible の Playbook を書いていると、条件によって実行したいタスク、スキップしたタスク、というものが出てくることがあります。 そんな場合に when
というステートメントで制御するのですが、なかなかきちんと使う機会が少なく、行き当たりばったりな感じで使うことも多くありました。
なので、一度しっかりと when
の使い方を学んでみようと思います。
題材は、もちろん本家のドキュメント。
Ansible Documentation > Playbooks > Conditionals
数回に分けて、記事にしながら理解を深めていきます。 まずは、 when
の基礎的なところから。
The When Statement
when
では、条件評価を行なって「真」となったらそのタスクを実行する、という挙動になります。 条件評価については、 Jinja2
の評価式が利用可能だそうです。
Jinja2 Template Designer Documentation Comparisons
ちなみに、 Jinja2
の簡単な説明と使い方は以前の記事をご参照ください。
https://blog.tacck.net/archives/43
when
の条件評価例
というわけで、ドキュメント内の例をベースに見ていきたいと思います。
その1
これは、Ansibleの操作対象マシンのOSが “Debian” 系だった場合に、 command
の内容である /bin/shutdown
を実行します。 つまり、 OSが “RedHat” 系だったり、 “FreeBSD” だったりした場合は、このタスクはスキップとなりますね。
tasks:
- name: "shut down Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_os_family == "Debian"
# note that Ansible facts and vars like ansible_os_family can be used
# directly in conditionals without double curly braces
その2
今度は、Linuxのディストリビューションが”CentOS”の6系、または、 “Debian” の7系、の場合にコマンドが実行されます。 つまり、Debian系でも “Ubuntu” であったり、 “CentOS” でもバージョンが7の場合は、やはりタスクはスキップとなります。
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
(ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
また、条件についてはリストで書くこともできるようです。この場合は、すべての条件を満たしたときにタスクが実行されるため、 and
と同じ効果になるようです。
tasks:
- name: "shut down CentOS 6 systems"
command: /sbin/shutdown -t now
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "6"
その3
こちらはちょっと長いですが、あるタスクの結果に応じて(成功:succeeded、失敗:failed、スキップ:skipped)実行するタスクを選択する、という時の書き方になります。 例えば、Apache Httpdの設定の書き換えが成功した場合(succeeded)のみhttpdの再起動を行なう、、、というような使い方ができます。
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
# In older versions of ansible use |success, now both are valid but succeeded uses the correct tense.
- command: /bin/something_else
when: result|succeeded
- command: /bin/still/something_else
when: result|skipped
ちなみに、3行目の register
は、タスクの実行結果を result
という変数に格納する、という意味になります。 when
の後にある |
については、Jinja2
の filters
という機能です。 すごくざっくり言えば、 result
の中に色々と含まれている情報の中に、 failed
や skipped
があれば、、、のような動作となります。
また、 filters
を使って文字列を整数として評価させることもできるようです。 ここでは、変数 ansible_lsb.major_release
を int
で整数にして >=
で評価を行なっていますね。
tasks:
- shell: echo "only on Red Hat 6, derivatives, and later"
when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
その4
ここは変数を取り扱うパターンです。 ドキュメントにいくつかのパターンが分割して書かれてありますが、ここはまとめて。
vars:
epic: true
tasks:
- shell: echo "This certainly is epic!"
when: epic
- shell: echo "This certainly isn't epic!"
when: not epic
- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
when: foo is defined
- fail: msg="Bailing out. this play requires 'bar'"
when: bar is undefined
最初の vars
で、このPlaybook内で使う変数を定義できます。 直後の when: epic
は、変数の内容が true
なのでこのタスクが実行されることになります。 epic
が false
の場合は、その次の when: not epic
のタスクの方が実行されます。
3つ目、4つ目は foo
という変数がそもそも定義されているか、という条件になります。(これもJinja2の機能のようです。) 定義されていれば3つ目、定義されていなければ4つ目、のタスクが実行されます。
まとめ
駆け足で when
の基本的な使い方を見てみました。
非常にシンプルですが、特に Jinja2
の条件評価を使えることがよくわかりました。 また、この when
で変数を使う場合は、他の部分で使うような {{}} で囲む必要が無いともドキュメントに書かれています。
こういったところに気をつけつつ、 より良いPlaybookを書いていきたいと思います。
続きは次回!