Chapter 15

条件 : when

y_mrok
y_mrok
2021.10.17に更新

when ディレクティブを使用して、タスクを実行するときの条件を設定します。タスクは指定した条件が成立したとき (true のとき ) だけ実行します。

管理対象ノードとインベントリー

使用する管理対象ノードの情報とインベントリーです。

管理対象ノード ディストリビューション バージョン OS ファミリー
marutamachi CentOS 8.4 RedHat
takeyamachi CentOS 7.8 RedHat
ebisugawa Ubuntu 20.04 Debian
nijyo Ubuntu 18.04 Debian
oshikoji Debian 10 Debian
oike Alma Linux 8.4 RedHat
hosts.yml
---
all:
  hosts:
    marutamachi:
  children:
    web:
      hosts:
        takeyamachi:
        ebisugawa:
        nijyo:
    mail:
      hosts:
        nijyo:
    database:
      hosts:
        oshikoji:
        oike:

比較条件

2 つの値を比較する条件式です。

比較演算子

比較演算子 true になるとき
X == Y X の値と Y の値が等しいとき
X != Y X の値と Y の値が等しくないとき
X > Y X の値が Y の値より大きいとき
X >= Y X の値が Y の値より大きいか等しいとき
X < Y X の値が Y の値より小さいとき
x <= y X の値が Y の値より小さいか等しいとき

使用例

RedHat 系の管理対象ノードだけリブートするプレイブックです。 when ディレクティブの条件式で変数を参照する場合 {{}} でくくりません。

reboot_node.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Reboot the RedHat system only.
      ansible.builtin.reboot:
      when: ansible_facts['os_family'] == "RedHat"

実行ログです。タスク Reboot the RedHat system only. の実行で changed が条件が成立してリブートした管理対象ノード、 skipping が条件が不成立となりリブートをスキップした管理対象ノードです。 RedHat 系の管理対象ノード marutamachi , takeyamachi , oike の 3 台がリブートしました。
Recap の skipped は管理対象ノードがタスクの実行をスキップした数をカウントします。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************
ok: [oshikoji]
ok: [takeyamachi]
ok: [marutamachi]
ok: [ebisugawa]
ok: [nijyo]
ok: [oike]

TASK [Reboot the RedHat system only.] ****************************************************************************************************************
skipping: [ebisugawa]
skipping: [nijyo]
skipping: [oshikoji]
changed: [takeyamachi]
changed: [marutamachi]
changed: [oike]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
marutamachi                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
nijyo                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oike                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oshikoji                   : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
takeyamachi                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

論理条件

2 つ以上の条件式を結合した条件式です。複数種類の論理演算子を使用した場合、定められた優先順序の高い論理演算子を使用した条件式から評価します。条件式を ( ) でくくって、明示的に優先順序を示せます。

論理演算子

論理演算子 true になるとき 優先順序
条件A and 条件B 条件A と条件B がともに True のとき 2
条件A or 条件B 条件A か条件B のどちらかが True のとき 3
not 条件A 条件A が false のとき 1

使用例

条件式を結合した例

RedHat 系 かつ メジャーバージョンが 8 の管理対象ノードだけリブートするプレイブックです。

reboot_node1.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Only RedHat and major version 8 will reboot.
      ansible.builtin.reboot:
      when: ansible_facts['os_family'] == "RedHat" and ansible_facts['distribution_major_version'] == "8"

実行ログです。RedHat 系かつバージョンが 8.x が対象なので、管理対象ノード marutamachi, oike が再起動しました。 RedHat 系の takeyamachi のバージョンは 7.8 のため skipping しました。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node1.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************
ok: [oshikoji]
ok: [takeyamachi]
ok: [marutamachi]
ok: [nijyo]
ok: [ebisugawa]
ok: [oike]

