Ansible插件开发
Ansible 的插件机制非常强大,它允许开发者扩展 Ansible 的功能,在执行 Playbook、Task、Inventory、Callback 等不同阶段插入自定义逻辑。
🔹 一、Ansible 插件的基本概念
插件(Plugin)是 扩展 Ansible 功能 的模块化代码片段。
插件不同于 模块(Module):
模块:执行具体任务(如
copy
、shell
)。插件:增强或修改 Ansible 的运行方式(例如:改变日志输出格式、修改 inventory 加载方式等)。
插件在 Ansible 执行流程的不同阶段 被调用。
🔹 二、Ansible 插件的主要类型
常见的插件类型及作用:
插件类型 | 作用 | 示例 |
---|---|---|
Action 插件 | 扩展/改写模块执行逻辑 | normal.py (默认执行逻辑) |
Cache 插件 | 缓存 Facts 数据 | jsonfile 、memcached |
Callback 插件 | 自定义执行结果输出、事件钩子 | default 、json 、yaml |
Connection 插件 | 定义与远程主机通信方式 | ssh 、paramiko 、local |
Filter 插件 | 在 Jinja2 模板中定义过滤器 | to_json |
Inventory 插件 | 定义动态/静态 inventory 加载方式 | yaml 、ini 、aws_ec2 |
Lookup 插件 | 查找数据源(文件、数据库等) | file 、passwordstore |
Strategy 插件 | 控制任务执行顺序 | linear 、free |
Vars 插件 | 提供额外变量源 | host_group_vars |
Test 插件 | 在 Jinja2 表达式中定义测试函数 | is even |
Terminal 插件 | 定义交互式设备终端行为(网络设备自动化用得多) | paramiko_ssh |
🔹 三、插件的目录结构
Ansible 会在以下目录查找插件:
系统路径(内置插件)
/usr/lib/pythonX.Y/site-packages/ansible/plugins/
项目路径(推荐)
project/ ├── ansible.cfg ├── inventory/ └── plugins/├── callback/├── connection/├── filter/├── lookup/└── vars/
环境变量
可以通过
ANSIBLE_CALLBACK_PLUGINS
等环境变量指定路径。
配置文件
ansible.cfg
[defaults] callback_plugins = ./plugins/callback action_plugins = ./plugins/action filter_plugins = ./plugins/filter
🔹 四、编写插件的基本方法
1. Callback 插件示例
用途:自定义任务执行结果的输出。
保存到 plugins/callback/mylog.py
# mylog.py
from ansible.plugins.callback import CallbackBaseclass CallbackModule(CallbackBase):CALLBACK_VERSION = 2.0CALLBACK_TYPE = 'notification'CALLBACK_NAME = 'mylog'def v2_runner_on_ok(self, result, **kwargs):host = result._hostprint(f"✅ 成功: {host.name} 执行 {result.task_name}")def v2_runner_on_failed(self, result, ignore_errors=False):host = result._hostprint(f"❌ 失败: {host.name} 执行 {result.task_name}")
启用方法:
[defaults]
stdout_callback = mylog
callback_plugins = ./plugins/callback
2. Filter 插件示例
用途:在 Jinja2 模板中自定义过滤器。
保存到 plugins/filter/myfilters.py
class FilterModule(object):def filters(self):return {'reverse_str': self.reverse_str}def reverse_str(self, value):return value[::-1]
使用:
- debug:msg: "{{ 'hello' | reverse_str }}"
输出:
olleh
3. Inventory 插件示例
用途:动态获取主机列表。
保存到 plugins/inventory/myinventory.py
from ansible.plugins.inventory import BaseInventoryPluginclass InventoryModule(BaseInventoryPlugin):NAME = 'myinventory'def verify_file(self, path):return path.endswith(('myinv.yaml', 'myinv.yml'))def parse(self, inventory, loader, path, cache=True):super(InventoryModule, self).parse(inventory, loader, path)# 解析逻辑self.inventory.add_host('server1')self.inventory.add_host('server2')
配置:
plugin: myinventory
🔹 五、调试插件
直接运行 Ansible 命令并启用调试:
ansible-playbook play.yml -vvv
插件开发时常用
print()
或logging
调试。可以写单元测试,使用 Python 的
pytest
或unittest
。
🔹 六、最佳实践
放在项目的
plugins/
目录,避免污染系统插件。明确插件类型(Callback、Filter 等),不同类型类定义方式不同。
遵循 Ansible 插件基类(如
CallbackBase
、BaseInventoryPlugin
)。使用 ansible.cfg 显式声明插件路径。
插件发布可通过 Galaxy 或私有仓库。