はじめに
Ansibleでループ処理をするためにwith_itemsにリストを渡すというのはよくあるが、リストから一部のリストを除外するいい方法について書く。
実行version: Ansible 2.6
リストの除外をする例
SSL自己証明書や正規のSSL証明書をサーバに入れるroleを例にあげたい。
NginxとApacheで以下のような変数を定義し、https: true
となっている場合はSSL自己証明書を発行したい。
nginx:
sites:
- server_name: www.example.com
https: true
- server_name: api.example.com
https: true
ただし次のように追加で定義した場合は正規の証明書をcopyする。
ssl_cert:
certs:
- server_name: www.example.com
local_key_path: /tmp/server.key # Ansible実行サーバにある配布する秘密鍵
local_crt_path: /tmp/server.crt # Ansible実行サーバにある配布する証明書
これを実現するには、nginx.sites
からssl_cert.certs
を引いたリストをwith_itemsに渡さなければいけない。
differenceフィルタ
リストの引き算はdifferenceフィルタを使ってlist1 | difference(list2)
で対応できる。
- include_tasks: self_signed_ssl.yml
with_items:
- '{{ nginx.sites | selectattr("https") | map(attribute="server_name") | unique | list | difference(ssl_cert.certs | map(attribute="server_name") | list) }}'
- '{{ apache.sites | selectattr("https") | map(attribute="server_name") | unique | list | difference(ssl_cert.certs | map(attribute="server_name") | list) }}'
differenceフィルタでも問題ないが、NginxのリストとApacheのリストの両方から正規証明書リストを引かなくてはならず、重複してしまっている。また横に間延びしてしまっている。
when item not in list
このような場合はwhen
を使うときれいに書ける。
- include_tasks: self_signed_ssl.yml
when: item not in (ssl_cert.certs | map(attribute="server_name") | list)
with_items:
- '{{ nginx.sites | selectattr("https") | map(attribute="server_name") | unique | list }}'
- '{{ apache.sites | selectattr("https") | map(attribute="server_name") | unique | list }}'
これであればwith_items
にどれだけリストを並べても各ループごとにwhen
で除外対象のリストに含まれているかどうかチェックしたうえで実行可否を判断してくれる。