Объединение элементов JSON с использованием JMESpath и / или Ansible

#json #ansible #jmespath

#json #ansible #jmespath

Вопрос:

У меня есть Ansible playbook, который запрашивает API инвентаризации устройств и возвращает результат JSON, который содержит много записей в этом формате:

 {
    "service_level": "Test", 
    "tags": [
        "Application:MyApp1"
    ], 
    "fqdn": "matestsvcapp1.vipcustomers.com", 
    "ip": "172.20.11.237", 
    "name": "matestsvcapp1.vipcustomers.com"
}
  

Затем я перебираю эти задачи ansible, чтобы запросить результат JSON для каждого из интересующих меня IP-адресов:

 - name: Set JMESQuery
  set_fact:
    jmesquery: "Devices[?ip_addresses[?ip.contains(@,'{{ ip_to_query }}' )]].{ip: '{{ ip_to_query }}', tags: tags[], , service_level: service_level }"

- name: Store values
  set_fact:
    inven_results: "{{ (inven_results| default([]))   (existing_device_info.json | to_json | from_json | json_query(jmesquery)) }}"
  

Затем я продолжаю выполнять другие задачи в ansible, перенося эти данные в другие системы, и все работает нормально.

Однако я только что получил запрос от руководства о том, что они хотели бы видеть «уровень обслуживания», представленный в виде тега в некоторых системах, в которые я загружаю эти данные. Поэтому мне нужно объединить элементы ‘tags’ и ‘service_level’, в результате чего получится нечто, похожее на это:

 { 
    "tags": [
        "Application:MyApp1",
        "service_level:Test"
    ], 
    "fqdn": "matestsvcapp1.vipcustomers.com", 
    "ip": "172.20.11.237", 
    "name": "matestsvcapp1.vipcustomers.com"
}
  

Я попытался изменить запрос JMESpath, чтобы объединить результаты вместе с помощью функции join, и попытался сделать это способом ‘ansible’, используя combine или map, но я также не смог заставить ни один из них работать.

Есть мысли о правильном способе справиться с этим? Заранее спасибо!

Примечание: ‘tags’ — это список строк, и хотя он написан в формате key:value, на самом деле это просто строка.

Комментарии:

1. Я не совсем понимаю, как выглядят ваши данные. Можете ли вы опубликовать минимальный сборник задач, включающий образцы данных, которые полностью воспроизводят проблему, которую вы пытаетесь решить?

Ответ №1:

чтобы добавить два массива, вы используете оператор, подобный этому:

 ansible localhost -m debug -a 'msg="{{ b   ["String3"] }}"' -e '{"b":["String1", "String2"]}'
  

Результат:

 localhost | SUCCESS => {
    "msg": [
        "String1",
        "String2",
        "String3"
    ]
}
  

Итак, если я возьму ваш код json, test.json который вы могли бы запустить

 ansible localhost -m debug -a 'msg="{{ tags   ["service_level:" ~ service_level ] }}"' -e @test.json
  

Результат:

 localhost | SUCCESS => {
    "msg": [
        "Application:MyApp1",
        "service_level:Test"
    ]
}
  

Зная это, вы можете использовать set_fact, чтобы поместить этот новый массив в переменную для последующего использования.

Комментарии:

1. Это был не точный ответ, но он привел меня по пути. Я в основном узнал, что вы не можете обновить существующий элемент, но вам нужно зарегистрировать новый. Позже в моем сборнике я объединил несколько значений, и добавление tags ["service_level:" ~ service_level ] раздела к этому позволило мне объединить нужные мне элементы. Спасибо!