将 Runner 作为 Ansible 的 Python 模块接口使用

Ansible Runner 旨在提供一个可直接导入和使用的 API,用于与Ansible本身交互,并公开了一些辅助接口。

这些模块围绕着 Runner 对象。辅助方法将返回此对象的实例,该实例提供与执行Ansible命令结果的交互接口,或者返回一个包含实际输出和错误响应的元组,具体取决于接口。

Ansible Runner本身是Ansible执行的包装器,因此它向系统添加了插件和接口,以便收集更多信息并对其进行处理/存储以供以后使用。

辅助接口

辅助 interfaces 提供了一种快速方法,可以提供推荐的输入以启动Runner进程。这些接口还允许覆盖和提供超出独立或容器接口支持范围的输入。您可以在链接的模块文档中查看输入的完整列表。

run() 辅助函数

ansible_runner.interface.run()

调用此函数时,它将获取输入(作为直接输入提供给函数,或来自 Runner 输入目录层次结构),并执行Ansible。它将在前台运行,并在完成后返回 Runner 对象。

run_async() 辅助函数

ansible_runner.interface.run_async()

采用与 ansible_runner.interface.run() 相同的参数,但会异步启动Ansible,并返回一个包含 thread 对象和 Runner 对象的元组。可以在执行期间检查Runner对象。

run_command() 辅助函数

ansible_runner.interface.run_command()

调用此函数时,它将获取输入(作为直接输入提供给函数,或来自 Runner 输入目录层次结构),并执行传递的命令,该命令是在本地执行还是在容器中执行,具体取决于传递的参数。它将在前台运行,并在完成后返回输出和错误响应的元组。在容器映像内运行命令时,当前本地工作目录将被挂载到容器内,此外,对于任何 Ansible 命令行实用程序,如果在 cmdline_args 参数中提供,则库存、保管库密码文件、私钥文件路径也将被挂载。

run_command_async() 辅助函数

ansible_runner.interface.run_command_async()

采用与 ansible_runner.interface.run_command() 相同的参数,但会异步启动,并返回一个包含 thread 对象和 Runner 对象的元组。可以在执行期间检查Runner对象。

get_plugin_docs() 辅助函数

ansible_runner.interface.get_plugin_docs()

调用此函数时,它将获取输入,并执行 ansible-doc 命令以返回传递的插件名称列表的插件文档或剧本片段。插件文档可以从本地安装的插件或容器映像中获取,具体取决于传递的参数。它将在前台运行,并在完成后返回输出和错误响应的元组。在容器内运行命令时,当前本地工作目录将被挂载到容器内。

get_plugin_docs_async() 辅助函数

ansible_runner.interface.get_plugin_docs_async()

采用与 ansible_runner.interface.get_plugin_docs_async() 相同的参数,但会异步启动,并返回一个包含 thread 对象和 Runner 对象的元组。可以在执行期间检查Runner对象。

get_plugin_list() 辅助函数

ansible_runner.interface.get_plugin_list()

调用此函数时,它将获取输入,并执行 ansible-doc 命令以返回已安装的插件列表。已安装的插件可以从本地环境或容器映像中获取,具体取决于传递的参数。它将在前台运行,并在完成后返回输出和错误响应的元组。在容器内运行命令时,当前本地工作目录将被挂载到容器内。

get_inventory() 辅助函数

ansible_runner.interface.get_inventory()

调用此函数时,它将获取输入,并执行 ansible-inventory 命令以返回基于操作的库存相关信息。如果 actionlist,它将返回适用于 Ansible 的所有配置选项;对于 host 操作,它将返回单个主机的信息;对于 graph 操作,它将返回库存。执行将在前台进行,并在完成后返回输出和错误响应的元组。在容器内运行命令时,当前本地工作目录将被挂载到容器内。

get_ansible_config() 辅助函数

ansible_runner.interface.get_ansible_config()

当调用此函数时,它将获取输入并执行 ansible-config 命令,根据操作返回与 Ansible 配置相关的的信息。如果 actionlist,它将返回所有主机相关的信息,包括主机和组变量;对于 dump 操作,它将返回完整的活动配置,并且可以通过将 only_changed 布尔参数设置为 True 来定制为仅返回更改的配置值。对于 view 操作,它将返回活动配置文件的视图。执行将在前台进行,并在完成时返回一个包含输出和错误响应的元组。在容器中运行命令时,当前本地工作目录将被挂载到容器中。

get_role_list() 辅助函数

ansible_runner.interface.get_role_list()

添加版本: 2.2

