Ansible: changed_when の使い方

Ansible の Playbook での、changed_when の使い方を説明します。
changed_when は冪等性を考慮した Playbook を書くために、重要な要素になります。

changed_when が必要なケース

下のような Playbook があるとします。

---
- name: Test Playbook
  hosts: 192.168.1.1

  tasks:
  - name: Absent tmp folder
    win_shell: |
      $ret = Test-Path -Path C:\tmp
      if ($ret) {
        Remove-Item -Path C:\tmp -Force
      }

C:\tmp フォルダーがない状態にする Playbookです。
フォルダーがある場合のみ削除を実行し、ない場合は何もしていません。
一見、冪等性を考慮した書き方になっていますが、この Playbook を実行すると、C:\tmp の有無にかかわらず、必ず次のような結果となります。

PLAY [Test Playbook] *****************************************************************************

TASK [Absent tmp folder] *************************************************************************
changed: [192.168.1.1]

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

このままでは、win_shell が実行された場合は必ず changed=1 となってしまいます。

changed_when を使ったPlaybook

フォルダーを削除した場合のみ changed=1 としたい場合は、Playbook を次のように書きます。

---
- name: Test Playbook
  hosts: 192.168.1.1

  tasks:
  - name: Absent tmp folder
    win_shell: |
      $ret = Test-Path -Path C:\tmp
      if ($ret) {
        Remove-Item -Path C:\tmp -Force
        Write-Output 1
      }
    register: ret
    changed_when: (ret.stdout | int) == 1

フォルダーの削除を実行した場合は、標準出力に 1 を出力しています。

        Write-Output 1

register で win_shell の戻り値を ret に格納しています。

    register: ret

win_shell の戻り値については、次のサイトを参照してください。
https://docs.ansible.com/ansible/2.9_ja/modules/win_shell_module.html#return-values

ret.stdout は、win_shell の標準出力です。標準出力の値が「1」の場合、changed=1 とします。

    changed_when: (ret.stdout | int) == 1

ret.stdout は文字列なので、(ret.stdout | int) と数値に変換してから判別しています。

以上のような changed_when の使い方で、どのような場合に changed=1 にするかを制御できます。