You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ansible/docs/docsite/rst/user_guide/complex_data_manipulation.rst

244 lines
9.0 KiB
ReStructuredText

[2.10] Docs Backportapalooza 7 (#71261) * Fixes due to branch being renamed (#71115) The ansible collection repository correctly renamed their default branch from `master` to `main`, which has caused a number for broken urls. This PR fixes those urls. (cherry picked from commit fb9c9570d50792f66f47d4d8d3e9beba8a4a7780) * Docs: Fix typo (#71119) (cherry picked from commit cb9336ab6d3ec15a509c328ee89c7361104c59f3) * remove network for 2.10 base porting guide (#71158) (cherry picked from commit 56748a80609c5d402a8cf72c0a4396f87282957f) * Updating Getting Started with Resources section #68962 (#71102) * Updating Getting Started with Resources section #68962 * Add links, including Workshops URL #68962 (cherry picked from commit 5f8b45a70e8e4e378cdafde6cc6c39f32af39e65) * start of 'data manipulation' examples (#46979) Co-authored-by: Klaus Frank <agowa338@users.noreply.github.com> Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit f46b124d656baa515455cd077595d1b1dfc93b38) * toml: Clarify about inventory examples (#71180) Add a note in toml inventory plugin about three different inventory examples. Fixes: #67003 Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit edac065bd2ad3c613413c125cad3eee45e5f0835) * filters: minor doc fix (#71178) Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit 0a7ab396c7595d9a2ace341395e50e5116a0dd15) * docs: 'ansible_play_hosts' lists active hosts, not limited by serial (#71116) ansible_play_batch lists the currently targeted host(s) in the serial/batch, while ansible_play_hosts lists all the hosts which will be targeted by the play. (cherry picked from commit e72e12aa2747b9fb747775365588b67ec17832a9) * Fix references to Ansible Collections Overview (#71227) (cherry picked from commit 19589db10cdaf400bf7a2e214043c2c94a92cf9e) * add another resource module example (#71162) * Update docs/docsite/rst/network/user_guide/network_resource_modules.rst Co-authored-by: Nilashish Chakraborty <nilashishchakraborty8@gmail.com> (cherry picked from commit f4388de14dbdd422480c8bc4eb60b2cbf1889f92) * Adds fest link (#71241) (cherry picked from commit ae3b8eec1277f1cb75f131314d1eedc9ea059820) * Update release page for ansible and ansible-base (#71229) * [docs] 2.7 is EOL, add 2.10 which is almost out - Remove 2.7 support from the maintenance schedule - Add 2.10 which is in RC and will be out soon enough. Signed-off-by: Rick Elrod <rick@elrod.me> * Update docs/docsite/rst/reference_appendices/release_and_maintenance.rst, fix table and separate ansible-base from ansible, fix rstcheck errors, clean up sections, explain the two packages Co-authored-by: Sandra McCann <samccann@redhat.com> Co-authored-by: Rick Elrod <rick@elrod.me> (cherry picked from commit 553ccedcd3a2292c2665768e5dc97f5e0ff0bb87) Co-authored-by: Daniel Finneran <dan@thebsdbox.co.uk> Co-authored-by: Liviu Chircu <liviu@opensips.org> Co-authored-by: kshitijcode <ikshitijsharma@gmail.com> Co-authored-by: Brian Coca <bcoca@users.noreply.github.com> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> Co-authored-by: Håkon Solbjørg <hakon@solbj.org> Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> Co-authored-by: Alicia Cozine <879121+acozine@users.noreply.github.com>
4 years ago
.. _complex_data_manipulation:
Data manipulation
#########################
In many cases, you need to do some complex operation with your variables, while Ansible is not recommended as a data processing/manipulation tool, you can use the existing Jinja2 templating in conjunction with the many added Ansible filters, lookups and tests to do some very complex transformations.
Let's start with a quick definition of each type of plugin:
- lookups: Mainly used to query 'external data', in Ansible these were the primary part of loops using the ``with_<lookup>`` construct, but they can be used independently to return data for processing. They normally return a list due to their primary function in loops as mentioned previously. Used with the ``lookup`` or ``query`` Jinja2 operators.
- filters: used to change/transform data, used with the ``|`` Jinja2 operator.
- tests: used to validate data, used with the ``is`` Jinja2 operator.
.. _note:
* Some tests and filters are provided directly by Jinja2, so their availability depends on the Jinja2 version, not Ansible.
.. _for_loops_or_list_comprehensions:
Loops and list comprehensions
=============================
Most programming languages have loops (``for``, ``while``, and so on) and list comprehensions to do transformations on lists including lists of objects. Jinja2 has a few filters that provide this functionality: ``map``, ``select``, ``reject``, ``selectattr``, ``rejectattr``.
[2.10] Docs Backportapalooza 7 (#71261) * Fixes due to branch being renamed (#71115) The ansible collection repository correctly renamed their default branch from `master` to `main`, which has caused a number for broken urls. This PR fixes those urls. (cherry picked from commit fb9c9570d50792f66f47d4d8d3e9beba8a4a7780) * Docs: Fix typo (#71119) (cherry picked from commit cb9336ab6d3ec15a509c328ee89c7361104c59f3) * remove network for 2.10 base porting guide (#71158) (cherry picked from commit 56748a80609c5d402a8cf72c0a4396f87282957f) * Updating Getting Started with Resources section #68962 (#71102) * Updating Getting Started with Resources section #68962 * Add links, including Workshops URL #68962 (cherry picked from commit 5f8b45a70e8e4e378cdafde6cc6c39f32af39e65) * start of 'data manipulation' examples (#46979) Co-authored-by: Klaus Frank <agowa338@users.noreply.github.com> Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit f46b124d656baa515455cd077595d1b1dfc93b38) * toml: Clarify about inventory examples (#71180) Add a note in toml inventory plugin about three different inventory examples. Fixes: #67003 Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit edac065bd2ad3c613413c125cad3eee45e5f0835) * filters: minor doc fix (#71178) Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit 0a7ab396c7595d9a2ace341395e50e5116a0dd15) * docs: 'ansible_play_hosts' lists active hosts, not limited by serial (#71116) ansible_play_batch lists the currently targeted host(s) in the serial/batch, while ansible_play_hosts lists all the hosts which will be targeted by the play. (cherry picked from commit e72e12aa2747b9fb747775365588b67ec17832a9) * Fix references to Ansible Collections Overview (#71227) (cherry picked from commit 19589db10cdaf400bf7a2e214043c2c94a92cf9e) * add another resource module example (#71162) * Update docs/docsite/rst/network/user_guide/network_resource_modules.rst Co-authored-by: Nilashish Chakraborty <nilashishchakraborty8@gmail.com> (cherry picked from commit f4388de14dbdd422480c8bc4eb60b2cbf1889f92) * Adds fest link (#71241) (cherry picked from commit ae3b8eec1277f1cb75f131314d1eedc9ea059820) * Update release page for ansible and ansible-base (#71229) * [docs] 2.7 is EOL, add 2.10 which is almost out - Remove 2.7 support from the maintenance schedule - Add 2.10 which is in RC and will be out soon enough. Signed-off-by: Rick Elrod <rick@elrod.me> * Update docs/docsite/rst/reference_appendices/release_and_maintenance.rst, fix table and separate ansible-base from ansible, fix rstcheck errors, clean up sections, explain the two packages Co-authored-by: Sandra McCann <samccann@redhat.com> Co-authored-by: Rick Elrod <rick@elrod.me> (cherry picked from commit 553ccedcd3a2292c2665768e5dc97f5e0ff0bb87) Co-authored-by: Daniel Finneran <dan@thebsdbox.co.uk> Co-authored-by: Liviu Chircu <liviu@opensips.org> Co-authored-by: kshitijcode <ikshitijsharma@gmail.com> Co-authored-by: Brian Coca <bcoca@users.noreply.github.com> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> Co-authored-by: Håkon Solbjørg <hakon@solbj.org> Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> Co-authored-by: Alicia Cozine <879121+acozine@users.noreply.github.com>
4 years ago
- map: this is a basic for loop that just allows you to change every item in a list, using the 'attribute' keyword you can do the transformation based on attributes of the list elements.
- select/reject: this is a for loop with a condition, that allows you to create a subset of a list that matches (or not) based on the result of the condition.
- selectattr/rejectattr: very similar to the above but it uses a specific attribute of the list elements for the conditional statement.
.. _keys_from_dict_matching_list:
Extract keys from a dictionary matching elements from a list
------------------------------------------------------------
The Python equivalent code would be:
.. code-block:: python
chains = [1, 2]
for chain in chains:
for config in chains_config[chain]['configs']:
print(config['type'])
There are several ways to do it in Ansible, this is just one example:
.. code-block:: YAML+Jinja
:emphasize-lines: 3
:caption: Way to extract matching keys from a list of dictionaries
tasks:
- name: Show extracted list of keys from a list of dictionaries
debug: msg="{{ chains | map('extract', chains_config) | map(attribute='configs') | flatten | map(attribute='type') | flatten }}"
vars:
chains: [1, 2]
chains_config:
1:
foo: bar
configs:
- type: routed
version: 0.1
- type: bridged
version: 0.2
2:
foo: baz
configs:
- type: routed
version: 1.0
- type: bridged
version: 1.1
.. code-block:: ansible-output
:caption: Results of debug task, a list with the extracted keys
ok: [localhost] => {
"msg": [
"routed",
"bridged",
"routed",
"bridged"
]
}
.. _find_mount_point:
Find mount point
----------------
In this case, we want to find the mount point for a given path across our machines, since we already collect mount facts, we can use the following:
.. code-block:: YAML+Jinja
:caption: Use selectattr to filter mounts into list I can then sort and select the last from
:emphasize-lines: 7
- hosts: all
gather_facts: True
vars:
path: /var/lib/cache
tasks:
- name: The mount point for {{path}}, found using the Ansible mount facts, [-1] is the same as the 'last' filter
debug: msg="{{(ansible_facts.mounts | selectattr('mount', 'in', path) | list | sort(attribute='mount'))[-1]['mount']}}"
Omit elements from a list
-------------------------
The special ``omit`` variable ONLY works with module options, but we can still use it in other ways as an identifier to tailor a list of elements:
.. code-block:: YAML+Jinja
:caption: Inline list filtering when feeding a module option
:emphasize-lines: 3, 7
- name: enable a list of Windows features, by name
set_fact:
win_feature_list: "{{ namestuff | reject('equalto', omit) | list }}"
vars:
namestuff:
- "{{ (fs_installed_smb_v1 | default(False)) | ternary(omit, 'FS-SMB1') }}"
- "foo"
- "bar"
Another way is to avoid adding elements to the list in the first place, so you can just use it directly:
.. code-block:: YAML+Jinja
:caption: Using set_fact in a loop to increment a list conditionally
:emphasize-lines: 3, 4, 6
- name: build unique list with some items conditionally omittted
set_fact:
namestuff: ' {{ (namestuff | default([])) | union([item]) }}'
when: item != omit
loop:
- "{{ (fs_installed_smb_v1 | default(False)) | ternary(omit, 'FS-SMB1') }}"
- "foo"
- "bar"
.. _complex_type_transfomations:
Complex Type transformations
=============================
Jinja provides filters for simple data type transformations (``int``, ``bool``, and so on), but when you want to transform data structures things are not as easy.
[2.10] Docs Backportapalooza 7 (#71261) * Fixes due to branch being renamed (#71115) The ansible collection repository correctly renamed their default branch from `master` to `main`, which has caused a number for broken urls. This PR fixes those urls. (cherry picked from commit fb9c9570d50792f66f47d4d8d3e9beba8a4a7780) * Docs: Fix typo (#71119) (cherry picked from commit cb9336ab6d3ec15a509c328ee89c7361104c59f3) * remove network for 2.10 base porting guide (#71158) (cherry picked from commit 56748a80609c5d402a8cf72c0a4396f87282957f) * Updating Getting Started with Resources section #68962 (#71102) * Updating Getting Started with Resources section #68962 * Add links, including Workshops URL #68962 (cherry picked from commit 5f8b45a70e8e4e378cdafde6cc6c39f32af39e65) * start of 'data manipulation' examples (#46979) Co-authored-by: Klaus Frank <agowa338@users.noreply.github.com> Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit f46b124d656baa515455cd077595d1b1dfc93b38) * toml: Clarify about inventory examples (#71180) Add a note in toml inventory plugin about three different inventory examples. Fixes: #67003 Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit edac065bd2ad3c613413c125cad3eee45e5f0835) * filters: minor doc fix (#71178) Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit 0a7ab396c7595d9a2ace341395e50e5116a0dd15) * docs: 'ansible_play_hosts' lists active hosts, not limited by serial (#71116) ansible_play_batch lists the currently targeted host(s) in the serial/batch, while ansible_play_hosts lists all the hosts which will be targeted by the play. (cherry picked from commit e72e12aa2747b9fb747775365588b67ec17832a9) * Fix references to Ansible Collections Overview (#71227) (cherry picked from commit 19589db10cdaf400bf7a2e214043c2c94a92cf9e) * add another resource module example (#71162) * Update docs/docsite/rst/network/user_guide/network_resource_modules.rst Co-authored-by: Nilashish Chakraborty <nilashishchakraborty8@gmail.com> (cherry picked from commit f4388de14dbdd422480c8bc4eb60b2cbf1889f92) * Adds fest link (#71241) (cherry picked from commit ae3b8eec1277f1cb75f131314d1eedc9ea059820) * Update release page for ansible and ansible-base (#71229) * [docs] 2.7 is EOL, add 2.10 which is almost out - Remove 2.7 support from the maintenance schedule - Add 2.10 which is in RC and will be out soon enough. Signed-off-by: Rick Elrod <rick@elrod.me> * Update docs/docsite/rst/reference_appendices/release_and_maintenance.rst, fix table and separate ansible-base from ansible, fix rstcheck errors, clean up sections, explain the two packages Co-authored-by: Sandra McCann <samccann@redhat.com> Co-authored-by: Rick Elrod <rick@elrod.me> (cherry picked from commit 553ccedcd3a2292c2665768e5dc97f5e0ff0bb87) Co-authored-by: Daniel Finneran <dan@thebsdbox.co.uk> Co-authored-by: Liviu Chircu <liviu@opensips.org> Co-authored-by: kshitijcode <ikshitijsharma@gmail.com> Co-authored-by: Brian Coca <bcoca@users.noreply.github.com> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> Co-authored-by: Håkon Solbjørg <hakon@solbj.org> Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> Co-authored-by: Alicia Cozine <879121+acozine@users.noreply.github.com>
4 years ago
You can use loops and list comprehensions as shown above to help, also other filters and lookups can be chained and leveraged to achieve more complex transformations.
.. _create_dictionary_from_list:
Create dictionary from list
---------------------------
In most languages it is easy to create a dictionary (a.k.a. map/associative array/hash and so on) from a list of pairs, in Ansible there are a couple of ways to do it and the best one for you might depend on the source of your data.
[2.10] Docs Backportapalooza 7 (#71261) * Fixes due to branch being renamed (#71115) The ansible collection repository correctly renamed their default branch from `master` to `main`, which has caused a number for broken urls. This PR fixes those urls. (cherry picked from commit fb9c9570d50792f66f47d4d8d3e9beba8a4a7780) * Docs: Fix typo (#71119) (cherry picked from commit cb9336ab6d3ec15a509c328ee89c7361104c59f3) * remove network for 2.10 base porting guide (#71158) (cherry picked from commit 56748a80609c5d402a8cf72c0a4396f87282957f) * Updating Getting Started with Resources section #68962 (#71102) * Updating Getting Started with Resources section #68962 * Add links, including Workshops URL #68962 (cherry picked from commit 5f8b45a70e8e4e378cdafde6cc6c39f32af39e65) * start of 'data manipulation' examples (#46979) Co-authored-by: Klaus Frank <agowa338@users.noreply.github.com> Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit f46b124d656baa515455cd077595d1b1dfc93b38) * toml: Clarify about inventory examples (#71180) Add a note in toml inventory plugin about three different inventory examples. Fixes: #67003 Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit edac065bd2ad3c613413c125cad3eee45e5f0835) * filters: minor doc fix (#71178) Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> (cherry picked from commit 0a7ab396c7595d9a2ace341395e50e5116a0dd15) * docs: 'ansible_play_hosts' lists active hosts, not limited by serial (#71116) ansible_play_batch lists the currently targeted host(s) in the serial/batch, while ansible_play_hosts lists all the hosts which will be targeted by the play. (cherry picked from commit e72e12aa2747b9fb747775365588b67ec17832a9) * Fix references to Ansible Collections Overview (#71227) (cherry picked from commit 19589db10cdaf400bf7a2e214043c2c94a92cf9e) * add another resource module example (#71162) * Update docs/docsite/rst/network/user_guide/network_resource_modules.rst Co-authored-by: Nilashish Chakraborty <nilashishchakraborty8@gmail.com> (cherry picked from commit f4388de14dbdd422480c8bc4eb60b2cbf1889f92) * Adds fest link (#71241) (cherry picked from commit ae3b8eec1277f1cb75f131314d1eedc9ea059820) * Update release page for ansible and ansible-base (#71229) * [docs] 2.7 is EOL, add 2.10 which is almost out - Remove 2.7 support from the maintenance schedule - Add 2.10 which is in RC and will be out soon enough. Signed-off-by: Rick Elrod <rick@elrod.me> * Update docs/docsite/rst/reference_appendices/release_and_maintenance.rst, fix table and separate ansible-base from ansible, fix rstcheck errors, clean up sections, explain the two packages Co-authored-by: Sandra McCann <samccann@redhat.com> Co-authored-by: Rick Elrod <rick@elrod.me> (cherry picked from commit 553ccedcd3a2292c2665768e5dc97f5e0ff0bb87) Co-authored-by: Daniel Finneran <dan@thebsdbox.co.uk> Co-authored-by: Liviu Chircu <liviu@opensips.org> Co-authored-by: kshitijcode <ikshitijsharma@gmail.com> Co-authored-by: Brian Coca <bcoca@users.noreply.github.com> Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> Co-authored-by: Håkon Solbjørg <hakon@solbj.org> Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> Co-authored-by: Alicia Cozine <879121+acozine@users.noreply.github.com>
4 years ago
These example produces ``{"a": "b", "c": "d"}``
.. code-block:: YAML+Jinja
:caption: Simple list to dict by assuming the list is [key, value , key, value, ...]
vars:
single_list: [ 'a', 'b', 'c', 'd' ]
mydict: "{{ dict(single_list) | slice(2) | list }}"
.. code-block:: YAML+Jinja
:caption: It is simpler when we have a list of pairs:
vars:
list_of_pairs: [ ['a', 'b'], ['c', 'd'] ]
mydict: "{{ dict(list_of_pairs) }}"
Both end up being the same thing, with the ``slice(2) | list`` transforming ``single_list`` to the same structure as ``list_of_pairs``.
A bit more complex, using ``set_fact`` and a ``loop`` to create/update a dictionary with key value pairs from 2 lists:
.. code-block:: YAML+Jinja
:caption: Using set_fact to create a dictionary from a set of lists
:emphasize-lines: 3, 4
- name: Uses 'combine' to update the dictionary and 'zip' to make pairs of both lists
set_fact:
mydict: "{{ mydict | default({}) | combine({item[0]: item[1]}) }}"
loop: "{{ (keys | zip(values)) | list }}"
vars:
keys:
- foo
- var
- bar
values:
- a
- b
- c
This results in ``{"foo": "a", "var": "b", "bar": "c"}``.
You can even combine these simple examples with other filters and lookups to create a dictionary dynamically by matching patterns to variable names:
.. code-block:: YAML+Jinja
:caption: Using 'vars' to define dictionary from a set of lists without needing a task
vars:
myvarnames: "{{ q('varnames', '^my') }}"
mydict: "{{ dict(myvarnames | zip(q('vars', *myvarnames))) }}"
A quick explanation, since there is a lot to unpack from these two lines:
- The ``varnames`` lookup returns a list of variables that match "begin with ``my``".
- Then feeding the list from the previous step into the ``vars`` lookup to get the list of values.
The ``*`` is used to 'dereference the list' (a pythonism that works in Jinja), otherwise it would take the list as a single argument.
- Both lists get passed to the ``zip`` filter to pair them off into a unified list (key, value, key2, value2, ...).
- The dict function then takes this 'list of pairs' to create the dictionary.
An example on how to use facts to find a host's data that meets condition X:
.. code-block:: YAML+Jinja
vars:
uptime_of_host_most_recently_rebooted: "{{ansible_play_hosts_all | map('extract', hostvars, 'ansible_uptime_seconds') | sort | first}}"
Using an example from @zoradache on reddit, to show the 'uptime in days/hours/minutes' (assumes facts where gathered).
https://www.reddit.com/r/ansible/comments/gj5a93/trying_to_get_uptime_from_seconds/fqj2qr3/
.. code-block:: YAML+Jinja
- debug:
msg: Timedelta {{ now() - now().fromtimestamp(now(fmt='%s') | int - ansible_uptime_seconds) }}
.. seealso::
:doc:`playbooks_filters`
Jinja2 filters included with Ansible
:doc:`playbooks_tests`
Jinja2 tests included with Ansible
`Jinja2 Docs <http://jinja.pocoo.org/docs/>`_
Jinja2 documentation, includes lists for core filters and tests