我们想听听您的意见!帮助我们深入了解 Ansible 生态系统的现状。
参加 2024 年 Ansible 项目调查

创建 Ansible Lint 自定义规则

创建 Ansible Lint 自定义规则

什么是 Ansible Lint?

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

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

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

为什么要使用 Ansible Lint?

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

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

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

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

添加新规则的指南

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

创建新的 Ansible Lint 规则的一些指南包括:

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

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

创建自定义规则

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

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

  • ID:唯一的标识符。
  • 简短说明:对规则的简要描述。
  • 说明:规则查找的内容。
  • 标签:一个或多个可用于包含或排除规则的标签。
  • 至少以下方法之一:
    • 匹配:接受一行并返回 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 的任务参数包含许多键 - 最关键的键是 action。任务 action 的值包含正在使用的模块,以及传递的参数,两者都作为键值对和参数列表(例如,与 shell 一起使用的命令)。

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

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

打包自定义规则

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

要使自定义规则自动加载,您需要以下操作:

  • 将您的自定义规则打包为一个名为一些描述性的包,例如 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 是开源的,社区中的任何人都可以为该项目贡献新的规则。

以下是一些每个人都应该遵循的步骤:

  • 首先在您自己的分支上创建拉取请求。
  • 在 GitHub 上创建分支后,在命令行中执行以下操作:
$ git clone git@github.com: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