调试模块
详细调试步骤
Ansible 模块被打包成一个 zip 文件,包含模块文件以及封装脚本(wrapper script)内部的各种 Python 模块样板代码。为了查看模块中实际发生了什么,您需要从封装脚本中提取该文件。封装脚本提供了允许您执行此操作的辅助方法。
以下步骤使用 localhost 作为目标主机,但您也可以使用相同的步骤对远程主机进行调试。关于无需使用临时文件的更简单调试方法,请参阅 简单调试。
在控制主机上将
ANSIBLE_KEEP_REMOTE_FILES设置为1,这样 Ansible 在模块执行完毕后将保留远程模块文件而不会将其删除。使用-vvv选项使 Ansible 的输出更详细。这将显示临时模块文件的文件名。$ ANSIBLE_KEEP_REMOTE_FILES=1 ansible localhost -m ping -a 'data=debugging_session' -vvv <127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: badger <127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595 `" )' <127.0.0.1> PUT /var/tmp/tmpjdbJ1w TO /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/AnsiballZ_ping.py <127.0.0.1> EXEC /bin/sh -c 'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/AnsiballZ_ping.py && sleep 0' localhost | SUCCESS => { "changed": false, "invocation": { "module_args": { "data": "debugging_session" }, "module_name": "ping" }, "ping": "debugging_session" }
导航到上一步中的临时目录。如果之前的命令是针对远程主机运行的,请先连接到该主机,然后再尝试导航到临时目录。
$ ssh remotehost # only if not debugging against localhost $ cd /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595
运行封装脚本的
explode命令,将字符串转换为您可以操作的 Python 文件。$ python AnsiballZ_ping.py explode Module expanded into: /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/debug_dir
如果您想检查封装文件,可以这样做。它将显示一个包含大型 base64 编码字符串的小型 Python 脚本。该字符串包含要执行的模块。
当您查看临时目录时,会看到如下结构
├── AnsiballZ_ping.py └── debug_dir ├── ansible │ ├── __init__.py │ ├── module_utils │ │ ├── __init__.py │ │ ├── _text.py │ │ ├── basic.py │ │ ├── common │ │ ├── compat │ │ ├── distro │ │ ├── parsing │ │ ├── pycompat24.py │ │ └── six │ └── modules │ ├── __init__.py │ └── ping.py └── args
AnsiballZ_ping.py是一个 Python 脚本,模块代码存储在 base64 编码的字符串中。它包含用于执行模块的各种辅助函数。ping.py是模块本身的代码。您可以修改此代码以查看其对模块产生的影响,或用于调试目的。args文件包含一个 JSON 字符串。该字符串是一个字典,包含模块参数以及 Ansible 传递给模块以改变其行为的其他变量。修改此文件可更改传递给模块的参数。ansible目录在modules中包含模块代码,以及模块所使用的来自ansible.module_utils的代码。Ansible 会包含模块中任何ansible.module_utils导入的文件,但不包含来自任何其他模块的文件。如果您的模块使用了ansible.module_utils.url,Ansible 会为您将其包含在内。但如果您的模块包含了 requests,那么您必须确保在运行模块之前,系统中已安装 Python requests 库。
如果您怀疑模块的问题出在这些样板代码而非您编写的模块代码中,您可以修改此目录中的文件。
在解压后的目录树中编辑代码或参数后,使用
execute子命令运行它$ python AnsiballZ_ping.py execute {"invocation": {"module_args": {"data": "debugging_session"}}, "changed": false, "ping": "debugging_session"}
此子命令将
debug_dir的绝对路径插入到sys.path的第一项中,并使用args文件中的参数调用脚本。您可以继续这样运行模块,直到理解问题所在。然后,您可以将更改复制回真实的模块文件中,并使用ansible或ansible-playbook测试真实模块是否正常工作。
简单调试
在本地或远程模块中运行调试器的最简单方法是使用 madbg。在控制节点上的模块代码中,在所需的断点处添加 import madbg; madbg.set_trace()。要连接到调试器,请运行 madbg connect。有关如何指定 host 和 port,请参阅 madbg 文档。如果连接到远程节点,请确保使用的端口被控制节点和远程节点之间的任何防火墙所允许。
这种技术应该适用于任何远程调试器,但我们不保证任何特定的远程调试工具都能正常工作。
q 库是另一个非常实用的调试工具。
由于 print() 语句在模块内部不起作用,如果您只想查看某些特定数据,抛出异常是一个好方法。在模块的某处放置 raise Exception(some_value) 并正常运行。Ansible 将处理此异常,将消息传回控制节点并将其显示出来。