【Ansible】json_queryの活用～1回目：contain/starts_with/ends_with/and/or～

### はじめに
<バージョン>
ansible 2.9.1
jinja2 2.11
jmespath 0.9.3

Ansibleのjson_queryフィルタは便利なのですが、意外に記事が少なくて調べるのに苦労したので
まとめておきます。特に、contain/starts_with/ends_withはクセが強めで
使い方を理解するのに2時間くらいかかった気がします。

### Playbook紹介
今回はよくある7パターンを紹介します

| パターン | 内容 | playbookでの抽出例 | 
|:-----------|:------------|:------------|
| 1 | 特定の文字列に一致する(query_stringに変数なし) | "aaa_bbb.txt"に一致する |
| 2 | 特定の文字列に一致する(query_stringに変数あり) | "aaa_bbb.txt"に一致する |
| 3 | 特定の文字列を含む（contain） | "aaa"を含む |
| 4 | 特定の文字列から始まる（starts_with） | "bbb"から始まる |
| 5 | 特定の文字列で終わる（ends_with） | ".txt"で終わる |
| 6 | and条件 | "aaa"から始まる __and__ ".txt"で終わる |
| 7 | or条件 | "aaa"から始まる __or__ ".txt"で終わる |

__ポイント__
（1）パターン2のようにquery_stringに変数を入れる場合、{{ search_name }}のように変数を囲む
　　[参考：属性がAnsibleの変数と等しいjson配列から値を取得する](https://www.366service.com/jp/qa/ae1eb68c39dd20793a4bd7c0f4cc3fe8)
（2）containやstarts_withを使う場合は、to_json | from_json とフィルタを通す

```yaml:jmes_path.yml
---
- name: "json_query test"
  hosts: localhost
  connection: local
  gather_facts: no
  vars:
    search_name: "aaa_bbb"
    sample:
      - id: 1
        name: "aaa_bbb.txt"
      - id: 2
        name: "bbb_ccc.log"
      - id: 3
        name: "aaa_bbb_txt"

  tasks:
    - name: "pattern1 - {{ query_string }}"
      debug:
        var: sample | json_query(query_string)
      vars:
        query_string: "[?name=='aaa_bbb.txt'].name"

    - name: "pattern2 - {{ query_string }}"
      debug:
        var: sample | json_query(query_string)
      vars:
        query_string: "[?name=='{{ search_name }}.txt'].name"    # ポイント(1)

    - name: "pattern3 - {{ query_string }}"
      debug:
        var: sample | to_json | from_json | json_query(query_string)    # ポイント(2)
      vars:
        query_string: "[?contains(name, 'aaa')].name"

    - name: "pattern4 - {{ query_string }}"
      debug:
        var: sample | to_json | from_json | json_query(query_string)
      vars:
        query_string: "[?starts_with(name, 'bbb')].name"

    - name: "pattern5 - {{ query_string }}"
      debug:
        var: sample | to_json | from_json | json_query(query_string)
      vars:
        query_string: "[?ends_with(name, '.txt')].name"

    - name: "pattern6 - {{ query_string }}"
      debug:
        var: sample | to_json | from_json | json_query(query_string)
      vars:
        query_string: "[?starts_with(name, 'aaa') && ends_with(name, '.txt')].name"

    - name: "pattern7 - {{ query_string }}"
      debug:
        var: sample | to_json | from_json | json_query(query_string)
      vars:
        query_string: "[?starts_with(name, 'aaa') || ends_with(name, '.txt')].name"
```

### 実行結果
想定通りの結果を得ることが出来ました

```text:出力
[ec2-user@ip-<ip addr> ansible]$ ansible-playbook jmes_path.yml

PLAY [json_query test] *************************************************************************************************

TASK [pattern1 - [?name=='aaa_bbb.txt'].name] **************************************************************************
ok: [localhost] =>
  sample | json_query(query_string):
  - aaa_bbb.txt

TASK [pattern2 - [?name=='aaa_bbb.txt'].name] **************************************************************************
ok: [localhost] =>
  sample | json_query(query_string):
  - aaa_bbb.txt

TASK [pattern3 - [?contains(name, 'aaa')].name] ************************************************************************
ok: [localhost] =>
  sample | to_json | from_json | json_query(query_string):
  - aaa_bbb.txt
  - aaa_bbb_txt

TASK [pattern4 - [?starts_with(name, 'bbb')].name] *********************************************************************
ok: [localhost] =>
  sample | to_json | from_json | json_query(query_string):
  - bbb_ccc.log

TASK [pattern5 - [?ends_with(name, '.txt')].name] **********************************************************************
ok: [localhost] =>
  sample | to_json | from_json | json_query(query_string):
  - aaa_bbb.txt

TASK [pattern6 - [?starts_with(name, 'aaa') && ends_with(name, '.txt')].name] ******************************************
ok: [localhost] =>
  sample | to_json | from_json | json_query(query_string):
  - aaa_bbb.txt

TASK [pattern7 - [?starts_with(name, 'aaa') || ends_with(name, '.txt')].name] ******************************************
ok: [localhost] =>
  sample | to_json | from_json | json_query(query_string):
  - aaa_bbb.txt
  - aaa_bbb_txt

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

### 参考資料

[JMESPath Specification](https://jmespath.org/specification.html#or-expressions)
[Ansible Documentation](https://docs.ansible.com/ansible/2.9/user_guide/playbooks_filters.html#json-query-filter)
[属性がAnsibleの変数と等しいjson配列から値を取得する](https://www.366service.com/jp/qa/ae1eb68c39dd20793a4bd7c0f4cc3fe8)

### 関連記事

[【Ansible】json_queryの活用～2回目：to_string/max_by/min_by/length/type～](https://qiita.com/masa2223/items/f12dba3237bcdcd33321)