Ansible: Playbookの実行条件制御 `when` の使い方(1)

Ansible の Playbook を書いていると、条件によって実行したいタスク、スキップしたタスク、というものが出てくることがあります。
そんな場合に when というステートメントで制御するのですが、なかなかきちんと使う機会が少なく、行き当たりばったりな感じで使うことも多くありました。

なので、一度しっかりと when の使い方を学んでみようと思います。

題材は、もちろん本家のドキュメント。

数回に分けて、記事にしながら理解を深めていきます。
まずは、 when の基礎的なところから。

The When Statement

when では、条件評価を行なって「真」となったらそのタスクを実行する、という挙動になります。
条件評価については、 Jinja2 の評価式が利用可能だそうです。

Jinja2 Template Designer Documentation Comparisons

ちなみに、 Jinja2 の簡単な説明と使い方は以前の記事をご参照ください。

Ansible: template モジュールを使って nginx の バーチャルホスト設定

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 の後にある | については、Jinja2filters という機能です。
すごくざっくり言えば、 result の中に色々と含まれている情報の中に、 failedskipped があれば、、、のような動作となります。

また、 filters を使って文字列を整数として評価させることもできるようです。
ここでは、変数 ansible_lsb.major_releaseintで整数にして >= で評価を行なっていますね。

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 なのでこのタスクが実行されることになります。
epicfalse の場合は、その次の when: not epic のタスクの方が実行されます。

3つ目、4つ目は foo という変数がそもそも定義されているか、という条件になります。(これもJinja2の機能のようです。)
定義されていれば3つ目、定義されていなければ4つ目、のタスクが実行されます。

まとめ

駆け足で when の基本的な使い方を見てみました。

非常にシンプルですが、特に Jinja2 の条件評価を使えることがよくわかりました。
また、この when で変数を使う場合は、他の部分で使うような {{}} で囲む必要が無いともドキュメントに書かれています。

こういったところに気をつけつつ、 より良いPlaybookを書いていきたいと思います。

続きは次回!

tacck
  • tacck
  • 北の大地の普通のソフトウェアエンジニア。
    インフラ・バックエンド・フロントエンドと、色々やります。

    初心者・若手向けのメンターも希望あればお受けします。

    勉強会運営中
    * ゆるWeb勉強会@札幌
    * スマートスピーカーで遊ぼう会@札幌