TASK [Only RedHat and major version 8 will reboot.] **************************************************************************************************
skipping: [takeyamachi]
skipping: [ebisugawa]
skipping: [nijyo]
skipping: [oshikoji]
changed: [marutamachi]
changed: [oike]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
marutamachi                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
nijyo                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oike                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oshikoji                   : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
takeyamachi                : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

論理演算子で結合した条件式は横に長くなり、可読性が下がります。次のように記述しても同じです。

reboot_node2.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Only RedHat and major version 8 will reboot.
      ansible.builtin.reboot:
      when: ansible_facts['os_family'] == "RedHat" 
        and ansible_facts['distribution_major_version'] == "8"

上述のように条件式を論理演算子 and だけで結合する場合、条件をシーケンスで記述できます。

reboot_node3.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Only RedHat and major version 8 will reboot.
      ansible.builtin.reboot:
      when:
        - ansible_facts['os_family'] == "RedHat" 
        - ansible_facts['distribution_major_version'] == "8"

かっこを使用した例

数式でかっこを使用した場合と同様に条件式でかっこを使用した場合、かっこでくくった条件式の評価が優先されます。

CentOS でメジャーバージョンが 7 または 8 の管理対象ノードだけ再起動するプレイブックです。

reboot_node4.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Reboot only managed nodes with major version 7 or 8 on CentOS.
      ansible.builtin.reboot:
      when: ansible_facts['distribution] == "CentOS" 
        and ansible_facts['distribution_major_version'] == "7"
        or  ansible_facts['distribution_major_version'] == "8"

実行ログです。管理対象ノード marutamachi(CentOS 8) , takeyamachi(CentOS 7) だけリブートするはずが oike(Alma Linux 8) までリブートしています。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node4.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************
ok: [oshikoji]
ok: [takeyamachi]
ok: [marutamachi]
ok: [nijyo]
ok: [ebisugawa]
ok: [oike]

TASK [Reboot only managed nodes with major version 7 or 8 on CentOS.] ********************************************************************************
skipping: [ebisugawa]
skipping: [nijyo]
skipping: [oshikoji]
changed: [takeyamachi]
changed: [oike]
changed: [marutamachi]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
marutamachi                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
nijyo                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oike                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oshikoji                   : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
takeyamachi                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

論理演算子の優先順序から、次の 2 つの条件式を or で結合し評価した結果、後者の条件に管理対象ノード oike が該当します。

            ansible_facts['distribution] == "CentOS" 
        and ansible_facts['distribution_major_version'] == "7"

            ansible_facts['distribution_major_version'] == "8"

かっこを使用して修正したプレイブックです。

reboot_node5.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Reboot only managed nodes with major version 7 or 8 on CentOS.
      ansible.builtin.reboot:
      when: ansible_facts['distribution'] == "CentOS" 
        and ( ansible_facts['distribution_major_version'] == "7" or
              ansible_facts['distribution_major_version'] == "8" )

実行ログです。今度は正しく管理対象ノード marutamachi , takeyamachi がリブートしました。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node5.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************
ok: [oshikoji]
ok: [takeyamachi]
ok: [marutamachi]
ok: [nijyo]
ok: [ebisugawa]
ok: [oike]

TASK [Reboot only managed nodes with major version 7 or 8 on CentOS.] ********************************************************************************
skipping: [ebisugawa]
skipping: [nijyo]
skipping: [oshikoji]
skipping: [oike]
changed: [takeyamachi]
changed: [marutamachi]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
marutamachi                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
nijyo                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oike                       : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oshikoji                   : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
takeyamachi                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

このように、かっこを使用して条件式の評価順序を変更することで、意図した条件式を作成します。
下記のように、条件式を固まりごとにかっこでくくることで、条件式の意図を明確にできます。

reboot_node6.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Reboot only managed nodes with major version 7 or 8 on CentOS.
      ansible.builtin.reboot:
      when: ( ansible_facts['distribution'] == "CentOS" )
        and ( ansible_facts['distribution_major_version'] == "7" or
              ansible_facts['distribution_major_version'] == "8" )

論理演算子 not を使用した例

論理演算子 not は条件式の評価結果を反対にします。 true であれば false に、false であれば true に評価結果を変更します。

CentOS 以外の管理対象ノードをリブートするプレイブックです。

reboot_node7.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes

  tasks:
    - name: Reboot the managed nodes other than CentOS.
      ansible.builtin.reboot:
      when: not ( ansible_facts['distribution'] == "CentOS" )

実行ログです。CentOS 以外の管理対象ノードがリブートしました。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node7.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************
ok: [oshikoji]
ok: [takeyamachi]
ok: [marutamachi]
ok: [nijyo]
ok: [ebisugawa]
ok: [oike]

TASK [Reboot the managed nodes other than CentOS.] ***************************************************************************************************
skipping: [marutamachi]
skipping: [takeyamachi]
changed: [oshikoji]
changed: [nijyo]
changed: [ebisugawa]
changed: [oike]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
marutamachi                : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
nijyo                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oike                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oshikoji                   : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
takeyamachi                : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

in / not in

列記した値の中に該当する値があるか否かを判断する条件式です。

条件式

演算子 true になるとき
A in [X, Y, Z] A と同じ値が X, Y, Z の中にあるとき
A not in [X, Y, Z] A と同じ値が X, Y, Z の中にないとき

使用例

基本的な使用例

管理対象ノード marutamachi, nijyo , oike だけを再起動するプレイブックです。

reboot_node8.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes
  gather_facts: no

  tasks:
    - name: Reboot only the managed nodes marutamachi, nijyo, and oike.
      ansible.builtin.reboot:
      when: inventory_hostname in ["marutamachi", "nijyo", "oike"]

実行ログです。 IN で指定した管理対象ノードだけがリブートしました。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node8.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Reboot only the managed nodes marutamachi, nijyo, and oike.] ***********************************************************************************
skipping: [takeyamachi]
skipping: [ebisugawa]
skipping: [oshikoji]
changed: [nijyo]
changed: [marutamachi]
changed: [oike]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
marutamachi                : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
nijyo                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oike                       : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oshikoji                   : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
takeyamachi                : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

in の代わりに not in を使用したプレイブックです。

reboot_node9.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes
  gather_facts: no

  tasks:
    - name: Reboot the managed nodes except marutamachi, nijyo, and oike.
      ansible.builtin.reboot:
      when: inventory_hostname not in ["marutamachi", "nijyo", "oike"]

実行ログです。先の結果とは逆に管理対象ノード takeyamachi , ebisugawa , oshikoji がリブートしました。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node9.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Reboot the managed nodes except marutamachi, nijyo, and oike.] *********************************************************************************
skipping: [marutamachi]
skipping: [nijyo]
skipping: [oike]
changed: [oshikoji]
changed: [takeyamachi]
changed: [ebisugawa]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
marutamachi                : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
nijyo                      : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oike                       : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oshikoji                   : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
takeyamachi                : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

