Doc backportapalooza 2 (#70440)

* doc: avoid mix of single and double quotes (#70115)

Avoid mix of single and double quotes in the `ternary`, this way
we can copy/past the example without any surprise.

(cherry picked from commit b491f776b9)

* document FQCN for M()  and :seealso: in DOCUMENTATION blocks (#70245)

* document FQCN for M() in DOCUMENTATION blocks

* add note about c

(cherry picked from commit 83f6e4850b)

* Fix bullet points in intro_getting_started.rst. (#70365)

The layout was jumbled due to issues with whitespace.

(cherry picked from commit dc6f4b6502)

* Add steps for how to create changelog.rst for a collection (#70262)

* Update docs/docsite/rst/dev_guide/developing_collections.rst
* add steps to create changelogs, add sentence about not using the tool
* add note for rerunning the command

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 5a28b2b86c)

* ansible-doc: avoid problems with YAML anchors when formatting man page (#70045)

* Avoid problems with YAML anchors when formatting man page.

* Add changelog.

(cherry picked from commit 5e4f708241)

* Minor grammatical fix (#70405)

'you' -> 'your'

(cherry picked from commit a1ac595d42)

* incorporate minimalism feedback on filters page (#70366)

Co-authored-by: Alicia Cozine <acozine@users.noreply.github.com>
(cherry picked from commit c89f3cda9e)

* more correct info about role main.yml (#70326)

fixes #40496

(cherry picked from commit 5d3d097de3)

* Fix a small typo in cache plugin description @ `config/base.yml`

PR #70420

(cherry picked from commit 626df08d9d)

* with_sequence: example using vars (#69369)

Added an example for using vars in with_sequence.

Fixes: #68836

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 5709173c32)

* Update pull.py (#70393)

(cherry picked from commit 46ad3c1162)

* Update playbooks.rst (#70317)

(cherry picked from commit 7c90a2d2a6)

* Add documentation for ipaddr filters  (#70343)

(cherry picked from commit 9eb904ea61)

* update platform table with links to collections (#70373)

(cherry picked from commit aa59c23aed)

* Add description of collections and become_exe keywords (#68055)

* Add description of collections keyword
* Update based on feedback.
- Add link to become plugins.
- Add note about how the collections keyword works with roles.

(cherry picked from commit 5833af9e2a)

Co-authored-by: Gonéri Le Bouder <goneri@lebouder.net>
Co-authored-by: Mark Sanders <ziplokk.mark.sanders@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Sir Mobus Gochfulshigan Dorphin Esquire XXIII <celestialtuba@gmail.com>
Co-authored-by: Alicia Cozine <879121+acozine@users.noreply.github.com>
Co-authored-by: Brian Coca <bcoca@users.noreply.github.com>
Co-authored-by: Michael Scherer <mscherer@users.noreply.github.com>
Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
Co-authored-by: Ethan <smithe2413@gmail.com>
Co-authored-by: jafiala <56597272+jafiala@users.noreply.github.com>
Co-authored-by: Baptiste Mille-Mathias <baptiste.millemathias@gmail.com>
Co-authored-by: Sam Doran <sdoran@redhat.com>
This commit is contained in:
Sandra McCann 2020-07-08 17:05:41 -04:00 committed by GitHub
parent d07a84e233
commit 374d4ecd98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 411 additions and 230 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- "ansible-doc - improve man page formatting to avoid problems when YAML anchors are used (https://github.com/ansible/ansible/pull/70045)."

View file

@ -0,0 +1,2 @@
minor_changes:
- Add an example for using var in with_sequence (https://github.com/ansible/ansible/issues/68836).

View file

@ -6,23 +6,25 @@ args: "A secondary way to add arguments into a task. Takes a dictionary in which
always: List of tasks, in a block, that execute no matter if there is an error in the block or not. always: List of tasks, in a block, that execute no matter if there is an error in the block or not.
any_errors_fatal: Force any un-handled task errors on any host to propagate to all hosts and end the play. any_errors_fatal: Force any un-handled task errors on any host to propagate to all hosts and end the play.
async: Run a task asynchronously if the C(action) supports this; value is maximum runtime in seconds. async: Run a task asynchronously if the C(action) supports this; value is maximum runtime in seconds.
become: Boolean that controls if privilege escalation is used or not on :term:`Task` execution. become: Boolean that controls if privilege escalation is used or not on :term:`Task` execution. Implemented by the become plugin. See :ref:`become_plugins`.
become_exe: Path to the executable used to elevate privileges. Implemented by the become plugin. See :ref:`become_plugins`.
become_flags: A string of flag(s) to pass to the privilege escalation program when :term:`become` is True. become_flags: A string of flag(s) to pass to the privilege escalation program when :term:`become` is True.
become_method: Which method of privilege escalation to use (such as sudo or su). become_method: Which method of privilege escalation to use (such as sudo or su).
become_user: "User that you 'become' after using privilege escalation. The remote/login user must have permissions to become this user." become_user: "User that you 'become' after using privilege escalation. The remote/login user must have permissions to become this user."
block: List of tasks in a block. block: List of tasks in a block.
changed_when: "Conditional expression that overrides the task's normal 'changed' status." changed_when: "Conditional expression that overrides the task's normal 'changed' status."
check_mode: | check_mode: A boolean that controls if a task is executed in 'check' mode. See :ref:`check_mode_dry`.
A boolean that controls if a task is executed in 'check' mode collections: |
.. seealso:: :ref:`check_mode_dry` List of collection namespaces to search for modules, plugins, and roles. See :ref:`collections_using_playbook`
connection: | .. note::
Allows you to change the connection plugin used for tasks to execute on the target.
.. seealso:: :ref:`using_connection` Tasks within a role do not inherit the value of ``collections`` from the play. To have a role search a list of collections, use the ``collections`` keyword in ``meta/main.yml`` within a role.
debugger: Enable debugging tasks based on state of the task result. See :ref:`playbook_debugger`
connection: Allows you to change the connection plugin used for tasks to execute on the target. See :ref:`using_connection`.
debugger: Enable debugging tasks based on state of the task result. See :ref:`playbook_debugger`.
delay: Number of seconds to delay between retries. This setting is only used in combination with :term:`until`. delay: Number of seconds to delay between retries. This setting is only used in combination with :term:`until`.
delegate_facts: Boolean that allows you to apply facts to a delegated host instead of inventory_hostname. delegate_facts: Boolean that allows you to apply facts to a delegated host instead of inventory_hostname.
delegate_to: Host to execute task instead of the target (inventory_hostname). Connection vars from the delegated host will also be used for the task. delegate_to: Host to execute task instead of the target (inventory_hostname). Connection vars from the delegated host will also be used for the task.

View file

@ -613,6 +613,59 @@ Now you can use this checkout of ``community.general`` in playbooks and roles wi
For collections hosted in the ``ansible_collections`` GitHub org, create a branch and commit your changes on the branch. When you are done (remember to add tests, see :ref:`testing_collections`), push your changes to your fork of the collection and create a Pull Request. For other collections, especially for collections not hosted on GitHub, check the ``README.md`` of the collection for information on contributing to it. For collections hosted in the ``ansible_collections`` GitHub org, create a branch and commit your changes on the branch. When you are done (remember to add tests, see :ref:`testing_collections`), push your changes to your fork of the collection and create a Pull Request. For other collections, especially for collections not hosted on GitHub, check the ``README.md`` of the collection for information on contributing to it.
.. _collection_changelogs:
Generating changelogs for a collection
======================================
We recommend that you use the `antsibull-changelog <https://github.com/ansible-community/antsibull-changelog>`_ tool to generate Ansible-compatible changelogs for your collection. The Ansible changelog uses the output of this tool to collate all the collections included in an Ansible release into one combined changelog for the release.
.. note::
Ansible here refers to the Ansible 2.10 or later release that includes a curated set of collections.
If your collection is part of Ansible but you are not using this tool, your collection should include the properly formatted ``changelog.yaml`` file or your changelogs will not be part of the combined Ansible CHANGELOG.rst and Porting Guide at release. See the `changlog.yaml format <https://github.com/ansible-community/antsibull-changelog/blob/main/docs/changelog.yaml-format.md>`_ for details.
Understanding antsibull-changelog
---------------------------------
The ``antsibull-changelog`` tool allows you to create and update changelogs for Ansible collections that are compatible with the combined Ansible changelogs. This is an update to the changelog generator used in prior Ansible releases. The tool adds three new changelog fragment categories: ``breaking_changes``, ``security_fixes`` and ``trivial``. The tool also generates the ``changelog.yaml`` file that Ansible uses to create the combined ``CHANGELOG.rst`` file and Porting Guide for the release.
See :ref:`changelogs_how_to` and the `antsibull-changelog documentation <https://github.com/ansible-community/antsibull-changelog/tree/main/docs>`_ for complete details.
.. note::
The collection maintainers set the changelog policy for their collections. See the individual collection contributing guidelines for complete details.
Generating changelogs
---------------------
To initialize changelog generation:
#. Install ``antsibull-changelog``: :code:`pip install antsibull-changelog`.
#. Initialize changelogs for your repository: :code:`antsibull-changelog init <path/to/your/collection>`.
#. Optionally, edit the ``changelogs/config.yaml`` file to customize the location of the generated changelog ``.rst`` file or other options. See `Bootstrapping changelogs for collections <https://github.com/ansible-community/antsibull-changelog/blob/main/docs/changelogs.rst#bootstrapping-changelogs-for-collections>`_ for details.
To generate changelogs from the changelog fragments you created:
#. Optionally, validate your changelog fragments: :code:`antsibull-changelog lint`.
#. Generate the changelog for your release: :code:`antsibull-changelog release [--version version_number]`.
.. note::
Add the ``--reload-plugins`` option if you ran the ``antsibull-changelog release`` command previously and the version of the collection has not changed. ``antsibull-changelog`` caches the information on all plugins and does not update its cache until the collection version changes.
Porting Guide entries
----------------------
The following changelog fragment categories are consumed by the Ansible changelog generator into the Ansible Porting Guide:
* ``major_changes``
* ``breaking_changes``
* ``deprecated_features``
* ``removed_features``
.. seealso:: .. seealso::

View file

@ -193,6 +193,7 @@ All fields in the ``DOCUMENTATION`` block are lower-case. All fields are require
:seealso: :seealso:
* A list of references to other modules, documentation or Internet resources * A list of references to other modules, documentation or Internet resources
* In Ansible 2.10 and later, references to modules must use the FQCN or ``ansible.builtin`` for modules in ``ansible-base``.
* A reference can be one of the following formats: * A reference can be one of the following formats:
@ -201,10 +202,10 @@ All fields in the ``DOCUMENTATION`` block are lower-case. All fields are require
seealso: seealso:
# Reference by module name # Reference by module name
- module: aci_tenant - module: cisco.aci.aci_tenant
# Reference by module name, including description # Reference by module name, including description
- module: aci_tenant - module: cisco.aci.aci_tenant
description: ACI module to create tenants on a Cisco ACI fabric. description: ACI module to create tenants on a Cisco ACI fabric.
# Reference by rST documentation anchor # Reference by rST documentation anchor
@ -232,18 +233,23 @@ You can link from your module documentation to other module docs, other resource
* ``R()`` for cross-references with a heading (added in Ansible 2.10). For example: ``See R(Cisco IOS Platform Guide,ios_platform_options)``. Use the RST anchor for the cross-reference. See :ref:`adding_anchors_rst` for details. * ``R()`` for cross-references with a heading (added in Ansible 2.10). For example: ``See R(Cisco IOS Platform Guide,ios_platform_options)``. Use the RST anchor for the cross-reference. See :ref:`adding_anchors_rst` for details.
* ``I()`` for option names. For example: ``Required if I(state=present).`` * ``I()`` for option names. For example: ``Required if I(state=present).``
* ``C()`` for files and option values. For example: ``If not set the environment variable C(ACME_PASSWORD) will be used.`` * ``C()`` for files and option values. For example: ``If not set the environment variable C(ACME_PASSWORD) will be used.``
* ``M()`` for module names. For example: ``See also M(win_copy) or M(win_template).`` * ``M()`` for module names. For example: ``See also M(ansible.builtin.yum) or M(community.general.apt_rpm)``.
.. note:: .. note::
For links between modules and documentation within a collection, you can use any of the options above. For links outside of your collection, use ``R()`` if available. Otherwise, use ``U()`` or ``L()`` with full URLs (not relative links). If you are creating your own documentation site, you will need to use the `intersphinx extension <https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html>`_ to convert ``R()`` and ``M()`` to the correct links. For links between modules and documentation within a collection, you can use any of the options above. For links outside of your collection, use ``R()`` if available. Otherwise, use ``U()`` or ``L()`` with full URLs (not relative links). For modules, use ``M()`` with the FQCN or ``ansible.builtin`` as shown in the example. If you are creating your own documentation site, you will need to use the `intersphinx extension <https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html>`_ to convert ``R()`` and ``M()`` to the correct links.
.. note::
- To refer to a group of modules in a collection, use ``R()``. When a collection is not the right granularity, use ``C(..)``:
-``Refer to the R(community.kubernetes collection, plugins_in_community.kubernetes) for information on managing kubernetes clusters.``
-``The C(win_*) modules (spread across several collections) allow you to manage various aspects of windows hosts.``
.. note:: .. note::
- To refer a group of modules, use ``C(..)``, e.g. ``Refer to the C(win_*) modules.`` Because it stands out better, use ``seealso`` for general references over the use of notes or adding links to the description.
- Because it stands out better, using ``seealso`` is preferred for general references over the use of notes or adding links to the description.
.. _module_docs_fragments: .. _module_docs_fragments:

View file

@ -59,35 +59,61 @@ Settings by Platform
-------------------------------------------------------- ------------------------------------------ -------------------------------------------------------- ------------------------------------------
Network OS ``ansible_network_os:`` network_cli netconf httpapi local Network OS ``ansible_network_os:`` network_cli netconf httpapi local
=============================== ======================= =========== ======= ======= =========== =============================== ======================= =========== ======= ======= ===========
Arista EOS `[†]`_ ``eos`` ✓ ✓ ✓ `Arista EOS`_ `[†]`_ ``eos`` ✓ ✓ ✓
Cisco ASA ``asa`` ✓ ✓ `Cisco ASA`_ `[†]`_ ``asa`` ✓ ✓
Cisco IOS `[†]`_ ``ios`` ✓ ✓ `Cisco IOS`_ `[†]`_ ``ios`` ✓ ✓
Cisco IOS XR `[†]`_ ``iosxr`` ✓ ✓ `Cisco IOS XR`_ `[†]`_ ``iosxr`` ✓ ✓
Cisco NX-OS `[†]`_ ``nxos`` ✓ ✓ ✓ `Cisco NX-OS`_ `[†]`_ ``nxos`` ✓ ✓ ✓
Cloudengine OS `[†]`_ ``ce`` ✓ ✓ ✓ `Cloudengine OS`_ ``ce`` ✓ ✓ ✓
Dell OS6 ``dellos6`` ✓ ✓ `Dell OS6`_ ``dellos6`` ✓ ✓
Dell OS9 ``dellos9`` ✓ ✓ `Dell OS9`_ ``dellos9`` ✓ ✓
Dell OS10 ``dellos10`` ✓ ✓ `Dell OS10`_ ``dellos10`` ✓ ✓
Ericsson ECCLI ``eric_eccli`` ✓ ✓ `Ericsson ECCLI`_ ``eric_eccli`` ✓ ✓
Extreme EXOS ``exos`` ✓ ✓ `Extreme EXOS`_ ``exos`` ✓ ✓
Extreme IronWare ``ironware`` ✓ ✓ `Extreme IronWare`_ ``ironware`` ✓ ✓
Extreme NOS ``nos`` `Extreme NOS`_ ``nos``
Extreme SLX-OS ``slxos`` `Extreme SLX-OS`_ ``slxos``
Extreme VOSS ``voss`` `Extreme VOSS`_ ``voss``
F5 BIG-IP ✓ `F5 BIG-IP`_
F5 BIG-IQ ✓ `F5 BIG-IQ`_
Junos OS `[†]`_ ``junos`` ✓ ✓ ✓ `Junos OS`_ `[†]`_ ``junos`` ✓ ✓ ✓
Lenovo CNOS ``cnos`` ✓ ✓ `Lenovo CNOS`_ ``cnos`` ✓ ✓
Lenovo ENOS ``enos`` ✓ ✓ `Lenovo ENOS`_ ``enos`` ✓ ✓
Meraki ``meraki`` `Meraki`_ ``meraki``
MikroTik RouterOS ``routeros`` `MikroTik RouterOS`_ ``routeros``
Nokia SR OS ``sros`` ✓ ✓ `Nokia SR OS`_ ``sros`` ✓ ✓
Pluribus Netvisor ``netvisor`` `Pluribus Netvisor`_ ``netvisor``
Ruckus ICX `[†]`_ ``icx`` `Ruckus ICX`_ ``icx``
VyOS `[†]`_ ``vyos`` ✓ ✓ `VyOS`_ `[†]`_ ``vyos`` ✓ ✓
OS that supports Netconf `[†]`_ ``<network-os>`` ✓ ✓ OS that supports Netconf `[†]`_ ``<network-os>`` ✓ ✓
=============================== ======================= =========== ======= ======= =========== =============================== ======================= =========== ======= ======= ===========
.. _Arista EOS: https://galaxy.ansible.com/arista/eos
.. _Cisco ASA: https://galaxy.ansible.com/cisco/asa
.. _Cisco IOS: https://galaxy.ansible.com/cisco/ios
.. _Cisco IOS XR: https://galaxy.ansible.com/cisco/iosxr
.. _Cisco NX-OS: https://galaxy.ansible.com/cisco/nxos
.. _Cloudengine OS: https://galaxy.ansible.com/community/network
.. _Dell OS6: https://github.com/ansible-collections/dellemc.os6
.. _Dell OS9: https://github.com/ansible-collections/dellemc.os9
.. _Dell OS10: https://galaxy.ansible.com/dellemc_networking/os10
.. _Ericsson ECCLI: https://galaxy.ansible.com/community/network
.. _Extreme EXOS: https://galaxy.ansible.com/community/network
.. _Extreme IronWare: https://galaxy.ansible.com/community/network
.. _Extreme NOS: https://galaxy.ansible.com/community/network
.. _Extreme SLX-OS: https://galaxy.ansible.com/community/network
.. _Extreme VOSS: https://galaxy.ansible.com/community/network
.. _F5 BIG-IP: https://galaxy.ansible.com/f5networks/f5_modules
.. _F5 BIG-IQ: https://galaxy.ansible.com/f5networks/f5_modules
.. _Junos OS: https://galaxy.ansible.com/junipernetworks/junos
.. _Lenovo CNOS: https://galaxy.ansible.com/community/network
.. _Lenovo ENOS: https://galaxy.ansible.com/community/network
.. _Meraki: https://galaxy.ansible.com/cisco/meraki
.. _MikroTik RouterOS: https://galaxy.ansible.com/community/network
.. _Nokia SR OS: https://galaxy.ansible.com/community/network
.. _Pluribus Netvisor: https://galaxy.ansible.com/community/network
.. _Ruckus ICX: https://galaxy.ansible.com/community/network
.. _VyOS: https://galaxy.ansible.com/vyos/vyos
.. _`[†]`: .. _`[†]`:
**[†]** Maintained by Ansible Network Team **[†]** Maintained by Ansible Network Team

View file

@ -93,7 +93,7 @@ Since `Vultr <https://www.vultr.com>`_ offers a public API, the execution of the
region: New Jersey region: New Jersey
From that point on, only you creativity is the limit. Make sure to read the documentation of the `available modules <https://docs.ansible.com/ansible/latest/modules/list_of_cloud_modules.html#vultr>`_. From that point on, only your creativity is the limit. Make sure to read the documentation of the `available modules <https://docs.ansible.com/ansible/latest/modules/list_of_cloud_modules.html#vultr>`_.
Dynamic Inventory Dynamic Inventory

View file

@ -50,8 +50,11 @@ Beyond the basics
You can override the default remote user name in several ways, including: You can override the default remote user name in several ways, including:
* passing the ``-u`` parameter at the command line * passing the ``-u`` parameter at the command line
* setting user information in your inventory file * setting user information in your inventory file
* setting user information in your configuration file * setting user information in your configuration file
* setting environment variables * setting environment variables
See :ref:`general_precedence_rules` for details on the (sometimes unintuitive) precedence of each method of passing user information. You can read more about connections in :ref:`connections`. See :ref:`general_precedence_rules` for details on the (sometimes unintuitive) precedence of each method of passing user information. You can read more about connections in :ref:`connections`.

View file

@ -1,6 +1,6 @@
.. _working_with_playbooks: .. _working_with_playbooks:
Working With Playbooks Working with playbooks
====================== ======================
Playbooks are Ansible's configuration, deployment, and orchestration language. They can describe a policy you want your remote systems to enforce, or a set of steps in a general IT process. Playbooks are Ansible's configuration, deployment, and orchestration language. They can describe a policy you want your remote systems to enforce, or a set of steps in a general IT process.

View file

@ -1,13 +1,12 @@
.. _playbooks_filters: .. _playbooks_filters:
******* ********************************
Filters Using filters to manipulate data
******* ********************************
Filters let you transform data inside template expressions. This page documents mainly Ansible-specific filters, but you can use any of the standard filters shipped with Jinja2 - see the list of :ref:`builtin filters <jinja2:builtin-filters>` in the official Jinja2 template documentation. You can also use :ref:`Python methods <jinja2:python-methods>` to manipulate variables. A few useful filters are typically added with each new Ansible release. The development documentation shows Filters let you transform JSON data into YAML data, split a URL to extract the hostname, get the SHA1 hash of a string, add or multiply integers, and much more. You can use the Ansible-specific filters documented here to manipulate your data, or use any of the standard filters shipped with Jinja2 - see the list of :ref:`built-in filters <jinja2:builtin-filters>` in the official Jinja2 template documentation. You can also use :ref:`Python methods <jinja2:python-methods>` to transform data. You can :ref:`create custom Ansible filters as plugins <developing_filter_plugins>`, though we generally welcome new filters into the ansible-base repo so everyone can use them.
how to create custom Ansible filters as plugins, though we generally welcome new filters into the core code so everyone can use them.
Templating happens on the Ansible controller, **not** on the target host, so filters execute on the controller and manipulate data locally. Because templating happens on the Ansible controller, **not** on the target host, filters execute on the controller and transform data locally.
.. contents:: .. contents::
:local: :local:
@ -15,7 +14,7 @@ Templating happens on the Ansible controller, **not** on the target host, so fil
Handling undefined variables Handling undefined variables
============================ ============================
Filters can help you manage missing or undefined variables by providing defaults or making some variable optional. If you configure Ansible to ignore most undefined variables, you can mark some variables as requiring values with the ``mandatory`` filter. Filters can help you manage missing or undefined variables by providing defaults or making some variables optional. If you configure Ansible to ignore most undefined variables, you can mark some variables as requiring values with the ``mandatory`` filter.
.. _defaulting_undefined_variables: .. _defaulting_undefined_variables:
@ -40,7 +39,7 @@ If you want to use the default value when variables evaluate to false or an empt
Making variables optional Making variables optional
------------------------- -------------------------
In some cases, you want to make a variable optional. For example, if you want to use a system default for some items and control the value for others. To make a variable optional, set the default value to the special variable ``omit``:: By default Ansible requires values for all variables in a templated expression. However, you can make specific variables optional. For example, you might want to use a system default for some items and control the value for others. To make a variable optional, set the default value to the special variable ``omit``::
- name: touch files with an optional mode - name: touch files with an optional mode
file: file:
@ -56,9 +55,7 @@ In some cases, you want to make a variable optional. For example, if you want to
In this example, the default mode for the files ``/tmp/foo`` and ``/tmp/bar`` is determined by the umask of the system. Ansible does not send a value for ``mode``. Only the third file, ``/tmp/baz``, receives the `mode=0444` option. In this example, the default mode for the files ``/tmp/foo`` and ``/tmp/bar`` is determined by the umask of the system. Ansible does not send a value for ``mode``. Only the third file, ``/tmp/baz``, receives the `mode=0444` option.
.. note:: If you are "chaining" additional filters after the ``default(omit)`` filter, you should instead do something like this: .. note:: If you are "chaining" additional filters after the ``default(omit)`` filter, you should instead do something like this:
``"{{ foo | default(None) | some_filter or omit }}"``. In this example, the default ``None`` (Python null) value will cause the ``"{{ foo | default(None) | some_filter or omit }}"``. In this example, the default ``None`` (Python null) value will cause the later filters to fail, which will trigger the ``or omit`` portion of the logic. Using ``omit`` in this manner is very specific to the later filters you're chaining though, so be prepared for some trial and error if you do this.
later filters to fail, which will trigger the ``or omit`` portion of the logic. Using ``omit`` in this manner is very specific to
the later filters you're chaining though, so be prepared for some trial and error if you do this.
.. _forcing_variables_to_be_defined: .. _forcing_variables_to_be_defined:
@ -71,94 +68,21 @@ If you configure Ansible to ignore undefined variables, you may want to define s
The variable value will be used as is, but the template evaluation will raise an error if it is undefined. The variable value will be used as is, but the template evaluation will raise an error if it is undefined.
Defining different values for true/false/null Defining different values for true/false/null (ternary)
============================================= =======================================================
You can create a test, then define one value to use when the test returns true and another when the test returns false (new in version 1.9):: You can create a test, then define one value to use when the test returns true and another when the test returns false (new in version 1.9)::
{{ (status == "needs_restart") | ternary('restart', 'continue') }} {{ (status == 'needs_restart') | ternary('restart', 'continue') }}
In addition, you can define a one value to use on true, one value on false and a third value on null (new in version 2.8):: In addition, you can define a one value to use on true, one value on false and a third value on null (new in version 2.8)::
{{ enabled | ternary('no shutdown', 'shutdown', omit) }} {{ enabled | ternary('no shutdown', 'shutdown', omit) }}
Manipulating data types Managing data types
======================= ===================
Sometimes a variables file or registered variable contains a dictionary when your playbook needs a list. Sometimes you have a list when your template needs a dictionary. These filters help you transform these data types.
.. _dict_filter:
Transforming dictionaries into lists
------------------------------------
.. versionadded:: 2.6
To turn a dictionary into a list of items, suitable for looping, use `dict2items`::
{{ dict | dict2items }}
Which turns::
tags:
Application: payment
Environment: dev
into::
- key: Application
value: payment
- key: Environment
value: dev
.. versionadded:: 2.8
``dict2items`` accepts 2 keyword arguments, ``key_name`` and ``value_name`` that allow configuration of the names of the keys to use for the transformation::
{{ files | dict2items(key_name='file', value_name='path') }}
Which turns::
files:
users: /etc/passwd
groups: /etc/group
into::
- file: users
path: /etc/passwd
- file: groups
path: /etc/group
Transforming lists into dictionaries
------------------------------------
.. versionadded:: 2.7
This filter turns a list of dicts with 2 keys, into a dict, mapping the values of those keys into ``key: value`` pairs::
{{ tags | items2dict }}
Which turns::
tags:
- key: Application
value: payment
- key: Environment
value: dev
into::
Application: payment
Environment: dev
This is the reverse of the ``dict2items`` filter.
``items2dict`` accepts 2 keyword arguments, ``key_name`` and ``value_name`` that allow configuration of the names of the keys to use for the transformation::
{{ tags | items2dict(key_name='key', value_name='value') }}
You might need to know, change, or set the data type on a variable. For example, a registered variable might contain a dictionary when your next task needs a list, or a user :ref:`prompt <playbooks_prompts>` might return a string when your playbook needs a boolean value. Use the ``type_debug``, ``dict2items``, and ``items2dict`` filters to manage data types. You can also use the data type itself to cast a value as a specific data type.
Discovering the data type Discovering the data type
------------------------- -------------------------
@ -169,10 +93,98 @@ If you are unsure of the underlying Python type of a variable, you can use the `
{{ myvar | type_debug }} {{ myvar | type_debug }}
.. _dict_filter:
Transforming dictionaries into lists
------------------------------------
.. versionadded:: 2.6
Use the ``dict2items`` filter to transform a dictionary into a list of items suitable for :ref:`looping <playbooks_loops>`::
{{ dict | dict2items }}
Dictionary data (before applying the ``dict2items`` filter)::
tags:
Application: payment
Environment: dev
List data (after applying the ``dict2items`` filter)::
- key: Application
value: payment
- key: Environment
value: dev
.. versionadded:: 2.8
The ``dict2items`` filter is the reverse of the ``items2dict`` filter.
If you want to configure the names of the keys, the ``dict2items`` filter accepts 2 keyword arguments. Pass the ``key_name`` and ``value_name`` arguments to configure the names of the keys in the list output::
{{ files | dict2items(key_name='file', value_name='path') }}
Dictionary data (before applying the ``dict2items`` filter)::
files:
users: /etc/passwd
groups: /etc/group
List data (after applying the ``dict2items`` filter)::
- file: users
path: /etc/passwd
- file: groups
path: /etc/group
Transforming lists into dictionaries
------------------------------------
.. versionadded:: 2.7
Use the ``items2dict``filter to transform a list into a dictionary, mapping the content into ``key: value`` pairs::
{{ tags | items2dict }}
List data (before applying the ``items2dict`` filter)::
tags:
- key: Application
value: payment
- key: Environment
value: dev
Dictionary data (after applying the ``items2dict`` filter)::
Application: payment
Environment: dev
The ``items2dict`` filter is the reverse of the ``dict2items`` filter.
Not all lists use ``key`` to designate keys and ``value`` to designate values. For example::
fruits:
- fruit: apple
color: red
- fruit: pear
color: yellow
- fruit: grapefruit
color: yellow
In this example, you must pass the ``key_name`` and ``value_name`` arguments to configure the transformation. For example::
{{ tags | items2dict(key_name='fruit', value_name='color') }}
If you do not pass these arguments, or do not pass the correct values for your list, you will see ``KeyError: key`` or ``KeyError: my_typo``.
Forcing the data type Forcing the data type
--------------------- ---------------------
You can cast values as certain types. For example, if you expect the input "True" from a :ref:`vars_prompt <playbooks_prompts>` and you want Ansible to recognize it as a Boolean value instead of a string:: You can cast values as certain types. For example, if you expect the input "True" from a :ref:`vars_prompt <playbooks_prompts>` and you want Ansible to recognize it as a boolean value instead of a string::
- debug: - debug:
msg: test msg: test
@ -188,10 +200,10 @@ If you want to perform a mathematical comparison on a fact and you want Ansible
.. _filters_for_formatting_data: .. _filters_for_formatting_data:
Controlling data formats: YAML and JSON Formatting data: YAML and JSON
======================================= ==============================
The following filters will take a data structure in a template and manipulate it or switch it from or to JSON or YAML format. These are occasionally useful for debugging:: You can switch a data structure in a template from or to JSON or YAML format, with options for formatting, indenting, and loading data. The basic filters are occasionally useful for debugging::
{{ some_variable | to_json }} {{ some_variable | to_json }}
{{ some_variable | to_yaml }} {{ some_variable | to_yaml }}
@ -245,7 +257,7 @@ for example::
Combining and selecting data Combining and selecting data
============================ ============================
These filters let you manipulate data from multiple sources and types and manage large data structures, giving you precise control over complex data. You can combine data from multiple sources and types, and select values from large data structures, giving you precise control over complex data.
.. _zip_filter: .. _zip_filter:
@ -264,7 +276,7 @@ To get a list combining the elements of other lists use ``zip``::
debug: debug:
msg: "{{ [1,2,3] | zip(['a','b','c','d','e','f']) | list }}" msg: "{{ [1,2,3] | zip(['a','b','c','d','e','f']) | list }}"
To always exhaust all list use ``zip_longest``:: To always exhaust all lists use ``zip_longest``::
- name: give me longest combo of three lists , fill with X - name: give me longest combo of three lists , fill with X
debug: debug:
@ -274,7 +286,7 @@ Similarly to the output of the ``items2dict`` filter mentioned above, these filt
{{ dict(keys_list | zip(values_list)) }} {{ dict(keys_list | zip(values_list)) }}
Which turns:: List data (before applying the ``zip`` filter)::
keys_list: keys_list:
- one - one
@ -283,7 +295,7 @@ Which turns::
- apple - apple
- orange - orange
into:: Dictonary data (after applying the ``zip`` filter)::
one: apple one: apple
two: orange two: orange
@ -297,7 +309,7 @@ The ``subelements`` filter produces a product of an object and the subelement va
{{ users | subelements('groups', skip_missing=True) }} {{ users | subelements('groups', skip_missing=True) }}
turns this data:: Data before applying the ``subelements`` filter::
users: users:
- name: alice - name: alice
@ -313,7 +325,7 @@ turns this data::
groups: groups:
- docker - docker
Into this data:: Data after applying the ``subelements`` filter::
- -
- name: alice - name: alice
@ -356,8 +368,7 @@ Combining hashes/dictionaries
.. versionadded:: 2.0 .. versionadded:: 2.0
The ``combine`` filter allows hashes to be merged. The ``combine`` filter allows hashes to be merged. For example, the following would override keys in one hash::
For example, the following would override keys in one hash::
{{ {'a':1, 'b':2} | combine({'b':3}) }} {{ {'a':1, 'b':2} | combine({'b':3}) }}
@ -370,8 +381,7 @@ The filter can also take multiple arguments to merge::
{{ a | combine(b, c, d) }} {{ a | combine(b, c, d) }}
{{ [a, b, c, d] | combine }} {{ [a, b, c, d] | combine }}
In this case, keys in ``d`` would override those in ``c``, which would In this case, keys in ``d`` would override those in ``c``, which would override those in ``b``, and so on.
override those in ``b``, and so on.
The filter also accepts two optional parameters: ``recursive`` and ``list_merge``. The filter also accepts two optional parameters: ``recursive`` and ``list_merge``.
@ -470,9 +480,7 @@ This would result in::
- patch - patch
- default - default
If ``list_merge='append_rp'``, arrays from the right hash will be appended to the ones in the left hash. If ``list_merge='append_rp'``, arrays from the right hash will be appended to the ones in the left hash. Elements of arrays in the left hash that are also in the corresponding array of the right hash will be removed ("rp" stands for "remove present"). Duplicate elements that aren't in both hashes are kept::
Elements of arrays in the left hash that are also in the corresponding array of the right hash will be removed ("rp" stands for "remove present").
Duplicate elements that aren't in both hashes are kept::
default: default:
a: a:
@ -575,8 +583,7 @@ Selecting values from arrays or hashtables
.. versionadded:: 2.1 .. versionadded:: 2.1
The `extract` filter is used to map from a list of indices to a list of The `extract` filter is used to map from a list of indices to a list of values from a container (hash or array)::
values from a container (hash or array)::
{{ [0,2] | map('extract', ['x','y','z']) | list }} {{ [0,2] | map('extract', ['x','y','z']) | list }}
{{ ['x','y'] | map('extract', {'x': 42, 'y': 31}) | list }} {{ ['x','y'] | map('extract', {'x': 42, 'y': 31}) | list }}
@ -590,12 +597,9 @@ The filter can take another argument::
{{ groups['x'] | map('extract', hostvars, 'ec2_ip_address') | list }} {{ groups['x'] | map('extract', hostvars, 'ec2_ip_address') | list }}
This takes the list of hosts in group 'x', looks them up in `hostvars`, This takes the list of hosts in group 'x', looks them up in `hostvars`, and then looks up the `ec2_ip_address` of the result. The final result is a list of IP addresses for the hosts in group 'x'.
and then looks up the `ec2_ip_address` of the result. The final result
is a list of IP addresses for the hosts in group 'x'.
The third argument to the filter can also be a list, for a recursive The third argument to the filter can also be a list, for a recursive lookup inside the container::
lookup inside the container::
{{ ['a'] | map('extract', b, ['x','y']) | list }} {{ ['a'] | map('extract', b, ['x','y']) | list }}
@ -631,9 +635,7 @@ Also see the :ref:`zip_filter`
products products
^^^^^^^^ ^^^^^^^^
The product filter returns the `cartesian product <https://docs.python.org/3/library/itertools.html#itertools.product>`_ of the input iterables. The product filter returns the `cartesian product <https://docs.python.org/3/library/itertools.html#itertools.product>`_ of the input iterables. This is roughly equivalent to nested for-loops in a generator expression.
This is roughly equivalent to nested for-loops in a generator expression.
For example:: For example::
@ -650,8 +652,7 @@ This would result in::
Selecting JSON data: JSON queries Selecting JSON data: JSON queries
--------------------------------- ---------------------------------
To select a single element or a data subset from a complex data structure in JSON format (for example, Ansible facts), use the ``json_query`` filter. The ``json_query`` filter lets you query a complex JSON structure and iterate over it using a loop structure.
Sometimes you end up with a complex data structure in JSON format and you need to extract only a small set of data within it. The **json_query** filter lets you query a complex JSON structure and iterate over it using a loop structure.
.. note:: .. note::
@ -716,14 +717,14 @@ To extract all clusters from this structure, you can use the following query::
var: item var: item
loop: "{{ domain_definition | community.general.json_query('domain.cluster[*].name') }}" loop: "{{ domain_definition | community.general.json_query('domain.cluster[*].name') }}"
Same thing for all server names:: To extract all server names::
- name: "Display all server names" - name: "Display all server names"
debug: debug:
var: item var: item
loop: "{{ domain_definition | community.general.json_query('domain.server[*].name') }}" loop: "{{ domain_definition | community.general.json_query('domain.server[*].name') }}"
This example shows ports from cluster1:: To extract ports from cluster1::
- name: "Display all ports from cluster1" - name: "Display all ports from cluster1"
debug: debug:
@ -734,15 +735,15 @@ This example shows ports from cluster1::
.. note:: You can use a variable to make the query more readable. .. note:: You can use a variable to make the query more readable.
Or, alternatively print out the ports in a comma separated string:: To print out the ports from cluster1 in a comma separated string::
- name: "Display all ports from cluster1 as a string" - name: "Display all ports from cluster1 as a string"
debug: debug:
msg: "{{ domain_definition | community.general.json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}" msg: "{{ domain_definition | community.general.json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}"
.. note:: Here, quoting literals using backticks avoids escaping quotes and maintains readability. .. note:: In the example above, quoting literals using backticks avoids escaping quotes and maintains readability.
Or, using YAML `single quote escaping <https://yaml.org/spec/current.html#id2534365>`_:: You can use YAML `single quote escaping <https://yaml.org/spec/current.html#id2534365>`_::
- name: "Display all ports from cluster1" - name: "Display all ports from cluster1"
debug: debug:
@ -751,7 +752,7 @@ Or, using YAML `single quote escaping <https://yaml.org/spec/current.html#id2534
.. note:: Escaping single quotes within single quotes in YAML is done by doubling the single quote. .. note:: Escaping single quotes within single quotes in YAML is done by doubling the single quote.
In this example, we get a hash map with all ports and names of a cluster:: To get a hash map with all ports and names of a cluster::
- name: "Display all server ports and names from cluster1" - name: "Display all server ports and names from cluster1"
debug: debug:
@ -789,7 +790,7 @@ Note that if anything is wrong with the prefix string, the filter will issue an
.. versionadded:: 2.9 .. versionadded:: 2.9
As of Ansible version 2.9, you can also initialize the random number generator from a seed. This way, you can create random-but-idempotent MAC addresses:: As of Ansible version 2.9, you can also initialize the random number generator from a seed to create random-but-idempotent MAC addresses::
"{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}" "{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}"
@ -799,9 +800,7 @@ As of Ansible version 2.9, you can also initialize the random number generator f
Random items or numbers Random items or numbers
----------------------- -----------------------
The ``random`` filter in Ansible is an extension of the default Jinja2 random filter, and can be used to return a random item from a sequence of items or to generate a random number based on a range.
This filter can be used similar to the default Jinja2 random filter (returning a random item from a sequence of
items), but can also generate a random number based on a range.
To get a random item from a list:: To get a random item from a list::
@ -813,27 +812,26 @@ To get a random number between 0 and a specified number::
"{{ 60 | random }} * * * * root /script/from/cron" "{{ 60 | random }} * * * * root /script/from/cron"
# => '21 * * * * root /script/from/cron' # => '21 * * * * root /script/from/cron'
Get a random number from 0 to 100 but in steps of 10:: To get a random number from 0 to 100 but in steps of 10::
{{ 101 | random(step=10) }} {{ 101 | random(step=10) }}
# => 70 # => 70
Get a random number from 1 to 100 but in steps of 10:: To get a random number from 1 to 100 but in steps of 10::
{{ 101 | random(1, 10) }} {{ 101 | random(1, 10) }}
# => 31 # => 31
{{ 101 | random(start=1, step=10) }} {{ 101 | random(start=1, step=10) }}
# => 51 # => 51
It's also possible to initialize the random number generator from a seed. This way, you can create random-but-idempotent numbers:: You can initialize the random number generator from a seed to create random-but-idempotent numbers::
"{{ 60 | random(seed=inventory_hostname) }} * * * * root /script/from/cron" "{{ 60 | random(seed=inventory_hostname) }} * * * * root /script/from/cron"
Shuffling a list Shuffling a list
---------------- ----------------
The ``shuffle`` filter randomizes an existing list, giving a different order every invocation.
This filter will randomize an existing list, giving a different order every invocation.
To get a random list from an existing list:: To get a random list from an existing list::
@ -842,20 +840,20 @@ To get a random list from an existing list::
{{ ['a','b','c'] | shuffle }} {{ ['a','b','c'] | shuffle }}
# => ['b','c','a'] # => ['b','c','a']
It's also possible to shuffle a list idempotent. All you need is a seed.:: You can initialize the shuffle generator from a seed to generate a random-but-idempotent order::
{{ ['a','b','c'] | shuffle(seed=inventory_hostname) }} {{ ['a','b','c'] | shuffle(seed=inventory_hostname) }}
# => ['b','a','c'] # => ['b','a','c']
The shuffle filter returns a list whenever possible. If you use it with a non 'listable' item, the filter does nothing. The shuffle filter returns a list whenever possible. If you use it with a non 'listable' item, the filter does nothing.
.. _list_filters: .. _list_filters:
List filters Managing list variables
============ =======================
These filters all operate on list variables.
You can search for the minimum or maximum value in a list, or flatten a multi-level list.
To get the minimum value from list of numbers:: To get the minimum value from list of numbers::
@ -878,10 +876,10 @@ Flatten only the first level of a list (akin to the `items` lookup)::
.. _set_theory_filters: .. _set_theory_filters:
Set theory filters Selecting from sets or lists (set theory)
================== =========================================
These functions return a unique set from sets or lists. You can select or combine items from sets or lists.
.. versionadded:: 1.4 .. versionadded:: 1.4
@ -908,11 +906,12 @@ To get the symmetric difference of 2 lists (items exclusive to each list)::
.. _math_stuff: .. _math_stuff:
Math filters Calculating numbers (math)
============ ==========================
.. versionadded:: 1.9 .. versionadded:: 1.9
You can calculate logs, powers, and roots of numbers with Ansible filters. Jinja2 provides other mathematical functions like abs() and round().
Get the logarithm (default is e):: Get the logarithm (default is e)::
@ -932,10 +931,9 @@ Square root, or the 5th::
{{ myvar | root }} {{ myvar | root }}
{{ myvar | root(5) }} {{ myvar | root(5) }}
Note that jinja2 already provides some like abs() and round().
Network filters Managing network interactions
=============== =============================
These filters help you with common network tasks. These filters help you with common network tasks.
@ -1171,7 +1169,7 @@ Network VLAN filters
.. versionadded:: 2.8 .. versionadded:: 2.8
Use the ``vlan_parser`` filter to manipulate an unsorted list of VLAN integers into a Use the ``vlan_parser`` filter to transform an unsorted list of VLAN integers into a
sorted string list of integers according to IOS-like VLAN list rules. This list has the following properties: sorted string list of integers according to IOS-like VLAN list rules. This list has the following properties:
* Vlans are listed in ascending order. * Vlans are listed in ascending order.
@ -1200,8 +1198,8 @@ This allows for dynamic generation of VLAN lists on a Cisco IOS tagged interface
.. _hash_filters: .. _hash_filters:
Encryption filters Encrypting and checksumming strings and passwords
================== =================================================
.. versionadded:: 1.9 .. versionadded:: 1.9
@ -1233,8 +1231,7 @@ An idempotent method to generate unique hashes per system is to use a salt that
{{ 'secretpassword' | password_hash('sha512', 65534 | random(seed=inventory_hostname) | string) }} {{ 'secretpassword' | password_hash('sha512', 65534 | random(seed=inventory_hostname) | string) }}
Hash types available depend on the master system running ansible, Hash types available depend on the master system running Ansible, 'hash' depends on hashlib, password_hash depends on passlib (https://passlib.readthedocs.io/en/stable/lib/passlib.hash.html).
'hash' depends on hashlib password_hash depends on passlib (https://passlib.readthedocs.io/en/stable/lib/passlib.hash.html).
.. versionadded:: 2.7 .. versionadded:: 2.7
@ -1244,18 +1241,17 @@ Some hash types allow providing a rounds parameter::
.. _other_useful_filters: .. _other_useful_filters:
Text filters Manipulating text
============ =================
These filters work with strings and text. Several filters work with text, including URLs, file names, and path names.
.. _comment_filter: .. _comment_filter:
Adding comments to files Adding comments to files
------------------------ ------------------------
The ``comment`` filter lets you create comments in a file from text in a template, with a variety of comment styles. By default Ansible uses ``#`` to start a comment line and adds a blank comment line above and below your comment text. For example the following::
The `comment` filter lets you turn text in a template into comments in a file, with a variety of comment styles. By default Ansible uses ``#`` to start a comment line and adds a blank comment line above and below your comment text. For example the following::
{{ "Plain style (default)" | comment }} {{ "Plain style (default)" | comment }}
@ -1420,9 +1416,8 @@ To replace text in a string with regex, use the "regex_replace" filter::
# change a multiline string # change a multiline string
{{ var | regex_replace('^', '#CommentThis#', multiline=True) }} {{ var | regex_replace('^', '#CommentThis#', multiline=True) }}
.. note:: If you want to match the whole string and you are using ``*`` make sure to always wraparound your regular expression with the start/end anchors. .. note::
For example ``^(.*)$`` will always match only one result, while ``(.*)`` on some Python versions will match the whole string and an empty string at the If you want to match the whole string and you are using ``*`` make sure to always wraparound your regular expression with the start/end anchors. For example ``^(.*)$`` will always match only one result, while ``(.*)`` on some Python versions will match the whole string and an empty string at the end, which means it will make two replacements::
end, which means it will make two replacements::
# add "https://" prefix to each item in a list # add "https://" prefix to each item in a list
GOOD: GOOD:
@ -1442,8 +1437,8 @@ To replace text in a string with regex, use the "regex_replace" filter::
BAD: BAD:
{{ hosts | map('regex_replace', '(.*)', '\\1:80') | list }} {{ hosts | map('regex_replace', '(.*)', '\\1:80') | list }}
.. note:: Prior to ansible 2.0, if "regex_replace" filter was used with variables inside YAML arguments (as opposed to simpler 'key=value' arguments), .. note::
then you needed to escape backreferences (e.g. ``\\1``) with 4 backslashes (``\\\\``) instead of 2 (``\\``). Prior to ansible 2.0, if "regex_replace" filter was used with variables inside YAML arguments (as opposed to simpler 'key=value' arguments), then you needed to escape backreferences (e.g. ``\\1``) with 4 backslashes (``\\\\``) instead of 2 (``\\``).
.. versionadded:: 2.0 .. versionadded:: 2.0
@ -1460,8 +1455,8 @@ To escape special characters within a POSIX basic regex, use the "regex_escape"
{{ '^f.*o(.*)$' | regex_escape('posix_basic') }} {{ '^f.*o(.*)$' | regex_escape('posix_basic') }}
Working with filenames and pathnames Managing file names and path names
------------------------------------ ----------------------------------
To get the last name of a file path, like 'foo.txt' out of '/etc/asdf/foo.txt':: To get the last name of a file path, like 'foo.txt' out of '/etc/asdf/foo.txt'::
@ -1511,7 +1506,7 @@ To get the relative path of a link, from a start point (new in version 1.7)::
{{ path | relpath('/etc') }} {{ path | relpath('/etc') }}
To get the root and extension of a path or filename (new in version 2.0):: To get the root and extension of a path or file name (new in version 2.0)::
# with path == 'nginx.conf' the return would be ('nginx', '.conf') # with path == 'nginx.conf' the return would be ('nginx', '.conf')
{{ path | splitext }} {{ path | splitext }}
@ -1522,8 +1517,8 @@ To join one or more path components::
.. versionadded:: 2.10 .. versionadded:: 2.10
String filters Manipulating strings
============== ====================
To add quotes for shell usage:: To add quotes for shell usage::
@ -1543,13 +1538,12 @@ As of version 2.6, you can define the type of encoding to use, the default is ``
{{ encoded | b64decode(encoding='utf-16-le') }} {{ encoded | b64decode(encoding='utf-16-le') }}
{{ decoded | string | b64encode(encoding='utf-16-le') }} {{ decoded | string | b64encode(encoding='utf-16-le') }}
.. note:: The ``string`` filter is only required for Python 2 and ensures that text to encode is a unicode string. .. note:: The ``string`` filter is only required for Python 2 and ensures that text to encode is a unicode string. Without that filter before b64encode the wrong value will be encoded.
Without that filter before b64encode the wrong value will be encoded.
.. versionadded:: 2.6 .. versionadded:: 2.6
UUID filters Managing UUIDs
============ ==============
To create a namespaced UUIDv5:: To create a namespaced UUIDv5::
@ -1568,8 +1562,8 @@ To make use of one attribute from each item in a list of complex variables, use
# get a comma-separated list of the mount points (e.g. "/,/mnt/stuff") on a host # get a comma-separated list of the mount points (e.g. "/,/mnt/stuff") on a host
{{ ansible_mounts | map(attribute='mount') | join(',') }} {{ ansible_mounts | map(attribute='mount') | join(',') }}
Date and time filters Handling dates and times
===================== ========================
To get a date object from a string use the `to_datetime` filter:: To get a date object from a string use the `to_datetime` filter::
@ -1602,8 +1596,8 @@ To format a date using a string (like with the shell date command), use the "str
.. note:: To get all string possibilities, check https://docs.python.org/2/library/time.html#time.strftime .. note:: To get all string possibilities, check https://docs.python.org/2/library/time.html#time.strftime
Kubernetes filters Getting Kubernetes resource names
================== =================================
.. note:: .. note::

View file

@ -32,6 +32,7 @@ It can usually be installed with either your system package manager or using
:depth: 2 :depth: 2
:backlinks: top :backlinks: top
Basic tests Basic tests
^^^^^^^^^^^ ^^^^^^^^^^^
@ -293,12 +294,15 @@ on an interface:
If needed, you can extract subnet and prefix information from the 'host/prefix' value:: If needed, you can extract subnet and prefix information from the 'host/prefix' value::
.. code-block:: jinja
# {{ host_prefix | ansible.netcommon.ipaddr('host/prefix') | ansible.netcommon.ipaddr('subnet') }} # {{ host_prefix | ansible.netcommon.ipaddr('host/prefix') | ansible.netcommon.ipaddr('subnet') }}
['2001:db8:deaf:be11::/64', '192.0.2.0/24'] ['2001:db8:deaf:be11::/64', '192.0.2.0/24']
# {{ host_prefix | ansible.netcommon.ipaddr('host/prefix') | ansible.netcommon.ipaddr('prefix') }} # {{ host_prefix | ansible.netcommon.ipaddr('host/prefix') | ansible.netcommon.ipaddr('prefix') }}
[64, 24] [64, 24]
Converting subnet masks to CIDR notation Converting subnet masks to CIDR notation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -330,6 +334,7 @@ This result can be converted to canonical form with ``ipaddr()`` to produce a su
# {{ net_mask | ansible.netcommon.ipaddr('net') }} # {{ net_mask | ansible.netcommon.ipaddr('net') }}
'192.168.0.0/24' '192.168.0.0/24'
Getting information about the network in CIDR notation Getting information about the network in CIDR notation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -346,6 +351,7 @@ This can be used to obtain the network address in CIDR notation format::
# {{ ip_address | ansible.netcommon.ipaddr('network/prefix') }} # {{ ip_address | ansible.netcommon.ipaddr('network/prefix') }}
'192.168.0.0/24' '192.168.0.0/24'
IP address conversion IP address conversion
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
@ -411,6 +417,7 @@ be automatically converted to a router address (with a ``::1/48`` host address):
.. _6to4: https://en.wikipedia.org/wiki/6to4 .. _6to4: https://en.wikipedia.org/wiki/6to4
Finding IP addresses within a range Finding IP addresses within a range
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -431,13 +438,6 @@ To find the available range of IP addresses from the given network address, use
# {{ '192.168.122.1/24' | ansible.netcommon.ipaddr('range_usable') }} # {{ '192.168.122.1/24' | ansible.netcommon.ipaddr('range_usable') }}
192.168.122.1-192.168.122.254 192.168.122.1-192.168.122.254
To find the next nth usable IP address within a range, use ``next_nth_usable``::
# {{ '192.168.122.1/24' | ansible.netcommon.next_nth_usable(2) }}
192.168.122.3
In this example, ``next_nth_usable`` returns the second usable IP address for the given IP range.
To find the peer IP address for a point to point link, use ``peer``:: To find the peer IP address for a point to point link, use ``peer``::
# {{ '192.168.122.1/31' | ansible.netcommon.ipaddr('peer') }} # {{ '192.168.122.1/31' | ansible.netcommon.ipaddr('peer') }}
@ -445,6 +445,69 @@ To find the peer IP address for a point to point link, use ``peer``::
# {{ '192.168.122.1/30' | ansible.netcommon.ipaddr('peer') }} # {{ '192.168.122.1/30' | ansible.netcommon.ipaddr('peer') }}
192.168.122.2 192.168.122.2
To return the nth ip from a network, use the filter ``nthhost``::
# {{ '10.0.0.0/8' | ansible.netcommon.nthhost(305) }}
10.0.1.49
``nthhost`` also supports a negative value::
# {{ '10.0.0.0/8' | ansible.netcommon.nthhost(-1) }}
10.255.255.255
To find the next nth usable IP address in relation to another within a range, use ``next_nth_usable``
In the example, ``next_nth_usable`` returns the second usable IP address for the given IP range::
# {{ '192.168.122.1/24' | ansible.netcommon.next_nth_usable(2) }}
192.168.122.3
If there is no usable address, it returns an empty string::
# {{ '192.168.122.254/24' | ansible.netcommon.next_nth_usable(2) }}
""
Just like ``next_nth_ansible``, you have ``previous_nth_usable`` to find the previous usable address::
# {{ '192.168.122.10/24' | ansible.netcommon.previous_nth_usable(2) }}
192.168.122.8
Testing if a address belong to a network range
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``network_in_usable`` filter returns whether an address passed as an argument is usable in a network.
Usable addresses are addresses that can be assigned to a host. The network ID and the broadcast address
are not usable addresses.::
# {{ '192.168.0.0/24' | ansible.netcommon.network_in_usable( '192.168.0.1' ) }}
True
# {{ '192.168.0.0/24' | ansible.netcommon.network_in_usable( '192.168.0.255' ) }}
False
# {{ '192.168.0.0/16' | ansible.netcommon.network_in_usable( '192.168.0.255' ) }}
True
The ``network_in_network`` filter returns whether an address or a network passed as argument is in a network.::
# {{ '192.168.0.0/24' | ansible.netcommon.network_in_network( '192.168.0.1' ) }}
True
# {{ '192.168.0.0/24' | ansible.netcommon.network_in_network( '192.168.0.0/24' ) }}
True
# {{ '192.168.0.0/24' | ansible.netcommon.network_in_network( '192.168.0.255' ) }}
True
# Check in a network is part of another network
# {{ '192.168.0.0/16' | ansible.netcommon.network_in_network( '192.168.0.0/24' ) }}
True
To check whether multiple addresses belong to a network, use the ``reduce_on_network`` filter::
# {{ '192.168.0.0/24' | ansible.netcommon.reduce_on_network( ['192.168.0.34', '10.3.0.3', '192.168.2.34'] ) }}
['192.168.0.34']
IP Math IP Math
^^^^^^^ ^^^^^^^
@ -455,24 +518,32 @@ The ``ipmath()`` filter can be used to do simple IP math/arithmetic.
Here are a few simple examples:: Here are a few simple examples::
# Get the next five addresses based on an IP address
# {{ '192.168.1.5' | ansible.netcommon.ipmath(5) }} # {{ '192.168.1.5' | ansible.netcommon.ipmath(5) }}
192.168.1.10 192.168.1.10
# Get the ten previous addresses based on an IP address
# {{ '192.168.0.5' | ansible.netcommon.ipmath(-10) }} # {{ '192.168.0.5' | ansible.netcommon.ipmath(-10) }}
192.167.255.251 192.167.255.251
# Get the next five addresses using CIDR notation
# {{ '192.168.1.1/24' | ansible.netcommon.ipmath(5) }} # {{ '192.168.1.1/24' | ansible.netcommon.ipmath(5) }}
192.168.1.6 192.168.1.6
# Get the previous five addresses using CIDR notation
# {{ '192.168.1.6/24' | ansible.netcommon.ipmath(-5) }} # {{ '192.168.1.6/24' | ansible.netcommon.ipmath(-5) }}
192.168.1.1 192.168.1.1
# Get the previous ten address using cidr notation
# It returns a address of the previous network range
# {{ '192.168.2.6/24' | ansible.netcommon.ipmath(-10) }} # {{ '192.168.2.6/24' | ansible.netcommon.ipmath(-10) }}
192.168.1.252 192.168.1.252
# Get the next ten addresses in IPv6
# {{ '2001::1' | ansible.netcommon.ipmath(10) }} # {{ '2001::1' | ansible.netcommon.ipmath(10) }}
2001::b 2001::b
# Get the previous ten address in IPv6
# {{ '2001::5' | ansible.netcommon.ipmath(-10) }} # {{ '2001::5' | ansible.netcommon.ipmath(-10) }}
2000:ffff:ffff:ffff:ffff:ffff:ffff:fffb 2000:ffff:ffff:ffff:ffff:ffff:ffff:fffb
@ -582,6 +653,7 @@ Because of the size of IPv6 subnets, iteration over all of them to find the
correct one may take some time on slower computers, depending on the size correct one may take some time on slower computers, depending on the size
difference between the subnets. difference between the subnets.
Subnet Merging Subnet Merging
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
@ -606,6 +678,7 @@ subnet which contains all of the inputs::
{{ ['192.168.1.42', '192.168.42.1'] | ansible.netcommon.cidr_merge('span') }} {{ ['192.168.1.42', '192.168.42.1'] | ansible.netcommon.cidr_merge('span') }}
# => '192.168.0.0/18' # => '192.168.0.0/18'
MAC address filter MAC address filter
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
@ -637,6 +710,15 @@ The supported formats result in the following conversions for the ``1a:2b:3c:4d:
linux or unix: 1a:2b:3c:4d:5e:6f: linux or unix: 1a:2b:3c:4d:5e:6f:
pgsql, postgresql, or psql: 1a2b3c:4d5e6f pgsql, postgresql, or psql: 1a2b3c:4d5e6f
Generate an IPv6 address in Stateless Configuration (SLAAC)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
the filter ``slaac()`` generates an IPv6 address for a given network and a MAC Address in Stateless Configuration::
# {{ fdcf:1894:23b5:d38c:0000:0000:0000:0000 | slaac('c2:31:b3:83:bf:2b') }}
fdcf:1894:23b5:d38c:c031:b3ff:fe83:bf2b
.. seealso:: .. seealso::

View file

@ -35,7 +35,7 @@ An Ansible role has a defined directory structure with seven main standard direc
defaults/ defaults/
meta/ meta/
Each directory within a role must contain a ``main.yml`` file with relevant content: By default Ansible will look in each directory within a role for a ``main.yml`` file for relevant content (also ``main.yaml`` and ``main``):
- ``tasks/main.yml`` - the main list of tasks that the role executes. - ``tasks/main.yml`` - the main list of tasks that the role executes.
- ``handlers/main.yml`` - handlers, which may be used within or outside this role. - ``handlers/main.yml`` - handlers, which may be used within or outside this role.

View file

@ -513,7 +513,8 @@ class DocCLI(CLI):
def add_fields(text, fields, limit, opt_indent, return_values=False, base_indent=''): def add_fields(text, fields, limit, opt_indent, return_values=False, base_indent=''):
for o in sorted(fields): for o in sorted(fields):
opt = fields[o] # Create a copy so we don't modify the original (in case YAML anchors have been used)
opt = dict(fields[o])
required = opt.pop('required', False) required = opt.pop('required', False)
if not isinstance(required, bool): if not isinstance(required, bool):
@ -562,7 +563,8 @@ class DocCLI(CLI):
conf = {} conf = {}
for config in ('env', 'ini', 'yaml', 'vars', 'keywords'): for config in ('env', 'ini', 'yaml', 'vars', 'keywords'):
if config in opt and opt[config]: if config in opt and opt[config]:
conf[config] = opt.pop(config) # Create a copy so we don't modify the original (in case YAML anchors have been used)
conf[config] = [dict(item) for item in opt.pop(config)]
for ignore in DocCLI.IGNORE: for ignore in DocCLI.IGNORE:
for item in conf[config]: for item in conf[config]:
if ignore in item: if ignore in item:
@ -593,6 +595,8 @@ class DocCLI(CLI):
@staticmethod @staticmethod
def get_man_text(doc): def get_man_text(doc):
# Create a copy so we don't modify the original
doc = dict(doc)
DocCLI.IGNORE = DocCLI.IGNORE + (context.CLIARGS['type'],) DocCLI.IGNORE = DocCLI.IGNORE + (context.CLIARGS['type'],)
opt_indent = " " opt_indent = " "

View file

@ -29,7 +29,7 @@ display = Display()
class PullCLI(CLI): class PullCLI(CLI):
''' is used to up a remote copy of ansible on each managed node, ''' Used to pull a remote copy of ansible on each managed node,
each set to run via cron and update playbook source via a source repository. each set to run via cron and update playbook source via a source repository.
This inverts the default *push* architecture of ansible into a *pull* architecture, This inverts the default *push* architecture of ansible into a *pull* architecture,
which has near-limitless scaling potential. which has near-limitless scaling potential.

View file

@ -189,7 +189,7 @@ AGNOSTIC_BECOME_PROMPT:
CACHE_PLUGIN: CACHE_PLUGIN:
name: Persistent Cache plugin name: Persistent Cache plugin
default: memory default: memory
description: Chooses which cache plugin to use, the default 'memory' is ephimeral. description: Chooses which cache plugin to use, the default 'memory' is ephemeral.
env: [{name: ANSIBLE_CACHE_PLUGIN}] env: [{name: ANSIBLE_CACHE_PLUGIN}]
ini: ini:
- {key: fact_caching, section: defaults} - {key: fact_caching, section: defaults}

View file

@ -60,6 +60,13 @@ EXAMPLES = """
- name: the final countdown - name: the final countdown
debug: msg={{item}} seconds to detonation debug: msg={{item}} seconds to detonation
with_sequence: end=0 start=10 with_sequence: end=0 start=10
- name: Use of variable
debug:
msg: "{{ item }}"
with_sequence: start=1 end="{{ end_at }}"
vars:
- end_at: 10
""" """
RETURN = """ RETURN = """