Ansibleで条件にマッチするファイルだけ処理する方法


Ansible2.2から追加されたjson_queryフィルターを使って、いくつかある候補のファイルのうち、存在するファイルだけ処理対象とする方法を紹介します。

たとえば、以下のような候補のうち、存在するファイルだけ処理したいとします。

  • /var/file1
  • /var/hoge/file2
  • /var/fuga/file2

よくある書き方だと以下のようなタスクの組合せをファイル毎に書かなければなりません。

- name: check if file exists
  stat:
    path: /var/file1
  register: file1

- name: do something with file1
  ...
  when: file1.stat.exists

以下のようにすること、ファイルの数にかかわらずタスクを2つ書くだけで済みます。

- name: "check target files existence"
  stat:
    path: "{{ item }}"
  with_items:
    - /var/file1
    - /var/hoge/file2
    - /var/fuga/file3
  register: target_file_existence

- name: do something with existing files
  shell: cat {{ item }}
  with_items: "{{ target_file_existence.results | json_query('[? stat.exists==`true`].item') }}"

解説編

target_file_existence変数に格納された、各ファイルのstatの結果は、以下のようになっています。

- debug:
    var: target_file_existence.results 
{
    "target_file_existence": {
        "changed": false,
        "msg": "All items completed",
        "results": [
            {
                ...
                "item": "/var/file1",
                "stat": {
                    ...
                    "exists": true,
                    ...
                }
                ...
            },
            {
                ...
                "item": "/var/hoge/file2",
                "stat": {
                    ...
                    "exists": true,
                    ...
                }
            },
            {
                ...
                "item": "/var/fuga/file3",
                "stat": {
                    "exists": false
                }
            }
        ]
    }
}

以下のように記述することで、target_file_existence変数のresult要素に対して、stat.existstrueであるitem要素(ファイル名)を抽出しています。

"{{ target_file_existence.results | json_query('[? stat.exists==`true`].item') }}"

応用編:候補のうち最初に見つかったファイルを対象にする

候補のうち最初に見つかった見つかったファイルを対象にしたい場合、さらにfirstフィルタを追加すれば簡単に実現できます。

"{{ target_file_existence.results | json_query('[? stat.exists==`true`].item') | first }}"

参考