调试模块

详细的调试步骤

Ansible 模块被组合成一个 zip 文件,该文件包含模块文件和各种 Python 模块样板,这些样板位于包装脚本中。要查看模块中实际发生了什么,你需要从包装器中提取文件。包装脚本提供了帮助方法,使你能够做到这一点。

以下步骤使用 localhost 作为目标主机,但你也可以使用相同的步骤来调试远程主机。要了解更简单的调试方法,而无需使用临时文件,请参见 简单调试

  1. 在控制主机上将 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"
    }
    
  2. 导航到上一步中的临时目录。如果之前命令针对远程主机运行,请先连接到该主机,然后尝试导航到临时目录。

    $ ssh remotehost  # only if not debugging against localhost
    $ cd /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595
    
  3. 运行包装器的 explode 命令将字符串转换为一些你可以使用的 Python 文件。

    $ python AnsiballZ_ping.py explode
    Module expanded into:
    /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/debug_dir
    

    如果你想检查包装器文件,你可以这样做。它将显示一个带有大型 base64 编码字符串的小型 Python 脚本。该字符串包含要执行的模块。

  4. 当你查看临时目录时,你会看到类似这样的结构

    ├── 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 库

    如果你怀疑模块在这些样板代码中出现问题,而不是在你编写的模块代码中出现问题,则可以修改此目录中的文件。

  5. 在编辑完爆炸树中的代码或参数后,使用 execute 子命令来运行它

    $ python AnsiballZ_ping.py execute
    {"invocation": {"module_args": {"data": "debugging_session"}}, "changed": false, "ping": "debugging_session"}
    

    此子命令将 debug_dir 的绝对路径插入到 sys.path 的第一个项目中,并使用 args 文件中的参数调用脚本。你可以继续像这样运行模块,直到你理解问题。然后,你可以将更改复制回你的真实模块文件,并通过使用 ansibleansible-playbook 测试真实模块是否正常工作。

简单调试

在模块中运行调试器的最简单方法(本地或远程)是使用 epdb。在控制节点上的模块代码中,在所需的断点处添加 import epdb; epdb.serve()。要连接到调试器,请运行 epdb.connect()。有关如何指定 hostport 的信息,请参见 epdb 文档。如果连接到远程节点,请确保使用控制节点和远程节点之间任何防火墙允许的端口。

此技术应该适用于任何远程调试器,但我们不保证任何特定的远程调试工具都能正常工作。

q 库是另一个非常有用的调试工具。

由于 print() 语句在模块内部不起作用,因此如果只想查看一些特定数据,则引发异常是一个不错的选择。在模块中的某个地方放置 raise Exception(some_value) 并正常运行它。Ansible 将处理此异常,将消息传递回控制节点,并显示它。