#json #filter #ansible #json-query
Вопрос:
Используя Ansible, у меня есть большой файл JSON, из которого мне нужно добавить несколько значений. Упрощенная версия приведена здесь, но показывает основную структуру:
{
"metadata": { "version": "1.2.3.4" },
"operations": [
{
"resourceType": "type1",
"items":
[
{ "sometag1": "someval1" },
{ "sometag2": "someval2" }
]
},
{
"resourceType": "/certificates/ca",
"items":
[
{
"fileData": "EncryptedCertFile1",
"id": "trustedCerts_cert1"
},
{
"fileData": "EncryptedCertFile2",
"id": "trustedCerts_cert2"
},
{
"fileData": "EncryptedCertFile3",
"id": "trustedCerts_cert3"
}
]
}
]
}
Это две задачи, которые я использую, чтобы получить значение:
- name: Get Source JSON Data
set_fact:
jsonExp: "{{ lookup('file', '/tmp/{{ src_file_name }}') | from_json }}"
- name: Get Cert Info
set_fact:
cert_data: "{{ jsonExp | json_query(jquery) }}"
vars:
jquery: "operations[?resourceType=='/certificates/ca'].items[?id=='trustedCerts_cert2')]"
Но мне возвращается пустой массив json. Я прошел уровень за уровнем, и с помощью этой строки запроса я могу полностью перейти к массиву элементов:
operations[?resourceType=='/certificates/ca'].items[*]
Я даже могу получить список конкретных лабораторных работ:
operations[?resourceType=='/certificates/ca'].items[*].id
или
operations[?resourceType=='/certificates/ca'].items[*].fileData
Я также могу нацелиться на определенный элемент, используя массив индексов:
operations[?resourceType=='/certificates/ca'].items[1]
Но я, похоже, не могу заставить запрос работать для получения определенного элемента путем фильтрации записи «идентификатор».
Есть какие-нибудь предложения?
Ответ №1:
Я все понял!! Этот сайт-отличный инструмент для решения сложных запросов, подобных этому(по крайней мере, для меня). Как только я добрался до элементов части запроса, мне нужно было передать это во второй запрос:
operations[?resourceType=='/certificates/ca'].items[] | [?Id=='trustedCerts_cert2'].fileData
Комментарии:
1. «этот сайт» на самом деле является официальной
jmespath
документацией, языком запросов, используемымjson_query
Ответ №2:
Отслеживание вашего автоматического ответа json_query
действительно очень эффективно для сложных запросов.
Между тем, он не является частью ядра ansible, поэтому требуется установить дополнительную коллекцию и библиотеку python. Кроме того, были (и все еще есть ИМО) некоторые проблемы, связанные с обслуживанием jmespath. Вы можете найти краткое изложение некоторых примеров проблем здесь, и to_json | from_json
, возможно, трюк, необходимый для некоторых сложных запросов, все еще необходим (хотя вас здесь это не касается).
Все вышесказанное объясняет, что, даже если я все еще большой json_query
поклонник, в настоящее время я склонен ограничивать его использование ситуацией, когда core ansible вообще не справляется с работой. В вашем примере это определенно не так.
Используя ваш точно такой же пример файла , который я сохранил /tmp/somedata.json
, в следующем сборнике:
---
- name: Search for elements
hosts: localhost
gather_facts: false
vars:
src_file_name: somedata.json
json_exp: "{{ lookup('file', '/tmp/' ~ src_file_name) | from_json }}"
search_type: "/certificates/ca"
search_id: "trustedCerts_cert2"
cert_list: >-
{{
json_exp.operations
| selectattr('resourceType', '==', search_type)
| map(attribute='items')
| flatten
| selectattr('id', '==', search_id)
| map(attribute='fileData')
}}
tasks:
- name: "Show Cert Info"
debug:
msg: "{{ cert_list }}"
дает:
PLAY [Search for elements] *****************************************************************************
TASK [Show Cert Info] *****************************************************************************
ok: [localhost] => {
"msg": [
"EncryptedCertFile2"
]
}
PLAY RECAP *****************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0