てくなべ (tekunabe)

ansible / network / automation

[Ansible] Jinja2 の select フィルターでリストから特定の型の要素を抽出する

はじめに

Ansible が内部で利用しているテンプレートエンジン Jinja2 には select というフィルターがあります。(逆は reject

これまでは、Jinja2 公式ドキュメントの例のように、条件と一致する要素を抽出するものだと思っていました。

あるとき「指定した型を一致する要素を抽出できないものか」とおもったときに、こんな方法を教えていただきました。

他にもいくつの型で試してみましたので、結果をまとめます。

  • 動作環境
    • Ansible 2.9.9
    • Jinja2 2.11.2

おためしPlaybook

以下のような Playbook で試します。

testlist にいろいろな型を含めたリストを定義します。そのリストに対して、select フィルターで numberstring などの型を指定して抽出します。

指定できそうな型をしらべるときはこのあたりを見ました。

---
- hosts: localhost
  gather_facts: false

  vars:
    testlist:
      - true
      - 123
      - "456"
      - "hello"
      - 
        - "a"
        - "b"
      - k1: v1
        k2: v2

  tasks:
    - name: select test
      debug:
        msg: "{{ testlist | select(item) | list }}"
      loop:
        - number
        - integer
        - float
        - boolean
        - sequence
        - mapping

結果

実行結果です。

TASK [select test] ***********************************
ok: [localhost] => (item=number) => {
    "msg": [   // true も抽出されたのが意外でした
        true
        123
    ]
}
ok: [localhost] => (item=integer) => {
    "msg": [   // 整数が抽出されました。"456" は文字列なので対象外。
        123
    ]
}
ok: [localhost] => (item=float) => {
    "msg": []   // 今回は float はなし
}
ok: [localhost] => (item=string) => {
    "msg": [    // 文字列が抽出つされました。"456" はやはり文字列。
        "456",
        "hello"
    ]
}
ok: [localhost] => (item=boolean) => {
    "msg": [    // 予想通り
        true
    ]
}
ok: [localhost] => (item=sequence) => {
    "msg": [    // 意外な結果。 iterable なものはなんでも抽出されるよう
        "456",
        "hello",
        [
            "a",
            "b"
        ],
        {
            "k1": "v1",
            "k2": "v2"
        }
    ]
}
ok: [localhost] => (item=mapping) => {
    "msg": [    // 予想通り
        {
            "k1": "v1",
            "k2": "v2"
        }
    ]
}

おわりに

sequence の結果が一番意外でした。本当にリストだけを抽出できる方法があれば知りたいです。

おまけ情報ですが、サンプル Playbook にある | listansible 2.10 から不要になります。