Ansible のフィルターに extract がある。 今までイマイチ使い方を理解してなかったが、ソースを見たりしてようやく理解に達した。

extract の使い方は Extracting values from containers に載っている。 が、ほぼ map との組み合わせを前提に作られているのため、単体としての動きが分かり難い。

単体で使う

map と組み合わせずに使うとどうなるか。

- hosts: localhost
  vars:
    container:
      a: AAA
      b: BBB

  tasks:
    - debug:
        msg: '{{ "a" | extract(container) }}'
TASK [debug] *************
ok: [localhost] => {
    "msg": "AAA"
}

container からフィルターとして与えたキー("a")の値を取り出す動作となる。

ただ、これって、{{ container.a }}{{ container['a'] }} と変わらず、何の意味がなるの?ってなってしまう。

mapと組み合わせる

ところが、mapとの組み合わせると有用性が出てくる。 フィルターとして与えたキーのリストから、それぞれの値を取り出すことができるようになる。

tasks:
  - debug:
      msg: '{{ ["a","b"] | map("extract", container) | list }}'
TASK [debug] *************
ok: [localhost] => {
    "msg": [
        "AAA",
        "BBB"
    ]
}

各ホストのファクト値をまとめて取り出す

各ホストで実行したタスクの結果を最後にまとめて出力させてみる。

- hosts: host1, host2
  tasks:
    - command: whoami
      register: whoami_result
        
  post_tasks:
    - debug:
        msg: |-
          {{ ansible_play_hosts |
              map("extract", hostvars, ["whoami_result", "stdout"]) |
                list }}'
      run_once: true

各playで実行したホストのリストはansible_play_hostsにある。また、hostvarsから各ホスト名をキーにしたdictにファクト情報がある。 hostavars[ホスト名].whoami_result.stdout を取り出すには、上記のような記述になる。

全てのホストでタスクが成功していたら、次のタスクを実行。みたいのに使えそうである。

json_query の方が楽かも^^;

ここまで書いておいてなんだけど、json_queryを使ったほうが楽かもしれない。

    - debug:
        msg: |-
          {{ hostvars | json_query("*.whoami_result.stdout") }}
      run_once: true