with_itemsとregisterを組み合わせたAnsible playbookで苦労した
趣味と仕事にて、Ansibleを使いこなせるよう勉強中です。今回は、古いログファイルを削除するplaybookを書く際に、気づけたことがあったのでメモします。
古いログファイルを削除するplaybook
playbookで実現したい操作を簡単に書くと、「対象ディレクトリ内にある古いファイルをfindモジュールで発見してregisterしておき、次にwith_itemsのループでファイルを削除すること」となる。サンプルのplaybookは、ウェブ検索で大量に見つけられる。
しかし、対象ディレクトリを複数にしようと考えた場合に、私にとっては一気に難しくなってしまったのであった。
対象ディレクトリが1つの場合
対象ディレクトリが「~/.screen_log/
」の1つであるplaybookは、次のようになる。簡素に書けて素晴らしい。
- hosts: all
tasks:
- name: Find old logfiles
find:
path: "~/.screen_log/"
age: "30d"
register: files_found
- name: Delete old logfiles
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ files_found.files }}"
対象ディレクトリが2つ以上の場合
対象ディレクトリが2つ以上の場合、「Find old logfiles」部分を、対象ディレクトリを複数指定できるようにwith_itemsを使って書くのが普通だろう。
しかしこの状態にしたところ、「Delete old logfiles」部分が対象ディレクトリ1つの場合と同じままだと動かない。1,2時間悩んでdebug
など使いながら理解したこととして。
「Find old logfiles」部分をwith_itemsを使って書いた場合は、files_foundに登録されるデータの構造が変わり、階層が追加された内容となるのだ。そこで、「Delete old logfiles」部分のファイル情報抽出で、下記のようにmap()
やlist()
を使うようにしたら問題解決した。
- hosts: all
tasks:
- name: Find old logfiles
find: paths={{ item.path }} age={{ item.age }}
with_items:
- { "path":"~/.screen_log/", "age":"30d" }
- { "path":"~/.tmux_log/", "age":"30d" }
register: files_found
- name: Delete old logfiles
file:
path: "{{ item.path }}"
state: absent
#with_items: "{{ files_found.files }}" # エラーになる
with_items: "{{ files_found.results | map(attribute='files') | list }}"