マッピングの中にシーケンスをネストした変数を使用した例

in または not in で指定する値をマッピングの中にシーケンスをネストした変数を指定した場合の例です。
web グループに属する管理対象ノードだけをリブートするプレイブックです。

reboot_node10.yml
---
- name: Reboot the managed node.
  hosts: all
  become: yes
  gather_facts: no

  tasks:
    - name: Reboot only the managed nodes that belong to the web group.
      ansible.builtin.reboot:
      when: inventory_hostname in groups['web']

実行ログです。web グループに属する管理対象ノードだけリブートしました。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml reboot_node10.yml 

PLAY [Reboot the managed node.] **********************************************************************************************************************

TASK [Reboot only the managed nodes that belong to the web group.] ***********************************************************************************
skipping: [marutamachi]
skipping: [oshikoji]
skipping: [oike]
changed: [takeyamachi]
changed: [nijyo]
changed: [ebisugawa]

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
marutamachi                : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
nijyo                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
oike                       : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oshikoji                   : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
takeyamachi                : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

is defined / is not defined

指定した変数が定義されているか否かを判断する条件式です。

条件式

演算子 true になるとき
変数A is defined 変数A が定義されているとき
変数A is not defined 変数A が定義されていないとき
変数が定義されている / いないを言い換えると、指定した変数のスコープ内か否かです。スコープ内であれば定義さていると判断します。

