我看到的是Ansible dnf 模块失败。但并不可靠。当它失败时,如果我再次运行 Ansible,它似乎会成功。
我的系统是Fedora 29 Workstation。 (更多版本信息如下所示)。
我从脚本运行 Ansible。它使用本地连接:sudo ansible-playbook -c local ...
$ ./localhost alan-laptop playbooks/alan-laptop.yml
[sudo] password for alan-sysop:
[DEPRECATION WARNING]: The use of 'static' has been deprecated. Use
'import_tasks' for static inclusion, or 'include_tasks' for dynamic inclusion.
This feature will be removed in version 2.12. Deprecation warnings can be
disabled by setting deprecation_warnings=False in ansible.cfg.
PLAY [alan-laptop] *************************************************************
TASK [Gathering Facts] *********************************************************
ok: [alan-laptop]
TASK [repos-fedora : Check OS is Fedora] ***************************************
ok: [alan-laptop] => {
"changed": false,
"msg": "All assertions passed"
}
TASK [repos-fedora : Configure Fedora repos using local cache] *****************
changed: [alan-laptop]
TASK [repos-fedora : Test "dnf check-update"] **********************************
changed: [alan-laptop]
TASK [sourcejedi.etckeeper : Install epel repo (needed for Centos)] ************
skipping: [alan-laptop]
TASK [sourcejedi.etckeeper : Install etckeeper] ********************************
fatal: [alan-laptop]: FAILED! => {"changed": false, "module_stderr": "<stdin>:17: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses\n", "module_stdout": "[master df9553e] saving uncommitted changes in /etc prior to dnf run\n Author: Alan Jenkins <[email protected]>\n 5 files changed, 79 insertions(+), 48 deletions(-)\n\n{\"msg\": \"Nothing to do\", \"changed\": false, \"results\": [\"Installed: etckeeper\"], \"rc\": 0, \"invocation\": {\"module_args\": {\"name\": [\"etckeeper\"], \"state\": \"present\", \"allow_downgrade\": false, \"autoremove\": false, \"bugfix\": false, \"disable_gpg_check\": false, \"disable_plugin\": [], \"disablerepo\": [], \"download_only\": false, \"enable_plugin\": [], \"enablerepo\": [], \"exclude\": [], \"installroot\": \"/\", \"install_repoquery\": true, \"security\": false, \"skip_broken\": false, \"update_cache\": false, \"update_only\": false, \"validate_certs\": true, \"conf_file\": null, \"disable_excludes\": null, \"list\": null, \"releasever\": null}}}\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 0}
[...]
我觉得“改变”的任务可能很重要 - 这些安装(并验证)我的 dnf 存储库文件。即当我再次运行 Ansible 时,这些任务自然不会“改变”。我尝试清除存储库文件,以强制任务“更改”。第一次,这似乎重现了dnf模块的故障。但现在我已经尝试了好几次了,并不总是能重现故障。
消息“MODULE FAILURE\nSee stdout/stderr for the certain error”表示某处应该有真正的错误消息,但我不知道它是什么! Ansible dnf 模块是否存在错误,这意味着它没有报告真正的错误?当然,弃用警告不是真正的错误 - 当然无论如何都会发生,但只有在存在真正错误时才会显示?
为什么会失败?
看起来相关
module_stdout
吗应该是有效的 JSON,但它已与来自 etckeeper 的 Git 消息混合在一起?我不认为这就是导致它的原因,因为有时 dnf 模块确实如此不是失败,即使有未提交的更改,例如 所示sudo etckeeper vcs diff
。我还认为这可能与 PackageKit 冲突,但是......
我检查过,似乎与、、或我的完整 Ansible 剧本
pkcon refresh force
没有冲突。两者甚至看起来是并行的。sudo dnf check-update --refresh
sudo dnf install etckeeper
sudo ansible localhost -m dnf -a "name=etckeeper state=present"
此外,之后我仍然可以看到此失败
systemctl mask --now --runtime packagekit.service
。(我仔细检查了一下,错误发生时服务没有运行)。
$ ansible --version
ansible 2.7.9
config file = /home/alan-sysop/ansible/ansible.cfg
configured module search path = ['/home/alan-sysop/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.7.2 (default, Mar 21 2019, 10:09:12) [GCC 8.3.1 20190223 (Red Hat 8.3.1-2)]
$ rpm -q ansible
ansible-2.7.9-1.fc29.noarch
答案1
module_stdout
问:看起来应该是有效的 JSON,但它与来自 etckeeper 的 Git 消息混合在一起,这是否相关?
A。是的。
Ansible 模块 [...] 在退出之前通过将 JSON 字符串打印到 stdout 来将信息返回给 ansible。
该问题具体是由于来自 etckeeper 的消息引起的,该消息以左方括号开头。
[master df9553e] saving uncommitted changes in /etc prior to dnf run
Author: Alan Jenkins <[email protected]>
5 files changed, 79 insertions(+), 48 deletions(-)
Ansible 旨在通过静默跳过非 json 标头行来解决类似问题。但[
是开始 JSON 文档的有效字符。看lib/ansible/module_utils/json_utils.py
:
def _filter_non_json_lines(data):
'''
Used to filter unrelated output around module JSON output, like messages from
tcagetattr, or where dropbear spews MOTD on every single command (which is nuts).
Filters leading lines before first line-starting occurrence of '{' or '[', and filter all
trailing lines after matching close character (working from the bottom of output).
'''