Ansibleのselectattrとmapとlist

最近またAnsibleでAWSの構成を書き始めました。

selectattrとmapが便利

次のような値を with_items で回してサブネットを作るとともに、publicなものを取り出してルートテーブルを作りたくなったのですが、selectattr()map()を使うと取り出すことができました。

---
vpc_subnets:
  - { name: bastion, az: ap-northeast-1a, cidr: 10.0.1.0/28, tier: bastion, public: true }
  - { name: web1a, az: ap-northeast-1a, cidr: 10.0.10.0/24, tier: web, public: true }
  - { name: web1c, az: ap-northeast-1c, cidr: 10.0.11.0/24, tier: web, public: true }
  - { name: db1a, az: ap-northeast-1a, cidr: 10.0.20.0/24, tier: db }
  - { name: db1c, az: ap-northeast-1c, cidr: 10.0.21.0/24, tier: db }
- name: get public cidr list
  set_fact:
    v: '{{ vpc_subnets | selectattr("public", "defined") | selectattr("public", "equalto", true) | map(attribute="cidr") | list}}'
- debug: var=v

結果

TASK [vpc : get public cidr list] **********************************************
ok: [localhost]

TASK [vpc : debug] *************************************************************
ok: [localhost] => {
    "v": [
        "10.0.1.0/28",
        "10.0.10.0/24",
        "10.0.11.0/24"
    ]
}

ドキュメント

generator object _select_or_rejectやgenerator object do_mapの中身を見るにはlist

selectattr()map()をかました変数をdebugで出力しようとするとオブジェクトになってしまって中身が見られないのですが、listを使ってあげると確認できるのも学びました。便利。

ok: [localhost] => {
    "v": "<generator object do_map at 0x1039fd730>"
}

とか

ok: [localhost] => {
    "v": "<generator object do_map at 0x1039fd730>"
}

が、listを使うと

ok: [localhost] => {
    "v": [
        {
            "az": "ap-northeast-1a",
            "cidr": "10.0.1.0/28",
            "name": "bastion",
            "public": true,
            "tier": "bastion"
        },
        {
            "az": "ap-northeast-1a",
            "cidr": "10.0.10.0/24",
            "name": "web1a",
            "public": true,
            "tier": "web"
        },
        {
            "az": "ap-northeast-1c",
            "cidr": "10.0.11.0/24",
            "name": "web1c",
            "public": true,
            "tier": "web"
        }
    ]
}

その他のフィルター

他にもいろんなフィルターがあって便利です。 ただ、できるからといっていろいろやりすぎるのは良くないですね。 1ヶ月後の自分が見ても分かるように、できるだけシンプルにわかりやすく記述したいところです。