1. ホーム
  2. python

[解決済み] Ansible - 異なるキーのyamlでselectattrを使用する方法

2022-02-06 02:26:23

質問

Ansibleでyamlを解析し、あるキーをフィルタリングするという簡単なこと(簡単にできると思っていた)をやろうと毛嫌いしています。

私のyamlファイルは次のようなものです。

---

- vm: "vm1"
  ip: 10.10.10.1
- vm: "vm2"
  ip: 10.10.10.2
- test_vm: something
- another_vm: something_other

のような式になるのではと思いました。

lookup('file','my_file.yaml') | from_yaml | selectattr('vm','search','vm1')|list

は動作しますが、次のようなエラーが発生します。

fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ lookup('file','{{sysfile}}') | from_yaml | selectattr('vm','search','vm1')|list}}): expected string or bytes-like object"}

test_vmとanother_vmのキーを削除すると、正常に動作します。

ok: [localhost] => {
    "msg": [
        {
            "ip": "10.10.10.1",
            "vm": "vm1"
        }
    ]
}


test_vmのキーを検索しようとすると、次のように失敗します。

fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'test_vm'\n\nThe error appears to be ...

selectattrフィルターは、リスト内のすべてのdictsが同じキーを持つことを期待していますか?なぜなら、Jinja2でカスタムdictsのリストをフィルターできないのは意味がないからです。

例えば、もっと複雑なyaml(それほどフラットではない)を持っている場合、Ansible内での検索とフィルタリングは制限されますか?

例えば、次のようなyamlがあったとします。

---

- vm: "vm1"
  ip: 10.10.10.1
- vm: "vm2"
  ip: 10.10.10.2
- test_vm: something
   - process_1: X
   - process_2: Y
   - process_3: Z
- another_vm: something_other

例えば、process_2 を素早くフィルタリングするにはどうすればよいですか? 何か方法があるのでしょうか?

よろしくお願いします。

どのように解決するのですか?

<ブロッククオート

selectattr フィルタは、リスト内のすべてのディクショ ンが同じキーを持つことを期待しているのでしょうか?

より正確には、リスト内のすべてのディクテが、選択中の属性を持つことを期待しているのです。もしリスト内のすべてのディクテがそれを持っていない場合、まずそれが定義されていない項目をフィルタリングする必要があります。これは、次のようにして行うことができます。 selectattr と同じです。(最初の回答から分かりやすくしてくれた@Randyに感謝します)。

あなたの状況では json_query フィルター (を実装しています。 jmespath ) も、時にはもっとコンパクトな方法で仕事をすることができます。しかし、これはコアフィルタではありません。 community.general コレクション をインストールした。

以下は、上記の要件からコアフィルタと json_query というソリューションがあります。

プレイブック

---
- name: "Filter data with core filters or json query"
  hosts: "localhost"
  gather_facts: false

  vars:
    # Your initial data on a single line for legibility
    test_var: [{"vm":"vm1"},{"ip":"10.10.10.1"},{"vm":"vm2","ip":"10.10.10.2"},{"test_vm":"something","process_1":"X","process_2":"Y","process_3":"Z"},{"another_vm":"something_other"}]

  tasks:
    - name: Get objects having vm==vm1
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('vm', 'defined') | selectattr('vm', '==', 'vm1') | list }}
          With json_query: {{ test_var | json_query("[?vm=='vm1']") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

    - name: Get all objects having vm attribute
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('vm', 'defined') | list }}
          With json_query: {{ test_var | json_query("[?vm]") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

    - name: Get all objects having process_2 attribute
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('process_2', 'defined') | list }}
          With json_query: {{ test_var | json_query("[?process_2]") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

    - name: Get only a list of process_2 attributes
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('process_2', 'defined') | map(attribute='process_2') | list }}
          With json_query: {{ test_var | json_query("[].process_2") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

となります。

PLAY [Filter data with core filters or json query] *********************************************************************

TASK [Get objects having vm==vm1] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: [{'vm': 'vm1', 'ip': '10.10.10.1'}]",
        "With json_query: [{'vm': 'vm1', 'ip': '10.10.10.1'}]"
    ]
}

TASK [Get all objects having vm attribute] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: [{'vm': 'vm1', 'ip': '10.10.10.1'}, {'vm': 'vm2', 'ip': '10.10.10.2'}]",
        "With json_query: [{'vm': 'vm1', 'ip': '10.10.10.1'}, {'vm': 'vm2', 'ip': '10.10.10.2'}]"
    ]
}

TASK [Get all objects having process_2 attribute] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: [{'test_vm': 'something', 'process_1': 'X', 'process_2': 'Y', 'process_3': 'Z'}]",
        "With json_query: [{'test_vm': 'something', 'process_1': 'X', 'process_2': 'Y', 'process_3': 'Z'}]"
    ]
}

TASK [Get only a list of process_2 attributes] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: ['Y']",
        "With json_query: ['Y']"
    ]
}

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