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

投稿者: | 2017-01-29

前回に引き続き、今回も Playbook でのタスク制御を行なう when の使い方を勉強していきます。

題材は、引き続き本家のドキュメント。

前回の記事はこちら。

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

Loops and Conditionals

ループと条件式、ということで、 when で指定したものでループの制御を行なうところです。

tasks:
    - command: echo {{ item }}
      with_items: [ 0, 2, 4, 6, 8, 10 ]
      when: item > 5

Ansible Playbook では、 with_items を指定することで command を繰り返し実行できますが、 when の指定によって実行するものを調整することができるようです。
実際に実行した結果は、下記のように表示されます。

TASK [command] *****************************************************************
skipping: [server1] => (item=0) 
skipping: [server1] => (item=2) 
skipping: [server1] => (item=4) 
changed: [server1] => (item=6)
changed: [server1] => (item=8)
changed: [server1] => (item=10)

5未満の数字は skipping となり、タスク実行がスキップされていることがわかります。

次に、リストと辞書形式リストで繰り返しをするパターンの例が書かれています。
ドキュメントだけだとイマイチ掴めなかったので、実際にリストなどを定義した Playbook を書いて確かめてみました。

- hosts: all
  vars:
    mylist: [ 0, 2, 4, 6, 8, 10 ]
    mydict:
      a: 0
      b: 2
      c: 4
      d: 6
      e: 8 
      f: 10
  tasks:
  - command: echo {{ item }}
    with_items: [ 0, 2, 4, 6, 8, 10 ]
    when: item > 5

  - command: echo {{ item }}
    with_items: "{{ mylist | default([]) }}"
    when: item > 5

  - command: echo {{ item.key }}
    with_dict: "{{ mydict | default({}) }}"
    when: item.value > 5

こんな感じです。実行すると、下記のようになります。

TASK [command] *****************************************************************
skipping: [server1] => (item=0) 
skipping: [server1] => (item=2) 
skipping: [server1] => (item=4) 
changed: [server1] => (item=6)
changed: [server1] => (item=8)
changed: [server1] => (item=10)

TASK [command] *****************************************************************
skipping: [server1] => (item=0) 
skipping: [server1] => (item=2) 
skipping: [server1] => (item=4) 
changed: [server1] => (item=6)
changed: [server1] => (item=8)
changed: [server1] => (item=10)

TASK [command] *****************************************************************
skipping: [server1] => (item={'key': u'a', 'value': 0}) 
skipping: [server1] => (item={'key': u'c', 'value': 4}) 
skipping: [server1] => (item={'key': u'b', 'value': 2}) 
changed: [server1] => (item={'key': u'e', 'value': 8})
changed: [server1] => (item={'key': u'd', 'value': 6})
changed: [server1] => (item={'key': u'f', 'value': 10})

mylist mydict を実際に定義して動かしてみると、きちんと動きました。
また、 mylist などの横にある default ですが、これは Jinja2 の filter 機能で、 “変数が未定義の場合の初期値” として動作するようです。
つまり、 mylist mydict が未定義だった場合でも動作するような書き方、ということですね。

Loading in Custom Facts

ここはちょっと(私には)難しいところでした。
書いてある意味は、わかるのですが。。。

tasks:
    - name: gather site specific fact data
      action: site_facts
    - command: /usr/bin/thingy
      when: my_custom_fact_just_retrieved_from_the_remote_system == '1234'

説明としては、自作のモジュール site_facts を実行し、その中で定義された facts である my_custom_fact_just_retrieved_from_the_remote_systemwhen の条件に使えるよ ( Playbook 内の変数だけじゃないよ ) 、、、というものです。

自分で facts を定義する話については Developing Modules を参照してね、、、とあるので、そのうちモジュール作成についても勉強したいと思います。

Applying ‘when’ to roles and includes

次は、 rolesinclude にも when が使えるよ、というところです。
これも動きはわかりましたが、説明で一部わからないところが。。。

ドキュメントと順番を変えますが、先に roles の例から。

- hosts: webservers
  roles:
     - { role: debian_stock_config, when: ansible_os_family == 'Debian' }

これはみた通り、 OSが Debian 系ならこのロールが実行される、、、となりそうです。

次は、 include の例。

- include: tasks/sometasks.yml
  when: "'reticulating splines' in output"

when にある英文は、そのまま使えるものじゃありません。
文章的に「ここに色々と条件書けるよ」という風な意味合いですかね。。。

また、ここの説明に「条件はすべてのタスクに適用される」という風に書かれています。
つまり、 include の条件に適合しなかったタスク(上記だと tasks/sometasks.yml に記載されているタスクたち)は、すべて評価された上でスキップになる、、、という風な意味合いのようですね。
実際に動かして確認してみます。

試した Playbook は下記。

- hosts: all
  vars:
    item: 4
  tasks:
  - include: playbook_task.yml
    when:
      - item > 5
      - item < 10 

- hosts: all
  vars:
    item: 6
  tasks:
  - include: playbook_task.yml
    when:
      - item > 5
      - item < 10 
  - debug:
      msg: "Debug:1 {{ item }}"

  - debug:
      msg: "Debug:2 {{ item }}"

条件が成立する変数と成立しない変数を用意して、同じタスクを実行するような感じです。
これの実行結果がこちらになります。

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [server1]

TASK [debug] *******************************************************************
skipping: [server1]

TASK [debug] *******************************************************************
skipping: [server1]

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [server1]

TASK [debug] *******************************************************************
ok: [server1] => {
    "msg": "Debug:1 6"
}

TASK [debug] *******************************************************************
ok: [server1] => {
    "msg": "Debug:2 6"
}

前半に skipping が二つ、後半に ok が二つ、それぞれありますね。
つまり条件に当てはまらない場合でも、全てのタスクを一度読み込んでスキップ処理を行なう、、、ということですね。
説明に書かれてあったことを、きちんと確認できました。

また、ドキュメントには「group_by モジュールを使うと、もっと良い感じにできるよ」と書かれているので、こちらも勉強必要ですね。

まとめ

今回は、 when の使い方の中盤でした。
書かれていることはわかるけど、徐々に複雑なものを取り扱う感じになってきています。
関連して学ぶ必要のあるところも出てきて、まだまだ奥が深いこともわかってきました。

次回で、 when の使い方を一通り完了したいと思います!