杰瑞科技汇

Python如何开发Ansible插件?

Ansible 插件是使用 Python 编写的代码块,它们在 Ansible 执行的特定生命周期中被调用,用于扩展或修改 Ansible 的核心功能。

Python如何开发Ansible插件?-图1
(图片来源网络,侵删)

你可以把 Ansible 想象成一个功能强大的汽车,而 Python 插件就像是各种可以安装的“模块”或“配件”,比如更强的引擎、更智能的导航系统或更酷炫的灯光,这些插件让这辆汽车能适应更多场景,完成更多任务。


为什么需要 Ansible 插件?

Ansible 的设计哲学是“无代理”(Agentless),通过 SSH 等协议管理远程节点,但为了保持核心的轻量级和灵活性,很多高级或特定领域的功能被实现为插件,使用插件的好处包括:

  1. 功能扩展:Ansible 核心无法预知所有需求,插件允许你添加连接方式(如连接到网络设备)、过滤数据(如处理 JSON)、加载变量(如从数据库读取)等。
  2. 代码复用:将复杂的逻辑封装在插件中,可以在多个 Playbook 和角色中重复使用,避免代码冗余。
  3. 核心稳定性:将实验性或特定于某个环境的功能放在插件中,不影响 Ansible 核心的稳定性和发布周期。
  4. 社区贡献:任何人都可以编写插件并为 Ansible 生态做贡献,极大地丰富了 Ansible 的功能库。

Ansible 插件的类型

Ansible 插件种类繁多,每种类型都在 Ansible 运行的不同阶段发挥作用,以下是最常见和最重要的一些类型:

连接插件

这是最基础的插件类型,定义了 Ansible 如何与被管理节点通信。

Python如何开发Ansible插件?-图2
(图片来源网络,侵删)
  • 作用:建立和管理与远程主机的连接。
  • 默认插件paramiko (基于 Python 的 SSH)、ssh (调用系统原生 SSH 命令,性能更好)。
  • 其他示例
    • local: 在本地执行,不通过 SSH。
    • docker: 在 Docker 容器内执行。
    • network_cli: 用于与网络设备(如 Cisco, Juniper)建立持久性 CLI 连接。
    • winrm: 用于连接 Windows 节点。

过滤器插件

Jinja2 模板系统的一部分,用于处理和转换变量数据。

  • 作用:在模板或 Playbook 中对变量进行格式化、计算、转换等操作。
  • 核心示例
    • {{ my_list | unique }}: 去重。
    • {{ 'hello world' | upper }}: 转换为大写。
    • {{ my_dict | dict2items }}: 将字典转换为列表。
  • 自定义示例:你可以编写一个自定义过滤器,{{ my_ip | is_valid_ip }} 来验证 IP 地址格式。

测试插件

同样是 Jinja2 模板系统的一部分,用于判断变量的值或状态。

  • 作用:在 if 语句中作为条件判断。
  • 核心示例
    • {% if my_string is defined %}: 检查变量是否已定义。
    • {% if my_list is empty %}: 检查列表是否为空。
    • {% if my_number is even %}: 检查数字是否为偶数。
  • 自定义示例:编写一个测试插件 {% if my_port is port_in_use %} 来检查某个端口是否被占用。

Lookup 插件

用于在 Playbook 执行期间从外部源检索数据。

  • 作用:获取动态数据,并将其注入到变量中。
  • 核心示例
    • {{ lookup('file', '/path/to/file.txt') }}: 读取文件内容。
    • {{ lookup('env', 'HOME') }}: 获取环境变量。
    • {{ lookup('password', 'chars=ascii,digits,length=8') }}: 生成一个随机密码。
  • 高级示例
    • {{ lookup('redis', 'key') }}: 从 Redis 数据库获取值。
    • {{ lookup('dnstxt', 'example.com') }}: 查询 DNS TXT 记录。
    • {{ lookup('k8s', 'my-pod', namespace='default') }}: 从 Kubernetes API 获取 Pod 信息。

回调插件

这是最强大的插件之一,允许你监听和干预 Ansible 的整个执行过程。

Python如何开发Ansible插件?-图3
(图片来源网络,侵删)
  • 作用:在任务执行前、执行后、失败时等事件点触发自定义逻辑,例如发送通知、记录日志、生成自定义报告等。
  • 示例
    • ansible.cfg 中配置 callback_plugins = /path/to/callback_plugins
    • 编写一个回调插件,在任何一个任务失败时,自动向 Slack 或钉钉发送报警消息。
    • 编写一个回调插件,在 Playbook 执行结束后,生成一个详细的 HTML 格式的报告。

动作插件

位于模块和核心执行引擎之间,可以拦截、修改模块的参数或结果。

  • 作用:在模块调用前后进行“劫持”和处理,实现“胶水”逻辑。
  • 示例
    • ansible.builtin.async_status 就是一个动作插件,它专门用来检查异步任务的执行状态。
    • 可以编写一个动作插件,在调用 yum 模块前,自动添加一个 -y 参数,或者在调用后自动记录安装的包列表。

