导入

Ansible 允许对某些特定目录中的库进行未经检查的导入。导入任何其他 Python 库都需要处理导入错误。这使得支持诸如validate-modules之类的健全性测试成为可能,并为用户提供更好的错误消息。

重要

请参阅常见问题解答,以获取有关解决此测试报告的常见错误的答案。

处理导入错误

Ansible 在许多主机上执行,并且可以同时使用多个 Python 解释器,这些解释器甚至可能具有不同的版本。为了确保用户获得可操作且易于理解的错误,我们尝试确保模块/插件中任何非核心导入都受到保护,以避免出现回溯,大多数用户将无法理解,更不用说将其用于解决问题了。

Ansible 执行此操作的另一个原因是为了导入代码以进行检查。这允许 Ansible 基于代码轻松地进行测试、记录、配置等,而无需在任何地方安装所有必需的依赖项,尤其是在这不是您执行代码的上下文时。

以下代码显示了如何避免导入错误,然后使用提供的 missing_required_lib 来确保用户知道缺少哪个库、在哪个主机上缺少以及需要它的特定解释器。

在模块中

不要使用 import another_library

import traceback

from ansible.module_utils.basic import missing_required_lib

try:
    import another_library
except ImportError:
    HAS_ANOTHER_LIBRARY = False
    ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
else:
    HAS_ANOTHER_LIBRARY = True
    ANOTHER_LIBRARY_IMPORT_ERROR = None

注意

上面的 missing_required_lib 导入将在下面使用。

然后在模块代码中,通常在 main 方法内部

module = AnsibleModule(...)

if not HAS_ANOTHER_LIBRARY:
    module.fail_json(
        msg=missing_required_lib('another_library'),
        exception=ANOTHER_LIBRARY_IMPORT_ERROR)

在插件中

不要使用 import another_library

try:
    import another_library
except ImportError as imp_exc:
    ANOTHER_LIBRARY_IMPORT_ERROR = imp_exc
else:
    ANOTHER_LIBRARY_IMPORT_ERROR = None

然后在插件代码中,例如在插件的 run 方法中(一些插件没有 run 方法,需要在 __init__ 方法中使用)

if ANOTHER_LIBRARY_IMPORT_ERROR:
    raise AnsibleError('another_library must be installed to use this plugin') from ANOTHER_LIBRARY_IMPORT_ERROR

用作基类时

重要

此解决方案建立在前两个示例的基础上。在继续使用此解决方案之前,请确保选择合适的解决方案。

有时在基类中使用导入,例如

from another_library import UsefulThing

class CustomThing(UsefulThing):
    pass

一种选择是使整个类定义成为条件性的

if not ANOTHER_LIBRARY_IMPORT_ERROR:
    class CustomThing(UsefulThing):
        pass

另一种选择是通过修改异常处理程序来定义一个替代基类

try:
    from another_library import UsefulThing
except ImportError:
    class UsefulThing:
        pass
    ...

允许的未经检查的导入

Ansible 允许从以下特定目录进行未经检查的导入

  • ansible-core

    • 对于 lib/ansible/modules/lib/ansible/module_utils/,仅允许从 Python 标准库进行未经检查的导入;

    • 对于 lib/ansible/plugins/,仅允许从 Python 标准库、ansible-core 的公共依赖项以及 ansible-core 本身进行未经检查的导入;

  • 集合

    • 对于 plugins/modules/plugins/module_utils/,仅允许从 Python 标准库进行未经检查的导入;

    • 对于 plugins/ 中的其他目录(有关列表,请参阅社区集合要求),仅允许从 Python 标准库、ansible-core 的公共依赖项以及 ansible-core 本身进行未经检查的导入。

ansible-core 的公共依赖项是

  • Jinja2

  • PyYAML

  • MarkupSafe(作为 Jinja2 的依赖项)

常见问题解答 (FAQ)

为什么我的模块或插件可以工作,但我却收到一个 ImportError 错误?

导入健全性测试与其他测试非常不同。根据设计,它只能看到 Python 标准库中的模块。这意味着您的模块或插件可以在您的 playbook、集成测试和单元测试中工作,但在导入健全性测试中会失败。

所有 ImportError 的出现都必须正确处理在发生错误的模块或插件中。

为什么测试没有使用我指定的 Python 解释器?

健全性测试将使用您指定的 Python 解释器。但是,它将使用该 Python 解释器创建自己的虚拟环境。

所有 ImportError 的出现都必须正确处理在发生错误的模块或插件中。

如何使用自定义虚拟环境?

这不可能,因为这样做会违背测试的目的。

所有 ImportError 的出现都必须正确处理在发生错误的模块或插件中。

如何指定在哪里查找我的导入?

这不可能,因为这样做会违背测试的目的。

所有 ImportError 的出现都必须正确处理在发生错误的模块或插件中。

如何指定要使用的哪个 requirements 文件?

这不可能,因为这样做会违背测试的目的。

所有 ImportError 的出现都必须正确处理在发生错误的模块或插件中。

如何在不更改代码的情况下修复 ImportError 错误?

如果不更改插件或模块,则无法修复其中的 ImportError 错误。

所有 ImportError 的出现都必须正确处理在发生错误的模块或插件中。