0

我编写了一个包含 Python 库的自定义模块。我将resultdict 定义如下:

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 都包含来自 lib 的相同日志消息,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."]}

问题是模块总是以“失败”告终,即使我知道我的代码运行成功,剧本也会终止。

2天后

好的,我现在知道问题所在了。这是由于我将输出包装到 STDOUT/STDERR 的库,因为它在内部使用子进程。当 Ansible 尝试解析 STDOUT 时,由于 STDOUT 中所有额外的非 JSON 输出,它在此方法中失败。如何处理这种情况?我怎么能保证我的自定义模块有一个原始的 STDOUT,只有 JSON 格式的输出?我试图做sys.stdout.flush()无济于事。

这实际上使得编写自定义模块毫无用处。请Ansible大师,任何提示?

4

1 回答 1

0

所以这个问题的答案很简单:当你打电话exit_json或者fail_json你不能有sys.stdout任何类型的输出时。原因也很简单:在你的代码运行之后,结果会被这个 Ansible 代码处理。哪个解析res.get('stdout', u''),如果有任何解析错误,那么你最终会得到我在问题中提到的大量 STDOUT 转储。

解决方案并不是那么简单。在调用模块退出方法之前,我尝试了各种技巧来清空 STDOUT,但它并没有真正奏效。因此,由于我可以完全控制我所调用的内容,我只需将我的日志记录更改为基于我调用的库中的临时文件,并做了一些其他事情来确保我不会sys.stdout以任何方式使用。这真的很愚蠢,我希望有人能给我一个更好的方法

于 2020-01-27T21:14:22.277 回答