Ansibleのタグの継承について

Ansibleのタグを使い始めた際に、継承について知らずにその動作に戸惑ったことがあったのでメモを残しておきます。
今回の記事ではAnsibleのコマンドについては説明していないので、ある程度Ansibleを触っている方が対象になります。

### タグの動作検証

最初に、次のようなplaybookを準備します。

```yaml:playbook.yml
---
- hosts: localhost
  gather_facts: false
  connection: local

  tasks:
    - name: task1
      debug:
        msg: task1
      tags:
        - blue

    - name: task2
      debug:
        msg: task2
      tags:
        - blue
        - green

    - name: task3
      debug:
        msg: task3
      tags:
        - green

    - name: task4
      debug:
        msg: task4
```

このplaybookにタグを指定して実行します。ここでは blue を指定します。

```console
$ ansible-playbook --tags=blue playbook.yml
PLAY [localhost] ************************************************************************************

TASK [task1] ****************************************************************************************
ok: [localhost] => {
    "msg": "task1"
}

TASK [task2] ****************************************************************************************
ok: [localhost] => {
    "msg": "task2"
}

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

```

タグに blue を設定したタスクのみが、実行されているのが確認できます。

次にロールを作成し、同様のタスクをロール下で行うように設定します。
まず、ロールを作成します。

```console
$ ansible-galaxy init --init-path="roles" blue
$ tree
.
├── playbook.yml
└── roles
    └── blue
        ├── README.md
        ├── defaults
        │   └── main.yml
        ├── files
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── tasks
        │   └── main.yml
        ├── templates
        ├── tests
        │   ├── inventory
        │   └── test.yml
        └── vars
            └── main.yml
```

次にroles/blue/tasks/main.ymlの内容を、先程のplaybookのタスクと同様の内容となるように記述します。

```yaml:roles/blue/tasks/main.yml
---
# tasks file for blue
- name: task1
  debug:
    msg: task1
  tags:
    - blue

- name: task2
  debug:
    msg: task2
  tags:
    - blue
    - green

- name: task3
  debug:
    msg: task3
  tags:
    - green

- name: task4
  debug:
    msg: task4
```

playbookの内容を、今作成したロールを実行するように修正します。

```yaml:playbook.yml
---
- hosts: localhost
  gather_facts: false
  connection: local

  roles:
    - role: blue
```

この状態で先程と同様にタグに blue を指定して実行します。

```console
$ ansible-playbook --tags=blue playbook.yml
PLAY [localhost] ************************************************************************************

TASK [blue : task1] *********************************************************************************
ok: [localhost] => {
    "msg": "task1"
}

TASK [blue : task2] *********************************************************************************
ok: [localhost] => {
    "msg": "task2"
}

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

```

結果も先程と同様で、タグに blue を設定したタスクのみが実行されています。

次にplaybookのロールの設定にタグの設定を追加して、同様のコマンドを実行します。

```yaml:playbook.yml
---
- hosts: localhost
  gather_facts: false
  connection: local

  roles:
    - role: blue
      tags: blue
```

```console
$ ansible-playbook --tags=blue playbook.yml
PLAY [localhost] ************************************************************************************

TASK [blue : task1] *********************************************************************************
ok: [localhost] => {
    "msg": "task1"
}

TASK [blue : task2] *********************************************************************************
ok: [localhost] => {
    "msg": "task2"
}

TASK [blue : task3] *********************************************************************************
ok: [localhost] => {
    "msg": "task3"
}

TASK [blue : task4] *********************************************************************************
ok: [localhost] => {
    "msg": "task4"
}

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

```

すると、タグに blue を設定していないタスクまで実行されているのが確認できます。

### タグの継承について
この動作は、Ansibleのユーザーガイドにも記載されている「タグの継承」による動作になります。

https://docs.ansible.com/ansible/2.9_ja/user_guide/playbooks_tags.html#tag-inheritance

タスクのインポートやロールを設定する際に tags: の設定を追加すると、含まれている全てのタスクにタグを追加します。これが「タグの継承」です。

わかるとなるほどと思うのですが、知らずに触っている時は「あれ？」と首を傾げてしまいました。

### タグをスキップする際の注意
Ansibleには--skip-tagsオプションを指定して、タグが設定されたタスクをスキップすることができます。
しかしながら「タグの継承」が行われている状況では、このオプションの以下のような特性に注意する必要があります。

- 「タグの継承」が行われてから適用されます。
- --tagsの指定より、--skip-tagsの指定が優先されます。

先程のplaybookに--skip-tagsの指定を追加して実行してみます。

```console
$ ansible-playbook --tags=blue --skip-tags=green playbook.yml
PLAY [localhost] ************************************************************************************

TASK [blue : task1] *********************************************************************************
ok: [localhost] => {
    "msg": "task1"
}

TASK [blue : task4] *********************************************************************************
ok: [localhost] => {
    "msg": "task4"
}

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

先程までと違い、タスク1とタスク4が実行されています。

- タスク1はblueタグが設定されているので、実行されます。
- タスク2はblueタグとgreenタグが設定されていますが、--skip-tags=greenの指定が優先され実行されません。
- タスク3はgreenタグと「タグの継承」によりblueタグが設定されていますが、--skip-tags=greenの指定が優先され実行されません。
- タスク4は「タグの継承」によりblueタグが自動設定され、実行されます。

タグのスキップは、「タグの継承」と組み合わされると思わぬ動作を引き起こす可能性が出てくるので、注意したいところです。

### 参考ページ

- [[Ansible] --tags と --skip-tags 併用時の挙動 - てくなべ (tekunabe)](https://tekunabe.hatenablog.jp/entry/2020/04/01/ansible_tags)