Ansibleの呼吸 壱ノ型 フィルター芸「テキストファイルが保存されているディレクトリパス抜き」


この投稿はAnsible 3 Advent Calendar 2019の1日目の記事です。

一先ず空いていたので、古い日付から思いついたフィルター芸を投稿していってみようと思います。

特定の条件にマッチしたファイルの一覧から保存されているディレクトリパスを抜き出したい時があったりなかったりあったりします。
その時の簡単なフィルターです。

ディレクトリ構成

こんな感じでtxtファイルが保存されています。

(venv) [root@localhost ansible]# tree tmp/
tmp/
├── dirA
│   └── testA.txt
├── dirB
│   └── testB.txt
├── dirC
│   └── dirD
│       └── testC.txt
└── testD.txt

このtxtファイルが保存されているディレクトリ情報を抜き出してみたいと思います。

Playbook

Playbookはこんな感じです。

---
- name: iti no kata playbook
  hosts: localhost
  gather_facts: no
  tasks:
    - name: find files
      find:
        paths: tmp/
        recurse: yes
      register: find_result

    - debug:
        msg: >-
          {{ item.path.split('/') | difference(data) | join('/') }}
      vars:
        data: >-
          {{ [-1]
            | map('extract', item.path.split('/'))
            | map('regex_search', '^.*txt$')
            | list
          }}
      loop: "{{ find_result.files }}"
      loop_control:
        label: "{{ item.path }}"
      when:
        - item.mode == "0644"

findで tmp ディレクトリ配下のファイル情報を取得して loop で結果を回します。
ここでは、条件としてファイルのパーミッションが 0644 になっていているものが対象で、マッチしたものは data 変数の処理に移ります。
data では path キーの値を / でsplitして正規表現でマッチしたものをリスト化して最後の要素を抜き出し data 変数に格納します。
最後に path/ でsplitした者に対して difference フィルターを使って data 情報とマッチしている値を削除し / でjoinしています。

これを実行してみます。

playbook実行

(venv) [root@localhost ansible]# ansible-playbook main.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'


PLAY [iti no kata playbook] *****************************************************************************************************************************************

TASK [find files] ***************************************************************************************************************************************************
ok: [localhost]

TASK [debug] ********************************************************************************************************************************************************
ok: [localhost] => (item=tmp/testD.txt) => {
    "msg": "tmp"
}
ok: [localhost] => (item=tmp/dirA/testA.txt) => {
    "msg": "tmp/dirA"
}
ok: [localhost] => (item=tmp/dirB/testB.txt) => {
    "msg": "tmp/dirB"
}
ok: [localhost] => (item=tmp/dirC/dirD/testC.txt) => {
    "msg": "tmp/dirC/dirD"
}

PLAY RECAP **********************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

各ファイルが保存されているディレクトリがmsgで表示されました :)