#json #ansible #jq
#json #ansible #jq
Вопрос:
Используя Ansible, я хочу заменить строку в файле json. Кажется, что в Ansible нет аналогичного модуля, такого как xml для json, я использую jq
инструмент cli. Поскольку требуется перезапуск в базовом приложении (что занимает некоторое время, поскольку это тяжелое и старое java-приложение), я хотел бы иметь обнаружение изменений, чтобы перезапуск применялся только при необходимости.
Код возврата с -e
параметром не меняется, поэтому моя идея заключалась в том, чтобы получить хэш файла перед jq
запуском и сравнить его с хэшем после этого. Извлечение хэша может быть выполнено с stat
помощью модуля:
- set_fact:
common_properties_file: "{{ resources_dir }}/commonProperties.json"
- name: Get hash of {{ common_properties_file }}
stat: path={{ common_properties_file }}
register: coomon_properties_check
- name: Hash before modification
debug:
var: coomon_properties_check.stat.checksum
Но во время тестирования я обнаружил, что хэш изменяется даже при простой печати файла без каких-либо изменений. Разница показывает, что весь файл был изменен с помощью другого отступа:
# jq '.' resources/commonProperties.json > resources/commonProperties.json_jq
# colordiff resources/commonProperties.json resources/commonProperties.json_jq
2,14c2,10
< "name": "Notification mail customization",
< "type": "com.ibm.connections.notification.mail",
< "payload": {
< "platformName": "HCL Connections",
< "photoType":"url",
< "style": {
< "bodyBackgroundColor": "#eeeeee",
< "sidebarBackgroundColor": "#3d6cf0",
< "messageBackgroundColor": "#ffffff"
< },
< "activityDateFormat": "dd MMM",
< "activityMax" : "25",
< "subjectAppNameAppend" : "tail"
---
> "name": "Notification mail customization",
> "type": "com.ibm.connections.notification.mail",
> "payload": {
> "platformName": "HCL Connections",
> "photoType": "url",
> "style": {
> "bodyBackgroundColor": "#eeeeee",
> "sidebarBackgroundColor": "#3d6cf0",
> "messageBackgroundColor": "#ffffff"
16c12,16
< "path": "notify"
---
> "activityDateFormat": "dd MMM",
> "activityMax": "25",
> "subjectAppNameAppend": "tail"
> },
> "path": "notify"
Я также jq --tab
безуспешно пытался. Единственный способ, который я вижу, — это написать небольшой модуль Ansible, который преобразует json в массив, проверяет, нужно ли применять изменения, и устанавливает измененное состояние, чтобы я мог использовать их, чтобы решить, нужен ли нам перезапуск.
Есть ли собственный способ без необходимости писать модуль Ansible для этой цели?
Ответ №1:
Вы можете проверить, равен ли новый файл JSON исходному файлу, используя ==
оператор jq. Одним из способов сделать это без создания каких-либо выходных данных в стандартном выводе было бы использование встроенного jq halt_error/1
. Существует много возможностей, но вот простая отдельная иллюстрация:
echo '{"a": 0}' | jq --argfile f1 <(echo {}) '
if . == $f1 then empty else null|halt_error(99) end'
Чтобы избежать повторного вызова jq, альтернативой было бы использовать jq КАК для записи возможно измененного файла, так И для установки кода возврата соответствующим образом, в соответствии с приведенным выше примером использования halt_error
.
Комментарии:
1. Это хорошая идея.
p="HCL Connections" jq 'if .payload.platformName == env.p then . else .payload.platformName = env.p | halt_error(99) end' resources/commonProperties.json > /tmp/out.json 2>amp;1
работает, но с одним побочным эффектом: когда я устанавливаюp="HCL Connections1"
(= требуется модификация), выходной json/tmp/out.json
уменьшается:{"name":"Notification mail customization","type": ...
это трудно читать для целей отладки, есть ли способ сделать это красиво? Без изменений (.
часть if) он улучшен, но кажетсяhalt_error
, что это останавливается до завершения улучшения2. Что касается красивого вывода, это работает:
p="HCL Connections1" jq 'if .payload.platformName == env.p then . else .payload.platformName = env.p, (empty|halt_error(99)) end' resources/commonProperties.json
ноecho $?
дал мне0
, даже когда команда заменена"platformName": "HCL Connections
на"platformName": "HCL Connections1
— RC работал в предыдущей командеp="HCL Connections" jq 'if .payload.platformName == env.p then . else .payload.platformName = env.p | halt_error(99) end'
, которая дала мне RC 99 в$?
3. Упс, я имел в виду
if .payload.platformName == env.p then . else .payload.platformName = env.p , ( null|halt_error(99)) end
4. Это работает, а также делает ненужным перенаправление stderr на stdout, поскольку json был напечатан в формате stdout вместо неформатированного в stderr. Спасибо! 🙂
Ответ №2:
С помощью @peak я нашел решение:
jq --arg platform "MyPlatformName" 'if .payload.platformName == $platform then . else .payload.platformName = $platform, (null|halt_error(99)) end' resources/commonProperties.json > /tmp/out.json
Это приведет к коду возврата 99, если файл был отредактирован
# echo $?
99
Если мы повторно запустим инструмент для измененного файла, никаких изменений применять не нужно, и мы получим rc = 0
# jq --arg platform "MyPlatformName" 'if .payload.platformName == $platform then . else .payload.platformName = $platform, (null|halt_error(99)) end' /tmp/out.json > /tmp/out2.json
# echo $?
0