mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Developer documentation update involving module invocation (#55747)
* Update docs for the 2.7 change to AnsiballZ which invokes modules with one less Python interpreter * Add a section on how module results are returned and on trust between modules, action plugins, and the executor. * Update docs/docsite/rst/dev_guide/developing_program_flow_modules.rst Co-Authored-By: abadger <a.badger@gmail.com>
This commit is contained in:
parent
c455635500
commit
edafa71f42
1 changed files with 180 additions and 181 deletions
|
@ -5,13 +5,9 @@
|
|||
Ansible module architecture
|
||||
***************************
|
||||
|
||||
This in-depth dive helps you understand Ansible's program flow to execute
|
||||
modules. It is written for people working on the portions of the Core Ansible
|
||||
Engine that execute a module. Those writing Ansible Modules may also find this
|
||||
in-depth dive to be of interest, but individuals simply using Ansible Modules
|
||||
will not likely find this to be helpful.
|
||||
If you're working on Ansible's Core code, writing an Ansible module, or developing an action plugin, this deep dive helps you understand how Ansible's program flow executes. If you're just using Ansible Modules in playbooks, you can skip this section.
|
||||
|
||||
.. contents:: Topics
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
.. _flow_types_of_modules:
|
||||
|
@ -27,17 +23,15 @@ these are for backwards compatibility and others are to enable flexibility.
|
|||
Action plugins
|
||||
--------------
|
||||
|
||||
Action Plugins look like modules to end users who are writing :term:`playbooks` but
|
||||
they're distinct entities for the purposes of this document. Action Plugins
|
||||
always execute on the controller and are sometimes able to do all work there
|
||||
(for instance, the ``debug`` Action Plugin which prints some text for the user to
|
||||
see or the ``assert`` Action Plugin which can test whether several values in
|
||||
a playbook satisfy certain criteria.)
|
||||
Action plugins look like modules to anyone writing a playbook. Usage documentation for most action plugins lives inside a module of the same name. Some action plugins do all the work, with the module providing only documentation. Some action plugins execute modules. The ``normal`` action plugin executes modules that don't have special action plugins. Action plugins always execute on the controller.
|
||||
|
||||
More often, Action Plugins set up some values on the controller, then invoke an
|
||||
actual module on the managed node that does something with these values. An
|
||||
easy to understand version of this is the :ref:`template Action Plugin
|
||||
<template_module>`. The :ref:`template Action Plugin <template_module>` takes values from
|
||||
Some action plugins do all their work on the controller. For
|
||||
example, the :ref:`debug <debug_module>` action plugin (which prints text for
|
||||
the user to see) and the :ref:`assert <assert_module>` action plugin (which
|
||||
tests whether values in a playbook satisfy certain criteria) execute entirely on the controller.
|
||||
|
||||
Most action plugins set up some values on the controller, then invoke an
|
||||
actual module on the managed node that does something with these values. For example, the :ref:`template <template_module>` action plugin takes values from
|
||||
the user to construct a file in a temporary location on the controller using
|
||||
variables from the playbook environment. It then transfers the temporary file
|
||||
to a temporary file on the remote system. After that, it invokes the
|
||||
|
@ -49,23 +43,20 @@ into its final location, sets file permissions, and so on.
|
|||
New-style modules
|
||||
-----------------
|
||||
|
||||
All of the modules that ship with Ansible fall into this category.
|
||||
All of the modules that ship with Ansible fall into this category. While you can write modules in any language, all official modules (shipped with Ansible) use either Python or PowerShell.
|
||||
|
||||
New-style modules have the arguments to the module embedded inside of them in
|
||||
some manner. Non-new-style modules must copy a separate file over to the
|
||||
some manner. Old-style modules must copy a separate file over to the
|
||||
managed node, which is less efficient as it requires two over-the-wire
|
||||
connections instead of only one.
|
||||
|
||||
.. _flow_python_modules:
|
||||
|
||||
Python
|
||||
------
|
||||
^^^^^^
|
||||
|
||||
New-style Python modules use the :ref:`Ansiballz` framework for constructing
|
||||
modules. All official modules (shipped with Ansible) use either this or the
|
||||
:ref:`powershell module framework <flow_powershell_modules>`.
|
||||
|
||||
These modules use imports from :code:`ansible.module_utils` in order to pull in
|
||||
modules. These modules use imports from :code:`ansible.module_utils` to pull in
|
||||
boilerplate module code, such as argument parsing, formatting of return
|
||||
values as :term:`JSON`, and various file operations.
|
||||
|
||||
|
@ -76,21 +67,21 @@ values as :term:`JSON`, and various file operations.
|
|||
|
||||
.. _flow_powershell_modules:
|
||||
|
||||
Powershell
|
||||
----------
|
||||
PowerShell
|
||||
^^^^^^^^^^
|
||||
|
||||
New-style powershell modules use the :ref:`module_replacer` framework for
|
||||
constructing modules. These modules get a library of powershell code embedded
|
||||
New-style PowerShell modules use the :ref:`module_replacer` framework for
|
||||
constructing modules. These modules get a library of PowerShell code embedded
|
||||
in them before being sent to the managed node.
|
||||
|
||||
.. _flow_jsonargs_modules:
|
||||
|
||||
JSONARGS
|
||||
--------
|
||||
JSONARGS modules
|
||||
----------------
|
||||
|
||||
Scripts can arrange for an argument string to be placed within them by placing
|
||||
the string ``<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>`` somewhere inside of the
|
||||
file. The module typically sets a variable to that value like this:
|
||||
These modules are scripts that include the string
|
||||
``<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>`` in their body.
|
||||
This string is replaced with the JSON-formatted argument string. These modules typically set a variable to that value like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -114,8 +105,8 @@ Which is expanded as:
|
|||
a :ref:`non-native JSON module <flow_want_json_modules>` or
|
||||
:ref:`Old-style module <flow_old_style_modules>` instead.
|
||||
|
||||
The module typically parses the contents of ``json_arguments`` using a JSON
|
||||
library and then use them as native variables throughout the rest of its code.
|
||||
These modules typically parse the contents of ``json_arguments`` using a JSON
|
||||
library and then use them as native variables throughout the code.
|
||||
|
||||
.. _flow_want_json_modules:
|
||||
|
||||
|
@ -143,11 +134,11 @@ Binary modules
|
|||
From Ansible 2.2 onwards, modules may also be small binary programs. Ansible
|
||||
doesn't perform any magic to make these portable to different systems so they
|
||||
may be specific to the system on which they were compiled or require other
|
||||
binary runtime dependencies. Despite these drawbacks, a site may sometimes
|
||||
have no choice but to compile a custom module against a specific binary
|
||||
library if that's the only way they have to get access to certain resources.
|
||||
binary runtime dependencies. Despite these drawbacks, you may have
|
||||
to compile a custom module against a specific binary
|
||||
library if that's the only way to get access to certain resources.
|
||||
|
||||
Binary modules take their arguments and will return data to Ansible in the same
|
||||
Binary modules take their arguments and return data to Ansible in the same
|
||||
way as :ref:`want JSON modules <flow_want_json_modules>`.
|
||||
|
||||
.. seealso:: One example of a `binary module
|
||||
|
@ -162,10 +153,8 @@ Old-style modules
|
|||
Old-style modules are similar to
|
||||
:ref:`want JSON modules <flow_want_json_modules>`, except that the file that
|
||||
they take contains ``key=value`` pairs for their parameters instead of
|
||||
:term:`JSON`.
|
||||
|
||||
Ansible decides that a module is old-style when it doesn't have any of the
|
||||
markers that would show that it is one of the other types.
|
||||
:term:`JSON`. Ansible decides that a module is old-style when it doesn't have
|
||||
any of the markers that would show that it is one of the other types.
|
||||
|
||||
.. _flow_how_modules_are_executed:
|
||||
|
||||
|
@ -193,30 +182,29 @@ to that Action Plugin for further processing.
|
|||
|
||||
.. _flow_normal_action_plugin:
|
||||
|
||||
Normal action plugin
|
||||
--------------------
|
||||
The ``normal`` action plugin
|
||||
----------------------------
|
||||
|
||||
The ``normal`` action plugin executes the module on the remote host. It is
|
||||
the primary coordinator of much of the work to actually execute the module on
|
||||
the managed machine.
|
||||
|
||||
* It takes care of creating a connection to the managed machine by
|
||||
instantiating a ``Connection`` class according to the inventory
|
||||
configuration for that host.
|
||||
* It adds any internal Ansible variables to the module's parameters (for
|
||||
* It loads the appropriate connection plugin for the task, which then transfers
|
||||
or executes as needed to create a connection to that host.
|
||||
* It adds any internal Ansible properties to the module's parameters (for
|
||||
instance, the ones that pass along ``no_log`` to the module).
|
||||
* It takes care of creating any temporary files on the remote machine and
|
||||
* It works with other plugins (connection, shell, become, other action plugins)
|
||||
to create any temporary files on the remote machine and
|
||||
cleans up afterwards.
|
||||
* It does the actual work of pushing the module and module parameters to the
|
||||
* It pushes the module and module parameters to the
|
||||
remote host, although the :ref:`module_common <flow_executor_module_common>`
|
||||
code described in the next section does the work of deciding which format
|
||||
code described in the next section decides which format
|
||||
those will take.
|
||||
* It handles any special cases regarding modules (for instance, various
|
||||
complications around Windows modules that must have the same names as Python
|
||||
modules, so that internal calling of modules from other Action Plugins work.)
|
||||
* It handles any special cases regarding modules (for instance, async
|
||||
execution, or complications around Windows modules that must have the same names as Python modules, so that internal calling of modules from other Action Plugins work.)
|
||||
|
||||
Much of this functionality comes from the `BaseAction` class,
|
||||
which lives in :file:`plugins/action/__init__.py`. It makes use of
|
||||
which lives in :file:`plugins/action/__init__.py`. It uses the
|
||||
``Connection`` and ``Shell`` objects to do its work.
|
||||
|
||||
.. note::
|
||||
|
@ -230,16 +218,15 @@ which lives in :file:`plugins/action/__init__.py`. It makes use of
|
|||
Executor/module_common.py
|
||||
-------------------------
|
||||
|
||||
Code in :file:`executor/module_common.py` takes care of assembling the module
|
||||
Code in :file:`executor/module_common.py` assembles the module
|
||||
to be shipped to the managed node. The module is first read in, then examined
|
||||
to determine its type. :ref:`PowerShell <flow_powershell_modules>` and
|
||||
:ref:`JSON-args modules <flow_jsonargs_modules>` are passed through
|
||||
:ref:`Module Replacer <module_replacer>`. New-style
|
||||
:ref:`Python modules <flow_python_modules>` are assembled by :ref:`Ansiballz`.
|
||||
:ref:`Non-native-want-JSON <flow_want_json_modules>`,
|
||||
:ref:`Binary modules <flow_binary_modules>`, and
|
||||
:ref:`Old-Style modules <flow_old_style_modules>` aren't touched by either of
|
||||
these and pass through unchanged. After the assembling step, one final
|
||||
to determine its type:
|
||||
|
||||
* :ref:`PowerShell <flow_powershell_modules>` and :ref:`JSON-args modules <flow_jsonargs_modules>` are passed through :ref:`Module Replacer <module_replacer>`.
|
||||
* New-style :ref:`Python modules <flow_python_modules>` are assembled by :ref:`Ansiballz`.
|
||||
* :ref:`Non-native-want-JSON <flow_want_json_modules>`, :ref:`Binary modules <flow_binary_modules>`, and :ref:`Old-Style modules <flow_old_style_modules>` aren't touched by either of these and pass through unchanged.
|
||||
|
||||
After the assembling step, one final
|
||||
modification is made to all modules that have a shebang line. Ansible checks
|
||||
whether the interpreter in the shebang line has a specific path configured via
|
||||
an ``ansible_$X_interpreter`` inventory variable. If it does, Ansible
|
||||
|
@ -248,7 +235,10 @@ this, Ansible returns the complete module data and the module type to the
|
|||
:ref:`Normal Action <flow_normal_action_plugin>` which continues execution of
|
||||
the module.
|
||||
|
||||
Next we'll go into some details of the two assembler frameworks.
|
||||
Assembler frameworks
|
||||
--------------------
|
||||
|
||||
Ansible supports two assembler frameworks: Ansiballz and the older Module Replacer.
|
||||
|
||||
.. _module_replacer:
|
||||
|
||||
|
@ -256,7 +246,7 @@ Module Replacer framework
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The Module Replacer framework is the original framework implementing new-style
|
||||
modules. It is essentially a preprocessor (like the C Preprocessor for those
|
||||
modules, and is still used for PowerShell modules. It is essentially a preprocessor (like the C Preprocessor for those
|
||||
familiar with that programming language). It does straight substitutions of
|
||||
specific substring patterns in the module file. There are two types of
|
||||
substitutions:
|
||||
|
@ -275,9 +265,7 @@ substitutions:
|
|||
:file:`ansible/module_utils/powershell.ps1`. It should only be used with
|
||||
:ref:`new-style Powershell modules <flow_powershell_modules>`.
|
||||
|
||||
* Replacements that are used by ``ansible.module_utils`` code. These are internal
|
||||
replacement patterns. They may be used internally, in the above public
|
||||
replacements, but shouldn't be used directly by modules.
|
||||
* Replacements that are used by ``ansible.module_utils`` code. These are internal replacement patterns. They may be used internally, in the above public replacements, but shouldn't be used directly by modules.
|
||||
|
||||
- :code:`"<<ANSIBLE_VERSION>>"` is substituted with the Ansible version. In
|
||||
:ref:`new-style Python modules <flow_python_modules>` under the
|
||||
|
@ -317,29 +305,33 @@ substitutions:
|
|||
Ansiballz framework
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Ansible 2.1 switched from the :ref:`module_replacer` framework to the
|
||||
Ansiballz framework for assembling modules. The Ansiballz framework differs
|
||||
from module replacer in that it uses real Python imports of things in
|
||||
The Ansiballz framework was adopted in Ansible 2.1 and is used for all new-style Python modules. Unlike the Module Replacer, Ansiballz uses real Python imports of things in
|
||||
:file:`ansible/module_utils` instead of merely preprocessing the module. It
|
||||
does this by constructing a zipfile -- which includes the module file, files
|
||||
in :file:`ansible/module_utils` that are imported by the module, and some
|
||||
boilerplate to pass in the module's parameters. The zipfile is then Base64
|
||||
encoded and wrapped in a small Python script which decodes the Base64 encoding
|
||||
and places the zipfile into a temp directory on the managed node. It then
|
||||
extracts just the ansible module script from the zip file and places that in
|
||||
the temporary directory as well. Then it sets the PYTHONPATH to find python
|
||||
modules inside of the zip file and invokes :command:`python` on the extracted
|
||||
ansible module.
|
||||
extracts just the Ansible module script from the zip file and places that in
|
||||
the temporary directory as well. Then it sets the PYTHONPATH to find Python
|
||||
modules inside of the zip file and imports the Ansible module as the special name, ``__main__``.
|
||||
Importing it as ``__main__`` causes Python to think that it is executing a script rather than simply
|
||||
importing a module. This lets Ansible run both the wrapper script and the module code in a single copy of Python on the remote machine.
|
||||
|
||||
.. note::
|
||||
Ansible wraps the zipfile in the Python script for two reasons:
|
||||
* Ansible wraps the zipfile in the Python script for two reasons:
|
||||
|
||||
* for compatibility with Python 2.6 which has a less
|
||||
functional version of Python's ``-m`` command line switch.
|
||||
|
||||
* so that pipelining will function properly. Pipelining needs to pipe the
|
||||
Python module into the Python interpreter on the remote node. Python
|
||||
understands scripts on stdin but does not understand zip files.
|
||||
|
||||
* Prior to Ansible 2.7, the module was executed via a second Python interpreter instead of being
|
||||
executed inside of the same process. This change was made once Python-2.4 support was dropped
|
||||
to speed up module execution.
|
||||
|
||||
In Ansiballz, any imports of Python modules from the
|
||||
:py:mod:`ansible.module_utils` package trigger inclusion of that Python file
|
||||
into the zipfile. Instances of :code:`#<<INCLUDE_ANSIBLE_MODULE_COMMON>>` in
|
||||
|
@ -355,30 +347,30 @@ the zipfile as well.
|
|||
import that has :py:mod:`ansible.module_utils` in it to allow Ansiballz to
|
||||
determine that the file should be included.
|
||||
|
||||
|
||||
.. _flow_passing_module_args:
|
||||
|
||||
Passing args
|
||||
------------
|
||||
|
||||
In :ref:`module_replacer`, module arguments are turned into a JSON-ified
|
||||
string and substituted into the combined module file. In :ref:`Ansiballz`,
|
||||
the JSON-ified string is passed into the module via stdin. When
|
||||
a :class:`ansible.module_utils.basic.AnsibleModule` is instantiated,
|
||||
it parses this string and places the args into
|
||||
:attr:`AnsibleModule.params` where it can be accessed by the module's
|
||||
other code.
|
||||
Arguments are passed differently by the two frameworks:
|
||||
|
||||
* In :ref:`module_replacer`, module arguments are turned into a JSON-ified string and substituted into the combined module file.
|
||||
* In :ref:`Ansiballz`, the JSON-ified string is part of the script which wraps the zipfile. Just before the wrapper script imports the Ansible module as ``__main__``, it monkey-patches the private, ``_ANSIBLE_ARGS`` variable in ``basic.py`` with the variable values. When a :class:`ansible.module_utils.basic.AnsibleModule` is instantiated, it parses this string and places the args into :attr:`AnsibleModule.params` where it can be accessed by the module's other code.
|
||||
|
||||
.. warning::
|
||||
If you are writing modules, remember that the way we pass arguments is an internal implementation detail: it has changed in the past and will change again as soon as changes to the common module_utils
|
||||
code allow Ansible modules to forgo using :class:`ansible.module_utils.basic.AnsibleModule`. Do not rely on the internal global ``_ANSIBLE_ARGS`` variable.
|
||||
|
||||
Very dynamic custom modules which need to parse arguments before they
|
||||
instantiate an ``AnsibleModule`` may use ``_load_params`` to retrieve those parameters.
|
||||
Although ``_load_params`` may change in breaking ways if necessary to support
|
||||
changes in the code, it is likely to be more stable than either the way we pass parameters or the internal global variable.
|
||||
|
||||
.. note::
|
||||
Internally, the `AnsibleModule` uses the helper function,
|
||||
:py:func:`ansible.module_utils.basic._load_params`, to load the parameters
|
||||
from stdin and save them into an internal global variable. Very dynamic
|
||||
custom modules which need to parse the parameters prior to instantiating
|
||||
an ``AnsibleModule`` may use ``_load_params`` to retrieve the
|
||||
parameters. Be aware that ``_load_params`` is an internal function and
|
||||
may change in breaking ways if necessary to support changes in the code.
|
||||
However, we'll do our best not to break it gratuitously, which is not
|
||||
something that can be said for either the way parameters are passed or
|
||||
the internal global variable.
|
||||
Prior to Ansible 2.7, the Ansible module was invoked in a second Python interpreter and the
|
||||
arguments were then passed to the script over the script's stdin.
|
||||
|
||||
|
||||
.. _flow_internal_arguments:
|
||||
|
||||
|
@ -392,61 +384,55 @@ Ansible features. Modules often do not need to know about these explicitly as
|
|||
the features are implemented in :py:mod:`ansible.module_utils.basic` but certain
|
||||
features need support from the module so it's good to know about them.
|
||||
|
||||
The internal arguments listed here are global. If you need to add a local internal argument to a custom module, create an action plugin for that specific module - see ``_original_basename`` in the `copy action plugin <https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/copy.py#L329>`_ for an example.
|
||||
|
||||
_ansible_no_log
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
This is a boolean. If it's True then the playbook specified ``no_log`` (in
|
||||
a task's parameters or as a play parameter). This automatically affects calls
|
||||
to :py:meth:`AnsibleModule.log`. If a module implements its own logging then
|
||||
it needs to check this value. The best way to look at this is for the module
|
||||
to instantiate an `AnsibleModule` and then check the value of
|
||||
:attr:`AnsibleModule.no_log`.
|
||||
Boolean. Set to True whenever a parameter in a task or play specifies ``no_log``. Any module that calls :py:meth:`AnsibleModule.log` handles this automatically. If a module implements its own logging then
|
||||
it needs to check this value. To access in a module, instantiate an
|
||||
``AnsibleModule`` and then check the value of :attr:`AnsibleModule.no_log`.
|
||||
|
||||
.. note::
|
||||
``no_log`` specified in a module's argument_spec are handled by a different mechanism.
|
||||
``no_log`` specified in a module's argument_spec is handled by a different mechanism.
|
||||
|
||||
_ansible_debug
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
This is a boolean that turns on more verbose logging. If a module uses
|
||||
Boolean. Turns more verbose logging on or off and turns on logging of
|
||||
external commands that the module executes. If a module uses
|
||||
:py:meth:`AnsibleModule.debug` rather than :py:meth:`AnsibleModule.log` then
|
||||
the messages are only logged if this is True. This also turns on logging of
|
||||
external commands that the module executes. This can be changed via
|
||||
the ``debug`` setting in :file:`ansible.cfg` or the environment variable
|
||||
:envvar:`ANSIBLE_DEBUG`. If, for some reason, a module must access this, it
|
||||
should do so by instantiating an `AnsibleModule` and accessing
|
||||
:attr:`AnsibleModule._debug`.
|
||||
the messages are only logged if ``_ansible_debug`` is set to ``True``.
|
||||
To set, add ``debug: True`` to :file:`ansible.cfg` or set the environment
|
||||
variable :envvar:`ANSIBLE_DEBUG`. To access in a module, instantiate an
|
||||
``AnsibleModule`` and access :attr:`AnsibleModule._debug`.
|
||||
|
||||
_ansible_diff
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
This boolean is turned on via the ``--diff`` command line option. If a module
|
||||
supports it, it will tell the module to show a unified diff of changes to be
|
||||
made to templated files. The proper way for a module to access this is by
|
||||
instantiating an `AnsibleModule` and accessing
|
||||
Boolean. If a module supports it, tells the module to show a unified diff of
|
||||
changes to be made to templated files. To set, pass the ``--diff`` command line
|
||||
option. To access in a module, instantiate an `AnsibleModule` and access
|
||||
:attr:`AnsibleModule._diff`.
|
||||
|
||||
_ansible_verbosity
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This value could be used for finer grained control over logging. However, it
|
||||
is currently unused.
|
||||
Unused. This value could be used for finer grained control over logging.
|
||||
|
||||
_ansible_selinux_special_fs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is a list of names of filesystems which should have a special selinux
|
||||
List. Names of filesystems which should have a special SELinux
|
||||
context. They are used by the `AnsibleModule` methods which operate on
|
||||
files (changing attributes, moving, and copying). The list of names is set
|
||||
via a comma separated string of filesystem names from :file:`ansible.cfg`::
|
||||
files (changing attributes, moving, and copying). To set, add a comma separated string of filesystem names in :file:`ansible.cfg`::
|
||||
|
||||
# ansible.cfg
|
||||
[selinux]
|
||||
special_context_filesystems=nfs,vboxsf,fuse,ramfs
|
||||
|
||||
If a module cannot use the builtin ``AnsibleModule`` methods to manipulate
|
||||
files and needs to know about these special context filesystems, it should
|
||||
instantiate an ``AnsibleModule`` and then examine the list in
|
||||
Most modules can use the built-in ``AnsibleModule`` methods to manipulate
|
||||
files. To access in a module that needs to know about these special context filesystems, instantiate an ``AnsibleModule`` and examine the list in
|
||||
:attr:`AnsibleModule._selinux_special_fs`.
|
||||
|
||||
This replaces :attr:`ansible.module_utils.basic.SELINUX_SPECIAL_FS` from
|
||||
|
@ -458,21 +444,19 @@ filesystem names. Under Ansiballz it's an actual list.
|
|||
_ansible_syslog_facility
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This parameter controls which syslog facility ansible module logs to. It may
|
||||
be set by changing the ``syslog_facility`` value in :file:`ansible.cfg`. Most
|
||||
This parameter controls which syslog facility Ansible module logs to. To set, change the ``syslog_facility`` value in :file:`ansible.cfg`. Most
|
||||
modules should just use :meth:`AnsibleModule.log` which will then make use of
|
||||
this. If a module has to use this on its own, it should instantiate an
|
||||
`AnsibleModule` and then retrieve the name of the syslog facility from
|
||||
:attr:`AnsibleModule._syslog_facility`. The code will look slightly different
|
||||
than it did under :ref:`module_replacer` due to how hacky the old way was
|
||||
:attr:`AnsibleModule._syslog_facility`. The Ansiballz code is less hacky than the old :ref:`module_replacer` code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Old way
|
||||
# Old module_replacer way
|
||||
import syslog
|
||||
syslog.openlog(NAME, 0, syslog.LOG_USER)
|
||||
|
||||
# New way
|
||||
# New Ansiballz way
|
||||
import syslog
|
||||
facility_name = module._syslog_facility
|
||||
facility = getattr(syslog, facility_name, syslog.LOG_USER)
|
||||
|
@ -483,7 +467,7 @@ than it did under :ref:`module_replacer` due to how hacky the old way was
|
|||
_ansible_version
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This parameter passes the version of ansible that runs the module. To access
|
||||
This parameter passes the version of Ansible that runs the module. To access
|
||||
it, a module should instantiate an `AnsibleModule` and then retrieve it
|
||||
from :attr:`AnsibleModule.ansible_version`. This replaces
|
||||
:attr:`ansible.module_utils.basic.ANSIBLE_VERSION` from
|
||||
|
@ -491,6 +475,21 @@ from :attr:`AnsibleModule.ansible_version`. This replaces
|
|||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
|
||||
.. _flow_module_return_values:
|
||||
|
||||
Module return values & Unsafe strings
|
||||
-------------------------------------
|
||||
|
||||
At the end of a module's execution, it formats the data that it wants to return as a JSON string and prints the string to its stdout. The normal action plugin receives the JSON string, parses it into a Python dictionary, and returns it to the executor.
|
||||
|
||||
If Ansible templated every string return value, it would be vulnerable to an attack from users with access to managed nodes. If an unscrupulous user disguised malicious code as Ansible return value strings, and if those strings were then templated on the controller, Ansible could execute arbitrary code. To prevent this scenario, Ansible marks all strings inside returned data as ``Unsafe``, emitting any Jinja2 templates in the strings verbatim, not expanded by Jinja2.
|
||||
|
||||
Strings returned by invoking a module through ``ActionPlugin._execute_module()`` are automatically marked as ``Unsafe`` by the normal action plugin. If another action plugin retrieves information from a module through some other means, it must mark its return data as ``Unsafe`` on its own.
|
||||
|
||||
In case a poorly-coded action plugin fails to mark its results as "Unsafe," Ansible audits the results again when they are returned to the executor,
|
||||
marking all strings as ``Unsafe``. The normal action plugin protects itself and any other code that it calls with the result data as a parameter. The check inside the executor protects the output of all other action plugins, ensuring that subsequent tasks run by Ansible will not template anything from those results either.
|
||||
|
||||
.. _flow_special_considerations:
|
||||
|
||||
Special considerations
|
||||
|
|
Loading…
Reference in a new issue