Ansible - работа с неожиданным STDOUT в настраиваемом модуле
Я написал специальный модуль, который обертывает библиотеку Python. Я определяюresult
диктуют следующим образом:
result = dict(
changed=False,
original_message='Running DBSCONTROL',
message=''
)
Позже в коде я переношу вызов библиотеки в try/except
как таковой:
try:
dbsc = DbsControl(
module.params.get('user'),
module.params.get('host'),
module.params.get('script')
)
dbsc.runme()
result['message'] = 'DBSCONTROL_SUCCESSFULL'
module.exit_json(**result)
except Exception as ex:
result['message'] = str(ex)
module.fail_json(msg='Failed DBSCONTROL execution', **result)
У меня нет ни одного print
оператор в любом месте модуля, и мои выходные данные lib записываются в файл.
Наконец, я называю эту роль Ansible
- name: Run dbscontrol utility
dbscontrol:
user: "{{ hostvars[groups['dbs_server'][0]]['ansible_user'] }}"
host: "{{ groups['dbs_server'][0] }}"
script: "dbscontrol_config.yml"
register: result
- debug:
msg: "{{ result }}"
Из последнего сообщения регистратора в моей библиотеке я ясно вижу, что запуск завершился успешно, однако мой модуль завершился сбоем с массивным выводом сообщений регистратора, который начинается с
MSG:
MODULE FAILURE
See stdout/stderr for the exact error
Как ни странно я вижу result
встроен в раздел MODULE_STDOUT вывода. Фактически, это последний раздел перед запуском MODULE_STDERR
И MODULE_STDOUT, и MODULE_STDERR состоят из идентичных сообщений журнала из библиотеки с той лишь разницей, что result
связанные строки:
2020-01-23 13:40:52,070 - ttautils.dbscontrol - INFO - DBS control run is complete, exiting
{"changed": false, "original_message": "Running DBSCONTROL", "message": "DBSCONTROL_SUCCESSFULL",
"invocation": {"module_args": {"user": "root", "host": "fiesta1.td.teradata.com", "script":
"dbscontrol_config.yml", "dbc_user": "dbc", "dbc_pwd": "dbc", "logfile": "dbscntl_2020-01-23-13-38-15.log",
"loglevel": "DEBUG", "validate": "False", "config": "user_config/common", "locale": "TPG_6700C",
"timeout": "7200", "disable_local_overrides": false, "params": "user_config/user.yml"}},
"warnings": ["The value False (type bool) in a string field was converted to 'False' (type string).
If this does not look like what you expect, quote the entire value to ensure it does not change."]}
Проблема в том, что модуль всегда заканчивается как "сбойный", и playbook завершается, даже если я знаю, что мой код был выполнен успешно.
2 дня спустя
Хорошо, теперь я знаю проблему. Это связано с библиотекой, которую я оборачиваю для записи вывода в STDOUT/STDERR, поскольку она использует подпроцесс внутри. Когда Ansible пытается проанализировать STDOUT, он не работает в этом методе из-за всего дополнительного вывода, отличного от JSON, в STDOUT. Как справиться с этой ситуацией? Как я могу гарантировать, что мой настраиваемый модуль имеет чистый STDOUT с выводом только в формате JSON? Я пытался сделатьsys.stdout.flush()
но безрезультатно.
Это практически делает написание специального модуля бесполезным. Пожалуйста, гуру Ansible, какие-нибудь подсказки?
1 ответ
Так что ответ на эту проблему прост: когда вы звоните exit_json
или fail_json
ты не можешь иметь sys.stdout
с любым выходом. Причина также проста: после запуска вашего кода результат обрабатывается этим кодом Ansible. Который разбираетres.get('stdout', u'')
и если есть какие-либо ошибки синтаксического анализа, вы получите тот массивный дамп STDOUT, который я упомянул в своем вопросе.
Решение не так просто. Я пробовал различные хаки, чтобы очистить STDOUT перед вызовом методов выхода из модуля, но это не сработало. Итак, поскольку у меня есть полный контроль над тем, что я вызываю, я просто изменил ведение журнала на временные файлы, основанные на вызываемой мной библиотеке, и сделал еще несколько вещей, чтобы убедиться, что я не используюsys.stdout
в любом случае. Что действительно глупо, и я надеюсь, что кто-нибудь покажет мне лучший способ