我们希望听到您的声音!帮助我们深入了解 Ansible 生态系统的现状。
参与 2024 年 Ansible 项目调查










创建 Ansible Lint 的自定义规则

创建 Ansible Lint 的自定义规则

什么是 Ansible Lint?

Ansible Lint 是一个命令行工具,是 ansible-lint 上游社区项目 的一部分,用于对 Ansible playbook、角色和集合进行 lint 检查。好的,那么“lint 检查”究竟是什么?它的根本目标是推广经过验证的行为、模式和实践,同时避免可能导致错误或使代码难以维护的常见陷阱。也就是说 - 通过工具利用社区建议和意见来编写 Ansible 内容,以帮助确保您编写的代码通常有效。

此外,Ansible Lint 旨在帮助用户更新其代码以与更新的 Ansible 版本一起使用。即使生产中使用的 Ansible 版本可能是旧版本的 ansible-core,我们建议将其与最新版本一起使用。

Ansible Lint 就像任何其他 lint 工具一样,具有自己的观点。但是,由于社区成员为其规则做出了贡献,因此每个用户可以选择在单个或类别基础上启用或禁用它们。

我为什么要使用 Ansible Lint?

Ansible Lint 的目标是标记编程错误、bug、样式错误和可疑结构,并确保不同人员创建的内容具有相似的外观和风格。这使得 Ansible 内容在社区中的采用和使用更加容易,进而也更容易在企业中使用。通过将可配置功能的数量保持在最低限度,作者可以获得更一致的结果。

Ansible Lint 应该被视为 Ansible 内容创建者的可信顾问,帮助他们编写和打包更高质量的 Ansible 内容。虽然并非所有规则都适用于所有情况,但应尽可能遵循它们。

在 2022 年,添加了其他规则来帮助内容创建者准备其内容以用于生产。使用 ansible-lint 和这些规则,开发人员可以确信他们的 playbook、角色和任务文件易于理解并产生一致的结果,无论是在家庭实验室的服务器上部署,还是在云中的关键任务系统上部署。

采用 Ansible Lint 将节省时间,因为可以更多地关注内容的质量,而减少对格式和样式细微差别的关注。由于代码格式不是艺术,因此我们可以通过应用标准化的代码样式和格式来节省项目的时间和精力。

添加新规则的指南

可以根据需要添加多个规则。添加新规则应结合实现、测试和文档。

创建新的 Ansible Lint 规则的一些指南包括以下内容

  • 使用简短但清晰的类名,该类名必须与文件名匹配。
  • 选择一个未使用的 ID;第一个数字用于确定规则部分。参考规则页面并选择最匹配您的新规则的页面,并查看哪一个最合适。
  • 包含实验性标签。任何新规则都必须至少保持两周的实验性状态,直到在下一个主要版本中删除此标签。
  • 更新所有类级变量。
  • 实现规则所需的 lint 方法,这些方法以 match 前缀开头。仅实现您需要的那些方法。目前,您需要查看类似规则是如何实现的,以弄清楚该怎么做。
  • 更新测试。它必须至少有一个测试,并且可能还有一个负匹配测试。
  • 如果规则是特定于任务的,最好包含一个测试来验证它在块内的使用情况。
  • 可以选择仅使用以下命令运行特定于规则的测试:tox -e py38-core -- -k NewRule
  • 运行 tox 以运行所有 ansible-lint 测试。添加新规则可能会破坏某些其他测试。如果需要,请更新它们。
  • 运行 ansible-lint -L 并检查规则描述是否正确呈现。
  • 使用 tox -e docs 命令构建文档,并检查新规则是否在其中正确显示。

这是一个参考示例 MetaTagValidRule,它可能对创建新规则很有用。

创建自定义规则

规则使用每个规则一个类文件进行描述。例如,默认规则命名为 DeprecatedVariableRule.py 等。