此函数将执行 ansible-doc 命令以返回已定义参数规范的已安装角色的列表。此数据可以从本地环境或从容器镜像中获取,具体取决于传递的参数。它将在前台运行,并在完成时返回一个包含输出和错误响应的元组。成功的输出将以 ansible-doc 返回的 JSON 格式呈现。

get_role_argspec() 辅助函数

ansible_runner.interface.get_role_argspec()

添加版本: 2.2

此函数将执行 ansible-doc 命令以返回角色参数规范。此数据可以从本地环境或从容器镜像中获取,具体取决于传递的参数。它将在前台运行,并在完成时返回一个包含输出和错误响应的元组。成功的输出将以 ansible-doc 返回的 JSON 格式呈现。

The Runner 对象

The Runner 对象作为 Ansible 自身执行的一部分返回。由于它同时包含执行和输出,因此它有一些辅助方法用于检查结果。除了方法和间接属性之外,对象实例本身还包含两个直接属性。

  • rc 将表示 Ansible 进程的实际返回代码。

  • status 将表示状态,可以是以下之一:
    • unstarted: 这是一个非常短暂的状态,Runner 任务已创建但尚未真正开始。

    • successful: ansible 进程已成功完成。

    • failed: ansible 进程失败。

Runner.stdout

The Runner 对象包含一个属性 ansible_runner.runner.Runner.stdout,它将返回一个包含 Ansible 进程 stdout 的打开文件句柄。

Runner.stderr

runner_mode 设置为 subprocess 时,Runner 对象使用一个属性 ansible_runner.runner.Runner.stderr,它将返回一个包含 Ansible 进程 stderr 的打开文件句柄。

Runner.events

ansible_runner.runner.Runner.events 是一个 generator,它将返回 剧本和主机事件,作为 Python dict 对象。

Runner.stats

ansible_runner.runner.Runner.stats 是一个属性,它将以 Python dict 的形式返回 Ansible 中的最终 playbook stats 事件。

Runner.host_events

ansible_runner.runner.Runner.host_events() 是一个方法,它在给定主机名的情况下,将返回一个仅包含在该主机上执行的 Ansible 事件数据的列表。

Runner.get_fact_cache

ansible_runner.runner.Runner.get_fact_cache() 是一个方法,它在给定主机名的情况下,将返回一个包含在执行期间为该主机存储的 事实 的字典。

Runner.event_handler

传递给 :class:Runner <ansible_runner.runner.Runner>__init__ 的函数,每当收到 Ansible 事件时都会调用它。您可以使用它来检查、处理或处理从 Ansible 中出现的事件。此函数应该返回 True 以保留事件,否则它将被丢弃。

Runner.cancel_callback

传递给 Runner__init__ 以及 ansible_runner.interface.run() 接口函数的函数。此函数将在 ansible_runner.interface.run() 事件循环的每次迭代中被调用,并且应该返回 True 以通知 Runner 取消并关闭 Ansible 进程,或者返回 False 以允许它继续。

Runner.finished_callback

传递给 Runner__init__ 以及 ansible_runner.interface.run() 接口函数的函数。此函数将在 Runner 事件循环完成之前立即调用,此时 Ansible 已关闭。

Runner.status_handler

