【Ansible】ホストごとにregisterした結果を集約したい

## はじめに

各ホストに対するタスクの結果をregisterで変数に格納し、結果を1つの変数に
集約したいということがあります。今回はこれをjson_query filterで実現してみようと思います。

## TL;DR

- ホストごとにregisterで変数に格納した結果は、`{{ hostvars['<ホスト名>']} }`で呼び出すことが可能
- ホストごとにregisterで変数に格納した結果は、json_query filterでlocalhostに集約する

## 前提条件

- Ansibleにおけるフィルターの使い方を理解していること

## 実行環境

- ansible-core: 2.16.0

## 詳細

### 1. 実行するPlaybook

- Playbookでは大きくわけて以下2つのことを実行します
  - ホストごとのdebugモジュールの結果を、変数`register_result`に格納する
  - ホストごとに定義した変数`register_result`を、json_query filterでlocalhostの変数`aggregate_result`に集約する

```yaml:aggregate_register.yml
---
- name: "Aggregate register"
  hosts: host01,host02
  gather_facts: false
  tasks:
    - name: Define register_result
      ansible.builtin.debug:
        msg: "Hello {{ inventory_hostname }}"
      register: register_result
    
    - name: Display variables
      ansible.builtin.debug:
        msg:
          - "register_result: {{ register_result }}"
          - "hostvars['host01'].register_result: {{ hostvars['host01'].register_result }}"
          - "hostvars['host02'].register_result: {{ hostvars['host02'].register_result }}"
    
    - name: Aggregate Variable to aggregate_result
      ansible.builtin.set_fact:
        aggregate_result: >-
          {{ hostvars | community.general.json_query("*.register_result") }} 
      delegate_to: localhost
      run_once: true

    - name: Display aggregate_result
      ansible.builtin.debug:
        var: aggregate_result
      delegate_to: localhost
      run_once: true
```

### 2. 実行結果

ホストごとにregisterで変数に格納した結果は、`{{ hostvars['<ホスト名>']} }`に格納されるので、
これを活用してlocalhostの変数`aggregate_result`に集約します

```console
$ ansible-navigator run aggregate_register.yml -i inventory -m stdout

PLAY [Aggregate register] ******************************************************

TASK [Define register_result] **************************************************
ok: [host01] => {
    "msg": "Hello host01"
}
ok: [host02] => {
    "msg": "Hello host02"
}

TASK [Display variables] *******************************************************
ok: [host01] => {
    "msg": [
        "register_result: {'msg': 'Hello host01', 'failed': False, 'changed': False}",
        "hostvars['host01'].register_result: {'msg': 'Hello host01', 'failed': False, 'changed': False}",
        "hostvars['host02'].register_result: {'msg': 'Hello host02', 'failed': False, 'changed': False}"
    ]
}
ok: [host02] => {
    "msg": [
        "register_result: {'msg': 'Hello host02', 'failed': False, 'changed': False}",
        "hostvars['host01'].register_result: {'msg': 'Hello host01', 'failed': False, 'changed': False}",
        "hostvars['host02'].register_result: {'msg': 'Hello host02', 'failed': False, 'changed': False}"
    ]
}

TASK [Aggregate Variable to aggregate_result] **********************************
ok: [host01 -> localhost]

TASK [Display aggregate_result] ************************************************
ok: [host01 -> localhost] => {
    "aggregate_result": [
        {
            "changed": false,
            "failed": false,
            "msg": "Hello host01"
        },
        {
            "changed": false,
            "failed": false,
            "msg": "Hello host02"
        }
    ]
}

PLAY RECAP *********************************************************************
host01                     : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host02                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

## さいごに

- json_query filterを使いこなすと、変数から必要な個所をだけを抽出することができる
- json_query filterにおけるクエリの書き方は、[JMESPath Tutorial](https://jmespath.org/tutorial.html)
を参考にするとよい

## 参考URL

- [community.general.json_query filter](https://docs.ansible.com/ansible/latest/collections/community/general/json_query_filter.html)
- [JMESPath Tutorial](https://jmespath.org/tutorial.html)