其他类型插件

  • Cache 插件:用于缓存 Facts 和其他数据,避免重复收集,提高执行速度(如 jsonfile, redis)。
  • Vars 插件:用于从特定来源动态加载变量(如从文件、数据库、云 API 加载)。
  • Terminal 插件:与 network_cli 连接插件配合,用于处理与网络设备的交互逻辑。

如何编写一个简单的 Python 插件?(以回调插件为例)

下面我们通过一个简单的“Hello World”回调插件,来感受一下编写过程。

目标:在 Ansible 执行完每个任务后,打印一条消息。

创建插件目录结构

你需要一个目录来存放你的插件,推荐在你的项目根目录下创建。

my_ansible_project/
├── ansible.cfg
├── inventory
└── plugins/
    └── callback_plugins/
        └── hello.py

配置 ansible.cfg

告诉 Ansible 你的插件在哪里,在 ansible.cfg 文件中添加:

[defaults]
callback_plugins = ./plugins/callback_plugins

编写 Python 插件代码 (plugins/callback_plugins/hello.py)

Ansible 插件是标准的 Python 类,回调插件需要继承 ansible.plugins.callback.CallbackBase

# plugins/callback_plugins/hello.py
from ansible.plugins.callback import CallbackBase
import time
# Ansible 会自动加载所有继承自 CallbackBase 的类
class CallbackModule(CallbackBase):
    """
    这是一个简单的 Hello World 回调插件。
    它会在每个任务执行后打印一条消息。
    """
    # v2_playbook_on_task_ok 方法会在任务成功执行后被调用
    def v2_playbook_on_task_ok(self, task):
        # 获取任务名称
        task_name = task.get_name().strip()
        # 获取执行时间
        execution_time = "%.2f" % task.duration
        print(f"\n[Hello Callback] 任务 '{task_name}' 执行成功!耗时: {execution_time} 秒。")
        # 必须调用父类的方法,否则会中断 Ansible 的正常流程
        super().v2_playbook_on_task_ok(task)
    # v2_playbook_on_task_failed 方法会在任务失败后被调用
    def v2_playbook_on_task_failed(self, task, **kwargs):
        task_name = task.get_name().strip()
        print(f"\n[Hello Callback] 警告!任务 '{task_name}' 执行失败!")
        # 同样,调用父类方法
        super().v2_playbook_on_task_failed(task, **kwargs)

使用插件

创建一个简单的 Playbook 来测试它。

---
- name: Test Callback Plugin
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: Task 1 - A successful task
      ansible.builtin.debug:
        msg: "This will succeed"
    - name: Task 2 - A failing task
      ansible.builtin.command: /bin/false # 这个命令会失败
      ignore_errors: true # 我们故意让它失败,但不中断 Playbook
    - name: Task 3 - Another successful task
      ansible.builtin.debug:
        msg: "This will also succeed"

运行并观察结果

ansible-playbook test_playbook.yml

你会看到类似下面的输出,注意观察我们自定义的回调信息是如何被插入到标准输出中的:

TASK [Task 1 - A successful task] ***************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "This will succeed"
}
[Hello Callback] 任务 'Task 1 - A successful task' 执行成功!耗时: 0.01 秒。
TASK [Task 2 - A failing task] ****************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001993", "end": "2025-10-27T10:30:00.123456", "msg": "non-zero return code", "rc": 1, "start": "2025-10-27T10:30:00.121463", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
[Hello Callback] 警告!任务 'Task 2 - A failing task' 执行失败!
... (忽略 ignore_errors 的处理) ...
TASK [Task 3 - Another successful task] ********************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "This will also succeed"
}
[Hello Callback] 任务 'Task 3 - Another successful task' 执行成功!耗时: 0.00 秒。

总结与学习资源

特性 描述
语言 Python,几乎所有的 Ansible 插件都是用 Python 编写的。
位置 通常存放在 ~/.ansible/plugins/ (全局) 或项目目录下的 plugins/ (项目级)。
加载 Ansible 会自动扫描配置的插件目录,并动态加载符合条件的插件。
核心 理解 Ansible 的生命周期(如 Playbook 开始、任务执行、结束等)是编写高级插件的关键。

如何深入学习?

  1. 官方文档是最佳起点

    • Developing Plugins: 官方开发者指南,介绍了所有插件类型的编写方法。
    • Callbacks: 回调插件的官方用户指南。
  2. 阅读源码

    • Ansible 自身包含了大量的插件实现,阅读它们的源码是最好的学习方式,源码可以在 Ansible GitHub 仓库 中找到。
  3. 社区贡献

    查看 Ansible Galaxy 或 GitHub 上其他人贡献的插件,学习他们的实现思路。

掌握 Ansible 插件的开发,意味着你不再仅仅是 Ansible 的使用者,而是成为了它的“赋能者”,可以根据自己的具体需求,无限地扩展其能力边界。

分享:
扫描分享到社交APP
上一篇
下一篇