Обнаружение изменений в файле json в Ansible: jq использует другой отступ -> Файл всегда изменяется

#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