with_itemsとregisterを組み合わせたAnsible playbookで苦労した

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 }}"