传递给 Runner__init__ 以及 ansible_runner.interface.run() 接口函数的函数。每当 status 发生变化时,都会调用此函数,预期的值是:

  • starting: 准备开始,但尚未开始运行。

  • running: Ansible 任务正在运行。

  • canceled: 任务已通过回调或 CLI 手动取消。

  • timeout: 在 Runner 设置中配置的超时时间已到期(请参阅 env/settings - Runner 本身的设置

  • failed: **Ansible** 进程失败

  • successful: **Ansible** 进程成功

使用示例

import ansible_runner
r = ansible_runner.run(private_data_dir='/tmp/demo', playbook='test.yml')
print("{}: {}".format(r.status, r.rc))
# successful: 0
for each_host_event in r.events:
    print(each_host_event['event'])
print("Final status:")
print(r.stats)
import ansible_runner

def my_artifacts_handler(artifacts_dir):
    # Do something here
    print(artifacts_dir)

# Do something with artifact directory after the run is complete
r = ansible_runner.run(private_data_dir='/tmp/demo', playbook='test.yml', artifacts_handler=my_artifacts_handler)
import ansible_runner

def my_status_handler(data, runner_config):
    # Do something here
    print(data)

r = ansible_runner.run(private_data_dir='/tmp/demo', playbook='test.yml', status_handler=my_status_handler)
import ansible_runner

def my_event_handler(data):
    # Do something here
    print(data)

r = ansible_runner.run(private_data_dir='/tmp/demo', playbook='test.yml', event_handler=my_event_handler)
import ansible_runner
r = ansible_runner.run(private_data_dir='/tmp/demo', host_pattern='localhost', module='shell', module_args='whoami')
print("{}: {}".format(r.status, r.rc))
# successful: 0
for each_host_event in r.events:
    print(each_host_event['event'])
print("Final status:")
print(r.stats)
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 the role named 'myrole' contained in the '<private_data_dir>/project/roles' directory
r = ansible_runner.run(private_data_dir='/tmp/demo', role='myrole')
print("{}: {}".format(r.status, r.rc))
print(r.stats)
# run ansible/generic commands in interactive mode within container
out, err, rc = ansible_runner.run_command(
    executable_cmd='ansible-playbook',
    cmdline_args=['gather.yaml', '-i', 'inventory', '-vvvv', '-k'],
    input_fd=sys.stdin,
    output_fd=sys.stdout,
    error_fd=sys.stderr,
    host_cwd='/home/demo',
    process_isolation=True,
    container_image='network-ee'
)
print("rc: {}".format(rc))
print("out: {}".format(out))
print("err: {}".format(err))
# run ansible/generic commands in interactive mode locally
out, err, rc = ansible_runner.run_command(
    executable_cmd='ansible-playbook',
    cmdline_args=['gather.yaml', '-i', 'inventory', '-vvvv', '-k'],
    input_fd=sys.stdin,
    output_fd=sys.stdout,
    error_fd=sys.stderr,
)
print("rc: {}".format(rc))
print("out: {}".format(out))
print("err: {}".format(err))
# get plugin docs from within container
out, err = ansible_runner.get_plugin_docs(
    plugin_names=['vyos.vyos.vyos_command'],
    plugin_type='module',
    response_format='json',
    process_isolation=True,
    container_image='network-ee'
)
print("out: {}".format(out))
print("err: {}".format(err))
# get plugin docs from within container in async mode
thread_obj, runner_obj = ansible_runner.get_plugin_docs_async(
    plugin_names=['ansible.netcommon.cli_config', 'ansible.netcommon.cli_command'],
    plugin_type='module',
    response_format='json',
    process_isolation=True,
    container_image='network-ee'
)
while runner_obj.status not in ['canceled', 'successful', 'timeout', 'failed']:
    time.sleep(0.01)
    continue

print("out: {}".format(runner_obj.stdout.read()))
print("err: {}".format(runner_obj.stderr.read()))
# get plugin list installed on local system
out, err = ansible_runner.get_plugin_list()
print("out: {}".format(out))
print("err: {}".format(err))
# get plugins with file list from within container
out, err = ansible_runner.get_plugin_list(list_files=True, process_isolation=True, container_image='network-ee')
print("out: {}".format(out))
print("err: {}".format(err))
# get list of changed ansible configuration values
out, err = ansible_runner.get_ansible_config(action='dump',  config_file='/home/demo/ansible.cfg', only_changed=True)
print("out: {}".format(out))
print("err: {}".format(err))

# get ansible inventory information
out, err = ansible_runner.get_inventory(
    action='list',
    inventories=['/home/demo/inventory1', '/home/demo/inventory2'],
    response_format='json',
    process_isolation=True,
    container_image='network-ee'
)
print("out: {}".format(out))
print("err: {}".format(err))
# get all roles with an arg spec installed locally
out, err = ansible_runner.get_role_list()
print("out: {}".format(out))
print("err: {}".format(err))
# get roles with an arg spec from the `foo.bar` collection in a container
out, err = ansible_runner.get_role_list(collection='foo.bar', process_isolation=True, container_image='network-ee')
print("out: {}".format(out))
print("err: {}".format(err))
# get the arg spec for role `baz` from the locally installed `foo.bar` collection
out, err = ansible_runner.get_role_argspec('baz', collection='foo.bar')
print("out: {}".format(out))
print("err: {}".format(err))
# get the arg spec for role `baz` from the `foo.bar` collection installed in a container
out, err = ansible_runner.get_role_argspec('baz', collection='foo.bar', process_isolation=True, container_image='network-ee')
print("out: {}".format(out))
print("err: {}".format(err))

提供自定义行为和输入

待办事项

辅助方法只是可能的入口点之一,扩展这些辅助方法使用的类可以实现更多自定义行为和功能。

展示

  • Runner Config 的使用方式以及如何覆盖方法和行为

  • 展示如何提供自定义取消和状态回调。