python的ansible库--ansible_runner
介绍
Ansible Runner是ansible官方提供的一个工具和python库,当直接与Ansible进行交互或作为另一个系统的一部分与Ansible进行交互时,无论是通过容器映像接口,作为独立工具还是作为可以导入的Python模块,它都可以提供帮助。 目的是为Ansible提供稳定且一致的接口抽象。
参考网站
安装
首先,确保您的系统已经安装了Python,并且具备pip包管理工具。使用以下命令来安装Ansible Runner:
pip install ansible-runner
目录准备
Runner输入的目录层次结构
官方给出的规范目录结构
.
├── env
│ ├── envvars
│ ├── extravars
│ ├── passwords
│ ├── cmdline
│ ├── settings
│ └── ssh_key
├── inventory
│ └── hosts
└── project
├── test.yml
└── roles
└── testrole
├── defaults
├── handlers
├── meta
├── README.md
├── tasks
├── tests
└── vars
目录 env
基本上是一些配置或者环境变量
文件env/envvars
Ansible Runner 将继承启动 shell 的环境。
此文件(可以是 json 或 yaml 格式)表示 将在运行时添加到环境中的 环境变量
例如
# env/envvars
---
TESTVAR: exampleval
在playbook中调用
---
- name: 测试主机
user: root
hosts: a
gather_facts: no
tasks:
- name: 设置fact变量
set_fact:
abc: "{{ lookup('env', 'TESTVAR') }}"
- name: 打印fact变量
debug:
var: abc
# "abc": "exampleval"
- name: 使用环境变量
debug:
msg: "The value of MY_VARIABLE is: {{ lookup('env', 'TESTVAR') }}"
# "msg": "The value of MY_VARIABLE is: exampleval"
可以看出来,就是变成环境的环境变量
使用的话,需要用 lookup('env', 'TESTVAR')
这种形式调用
无论是通过 set_fact使用 还是 直接使用
文件env/extravars
Ansible Runner 收集这个文件中提供的额外变量,并将它们提供给 Ansible 进程本身。此文件可以是 json
或 yaml
格式
就是python程序本身的变量,可以直接引用的变量
例如
# env/extravars
---
ansible_connection: local
test: val
在playbook中调用
---
- name: 测试主机
user: root
hosts: a
gather_facts: no
tasks:
- name: 打印变量
debug:
msg: "{{ test }}"
# "msg": "val"
如果在 Ansible 运行时,那就是 -e
后面传递的额外变量
文件env/passwords
Ansible 本身配置为 在 特定提示 时发出密码,这些提示可以根据需要请求(例如,请求连接密码)。
如果在 Ansible 运行时,那就是 -k
参数的意思
为了让 Runner 使用正确的密码进行响应,它需要能够匹配提示并提供正确的密码。目前支持此功能 通过提供具有正则表达式和要发出的值的 yaml 或 JSON 格式文件,例如:
---
"^SSH password:\\s*?$": "some_password"
"^BECOME password.*:\\s*?$": "become_password"
文件 env/cmdline
当前的 Ansible Runner 不会验证使用此方法传递的命令行参数,因此 playbook 编写者需要提供一组有效的选项。 此方法提供的命令行选项的优先级低于 Ansible Runner 设置的优先级。例如,这不会覆盖
inventory
或limit
值。
Ansible Runner 将这个文件提供的命令行选项收集为字符串,并将它们提供给 Ansible 进程本身。
此文件应包含要添加的参数
例如:
--tags one,two --skip-tags three -u ansible --become
或者
--tags=my_tag
--skip-tags=skip_me
--extra-vars=my_var=my_value
当使用ansible-runner运行playbook时,这些命令行参数将自动传递给ansible-playbook命令。这就可以在运行playbook时轻松地自定义其行为,而无需在命令行中手动指定这些参数。
例如上面的例子
--tags=my_tag
:仅运行具有标签my_tag的任务。--skip-tags=skip_me
:跳过具有标签skip_me的任务。--extra-vars=my_var=my_value
:设置一个名为my_var的额外变量,其值为my_value。
文件 env/ssh_key
目前只能通过此机制提供单个 ssh 密钥
此文件应包含用于连接到主机的 ssh 私钥。Runner 检测何时提供了私钥,并将对 Ansible 的调用包装在 ssh-agent 中。
要在 ansible-runner
项目中使用 env/ssh_key
文件,请按照以下步骤操作:
- 在项目目录中创建一个名为env的文件夹(如果尚未创建)。
- 将您的SSH私钥文件(通常是一个名为id_rsa的文件)复制到env文件夹中,并将其重命名为ssh_key。
现在,当您使用 ansible-runner
运行playbook时,这个私钥将用于与远程主机建立SSH连接。
请注意,为了保护您的私钥,请确保 env/ssh_key
文件的权限设置得当。通常,您应该将文件权限设置为600(只有所有者可以读取和写入)。
文件 env/settings
这个文件有所不同,settings是用来设置runner本身
Inventory
是用来存放主机清单的,可以是单个文件或者脚本,也可以是包含静态清单文件或者脚本的目录;
此清单在调用时会自动加载并提供给 Ansible,并且可以在命令行或通过环境变量进一步覆盖以直接指定主机。
例如
www.ixdba.net
[webservers]
#带端口
ixdba1.net:1234
#ip
10.1.2.3
#也可以这样指定端口
ixdba2.net ansible_ssh_port=9999
[dbservers]
db.ixdba1.net
#域名范围,从1到100
www[1:100].example.com
db.ixdba2.net
或者也可以带一些参数
[a]
192.168.1.2 ansible_ssh_pass='111111' ssh_port=22 ansible_user=root
192.168.1.3 ansible_ssh_pass='111111' ssh_port=22 ansible_user=root
目录 Project
Runner 目录是 playbook 根目录,其中包含这些 playbook 可以直接使用的 playbook 和角色。
各个playbook存放在这里,就可以在调用的使用直接指定对应playbook的文件名,而不用再指定路径
例如 有一个 project/test.yaml
那么,如果在命令行
ansible-runner run examples/ping/ -p test.yaml
如果是在python接口中
from ansible_runner import run
run(private_data_dir='examples/ping/', playbook='test.yaml')
Runner Artifacts 目录层次结构
还有一个不需要提前创建的目录 artifacts
这个目录将以分组的形式存放每次runner的运行结果
大概的目录情况
.
├── artifacts
│ └── identifier
├── env
├── inventory
└── project
而目录中分组的名称是生成一个UUID组成的标识符
这个UUID的获取方式
from ansible_runner import run
from ansible_runner.config.runner import RunnerConfig
directory = 'examples/ping'
ply = 'test.yaml'
runner = run(private_data_dir=directory, playbook=ply)
print(runner.stdout.read(), "===============")
print(runner.stderr.read(), "===============")
conf: RunnerConfig = runner.config
# 下面这三种方式都能获取到
print(conf.ident) # 456f20f5-4fff-49ea-853e-e87af1a2d3ef
print(conf.artifact_dir) # /data/pythonProject/artifacts/456f20f5-4fff-49ea-853e-e87af1a2d3ef
print(conf.env.get('AWX_ISOLATED_DATA_DIR')) #/data/pythonProject/artifacts/456f20f5-4fff-49ea-853e-e87af1a2d3ef
运行Runner后的目录结构
.
├── artifacts
│ └── 37f639a3-1f4f-4acb-abee-ea1898013a25
│ ├── fact_cache
│ │ └── localhost
│ ├── job_events
│ │ ├── 1-34437b34-addd-45ae-819a-4d8c9711e191.json
│ │ ├── 2-8c164553-8573-b1e0-76e1-000000000006.json
│ │ ├── 3-8c164553-8573-b1e0-76e1-00000000000d.json
│ │ ├── 4-f16be0cd-99e1-4568-a599-546ab80b2799.json
│ │ ├── 5-8c164553-8573-b1e0-76e1-000000000008.json
│ │ ├── 6-981fd563-ec25-45cb-84f6-e9dc4e6449cb.json
│ │ └── 7-01c7090a-e202-4fb4-9ac7-079965729c86.json
│ ├── rc
│ ├── status
│ └── stdout
├── env
├── inventory
└── project
如果又多个的话
.
├── artifacts
│ ├── 37f639a3-1f4f-4acb-abee-ea1898013a25
│ │ ├── fact_cache
│ │ │ ├── 192.168.1.11
│ │ │ └── 192.168.1.12
│ │ ├── job_events
│ │ │ ├── 1-34437b34-addd-45ae-819a-4d8c9711e191.json
│ │ │ ├── 2-8c164553-8573-b1e0-76e1-000000000006.json
│ │ │ ├── 3-8c164553-8573-b1e0-76e1-00000000000d.json
│ │ │ ├── 4-f16be0cd-99e1-4568-a599-546ab80b2799.json
│ │ │ ├── 5-8c164553-8573-b1e0-76e1-000000000008.json
│ │ │ ├── 6-981fd563-ec25-45cb-84f6-e9dc4e6449cb.json
│ │ │ └── 7-01c7090a-e202-4fb4-9ac7-079965729c86.json
│ │ ├── rc
│ │ ├── status
│ │ └── stdout
│ └── 4ee097bd-0929-4e36-9796-d81e6532f035
│ ├── fact_cache
│ │ └── localhost
│ ├── job_events
│ │ ├── 1-0fc6f26b-d8dd-45b7-909d-714292c95a48.json
│ │ ├── 2-d74d6cbd-a9a3-2aca-40e1-000000000003.json
│ │ ├── 3-d74d6cbd-a9a3-2aca-40e1-000000000005.json
│ │ ├── 4-79dbcd98-3eef-41ab-b47c-752b0577d041.json
│ │ ├── 5-227f77ee-d18e-4ba9-93cb-9c333c56450f.json
│ │ ├── 6-26a17488-8ab8-4861-99bc-c800da293def.json
│ │ ├── 7-c726a7e4-0376-4133-b537-2cd6f661e154.json
│ │ ├── 8-d74d6cbd-a9a3-2aca-40e1-000000000006.json
│ │ └── 9-df2fbfe9-330a-4577-b3e7-3bc85f3d917b.json
│ ├── rc
│ ├── status
│ └── stdout
├── env
├── inventory
└── project
rc文件
包含来自 Ansible 进程的实际返回代码。
status 文件
是显示playbook的执行状态
分别是下面三种情况:
- success:Ansible 进程成功完成
- failed:Ansible 进程失败
- timeout:Runner 超时
stdout 文件
是执行结果的输出,是文本格式
例如
PLAY [测试主机] ****************************************************************
TASK [ping主机] ****************************************************************
ok: [192.168.1.2]
TASK [获取主机名] **************************************************************
changed: [192.168.1.2]
TASK [打印主机名] **************************************************************
ok: [192.168.1.2] => {
"hostname.stdout": "ubuntu\r\n"
}
PLAY RECAP *********************************************************************
192.168.1.2 : ok=7 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
job_events文件夹
是用来存放执行步骤的,会将每步以单个json文件的形式存放
大概内容
{
"uuid": "d74d6cbd-a9a3-2a18-1d85-000000000003",
"counter": 2,
"stdout": "\r\nPLAY [\u6d4b\u8bd5\u4e3b\u673a] ****************************************************************",
"start_line": 0,
"end_line": 2,
"runner_ident": "456f20f5-4fff-49ea-853e-e8xxxxxxxxxxxxx",
"event": "playbook_on_play_start",
"pid": 10942,
"created": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"parent_uuid": "b87b3311-53d2-440b-9f64-b72b2bf152e6",
"event_data": {
"playbook": "test.yaml",
"playbook_uuid": "b87b3311-53d2-440b-9f64-b72b2bf152e6",
"play": "\u6d4b\u8bd5\u4e3b\u673a",
"play_uuid": "d74d6cbd-a9a3-2a18-1d85-000000000003",
"play_pattern": "a",
"name": "\u6d4b\u8bd5\u4e3b\u673a",
"pattern": "a",
"uuid": "d74d6cbd-a9a3-2aca-40e1-000000000003"
}
}
使用
ansible-runner有两种调用方式
- 作为命令行工具使用 https://ansible.readthedocs.io/projects/runner/en/latest/standalone/
- 作为python的库调用 https://ansible.readthedocs.io/projects/runner/en/latest/python_interface/
命令行工具
Ansible Runner
命令行工具可以用作 Ansible
本身的标准命令行界面,但主要目的是为了适应自动化和流水线工作流程。
因此,它的工作流程与 Ansible 本身略有不同,因为您可以在几种不同的模式之间进行选择来启动命令。
独立实用程序的调用示例
ansible-runner run /tmp/private -p playbook.yml
其中 playbook.yml
是 /tmp/private/projects
目录中的 playbook
,run
是要用于调用 Runner 的命令模式
runner 接受的不同命令包括:
run
ansible-runner在 前台 启动,并等待底层 Ansible 进程完成后再返回start
ansible-runner作为 后台守护进程 启动并生成 PID 文件stop
ansible-runner 终止 用start
在 后台 启动的进程is-alive
ansible-runner 检查用start
在 后台 启动的进程的状态
不管是哪种模式执行 ansible-runner,都会生产 artifacts
目录, 上面也介绍了,该目录下存放ansible-runner执行的结果、状态等, 可以通过 -i 参数来指定目录,不然的默认是在 <private_data_dir>/artifacts
下
直接运行模块
调用debug模块作为专用目录demo的示例
ansible-runner run demo -m debug --hosts localhost -a msg=hello
直接运行角色
ansible-runner run demo --role testrole --hosts localhost
以json的形式输出到控制台
Runner 支持将 json 事件数据结构直接输出到控制台(和 stdout 文件),而不是标准的 Ansible 输出
加上 -j
参数就可以了
ansible-runner ... -j ...
清理项目结果目录
通过选项 --rotate-artifacts
来控制,默认是0,表示不清理,会一直产生
ansible-runner run examples/ping/ -p test.yaml --rotate-artifacts 1
作为python的库调用
Ansible Runner旨在提供一个可以直接导入和使用的API,以便与Ansible本身进行交互,并公开了一些辅助接口。
这些模块主要围绕Runner对象构建。辅助方法将返回该对象的一个实例,该实例提供了执行Ansible命令结果的接口,或者根据接口的不同,返回包含实际输出和错误响应的元组。
Ansible Runner 本身是对Ansible执行过程的一个封装层,因此为了收集额外信息并对其进行处理和存储以便后续使用,它向系统中添加了插件和接口。
run() 方法
前台执行
具体参数
参数 | 类型 | 解释 |
---|---|---|
private_data_dir |
str | 包含 Runner 元数据所需的所有文件的目录,用于调用 Runner 模块。输出结果也将存储在此处以便后续消费。 |
playbook |
str或list | 要在 Ansible 执行时调用的 playbook(可以是 play 或 play 列表,或者相对于 private_data_dir/project 的路径)。 |
rotate_artifacts |
int | 最多保留 n 个工件目录,禁用则为 0(默认值)。用来控制运行结果的保留个数,0为全保存,用来清理产生的结果,非常方便 |
envvars |
dict | Ansible 执行时要使用的环境变量。还将从 private_data_dir 中的 env/envvars 中读取环境变量。 |
extravars |
dict | 在 Ansible 运行时通过 -e 传递的额外变量。还将从 private_data_dir 中的 env/extravars 中读取额外变量。 |
ssh_key |
str | 作为 ansible-playbook 运行的一部分传递给 ssh-agent 的 SSH 私钥。 |
artifact_dir |
str | 要在其中存储工件(artifact)的目录的路径,默认为 private_data_dir 中的 'artifacts'。 |
cmdline |
str | 从 private_data_dir 中的 env/cmdline 中读取的 Ansible 命令行选项。 |
limit |
str | 与 ansible 的 --limit 参数匹配以进一步限制要使用的清单。 |
forks |
int | 控制 Ansible 并行并发性。 |
verbosity |
int | 控制 ansible-playbook 的输出详细程度。 |
quiet |
bool | 禁用所有输出。 |
event_handler |
Callable | 可选回调,在 Runner 本身接收到任何事件时被调用,返回 True 以保留事件。 |
cancel_callback |
Callable | 可选回调,可以通知 Runner 取消(返回 True)或不取消(返回 False)。 |
finished_callback |
Callable | 可选回调,在关闭进程并完成清理后被调用。 |
status_handler |
Callable | 可选回调,每当状态发生变化(例如...启动、运行、失败、成功、超时)时被调用。 |
artifacts_handler |
Callable | 可选回调,在运行结束时处理来自运行的工件。 |
json_mode |
bool | 在控制台和 stdout 文件中以 JSON 格式存储事件数据,而不是标准输出。 |
module |
str | 在 ad-hoc 模式下要由 Runner 调用的模块。 |
module_args |
str | 将提供给 ad-hoc 模式的模块参数。 |
host_pattern |
str | 在 ad-hoc 模式下要匹配的主机模式。 |
inventory |
str或dict或list | 通过覆盖 private_data_dir/inventory 中的清单目录/文件来指定特定的主机或主机列表。可以采用以下形式: - private_data_dir 中的库存文件路径 - 支持 YAML/JSON 清单结构的本机 Python 字典 - INI 格式的文本 INI - 空列表以禁用传递清单 |
ident |
str | 此调用 Runner 的标识符。将用于创建和命名包含结果的 artifact 目录。 |
role |
str | 要执行的角色名称。 |
roles_path |
dict或list | 要分配给 ANSIBLE_ROLES_PATH 的目录或目录列表。 |
passwords |
dict | 一个字典,包含在处理 Ansible 输出时使用的密码提示模式和响应值。还将从 private_data_dir 中的 env/passwords 中读取密码。 |
settings |
dict | 一个字典,包含 ansible-runner 运行时环境的设置值。这些设置还将从 private_data_dir 中的 env/settings 中读取。 |
suppress_env_files |
bool | 禁用写入可能包含敏感信息的 env 文件。 |
project_dir |
str | playbook 内容的路径,默认为 private_data_dir 中的 'project'。 |
timeout |
int | 以秒为单位的超时值,将在执行命令时传递给 pexpect 或 subprocess 调用(基于选择的 runner_mode)。如果触发超时,它将强制取消执行。 |
streamer |
str | 可选地以流式传输管道的一个步骤调用 ansible-runner。 |
_input |
io.FileIO | 用于流式传输管道输入的可选项文件或类似文件的对象。 |
_output |
io.FileIO | 用于流式传输管道输出的可选项文件或类似文件的对象。 |
process_isolation |
bool | 启用进程隔离,使用容器引擎(例如 podman)或沙盒(例如 bwrap)。 |
process_isolation_executable |
str | 用于隔离执行的进程隔离可执行文件或容器引擎(默认:podman)。 |
process_isolation_path |
str | 隔离的 playbook 运行将用于暂存的路径。(默认:/tmp) |
process_isolation_hide_paths |
str或list | 系统中应隐藏 playbook 运行的一路径或多路径。 |
process_isolation_show_paths |
str或list | 系统中应暴露给 playbook 运行的一路径或多路径。 |
process_isolation_ro_paths |
str或list | 系统中应以只读方式暴露给 playbook 运行的一路径或多路径。 |
container_image |
str | 在运行 ansible 任务时要使用的容器镜像(默认:quay.io/ansible/ansible-runner:devel) |
container_volume_mounts |
list | 以 'host_dir:/container_dir' 形式的绑定挂载列表。 (默认:None) |
container_options |
list | 要传递给执行引擎的容器选项列表。 |
directory_isolation_base_path |
str | 一个可选路径,将用作临时目录的基本路径,项目内容将被复制到此位置,然后在此位置作为工作目录进行 playbook 执行。 |
fact_cache |
str | 用于 'jsonfile' 类型事实缓存的子目录的名称,该子目录位于 artifacts 目录中。 |
fact_cache_type |
str | 要使用的事实缓存类型。默认为 'jsonfile'。 |
omit_event_data |
bool | 省略额外的 ansible 事件数据,但仍包括 stdout 和事件。 |
only_failed_event_data |
bool | 除非事件失败,否则省略额外的 ansible 事件数据,但仍包括 stdout 和事件。 |
check_job_event_data |
bool | 检查作业事件数据是否完全生成。如果事件数据未完全生成且值为 'True',则会引发 'AnsibleRunnerException' 异常,如果设置为 'False',则记录一条调试消息并继续执行。默认值为 'False'。 |
最简单的例子
from ansible_runner import run
directory = 'examples/abc'
ply = 'test.yaml'
runner = run(private_data_dir=directory, playbook=ply)
print(runner.stdout.read(), "输出")
print(runner.stderr.read(), "异常")
设置结果保留个数,设置安静,设置环境变量,设置ansible的变量
from ansible_runner import run
directory = 'examples/ping'
ply = 'test.yaml'
runner = run(private_data_dir=directory, playbook=ply, rotate_artifacts=1,
envvars={ 'ansible_user': 'root' }, extra_vars={ 'abcd': 'xxx' },
quiet=True)
print(runner.stdout.read(), "输出")
print(runner.stderr.read(), "异常")
只运行简单的命令,设置安静,并以json的方式输出
from ansible_runner import run
r = run(
inventory={
"test": {
"hosts": {
"host01": {
"ansible_host" : "192.168.1.3",
"ansible_port" : 22,
"ansible_user" : "root",
"ansible_ssh_pass": "111111"
},
}
}
},
module="shell",
module_args="ip addr| grep 'inet 10.0'|awk '{print $2}'",
host_pattern="test",
quiet=True,
json_mode=True,
)
print("{}: {}".format(r.status, r.rc))
print(r.stdout.read())
回调函数部分
event_handler 回调函数
当回调函数返回为True的时候,数据才会被保存在产物中的job_events中
from ansible_runner import run
directory = 'examples/ping'
ply = 'test.yaml'
def event_callback(event_data):
# 处理回调事件
print("call event: ", event_data)
if event_data['stdout'] == '':
return False
else:
return True
runner = run(private_data_dir=directory, playbook=ply, rotate_artifacts=1,
event_handler=event_callback)
print(runner.stdout.read(), "输出")
print(runner.stderr.read(), "异常")
status_handler 回调函数
当状态发生变化的时候,会执行的回调函数
预期的值包括:
starting
:正在准备启动但尚未开始运行running
:Ansible任务正在运行canceled
:任务已通过回调或命令行手动取消timeout
:Runner设置中配置的超时时间已达到(参见 env/settings - Runner本身的设置)failed
:Ansible进程失败successful
:Ansible进程成功
from ansible_runner import run
directory = 'examples/ping'
ply = 'test.yaml'
def my_status_handler(data, runner_config):
print(data,"++++++++++++++")
"""
{
"status": "running",
"runner_ident": "e3436be2-f786-4acc-87bb-e25458c08395"
}
"""
print(runner_config,"========================================")
run(private_data_dir=directory, playbook=ply, rotate_artifacts=1,
status_handler=my_status_handler)
artifacts_handler 回调函数
结束的时候会调用这个回调函数 artifacts_dir就是最后输出产物的目录
from ansible_runner import run
directory = 'examples/ping'
ply = 'test.yaml'
def my_artifacts_handler(artifacts_dir):
# Do something here
print(artifacts_dir)
# /data/pythonProject/artifacts/456f20f5-4fff-49ea-853e-e87af1a2d3ef
runner = run(private_data_dir=directory, playbook=ply, rotate_artifacts=1,
artifacts_handler=my_artifacts_handler)
cancel_callback 回调函数
事件的每次循环迭代中都会调用,并应返回 True
以通知Runner取消并关闭Ansible进程,或返回 False
以允许其继续。
from ansible_runner import run
directory = 'examples/ping'
ply = 'test.yaml'
def my_cancel_handler():
print("cancel handler")
return True
run(private_data_dir=directory, playbook=ply, rotate_artifacts=1,
cancel_callback=my_cancel_handler)
finished_callback 回调函数
一旦Ansible关闭,Runner事件循环结束前将立即调用此函数
from ansible_runner import run
from ansible_runner.runner import Runner
directory = 'examples/ping'
ply = 'test.yaml'
def my_finished_handler(runner: Runner):
print("finished handler", runner.stdout.read())
run(private_data_dir=directory, playbook=ply, rotate_artifacts=1,
finished_callback=my_finished_handler)
通过配置的方式运行
from ansible_runner import Runner, RunnerConfig
# Using tag using RunnerConfig
rc = RunnerConfig(
private_data_dir="project",
playbook="main.yml",
tags='my_tag',
)
rc.prepare()
r = Runner(config=rc)
r.run()
run_async()
这个方法与 run()
的参数一致,只是这个方法是个异步的方法
用法完全一致
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/18061452