每个规则定义都应具有以下内容

  • ID:唯一的标识符。
  • 简短描述:规则的简短描述。
  • 描述:规则要查找的内容。
  • 标签:可用于包含或排除规则的一个或多个标签。
  • 至少以下方法之一
    • Match 接收一行并返回 none 或 false;如果该行与测试不匹配,则返回 true 或自定义消息,如果匹配则返回 true 或自定义消息。(这允许一个规则测试多种行为 - 例如,请参阅 CommandsInsteadOfModulesRule。)
    • Matchtask 对单个任务或处理程序进行操作,以便任务始终包含模块键和 module_arguments 键。如果存在,其他常见的任务修饰符,如 when、with_items 等,也可用作键。

使用 match 的示例规则是

from ansiblelint.rules import AnsibleLintRule
class DeprecatedVariableRule(AnsibleLintRule):
    """Deprecated variable declarations."""
    id = 'EXAMPLE002'
    description = 'Check for lines that have old style ${var} ' + \ 'declarations'
    tags = { 'deprecations' }
    def match(self, line: str) -> Union[bool, str]:
        return '${' in line

使用 matchtask 的示例规则是

from typing import TYPE_CHECKING, Any, Dict, Union
import ansiblelint.utils
from ansiblelint.rules import AnsibleLintRule
if TYPE_CHECKING:
    from ansiblelint.file_utils import Lintable
class TaskHasTag(AnsibleLintRule):
    """Tasks must have tag."""
    id = 'EXAMPLE001'
    description = 'Tasks must have tag'
    tags = ['productivity']
    def matchtask(self, task: Dict[str, Any], file: 'Lintable' | None = None) -> Union[bool,str]:
        # If the task include another task or make the playbook fail
        # Don't force to have a tag
        if not set(task.keys()).isdisjoint(['include','fail']):
            return False
        # Task should have tags
        if not task.has_key('tags'):
              return True
        return False

matchtask 的 task 参数包含许多键 - 其中关键的是 action。task 的 action 值包含正在使用的模块以及传递的参数,两者都以键值对的形式以及其他参数的列表形式(例如,与 shell 一起使用的命令)。

在 ansible-lint 2.0.0 中,task 的 action args 重命名为 task 的 action module_arguments,以避免当模块实际上将 args 作为参数键(例如 ec2_tag)时发生冲突。

在 ansible-lint 3.0.0 中,task 的 action module 重命名为 task 的 action __ansible_module__,以避免当模块将模块作为参数时发生冲突。作为预防措施,task 的 action module_arguments 重命名为 task 的 action __ansible_arguments__

打包自定义规则

ansible-lint 在其内置规则中提供了一个名为 custom 的子目录,例如 /usr/lib/python3.8/site-packages/ansiblelint/rules/custom/,用于从 v4.3.1 版本开始安装自定义规则。作为 Python 包打包并安装到此目录中的自定义规则将由 ansible-lint 自动加载和启用。

要使自定义规则自动加载,您需要以下内容

  • 将您的自定义规则打包为一个 Python 包,并使用一些描述性的名称,例如 ansible_lint_custom_rules_foo
  • 将其安装到 <ansible_lint_custom_rules_dir>/custom/<your_custom_rules_subdir> 中。

您可以通过在自定义规则 Python 包的 setup.cfg 文件的 [options] 部分添加一些配置来实现第二点,如下所示

[options]
packages =
    ansiblelint.rules.custom.<your_custom_rules_subdir>
Package_dir = ansiblelint.rules.custom.<your_custom_rules_subdir> = <your_rules_source_code_subdir>

Ansible Lint 入门和后续步骤

存储库在哪里?

Ansible 存储库是开源代码,您可以在 GitHub 上找到它

https://github.com/ansible/ansible-lint

是否有任何资源/文档?

Ansible Lint 的完整、深入的上游社区文档可以在以下位置找到:

https://ansible-lint.readthedocs.io/

如何贡献

由于 ansible-lint 是开源的,因此社区中的任何人都可以为该项目贡献新的规则。

以下是每个人都应遵循的步骤

  • 首先在您自己的 fork 的分支上创建 pull request。
  • 在 GitHub 上创建您的 fork 后,在命令行中执行以下操作
$ git clone [email protected]:your-name/ansible-lint
$ cd ansible-lint
$ git checkout -b your-branch-name
# DO SOME CODING HERE
$ git add your new files
$ git commit -v
$ git push origin your-branch-name