[Ansibleで条件分岐]タスクの実行結果に応じて次のタスクをするかしないか決める方法(小ネタ)

先日、社内のAnsible勉強会(TUF研修)にてAnsibleを扱ったのですが、冒頭で挙げた方法があるか調べることがありました。今回はその調査結果と実際にplaybookにどのように落とし込んだのか、その書き方をまとめます。

※TUF研修ってなに？チョット気になるという方に向けてリンクを貼っておきます。
　[「実績がないならつくればいいーーAPCが挑むエンジニア育成のベストプラクティス」](https://www.pr-table.com/ap-communications/stories/4113)


結論から言うとAnsibleでも一般的なプログラミングでいうif文のような条件分岐をさせることは可能です。

今回はhandlersとstatの2つを採用しました。
#Handlers
まずhandlersの書き方です。

・ここでは、以下の3つのタスクがあるとします。
　- 常に実行するwordpress.tar.gzのダウンロードというget wp
　- wordpress.tar.gzの展開というunarchive wp
　- wordpress.tar.gzの中身のファイル群の所有者(オーナー)の変更をするchown wp user


・またunarchive wpとchown wp userは、get wpの実行前と実行後で差分が見られる場合(ここでは、初めてwordpress.tar.gzをダウンロードした場合)のみ実行するタスクとします。
いわば、**get wpはunarchive wpとchown wp userにとってトリガー**というわけです。

それでは、Handlersを使ってplaybookを書いてみましょう。

```yaml

tasks:
  - name: get wp #トリガー
    get_url:
      url: "{{ wp_url }}"
        dest: "{{ wp_saved_at }}"
      notify:
        - unarchive wp  #トリガーとなるタスクを実行後、実行前と比較して差分が見られる場合(changedとなる場合)、実行
        - chown wp user #同上
       
handlers:
  - name: unarchive wp　#差分が見られる場合(changedとなる場合)、実行するタスク
    unarchive:
      src: "{{ wp_saved_at }}"
      dest: "{{ wp_unarchived_at }}"
      copy: no

  - name: chown wp user #差分が見られる場合(changedとなる場合)、実行するタスク
    file:
      path: "{{ wp_unarchived_at }}/wordpress"   #*1
      owner: ansible
      group: ansible
      recurse: yes 
```
*1 変数とベタ書きとを組み合わせて任意の値を指定することができます。
詳しくは[[Ansible]変数とベタ書きとを組み合わせて値を指定する方法(超小ネタ)](https://qiita.com/gkzz/items/973762e29b6f8e53b422)で取り上げているのでご参照ください。

ポイントは、トリガーの実行結果を踏まえてタスクの実行の有無を決めたいタスクはシーケンス形式(一般的なプログラミング言語では、配列、リストと同じような扱い)で定義するという点です。
なお、**シーケンス形式で記載したタスク同士のいずれかをトリガーとするようなことはできるかは不明**です。

#stat
続いてstatです。
ところでなぜHandlersだけではなく、statも扱うことにしたのでしょう？


それは、statはHandlersと違ってif文のように想定した条件に合致した場合、指定したタスクを実行することができるからです。

今回、私はwordpress.tar.gzを外部からダウンロードするのは1度だけにしたかったので、wordpress.tar.gzの存在が確認できない場合のみ、ダウンロードするというタスクを実行することとしました。

```yaml
---
- hosts: web
  become: yes
  vars:
    wp_url: http://wordpress.org/latest.tar.gz
    wp_saved_at: /tmp/wordpress.tar.gz
    wp_unarchived_at: /var/www/html/
 tasks:
    - stat: 
        path: "{{ wp_saved_at }}"　# *1 ls {{ wp_saved_at }}
      register: already_saved      # *2  *1の結果
    - name: get wp
      when: not already_saved.stat.exists   # *3 *2で保存した*1の正常出力が確認できない場合
　　　 when: already_saved.stat.exists #正常出力が確認できる場合
      get_url:
        url: "{{ wp_url }}"
        dest: "{{ wp_saved_at }}"
      notify:
        - unarchive wp
        - chown wp user
```


実行するとこんな感じで出力されます。

```
TASK [get wp] ******************************************************************
skipping: [192.168.33.210]
```

追記
社内の[@akira6592](https://twitter.com/akira6592)さんからフィードバックをいただき、下記のように書くとスマート！と教えていただいたので共有します。
chownのところをunarichiveに含めたかたちですね。
フィードバックありがとうございます。

```yaml

tasks:
  - name: unarchive wp
    unarchive:
      src: "{{ wp_url }}" 
      dest: "{{ wp_unarchived_at }}"
      owner: ansible
      group: ansible
```


参考
- [Handlers: Running Operations On Change - Ansible Documentation](https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html#handlers-running-operations-on-change
- [Ansiblejp Slack Community #qa](https://app.slack.com/client/TBV5736HY/CBV59MFV0)
- [Using Ansible to check version before install or upgrade - The Accidental Developer](
https://osric.com/chris/accidental-developer/2018/03/using-ansible-to-check-version-before-install-or-upgrade/)

P.S. Twitterもやってるのでフォローしていただけると泣いて喜びます！
[@gkzvoice](https://twitter.com/gkzvoice)