File: python_interface.rst

package info (click to toggle)
ansible-runner 2.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,232 kB
  • sloc: python: 9,896; makefile: 19
file content (418 lines) | stat: -rw-r--r-- 18,002 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
.. _python_interface:

Using Runner as a Python Module Interface to Ansible
====================================================

**Ansible Runner** is intended to provide a directly importable and usable API for interfacing with **Ansible** itself and exposes a few helper interfaces.

The modules center around the :class:`Runner <ansible_runner.runner.Runner>` object. The helper methods will either return an instance of this object which provides an
interface to the results of executing the **Ansible** command or a tuple the actual output and error response based on the interface.

**Ansible Runner** itself is a wrapper around **Ansible** execution and so adds plugins and interfaces to the system in order to gather extra information and
process/store it for use later.

Helper Interfaces
-----------------

The helper :mod:`interfaces <ansible_runner.interface>` provides a quick way of supplying the recommended inputs in order to launch a **Runner** process. These interfaces also allow overriding and providing inputs beyond the scope of what the standalone or container interfaces
support. You can see a full list of the inputs in the linked module documentation.

``run()`` helper function
-------------------------

:meth:`ansible_runner.interface.run`

When called, this function will take the inputs (either provided as direct inputs to the function or from the :ref:`inputdir`), and execute **Ansible**. It will run in the
foreground and return the :class:`Runner <ansible_runner.runner.Runner>` object when finished.

``run_async()`` helper function
-------------------------------

:meth:`ansible_runner.interface.run_async`

Takes the same arguments as :meth:`ansible_runner.interface.run` but will launch **Ansible** asynchronously and return a tuple containing
the ``thread`` object and a :class:`Runner <ansible_runner.runner.Runner>` object. The **Runner** object can be inspected during execution.

``run_command()`` helper function
---------------------------------

:meth:`ansible_runner.interface.run_command`

When called, this function will take the inputs (either provided as direct inputs to the function or from the :ref:`inputdir`), and execute the command passed either
locally or within an container based on the parameters passed. It will run in the foreground and return a tuple of output and error response when finished. While running
the within container image command the current local working directory will be volume mounted within the container, in addition to this for any of ansible command line
utilities the inventory, vault-password-file, private-key file path will be volume mounted if provided in the ``cmdline_args`` parameters.

``run_command_async()`` helper function
---------------------------------------

:meth:`ansible_runner.interface.run_command_async`

Takes the same arguments as :meth:`ansible_runner.interface.run_command` but will launch asynchronously and return a tuple containing
the ``thread`` object and a :class:`Runner <ansible_runner.runner.Runner>` object. The **Runner** object can be inspected during execution.

``get_plugin_docs()`` helper function
-------------------------------------

:meth:`ansible_runner.interface.get_plugin_docs`

When called, this function will take the inputs, and execute the ansible-doc command to return the either the plugin-docs or playbook snippet for the passed
list of plugin names. The plugin docs can be fetched either from locally installed plugins or from within an container image based on the parameters passed.
It will run in the foreground and return a tuple of output and error response when finished. While running the command within the container the current local
working directory will be volume mounted within the container.

``get_plugin_docs_async()`` helper function
-------------------------------------------

:meth:`ansible_runner.interface.get_plugin_docs_async`

Takes the same arguments as :meth:`ansible_runner.interface.get_plugin_docs_async` but will launch asynchronously and return a tuple containing
the ``thread`` object and a :class:`Runner <ansible_runner.runner.Runner>` object. The **Runner** object can be inspected during execution.

``get_plugin_list()`` helper function
-------------------------------------

:meth:`ansible_runner.interface.get_plugin_list`

When called, this function will take the inputs, and execute the ansible-doc command to return the list of installed plugins. The installed plugin can be fetched
either from local environment or from within an container image based on the parameters passed. It will run in the foreground and return a tuple of output and error
response when finished. While running the command within the container the current local working directory will be volume mounted within the container.

``get_inventory()`` helper function
-----------------------------------

:meth:`ansible_runner.interface.get_inventory`

When called, this function will take the inputs, and execute the ansible-inventory command to return the inventory related information based on the action.
If ``action`` is ``list`` it will return all the applicable configuration options for ansible, for ``host`` action it will return information
of a single host and for ``graph`` action it will return the inventory. The execution will be in the foreground and return a tuple of output and error
response when finished. While running the command within the container the current local working directory will be volume mounted within the container.

``get_ansible_config()`` helper function
----------------------------------------

:meth:`ansible_runner.interface.get_ansible_config`

When called, this function will take the inputs, and execute the ansible-config command to return the Ansible configuration related information based on the action.
If ``action`` is ``list`` it will return all the hosts related information including the host and group variables, for ``dump`` action it will return the entire active configuration
and it can be customized to return only the changed configuration value by setting the ``only_changed`` boolean parameter to ``True``. For ``view`` action it will return the
view of the active configuration file. The execution will be in the foreground and return a tuple of output and error response when finished.
While running the command within the container the current local working directory will be volume mounted within the container.

``get_role_list()`` helper function
-----------------------------------

:meth:`ansible_runner.interface.get_role_list`

*Version added: 2.2*

This function will execute the ``ansible-doc`` command to return the list of installed roles
that have an argument specification defined. This data can be fetched from either the local
environment or from within a container image based on the parameters passed. It will run in
the foreground and return a tuple of output and error response when finished. Successful output
will be in JSON format as returned from ``ansible-doc``.