使用例

web グループに定義されている変数です。

group_vars/web.yml
---
http_port: 8080

管理対象ノードごとに変数 http_port が存在するか否かを判断するプレイブックです。

check_vars.yml
---
- name: Check for the existence of variables.
  hosts: all
  gather_facts: no

  tasks:
    - name: When a variable exists
      ansible.builtin.debug:
        msg: "The variable specified for {{ inventory_hostname }} existed."
      when: http_port is defined
    - name: When the variable does not exist.
      ansible.builtin.debug:
        msg: "The variable specified for {{ inventory_hostname }} did not exist."
      when: http_port is not defined

実行ログです。 web グループに含まれる管理対象ノード ebisugawa, nijyo, oshikoji はタスク When a variable exists でメッセージを表示しています。含まれない marutamachi, oshikoji, oike はタスク When the variable does not exist. でメッセージを表示しています。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i hosts.yml check_vars.yml 

PLAY [Check for the existence of variables.] *********************************************************************************************************

TASK [When a variable exists] ************************************************************************************************************************
skipping: [marutamachi]
ok: [ebisugawa] => {
    "msg": "The variable specified for ebisugawa existed."
}
ok: [nijyo] => {
    "msg": "The variable specified for nijyo existed."
}
skipping: [oshikoji]
ok: [takeyamachi] => {
    "msg": "The variable specified for takeyamachi existed."
}
skipping: [oike]

TASK [When the variable does not exist.] *************************************************************************************************************
ok: [marutamachi] => {
    "msg": "The variable specified for marutamachi did not exist."
}
skipping: [takeyamachi]
skipping: [ebisugawa]
skipping: [nijyo]
ok: [oshikoji] => {
    "msg": "The variable specified for oshikoji did not exist."
}
ok: [oike] => {
    "msg": "The variable specified for oike did not exist."
}

PLAY RECAP *******************************************************************************************************************************************
ebisugawa                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
marutamachi                : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
nijyo                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oike                       : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
oshikoji                   : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
takeyamachi                : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

loop ディレクティブと併用

when ディレクティブと loop ディレクティブを併用した場合の動作を確認するプレイブックです。

loop.yml
---
- name: Use the loop directive in combination.
  hosts: all
  gather_facts: no

  tasks:
    - name: Use with the loop directive
      ansible.builtin.debug:
        msg: "Value of the variable item → {{ item }}"
      loop: 
        - 0
        - 2
        - 4
        - 6
        - 8
        - 10
      when: item < 5

実行ログです。 loop 変数 item に値をセットした後に when ディレクティブの条件式が評価されました。

y_mrok@ctrl:~/code/exam8$ ansible-playbook -i localhost, -c local loop.yml 

PLAY [Use the loop directive in combination.] ********************************************************************************************************

TASK [Use with the loop directive] *******************************************************************************************************************
ok: [localhost] => (item=0) => {
    "msg": "Value of the variable item → 0"
}
ok: [localhost] => (item=2) => {
    "msg": "Value of the variable item → 2"
}
ok: [localhost] => (item=4) => {
    "msg": "Value of the variable item → 4"
}
skipping: [localhost] => (item=6) 
skipping: [localhost] => (item=8) 
skipping: [localhost] => (item=10) 

PLAY RECAP *******************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

y_mrok@ctrl:~/code/exam8$ 

演習問題

演習問題はこのリンクをクリックしてください。