``get_role_argspec()`` helper function
--------------------------------------

:meth:`ansible_runner.interface.get_role_argspec`

*Version added: 2.2*

This function will execute the ``ansible-doc`` command to return a role argument specification.
This data can be fetched from either the local environment or from within a container image
based on the parameters passed. It will run in the foreground and return a tuple of output
and error response when finished. Successful output will be in JSON format as returned from
``ansible-doc``.


The ``Runner`` object
---------------------

The :class:`Runner <ansible_runner.runner.Runner>` object is returned as part of the execution of **Ansible** itself. Since it wraps both execution and output
it has some helper methods for inspecting the results. Other than the methods and indirect properties, the instance of the object itself contains two direct
properties:

* ``rc`` will represent the actual return code of the **Ansible** process
* ``status`` will represent the state and can be one of:
   * ``unstarted``: This is a very brief state where the Runner task has been created but hasn't actually started yet.
   * ``successful``: The ``ansible`` process finished successfully.
   * ``failed``: The ``ansible`` process failed.

``Runner.stdout``
-----------------

The :class:`Runner <ansible_runner.runner.Runner>` object contains a property :attr:`ansible_runner.runner.Runner.stdout` which will return an open file
handle containing the `stdout` of the **Ansible** process.

``Runner.stderr``
-----------------

When the ``runner_mode`` is set to ``subprocess`` the :class:`Runner <ansible_runner.runner.Runner>` object uses a property :attr:`ansible_runner.runner.Runner.stderr` which
will return an open file handle containing the ``stderr`` of the **Ansible** process.

``Runner.events``
-----------------

:attr:`ansible_runner.runner.Runner.events` is a ``generator`` that will return the :ref:`Playbook and Host Events<artifactevents>` as Python ``dict`` objects.

``Runner.stats``
----------------

:attr:`ansible_runner.runner.Runner.stats` is a property that will return the final ``playbook stats`` event from **Ansible** in the form of a Python ``dict``

``Runner.host_events``
----------------------
:meth:`ansible_runner.runner.Runner.host_events` is a method that, given a hostname, will return a list of only **Ansible** event data executed on that Host.

``Runner.get_fact_cache``
-------------------------

:meth:`ansible_runner.runner.Runner.get_fact_cache` is a method that, given a hostname, will return a dictionary containing the `Facts <https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variables-discovered-from-systems-facts>`_ stored for that host during execution.

``Runner.event_handler``
------------------------

A function passed to ``__init__`` of :class:``Runner <ansible_runner.runner.Runner>``, this is invoked every time an Ansible event is received. You can use this to
inspect/process/handle events as they come out of Ansible. This function should return ``True`` to keep the event, otherwise it will be discarded.

``Runner.cancel_callback``
--------------------------

A function passed to ``__init__`` of :class:`Runner <ansible_runner.runner.Runner>`, and to the :meth:`ansible_runner.interface.run` interface functions.
This function will be called for every iteration of the :meth:`ansible_runner.interface.run` event loop and should return `True`
to inform **Runner** cancel and shutdown the **Ansible** process or `False` to allow it to continue.

``Runner.finished_callback``
----------------------------

A function passed to ``__init__`` of :class:`Runner <ansible_runner.runner.Runner>`, and to the :meth:`ansible_runner.interface.run` interface functions.
This function will be called immediately before the **Runner** event loop finishes once **Ansible** has been shut down.

.. _runnerstatushandler:

``Runner.status_handler``
-------------------------

A function passed to ``__init__`` of :class:`Runner <ansible_runner.runner.Runner>` and to the :meth:`ansible_runner.interface.run` interface functions.
This function will be called any time the ``status`` changes, expected values are:

* ``starting``: Preparing to start but hasn't started running yet
* ``running``: The **Ansible** task is running
* ``canceled``: The task was manually canceled either via callback or the cli
* ``timeout``: The timeout configured in Runner Settings was reached (see :ref:`runnersettings`)
* ``failed``: The **Ansible** process failed
* ``successful``: The **Ansible** process succeeded

Usage examples
--------------
.. code-block:: python

  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)


.. code-block:: python

  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)


.. code-block:: python

  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)


.. code-block:: python

  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)

.. code-block:: python

  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)

.. code-block:: python

  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()

.. code-block:: python

  # 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)

.. code-block:: python

  # 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))

.. code-block:: python

  # 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))

.. code-block:: python

  # 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))

.. code-block:: python

  # 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()))

.. code-block:: python

  # get plugin list installed on local system
  out, err = ansible_runner.get_plugin_list()
  print("out: {}".format(out))
  print("err: {}".format(err))

.. code-block:: python

  # 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))

.. code-block:: python

  # 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))

.. code-block:: python

  # get all roles with an arg spec installed locally
  out, err = ansible_runner.get_role_list()
  print("out: {}".format(out))
  print("err: {}".format(err))

.. code-block:: python

  # 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))

.. code-block:: python

  # 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))

.. code-block:: python

  # 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))

Providing custom behavior and inputs
------------------------------------

**TODO**

The helper methods are just one possible entrypoint, extending the classes used by these helper methods can allow a lot more custom behavior and functionality.

Show:

* How :class:`Runner Config <ansible_runner.config.runner.RunnerConfig>` is used and how overriding the methods and behavior can work
* Show how custom cancel and status callbacks can be supplied.