Split filter docs (#17)
* Dedicated DOCUMENTATION for get_path * Comment out cross collection example * Remove sanity exception, unneeded * Remove extra empty lines * Dedicated DOCUMENTATION for index_of filter plugin * Dedicated DOCUMENTATION for to_paths filter plugin * Add rst docs for filter plugins, update README * lint and pep8 fixes * filter plugin doc update for wantlist Co-authored-by: cidrblock <brad@thethorntons.net>pull/18/head
parent
52118d8bb7
commit
3c42f13b30
|
@ -21,9 +21,9 @@ PEP440 is the schema used to describe the versions of Ansible.
|
|||
### Filter plugins
|
||||
Name | Description
|
||||
--- | ---
|
||||
ansible.utils.get_path|Retrieve the value in a variable using a path. [See examples](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.get_path_lookup.rst)
|
||||
ansible.utils.index_of|Find the indicies of items in a list matching some criteria. [See examples](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.index_of_lookup.rst)
|
||||
ansible.utils.to_paths|Flatten a complex object into a dictionary of paths and values. [See examples](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.to_paths_lookup.rst)
|
||||
[ansible.utils.get_path](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.get_path_filter.rst)|Retrieve the value in a variable using a path
|
||||
[ansible.utils.index_of](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.index_of_filter.rst)|Find the indicies of items in a list matching some criteria
|
||||
[ansible.utils.to_paths](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.to_paths_filter.rst)|Flatten a complex object into a dictionary of paths and values
|
||||
|
||||
### Lookup plugins
|
||||
Name | Description
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
.. _ansible.utils.get_path_filter:
|
||||
|
||||
|
||||
**********************
|
||||
ansible.utils.get_path
|
||||
**********************
|
||||
|
||||
**Retrieve the value in a variable using a path**
|
||||
|
||||
|
||||
Version added: 1.0
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
- Use a ``path`` to retreive a nested value from a ``var``
|
||||
- ``get_path`` is also available as a ``lookup plugin`` for convenience
|
||||
|
||||
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<table border=0 cellpadding=0 class="documentation-table">
|
||||
<tr>
|
||||
<th colspan="1">Parameter</th>
|
||||
<th>Choices/<font color="blue">Defaults</font></th>
|
||||
<th>Configuration</th>
|
||||
<th width="100%">Comments</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>path</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">string</span>
|
||||
/ <span style="color: red">required</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>The <code>path</code> in the <code>var</code> to retrieve the value of.</div>
|
||||
<div>The <code>path</code> needs to a be a valid jinja path</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>var</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">raw</span>
|
||||
/ <span style="color: red">required</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>The variable from which the value should be extraced</div>
|
||||
<div>This option represents the value that is passed to filter plugin in pipe format.</div>
|
||||
<div>For example <em>config_data|ansible.utils.get_path(</em>), in this case <em>config_data</em> represents this option.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>wantlist</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li>no</li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>If set to <code>True</code>, the return value will always be a list</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- name: Retrieve a value deep inside a using a path
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ a|ansible.utils.get_path(path) }}"
|
||||
vars:
|
||||
path: b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside a using a path] ******************
|
||||
# ok: [localhost] => changed=false
|
||||
# ansible_facts:
|
||||
# value: '0'
|
||||
|
||||
|
||||
#### Working with hostvars
|
||||
|
||||
- name: Retrieve a value deep inside all of the host's vars
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ look_in|ansible.utils.get_path(look_for) }}"
|
||||
vars:
|
||||
look_in: "{{ hostvars[inventory_hostname] }}"
|
||||
look_for: a.b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] ********
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
# as_lookup: '0'
|
||||
|
||||
|
||||
#### Used alongside ansible.utils.to_paths
|
||||
|
||||
- name: Get the paths for the object
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
|
||||
- name: Retrieve the value of each path from vars
|
||||
ansible.builtin.debug:
|
||||
msg: "The value of path {{ path }} in vars is {{ value }}"
|
||||
loop: "{{ paths.keys()|list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
vars:
|
||||
path: "{{ item }}"
|
||||
value: "{{ vars|ansible.utils.get_path(item) }}"
|
||||
|
||||
# TASK [Get the paths for the object] *******************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
# TASK [Retrieve the value of each path from vars] ******************
|
||||
# ok: [nxos101] => (item=a.b.c.d[0]) =>
|
||||
# msg: The value of path a.b.c.d[0] in vars is 0
|
||||
# ok: [nxos101] => (item=a.b.c.d[1]) =>
|
||||
# msg: The value of path a.b.c.d[1] in vars is 1
|
||||
# ok: [nxos101] => (item=a.b.c.e[0]) =>
|
||||
# msg: The value of path a.b.c.e[0] in vars is True
|
||||
# ok: [nxos101] => (item=a.b.c.e[1]) =>
|
||||
# msg: The value of path a.b.c.e[1] in vars is False
|
||||
|
||||
|
||||
#### Working with complex structures and transforming results
|
||||
|
||||
- name: Retrieve the current interface config
|
||||
cisco.nxos.nxos_interfaces:
|
||||
state: gathered
|
||||
register: interfaces
|
||||
|
||||
- name: Get the description of several interfaces
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ rekeyed|ansible.utils.get_path(item) }}"
|
||||
vars:
|
||||
rekeyed:
|
||||
by_name: "{{ interfaces.gathered|ansible.builtin.rekey_on_member('name') }}"
|
||||
loop:
|
||||
- by_name['Ethernet1/1'].description
|
||||
- by_name['Ethernet1/2'].description|upper
|
||||
- by_name['Ethernet1/3'].description|default('')
|
||||
|
||||
|
||||
# TASK [Get the description of several interfaces] ******************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) => changed=false
|
||||
# msg: Configured by ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description|upper) => changed=false
|
||||
# msg: CONFIGURED BY ANSIBLE
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/3'].description|default('')) => changed=false
|
||||
# msg: ''
|
||||
|
||||
|
||||
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
- Bradley Thornton (@cidrblock)
|
||||
|
||||
|
||||
.. hint::
|
||||
Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
|
|
@ -18,7 +18,7 @@ Version added: 1.0
|
|||
Synopsis
|
||||
--------
|
||||
- Use a ``path`` to retreive a nested value from a ``var``
|
||||
- ``get_path`` is also available as a ``filter_plugin`` for convenience
|
||||
- ``get_path`` is also available as a ``filter plugin`` for convenience
|
||||
|
||||
|
||||
|
||||
|
@ -116,29 +116,26 @@ Examples
|
|||
|
||||
- name: Retrieve a value deep inside a using a path
|
||||
ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.get_path', a, path) }}"
|
||||
as_filter: "{{ a|ansible.utils.get_path(path) }}"
|
||||
value: "{{ lookup('ansible.utils.get_path', a, path) }}"
|
||||
vars:
|
||||
path: b.c.d[0]
|
||||
|
||||
# TASK [ansible.builtin.set_fact] *************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# TASK [Retrieve a value deep inside a using a path] ******************
|
||||
# ok: [localhost] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
# as_lookup: '0'
|
||||
# value: '0'
|
||||
|
||||
|
||||
#### Working with hostvars
|
||||
|
||||
- name: Retrieve a value deep inside all of the host's vars
|
||||
ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.get_path', look_in, look_for) }}"
|
||||
as_filter: "{{ look_in|ansible.utils.get_path(look_for) }}"
|
||||
value: "{{ lookup('ansible.utils.get_path', look_in, look_for) }}"
|
||||
vars:
|
||||
look_in: "{{ hostvars[inventory_hostname] }}"
|
||||
look_for: a.b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] **********
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] ********
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
|
@ -149,7 +146,7 @@ Examples
|
|||
|
||||
- name: Get the paths for the object
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a, prepend='a') }}"
|
||||
|
||||
- name: Retrieve the value of each path from vars
|
||||
ansible.builtin.debug:
|
||||
|
@ -159,9 +156,9 @@ Examples
|
|||
label: "{{ item }}"
|
||||
vars:
|
||||
path: "{{ item }}"
|
||||
value: "{{ vars|ansible.utils.get_path(item) }}"
|
||||
value: "{{ lookup('ansible.utils.get_path', hostvars[inventory_hostname], item) }}"
|
||||
|
||||
# TASK [Get the paths for the object] *********************************
|
||||
# TASK [Get the paths for the object] *******************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
|
@ -170,7 +167,7 @@ Examples
|
|||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
# TASK [Retrieve the value of each path from vars] ********************
|
||||
# TASK [Retrieve the value of each path from vars] ******************
|
||||
# ok: [nxos101] => (item=a.b.c.d[0]) =>
|
||||
# msg: The value of path a.b.c.d[0] in vars is 0
|
||||
# ok: [nxos101] => (item=a.b.c.d[1]) =>
|
||||
|
@ -181,7 +178,7 @@ Examples
|
|||
# msg: The value of path a.b.c.e[1] in vars is False
|
||||
|
||||
|
||||
#### Working with complex structures
|
||||
#### Working with complex structures and transforming results
|
||||
|
||||
- name: Retrieve the current interface config
|
||||
cisco.nxos.nxos_interfaces:
|
||||
|
@ -190,19 +187,23 @@ Examples
|
|||
|
||||
- name: Get the description of several interfaces
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ rekeyed|ansible.utils.get_path(item) }}"
|
||||
msg: "{{ lookup('ansible.utils.get_path', rekeyed, item) }}"
|
||||
vars:
|
||||
rekeyed:
|
||||
by_name: "{{ interfaces.gathered|ansible.builtin.rekey_on_member('name') }}"
|
||||
loop:
|
||||
- by_name['Ethernet1/1'].description
|
||||
- by_name['Ethernet1/2'].description
|
||||
- by_name['Ethernet1/2'].description|upper
|
||||
- by_name['Ethernet1/3'].description|default('')
|
||||
|
||||
# TASK [Get the description of several interfaces] ********************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) =>
|
||||
# msg: Configured by Ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description) =>
|
||||
# msg: Configured by Ansible Network
|
||||
|
||||
# TASK [Get the description of several interfaces] ******************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) => changed=false
|
||||
# msg: Configured by ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description|upper) => changed=false
|
||||
# msg: CONFIGURED BY ANSIBLE
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/3'].description|default('')) => changed=false
|
||||
# msg: ''
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
.. _ansible.utils.index_of_filter:
|
||||
|
||||
|
||||
**********************
|
||||
ansible.utils.index_of
|
||||
**********************
|
||||
|
||||
**Find the indicies of items in a list matching some criteria**
|
||||
|
||||
|
||||
Version added: 1.0
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
- This plugin returns the indicies of items matching some criteria in a list
|
||||
- When working with a list of dictionaries, the key to evaluate can be specified
|
||||
- ``index_of`` is also available as a ``lookup plugin`` for convenience
|
||||
|
||||
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<table border=0 cellpadding=0 class="documentation-table">
|
||||
<tr>
|
||||
<th colspan="1">Parameter</th>
|
||||
<th>Choices/<font color="blue">Defaults</font></th>
|
||||
<th>Configuration</th>
|
||||
<th width="100%">Comments</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>data</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">list</span>
|
||||
/ <span style="color: red">required</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>A list of items to enumerate and test against</div>
|
||||
<div>This option represents the value that is passed to filter plugin in pipe format.</div>
|
||||
<div>For example <em>config_data|ansible.utils.index_of('x'</em>), in this case <em>config_data</em> represents this option.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>fail_on_missing</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li>no</li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>When provided a list of dictionaries, fail if the key is missing from one or more of the dictionaries</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>key</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">string</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>When the data provided is a list of dictionaries, run the test againt this dictionary key</div>
|
||||
<div>When using a <code>key</code>, the <code>data</code> must only contain dictionaries</div>
|
||||
<div>See <code>fail_on_missing</code> below to determine the behaviour when the <code>key</code> is missing from a dictionary in the <code>data</code></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>test</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">string</span>
|
||||
/ <span style="color: red">required</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>The name of the test to run against the list, a valid jinja2 test or ansible test plugin.</div>
|
||||
<div>Jinja2 includes the following tests <a href='http://jinja.palletsprojects.com/templates/#builtin-tests'>http://jinja.palletsprojects.com/templates/#builtin-tests</a>.</div>
|
||||
<div>An overview of tests included in ansible <a href='https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html'>https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html</a></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>value</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">raw</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>The value used to test each list item against</div>
|
||||
<div>{'Not required for simple tests (eg': '<code>true</code>, <code>false</code>, <code>even</code>, <code>odd</code>)'}</div>
|
||||
<div>May be a <code>string</code>, <code>boolean</code>, <code>number</code>, <code>regular expesion</code> <code>dict</code> etc, depending on the <code>test</code> used</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>wantlist</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li>no</li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>When only a single entry in the <code>data</code> is matched, that entries index is returned as an integer</div>
|
||||
<div>If set to <code>True</code>, the return value will always be a list, even if only a single entry is matched</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#### Simple examples
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
- name: Find the index of 2
|
||||
set_fact:
|
||||
indices: "{{ data|ansible.utils.index_of('eq', 2) }}"
|
||||
|
||||
# TASK [Find the index of 2] *************************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices: '1'
|
||||
|
||||
|
||||
- name: Find the index of 2, ensure list is returned
|
||||
set_fact:
|
||||
indices: "{{ data|ansible.utils.index_of('eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Find the index of 2, ensure list is returned] ************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices:
|
||||
# - 1
|
||||
|
||||
|
||||
- name: Find the index of 3 using the long format
|
||||
set_fact:
|
||||
indices: "{{ data|ansible.utils.index_of(test='eq', value=value, wantlist=True) }}"
|
||||
vars:
|
||||
value: 3
|
||||
|
||||
# TASK [Find the index of 3 using the long format] ***************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices:
|
||||
# - 2
|
||||
|
||||
|
||||
- name: Find numbers greater than 1, using loop
|
||||
debug:
|
||||
msg: "{{ data[item] }} is {{ test }} than {{ value }}"
|
||||
loop: "{{ data|ansible.utils.index_of(test, value) }}"
|
||||
vars:
|
||||
test: '>'
|
||||
value: 1
|
||||
|
||||
# TASK [Find numbers great than 1, using loop] *******************************
|
||||
# ok: [sw01] => (item=1) =>
|
||||
# msg: 2 is > than 1
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# msg: 3 is > than 1
|
||||
|
||||
|
||||
#### Working with lists of dictionaries
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
- name: sw01.example.lan
|
||||
type: switch
|
||||
- name: rtr01.example.lan
|
||||
type: router
|
||||
- name: fw01.example.corp
|
||||
type: firewall
|
||||
- name: fw02.example.corp
|
||||
type: firewall
|
||||
|
||||
- name: Find the index of all firewalls using the type key
|
||||
set_fact:
|
||||
firewalls: "{{ data|ansible.utils.index_of('eq', 'firewall', 'type') }}"
|
||||
|
||||
# TASK [Find the index of all firewalls using the type key] ******************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# firewalls:
|
||||
# - 2
|
||||
# - 3
|
||||
|
||||
- name: Find the index of all firewalls, use in a loop
|
||||
debug:
|
||||
msg: "The type of {{ device_type }} at index {{ item }} has name {{ data[item].name }}."
|
||||
loop: "{{ data|ansible.utils.index_of('eq', device_type, 'type') }}"
|
||||
vars:
|
||||
device_type: firewall
|
||||
|
||||
# TASK [Find the index of all firewalls, use in a loop, as a filter] *********
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp.
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp.
|
||||
|
||||
- name: Find the index of all devices with a .corp name
|
||||
debug:
|
||||
msg: "The device named {{ data[item].name }} is a {{ data[item].type }}"
|
||||
loop: "{{ data|ansible.utils.index_of('regex', expression, 'name') }}"
|
||||
vars:
|
||||
expression: '\.corp$' # ends with .corp
|
||||
|
||||
# TASK [Find the index of all devices with a .corp name] *********************
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The device named fw01.example.corp is a firewall
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The device named fw02.example.corp is a firewall
|
||||
|
||||
|
||||
#### Working with complex structures from resource modules
|
||||
|
||||
- name: Retrieve the current L3 interface configuration
|
||||
cisco.nxos.nxos_l3_interfaces:
|
||||
state: gathered
|
||||
register: current_l3
|
||||
|
||||
# TASK [Retrieve the current L3 interface configuration] *********************
|
||||
# ok: [sw01] => changed=false
|
||||
# gathered:
|
||||
# - name: Ethernet1/1
|
||||
# - name: Ethernet1/2
|
||||
# <...>
|
||||
# - name: Ethernet1/128
|
||||
# - ipv4:
|
||||
# - address: 192.168.101.14/24
|
||||
# name: mgmt0
|
||||
|
||||
- name: Find the indices interfaces with a 192.168.101.xx ip address
|
||||
set_fact:
|
||||
found: "{{ found + entry }}"
|
||||
with_indexed_items: "{{ current_l3.gathered }}"
|
||||
vars:
|
||||
found: []
|
||||
ip: '192.168.101.'
|
||||
address: "{{ item.1.ipv4|d([])|ansible.utils.index_of('search', ip, 'address', wantlist=True) }}"
|
||||
entry:
|
||||
- interface_idx: "{{ item.0 }}"
|
||||
address_idxs: "{{ address }}"
|
||||
when: address
|
||||
|
||||
# TASK [debug] ***************************************************************
|
||||
# ok: [sw01] =>
|
||||
# found:
|
||||
# - address_idxs:
|
||||
# - 0
|
||||
# interface_idx: '128'
|
||||
|
||||
- name: Show all interfaces and their address
|
||||
debug:
|
||||
msg: "{{ interface.name }} has ip {{ address }}"
|
||||
loop: "{{ found|subelements('address_idxs') }}"
|
||||
vars:
|
||||
interface: "{{ current_l3.gathered[item.0.interface_idx|int] }}"
|
||||
address: "{{ interface.ipv4[item.1].address }}"
|
||||
|
||||
# TASK [Show all interfaces and their address] *******************************
|
||||
# ok: [nxos101] => (item=[{'interface_idx': '128', 'address_idxs': [0]}, 0]) =>
|
||||
# msg: mgmt0 has ip 192.168.101.14/24
|
||||
|
||||
|
||||
#### Working with deeply nested data
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
interfaces:
|
||||
interface:
|
||||
- config:
|
||||
description: configured by Ansible - 1
|
||||
enabled: True
|
||||
loopback-mode: False
|
||||
mtu: 1024
|
||||
name: loopback0000
|
||||
type: eth
|
||||
name: loopback0000
|
||||
subinterfaces:
|
||||
subinterface:
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 1
|
||||
enabled: True
|
||||
index: 5
|
||||
index: 5
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 2
|
||||
enabled: False
|
||||
index: 2
|
||||
index: 2
|
||||
- config:
|
||||
description: configured by Ansible - 2
|
||||
enabled: False
|
||||
loopback-mode: False
|
||||
mtu: 2048
|
||||
name: loopback1111
|
||||
type: virt
|
||||
name: loopback1111
|
||||
subinterfaces:
|
||||
subinterface:
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 3
|
||||
enabled: True
|
||||
index: 10
|
||||
index: 10
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 4
|
||||
enabled: False
|
||||
index: 3
|
||||
index: 3
|
||||
|
||||
|
||||
- name: Find the description of loopback111, subinterface index 10
|
||||
debug:
|
||||
msg: |-
|
||||
{{ data.interfaces.interface[int_idx|int]
|
||||
.subinterfaces.subinterface[subint_idx|int]
|
||||
.config.description }}
|
||||
vars:
|
||||
# the values to search for
|
||||
int_name: loopback1111
|
||||
sub_index: 10
|
||||
# retrieve the index in each nested list
|
||||
int_idx: |
|
||||
{{ data.interfaces.interface|
|
||||
ansible.utils.index_of('eq', int_name, 'name') }}
|
||||
subint_idx: |
|
||||
{{ data.interfaces.interface[int_idx|int]
|
||||
.subinterfaces.subinterface|
|
||||
ansible.utils.index_of('eq', sub_index, 'index') }}
|
||||
|
||||
# TASK [Find the description of loopback111, subinterface index 10] ************
|
||||
# ok: [sw01] =>
|
||||
# msg: subinterface configured by Ansible - 3
|
||||
|
||||
|
||||
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
- Bradley Thornton (@cidrblock)
|
||||
|
||||
|
||||
.. hint::
|
||||
Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
|
|
@ -17,9 +17,9 @@ Version added: 1.0
|
|||
|
||||
Synopsis
|
||||
--------
|
||||
- This lookup returns the indicies of items matching some criteria in a list
|
||||
- This plugin returns the indicies of items matching some criteria in a list
|
||||
- When working with a list of dictionaries, the key to evaluate can be specified
|
||||
- ``index_of`` is also available as a ``filter_plugin`` for convenience
|
||||
- ``index_of`` is also available as a ``filter plugin`` for convenience
|
||||
|
||||
|
||||
|
||||
|
@ -159,7 +159,7 @@ Examples
|
|||
|
||||
.. code-block:: yaml
|
||||
|
||||
#### Simple examples using a list of values
|
||||
#### Simple examples
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
|
@ -167,66 +167,41 @@ Examples
|
|||
- 2
|
||||
- 3
|
||||
|
||||
- name: Find the index of 2, lookup or filter
|
||||
- name: Find the index of 2
|
||||
set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 2) }}"
|
||||
indices: "{{ lookup('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
|
||||
# TASK [Find the index of 2, lookup or filter] *******************************
|
||||
# ok: [sw01] => changed=false
|
||||
# TASK [Find the index of 2] *************************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '1'
|
||||
# as_lookup: '1'
|
||||
# indices: '1'
|
||||
|
||||
- name: Any test can be negated using not or !
|
||||
- name: Find the index of 2, ensure list is returned
|
||||
set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'not in', [1,2]) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('!in', [1,2]) }}"
|
||||
indices: "{{ lookup('ansible.utils.index_of', data, 'eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Any test can be negated using not or !] ******************************
|
||||
# ok: [localhost] => changed=false
|
||||
# TASK [Find the index of 2, ensure list is returned] ************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '2'
|
||||
# as_lookup: '2'
|
||||
|
||||
- name: Find the index of 2, lookup or filter, ensure list is returned
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 2, wantlist=True) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Find the index of 2, lookup or filter, ensure list is returned] ******
|
||||
# ok: [sw01] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 1
|
||||
# as_lookup:
|
||||
# - 1
|
||||
# as_query:
|
||||
# indices:
|
||||
# - 1
|
||||
|
||||
- name: Find the index of 3 using the long format
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data=data, test='eq', value=value) }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data=data, test='eq',value =value, wantlist=True) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of(test='eq', value=value, wantlist=True) }}"
|
||||
indices: "{{ lookup('ansible.utils.index_of', data=data, test='eq', value=value, wantlist=True) }}"
|
||||
vars:
|
||||
value: 3
|
||||
|
||||
# TASK [Find the index of 3 using the long format] ***************************
|
||||
# ok: [sw01] => changed=false
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 2
|
||||
# as_lookup:
|
||||
# - 2
|
||||
# as_query:
|
||||
# indices:
|
||||
# - 2
|
||||
|
||||
- name: Find numbers greater than 1, using loop
|
||||
debug:
|
||||
msg: "{{ data[item] }} is {{ test }} than {{ value }}"
|
||||
loop: "{{ data|ansible.utils.index_of(test, value) }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, test, value) }}"
|
||||
vars:
|
||||
test: '>'
|
||||
value: 1
|
||||
|
@ -248,13 +223,12 @@ Examples
|
|||
value: 1
|
||||
|
||||
# TASK [Find numbers greater than 1, using with] *****************************
|
||||
# ok: [sw01] => (item=1) =>
|
||||
# ok: [nxos101] => (item=1) =>
|
||||
# msg: 2 is > than 1
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: 3 is > than 1
|
||||
|
||||
|
||||
|
||||
#### Working with lists of dictionaries
|
||||
|
||||
- set_fact:
|
||||
|
@ -270,52 +244,43 @@ Examples
|
|||
|
||||
- name: Find the index of all firewalls using the type key
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 'firewall', 'type') }}"
|
||||
firewalls: "{{ lookup('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
|
||||
# TASK [Find the index of all firewalls using the type key] ******************
|
||||
# ok: [sw01] => changed=false
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 2
|
||||
# - 3
|
||||
# as_lookup:
|
||||
# - 2
|
||||
# - 3
|
||||
# as_query:
|
||||
# firewalls:
|
||||
# - 2
|
||||
# - 3
|
||||
|
||||
- name: Find the index of all firewalls, use in a loop, as a filter
|
||||
- name: Find the index of all firewalls, use in a loop
|
||||
debug:
|
||||
msg: "The type of {{ device_type }} at index {{ item }} has name {{ data[item].name }}."
|
||||
loop: "{{ data|ansible.utils.index_of('eq', device_type, 'type') }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'eq', device_type, 'type') }}"
|
||||
vars:
|
||||
device_type: firewall
|
||||
|
||||
# TASK [Find the index of all firewalls, use in a loop] **********************
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp
|
||||
# ok: [sw01] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp
|
||||
# TASK [Find the index of all firewalls, use in a loop, as a filter] *********
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp.
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp.
|
||||
|
||||
- name: Find the index of all devices with a .corp name, as a lookup
|
||||
- name: Find the index of all devices with a .corp name
|
||||
debug:
|
||||
msg: "The device named {{ data[item].name }} is a {{ data[item].type }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'regex', regex, 'name') }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'regex', expression, 'name') }}"
|
||||
vars:
|
||||
regex: '\.corp$' # ends with .corp
|
||||
expression: '\.corp$' # ends with .corp
|
||||
|
||||
# TASK [Find the index of all devices with a .corp name, as a lookup] **********
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# TASK [Find the index of all devices with a .corp name] *********************
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The device named fw01.example.corp is a firewall
|
||||
# ok: [sw01] => (item=3) =>
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The device named fw02.example.corp is a firewall
|
||||
|
||||
|
||||
|
||||
#### Working with data from resource modules
|
||||
#### Working with complex structures from resource modules
|
||||
|
||||
- name: Retrieve the current L3 interface configuration
|
||||
cisco.nxos.nxos_l3_interfaces:
|
||||
|
@ -333,14 +298,14 @@ Examples
|
|||
# - address: 192.168.101.14/24
|
||||
# name: mgmt0
|
||||
|
||||
- name: Find the index of the interface and address with a 192.168.101.xx ip address
|
||||
- name: Find the indices interfaces with a 192.168.101.xx ip address
|
||||
set_fact:
|
||||
found: "{{ found + entry }}"
|
||||
with_indexed_items: "{{ current_l3.gathered }}"
|
||||
vars:
|
||||
found: []
|
||||
ip: '192.168.101.'
|
||||
address: "{{ item.1.ipv4|d([])|ansible.utils.index_of('search', ip, 'address', wantlist=True) }}"
|
||||
address: "{{ lookup('ansible.utils.index_of', item.1.ipv4|d([]), 'search', ip, 'address', wantlist=True) }}"
|
||||
entry:
|
||||
- interface_idx: "{{ item.0 }}"
|
||||
address_idxs: "{{ address }}"
|
||||
|
@ -361,13 +326,12 @@ Examples
|
|||
interface: "{{ current_l3.gathered[item.0.interface_idx|int] }}"
|
||||
address: "{{ interface.ipv4[item.1].address }}"
|
||||
|
||||
# TASK [debug] ***************************************************************
|
||||
# ok: [sw01] => (item=[{'interface_idx': '128', 'address_idx': [0]}, 0]) =>
|
||||
# TASK [Show all interfaces and their address] *******************************
|
||||
# ok: [nxos101] => (item=[{'interface_idx': '128', 'address_idxs': [0]}, 0]) =>
|
||||
# msg: mgmt0 has ip 192.168.101.14/24
|
||||
|
||||
|
||||
|
||||
#### Working with complex structures
|
||||
#### Working with deeply nested data
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
|
@ -427,12 +391,13 @@ Examples
|
|||
sub_index: 10
|
||||
# retrieve the index in each nested list
|
||||
int_idx: |
|
||||
{{ data.interfaces.interface|
|
||||
ansible.utils.index_of('eq', int_name, 'name') }}
|
||||
{{ lookup('ansible.utils.index_of',
|
||||
data.interfaces.interface,
|
||||
'eq', int_name, 'name') }}
|
||||
subint_idx: |
|
||||
{{ data.interfaces.interface[int_idx|int]
|
||||
.subinterfaces.subinterface|
|
||||
ansible.utils.index_of('eq', sub_index, 'index') }}
|
||||
{{ lookup('ansible.utils.index_of',
|
||||
data.interfaces.interface[int_idx|int].subinterfaces.subinterface,
|
||||
'eq', sub_index, 'index') }}
|
||||
|
||||
# TASK [Find the description of loopback111, subinterface index 10] ************
|
||||
# ok: [sw01] =>
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
.. _ansible.utils.to_paths_filter:
|
||||
|
||||
|
||||
**********************
|
||||
ansible.utils.to_paths
|
||||
**********************
|
||||
|
||||
**Flatten a complex object into a dictionary of paths and values**
|
||||
|
||||
|
||||
Version added: 1.0
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
- Flatten a complex object into a dictionary of paths and values.
|
||||
- Paths are dot delimited whenever possible
|
||||
- Brakets are used for list indicies and keys that contain special characters
|
||||
- ``to_paths`` is also available as a ``lookup plugin`` for convenience
|
||||
|
||||
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<table border=0 cellpadding=0 class="documentation-table">
|
||||
<tr>
|
||||
<th colspan="1">Parameter</th>
|
||||
<th>Choices/<font color="blue">Defaults</font></th>
|
||||
<th>Configuration</th>
|
||||
<th width="100%">Comments</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>prepend</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">string</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Prepend each path entry. Useful to add the initial <code>var</code> name.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>var</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">raw</span>
|
||||
/ <span style="color: red">required</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>The value of <code>var</code> will be will be used.</div>
|
||||
<div>This option represents the value that is passed to filter plugin in pipe format.</div>
|
||||
<div>For example <em>config_data|ansible.utils.to_paths(</em>), in this case <em>config_data</em> represents this option.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>wantlist</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li>no</li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>If set to <code>True</code>, the return value will always be a list.</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#### Simple examples
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths }}"
|
||||
|
||||
# TASK [ansible.builtin.set_fact] ********************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
# b.c.e[1]: false
|
||||
|
||||
- name: Use prepend to add the initial variable name
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
|
||||
# TASK [Use prepend to add the initial variable name] **************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
|
||||
#### Using a complex object
|
||||
|
||||
- name: Make an API call
|
||||
uri:
|
||||
url: "https://nxos101/restconf/data/openconfig-interfaces:interfaces"
|
||||
headers:
|
||||
accept: "application/yang.data+json"
|
||||
url_password: password
|
||||
url_username: admin
|
||||
validate_certs: False
|
||||
register: result
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Flatten the complex object
|
||||
set_fact:
|
||||
paths: "{{ result.json|ansible.utils.to_paths }}"
|
||||
|
||||
# TASK [Flatten the complex object] ******************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# interfaces.interface[0].config.enabled: 'true'
|
||||
# interfaces.interface[0].config.mtu: '1500'
|
||||
# interfaces.interface[0].config.name: eth1/71
|
||||
# interfaces.interface[0].config.type: ethernetCsmacd
|
||||
# interfaces.interface[0].ethernet.config['auto-negotiate']: 'true'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-crc-errors']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-fragment-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-jabber-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-mac-control-frames']: '0'
|
||||
# <...>
|
||||
|
||||
|
||||
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
- Bradley Thornton (@cidrblock)
|
||||
|
||||
|
||||
.. hint::
|
||||
Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
|
|
@ -118,19 +118,12 @@ Examples
|
|||
- False
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.to_paths', a) }}"
|
||||
as_filter: "{{ a|ansible.utils.to_paths }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a) }}"
|
||||
|
||||
# TASK [set_fact] *****************************************************
|
||||
# task path: /home/brad/github/dotbracket/site.yaml:17
|
||||
# ok: [localhost] => changed=false
|
||||
# TASK [ansible.builtin.set_fact] ********************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
# b.c.e[1]: false
|
||||
# as_lookup:
|
||||
# paths:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
|
@ -138,18 +131,12 @@ Examples
|
|||
|
||||
- name: Use prepend to add the initial variable name
|
||||
ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.to_paths', a, prepend=('a')) }}"
|
||||
as_filter: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a, prepend='a') }}"
|
||||
|
||||
# TASK [Use prepend to add the initial variable name] *****************
|
||||
# TASK [Use prepend to add the initial variable name] **************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
# as_lookup:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
|
@ -171,12 +158,12 @@ Examples
|
|||
|
||||
- name: Flatten the complex object
|
||||
set_fact:
|
||||
flattened: "{{ result.json|ansible.utils.to_paths }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', result.json) }}"
|
||||
|
||||
# TASK [Flatten the complex object] ********************
|
||||
# TASK [Flatten the complex object] ******************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# flattened:
|
||||
# paths:
|
||||
# interfaces.interface[0].config.enabled: 'true'
|
||||
# interfaces.interface[0].config.mtu: '1500'
|
||||
# interfaces.interface[0].config.name: eth1/71
|
||||
|
@ -185,6 +172,8 @@ Examples
|
|||
# interfaces.interface[0].ethernet.state.counters['in-crc-errors']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-fragment-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-jabber-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-mac-control-frames']: '0'
|
||||
# <...>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -11,15 +11,148 @@ from __future__ import absolute_import, division, print_function
|
|||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
filter: get_path
|
||||
author: Bradley Thornton (@cidrblock)
|
||||
version_added: "1.0"
|
||||
short_description: Retrieve the value in a variable using a path
|
||||
description:
|
||||
- Use a C(path) to retreive a nested value from a C(var)
|
||||
- C(get_path) is also available as a C(lookup plugin) for convenience
|
||||
options:
|
||||
var:
|
||||
description:
|
||||
- The variable from which the value should be extraced
|
||||
- This option represents the value that is passed to filter plugin in pipe format.
|
||||
- For example I(config_data|ansible.utils.get_path()), in this case I(config_data) represents this option.
|
||||
type: raw
|
||||
required: True
|
||||
path:
|
||||
description:
|
||||
- The C(path) in the C(var) to retrieve the value of.
|
||||
- The C(path) needs to a be a valid jinja path
|
||||
type: str
|
||||
required: True
|
||||
wantlist:
|
||||
description:
|
||||
- If set to C(True), the return value will always be a list
|
||||
type: bool
|
||||
|
||||
notes:
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- name: Retrieve a value deep inside a using a path
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ a|ansible.utils.get_path(path) }}"
|
||||
vars:
|
||||
path: b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside a using a path] ******************
|
||||
# ok: [localhost] => changed=false
|
||||
# ansible_facts:
|
||||
# value: '0'
|
||||
|
||||
|
||||
#### Working with hostvars
|
||||
|
||||
- name: Retrieve a value deep inside all of the host's vars
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ look_in|ansible.utils.get_path(look_for) }}"
|
||||
vars:
|
||||
look_in: "{{ hostvars[inventory_hostname] }}"
|
||||
look_for: a.b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] ********
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
# as_lookup: '0'
|
||||
|
||||
|
||||
#### Used alongside ansible.utils.to_paths
|
||||
|
||||
- name: Get the paths for the object
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
|
||||
- name: Retrieve the value of each path from vars
|
||||
ansible.builtin.debug:
|
||||
msg: "The value of path {{ path }} in vars is {{ value }}"
|
||||
loop: "{{ paths.keys()|list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
vars:
|
||||
path: "{{ item }}"
|
||||
value: "{{ vars|ansible.utils.get_path(item) }}"
|
||||
|
||||
# TASK [Get the paths for the object] *******************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
# TASK [Retrieve the value of each path from vars] ******************
|
||||
# ok: [nxos101] => (item=a.b.c.d[0]) =>
|
||||
# msg: The value of path a.b.c.d[0] in vars is 0
|
||||
# ok: [nxos101] => (item=a.b.c.d[1]) =>
|
||||
# msg: The value of path a.b.c.d[1] in vars is 1
|
||||
# ok: [nxos101] => (item=a.b.c.e[0]) =>
|
||||
# msg: The value of path a.b.c.e[0] in vars is True
|
||||
# ok: [nxos101] => (item=a.b.c.e[1]) =>
|
||||
# msg: The value of path a.b.c.e[1] in vars is False
|
||||
|
||||
|
||||
#### Working with complex structures and transforming results
|
||||
|
||||
- name: Retrieve the current interface config
|
||||
cisco.nxos.nxos_interfaces:
|
||||
state: gathered
|
||||
register: interfaces
|
||||
|
||||
- name: Get the description of several interfaces
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ rekeyed|ansible.utils.get_path(item) }}"
|
||||
vars:
|
||||
rekeyed:
|
||||
by_name: "{{ interfaces.gathered|ansible.builtin.rekey_on_member('name') }}"
|
||||
loop:
|
||||
- by_name['Ethernet1/1'].description
|
||||
- by_name['Ethernet1/2'].description|upper
|
||||
- by_name['Ethernet1/3'].description|default('')
|
||||
|
||||
|
||||
# TASK [Get the description of several interfaces] ******************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) => changed=false
|
||||
# msg: Configured by ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description|upper) => changed=false
|
||||
# msg: CONFIGURED BY ANSIBLE
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/3'].description|default('')) => changed=false
|
||||
# msg: ''
|
||||
|
||||
"""
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from jinja2.filters import environmentfilter
|
||||
|
||||
from ansible_collections.ansible.utils.plugins.module_utils.common.get_path import (
|
||||
get_path,
|
||||
)
|
||||
from ansible_collections.ansible.utils.plugins.lookup.get_path import (
|
||||
DOCUMENTATION,
|
||||
)
|
||||
|
||||
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
|
||||
AnsibleArgSpecValidator,
|
||||
)
|
||||
|
@ -27,7 +160,7 @@ from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_valid
|
|||
|
||||
@environmentfilter
|
||||
def _get_path(*args, **kwargs):
|
||||
"""Retrieve the value in a variable using a path. [See examples](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.get_path_lookup.rst)"""
|
||||
"""Retrieve the value in a variable using a path."""
|
||||
keys = ["environment", "var", "path"]
|
||||
data = dict(zip(keys, args))
|
||||
data.update(kwargs)
|
||||
|
|
|
@ -11,14 +11,293 @@ from __future__ import absolute_import, division, print_function
|
|||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
filter: index_of
|
||||
author: Bradley Thornton (@cidrblock)
|
||||
version_added: "1.0"
|
||||
short_description: Find the indicies of items in a list matching some criteria
|
||||
description:
|
||||
- This plugin returns the indicies of items matching some criteria in a list
|
||||
- When working with a list of dictionaries, the key to evaluate can be specified
|
||||
- C(index_of) is also available as a C(lookup plugin) for convenience
|
||||
options:
|
||||
data:
|
||||
description:
|
||||
- A list of items to enumerate and test against
|
||||
- This option represents the value that is passed to filter plugin in pipe format.
|
||||
- For example I(config_data|ansible.utils.index_of('x')), in this case I(config_data) represents this option.
|
||||
type: list
|
||||
required: True
|
||||
test:
|
||||
description:
|
||||
- The name of the test to run against the list, a valid jinja2 test or ansible test plugin.
|
||||
- Jinja2 includes the following tests U(http://jinja.palletsprojects.com/templates/#builtin-tests).
|
||||
- An overview of tests included in ansible U(https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html)
|
||||
type: str
|
||||
required: True
|
||||
value:
|
||||
description:
|
||||
- The value used to test each list item against
|
||||
- Not required for simple tests (eg: C(true), C(false), C(even), C(odd))
|
||||
- May be a C(string), C(boolean), C(number), C(regular expesion) C(dict) etc, depending on the C(test) used
|
||||
type: raw
|
||||
key:
|
||||
description:
|
||||
- When the data provided is a list of dictionaries, run the test againt this dictionary key
|
||||
- When using a C(key), the C(data) must only contain dictionaries
|
||||
- See C(fail_on_missing) below to determine the behaviour when the C(key) is missing from a dictionary in the C(data)
|
||||
type: str
|
||||
fail_on_missing:
|
||||
description: When provided a list of dictionaries, fail if the key is missing from one or more of the dictionaries
|
||||
type: bool
|
||||
wantlist:
|
||||
description:
|
||||
- When only a single entry in the C(data) is matched, that entries index is returned as an integer
|
||||
- If set to C(True), the return value will always be a list, even if only a single entry is matched
|
||||
type: bool
|
||||
|
||||
notes:
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
|
||||
#### Simple examples
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
- name: Find the index of 2
|
||||
set_fact:
|
||||
indices: "{{ data|ansible.utils.index_of('eq', 2) }}"
|
||||
|
||||
# TASK [Find the index of 2] *************************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices: '1'
|
||||
|
||||
|
||||
- name: Find the index of 2, ensure list is returned
|
||||
set_fact:
|
||||
indices: "{{ data|ansible.utils.index_of('eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Find the index of 2, ensure list is returned] ************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices:
|
||||
# - 1
|
||||
|
||||
|
||||
- name: Find the index of 3 using the long format
|
||||
set_fact:
|
||||
indices: "{{ data|ansible.utils.index_of(test='eq', value=value, wantlist=True) }}"
|
||||
vars:
|
||||
value: 3
|
||||
|
||||
# TASK [Find the index of 3 using the long format] ***************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices:
|
||||
# - 2
|
||||
|
||||
|
||||
- name: Find numbers greater than 1, using loop
|
||||
debug:
|
||||
msg: "{{ data[item] }} is {{ test }} than {{ value }}"
|
||||
loop: "{{ data|ansible.utils.index_of(test, value) }}"
|
||||
vars:
|
||||
test: '>'
|
||||
value: 1
|
||||
|
||||
# TASK [Find numbers great than 1, using loop] *******************************
|
||||
# ok: [sw01] => (item=1) =>
|
||||
# msg: 2 is > than 1
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# msg: 3 is > than 1
|
||||
|
||||
|
||||
#### Working with lists of dictionaries
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
- name: sw01.example.lan
|
||||
type: switch
|
||||
- name: rtr01.example.lan
|
||||
type: router
|
||||
- name: fw01.example.corp
|
||||
type: firewall
|
||||
- name: fw02.example.corp
|
||||
type: firewall
|
||||
|
||||
- name: Find the index of all firewalls using the type key
|
||||
set_fact:
|
||||
firewalls: "{{ data|ansible.utils.index_of('eq', 'firewall', 'type') }}"
|
||||
|
||||
# TASK [Find the index of all firewalls using the type key] ******************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# firewalls:
|
||||
# - 2
|
||||
# - 3
|
||||
|
||||
- name: Find the index of all firewalls, use in a loop
|
||||
debug:
|
||||
msg: "The type of {{ device_type }} at index {{ item }} has name {{ data[item].name }}."
|
||||
loop: "{{ data|ansible.utils.index_of('eq', device_type, 'type') }}"
|
||||
vars:
|
||||
device_type: firewall
|
||||
|
||||
# TASK [Find the index of all firewalls, use in a loop, as a filter] *********
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp.
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp.
|
||||
|
||||
- name: Find the index of all devices with a .corp name
|
||||
debug:
|
||||
msg: "The device named {{ data[item].name }} is a {{ data[item].type }}"
|
||||
loop: "{{ data|ansible.utils.index_of('regex', expression, 'name') }}"
|
||||
vars:
|
||||
expression: '\.corp$' # ends with .corp
|
||||
|
||||
# TASK [Find the index of all devices with a .corp name] *********************
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The device named fw01.example.corp is a firewall
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The device named fw02.example.corp is a firewall
|
||||
|
||||
|
||||
#### Working with complex structures from resource modules
|
||||
|
||||
- name: Retrieve the current L3 interface configuration
|
||||
cisco.nxos.nxos_l3_interfaces:
|
||||
state: gathered
|
||||
register: current_l3
|
||||
|
||||
# TASK [Retrieve the current L3 interface configuration] *********************
|
||||
# ok: [sw01] => changed=false
|
||||
# gathered:
|
||||
# - name: Ethernet1/1
|
||||
# - name: Ethernet1/2
|
||||
# <...>
|
||||
# - name: Ethernet1/128
|
||||
# - ipv4:
|
||||
# - address: 192.168.101.14/24
|
||||
# name: mgmt0
|
||||
|
||||
- name: Find the indices interfaces with a 192.168.101.xx ip address
|
||||
set_fact:
|
||||
found: "{{ found + entry }}"
|
||||
with_indexed_items: "{{ current_l3.gathered }}"
|
||||
vars:
|
||||
found: []
|
||||
ip: '192.168.101.'
|
||||
address: "{{ item.1.ipv4|d([])|ansible.utils.index_of('search', ip, 'address', wantlist=True) }}"
|
||||
entry:
|
||||
- interface_idx: "{{ item.0 }}"
|
||||
address_idxs: "{{ address }}"
|
||||
when: address
|
||||
|
||||
# TASK [debug] ***************************************************************
|
||||
# ok: [sw01] =>
|
||||
# found:
|
||||
# - address_idxs:
|
||||
# - 0
|
||||
# interface_idx: '128'
|
||||
|
||||
- name: Show all interfaces and their address
|
||||
debug:
|
||||
msg: "{{ interface.name }} has ip {{ address }}"
|
||||
loop: "{{ found|subelements('address_idxs') }}"
|
||||
vars:
|
||||
interface: "{{ current_l3.gathered[item.0.interface_idx|int] }}"
|
||||
address: "{{ interface.ipv4[item.1].address }}"
|
||||
|
||||
# TASK [Show all interfaces and their address] *******************************
|
||||
# ok: [nxos101] => (item=[{'interface_idx': '128', 'address_idxs': [0]}, 0]) =>
|
||||
# msg: mgmt0 has ip 192.168.101.14/24
|
||||
|
||||
|
||||
#### Working with deeply nested data
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
interfaces:
|
||||
interface:
|
||||
- config:
|
||||
description: configured by Ansible - 1
|
||||
enabled: True
|
||||
loopback-mode: False
|
||||
mtu: 1024
|
||||
name: loopback0000
|
||||
type: eth
|
||||
name: loopback0000
|
||||
subinterfaces:
|
||||
subinterface:
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 1
|
||||
enabled: True
|
||||
index: 5
|
||||
index: 5
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 2
|
||||
enabled: False
|
||||
index: 2
|
||||
index: 2
|
||||
- config:
|
||||
description: configured by Ansible - 2
|
||||
enabled: False
|
||||
loopback-mode: False
|
||||
mtu: 2048
|
||||
name: loopback1111
|
||||
type: virt
|
||||
name: loopback1111
|
||||
subinterfaces:
|
||||
subinterface:
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 3
|
||||
enabled: True
|
||||
index: 10
|
||||
index: 10
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 4
|
||||
enabled: False
|
||||
index: 3
|
||||
index: 3
|
||||
|
||||
|
||||
- name: Find the description of loopback111, subinterface index 10
|
||||
debug:
|
||||
msg: |-
|
||||
{{ data.interfaces.interface[int_idx|int]
|
||||
.subinterfaces.subinterface[subint_idx|int]
|
||||
.config.description }}
|
||||
vars:
|
||||
# the values to search for
|
||||
int_name: loopback1111
|
||||
sub_index: 10
|
||||
# retrieve the index in each nested list
|
||||
int_idx: |
|
||||
{{ data.interfaces.interface|
|
||||
ansible.utils.index_of('eq', int_name, 'name') }}
|
||||
subint_idx: |
|
||||
{{ data.interfaces.interface[int_idx|int]
|
||||
.subinterfaces.subinterface|
|
||||
ansible.utils.index_of('eq', sub_index, 'index') }}
|
||||
|
||||
# TASK [Find the description of loopback111, subinterface index 10] ************
|
||||
# ok: [sw01] =>
|
||||
# msg: subinterface configured by Ansible - 3
|
||||
|
||||
"""
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from jinja2.filters import environmentfilter
|
||||
from ansible_collections.ansible.utils.plugins.module_utils.common.index_of import (
|
||||
index_of,
|
||||
)
|
||||
from ansible_collections.ansible.utils.plugins.lookup.index_of import (
|
||||
DOCUMENTATION,
|
||||
)
|
||||
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
|
||||
AnsibleArgSpecValidator,
|
||||
)
|
||||
|
@ -26,7 +305,7 @@ from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_valid
|
|||
|
||||
@environmentfilter
|
||||
def _index_of(*args, **kwargs):
|
||||
"""Find the indicies of items in a list matching some criteria. [See examples](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.index_of_lookup.rst)"""
|
||||
"""Find the indicies of items in a list matching some criteria."""
|
||||
|
||||
keys = [
|
||||
"environment",
|
||||
|
|
|
@ -12,20 +12,121 @@ from __future__ import absolute_import, division, print_function
|
|||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = """
|
||||
filter: to_paths
|
||||
author: Bradley Thornton (@cidrblock)
|
||||
version_added: "1.0"
|
||||
short_description: Flatten a complex object into a dictionary of paths and values
|
||||
description:
|
||||
- Flatten a complex object into a dictionary of paths and values.
|
||||
- Paths are dot delimited whenever possible
|
||||
- Brakets are used for list indicies and keys that contain special characters
|
||||
- C(to_paths) is also available as a C(lookup plugin) for convenience
|
||||
options:
|
||||
var:
|
||||
description:
|
||||
- The value of C(var) will be will be used.
|
||||
- This option represents the value that is passed to filter plugin in pipe format.
|
||||
- For example I(config_data|ansible.utils.to_paths()), in this case I(config_data) represents this option.
|
||||
type: raw
|
||||
required: True
|
||||
prepend:
|
||||
description: Prepend each path entry. Useful to add the initial C(var) name.
|
||||
type: str
|
||||
required: False
|
||||
wantlist:
|
||||
description:
|
||||
- If set to C(True), the return value will always be a list.
|
||||
type: bool
|
||||
|
||||
notes:
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
|
||||
#### Simple examples
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths }}"
|
||||
|
||||
# TASK [ansible.builtin.set_fact] ********************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
# b.c.e[1]: false
|
||||
|
||||
- name: Use prepend to add the initial variable name
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
|
||||
# TASK [Use prepend to add the initial variable name] **************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
|
||||
#### Using a complex object
|
||||
|
||||
- name: Make an API call
|
||||
uri:
|
||||
url: "https://nxos101/restconf/data/openconfig-interfaces:interfaces"
|
||||
headers:
|
||||
accept: "application/yang.data+json"
|
||||
url_password: password
|
||||
url_username: admin
|
||||
validate_certs: False
|
||||
register: result
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Flatten the complex object
|
||||
set_fact:
|
||||
paths: "{{ result.json|ansible.utils.to_paths }}"
|
||||
|
||||
# TASK [Flatten the complex object] ******************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# interfaces.interface[0].config.enabled: 'true'
|
||||
# interfaces.interface[0].config.mtu: '1500'
|
||||
# interfaces.interface[0].config.name: eth1/71
|
||||
# interfaces.interface[0].config.type: ethernetCsmacd
|
||||
# interfaces.interface[0].ethernet.config['auto-negotiate']: 'true'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-crc-errors']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-fragment-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-jabber-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-mac-control-frames']: '0'
|
||||
# <...>
|
||||
"""
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible_collections.ansible.utils.plugins.module_utils.common.to_paths import (
|
||||
to_paths,
|
||||
)
|
||||
from ansible_collections.ansible.utils.plugins.lookup.to_paths import (
|
||||
DOCUMENTATION,
|
||||
)
|
||||
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
|
||||
AnsibleArgSpecValidator,
|
||||
)
|
||||
|
||||
|
||||
def _to_paths(*args, **kwargs):
|
||||
"""Flatten a complex object into a dictionary of paths and values. [See examples](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.to_paths_lookup.rst)"""
|
||||
"""Flatten a complex object into a dictionary of paths and values."""
|
||||
keys = ["var", "prepend", "wantlist"]
|
||||
data = dict(zip(keys, args))
|
||||
data.update(kwargs)
|
||||
|
|
|
@ -19,7 +19,7 @@ DOCUMENTATION = """
|
|||
short_description: Retrieve the value in a variable using a path
|
||||
description:
|
||||
- Use a C(path) to retreive a nested value from a C(var)
|
||||
- C(get_path) is also available as a C(filter_plugin) for convenience
|
||||
- C(get_path) is also available as a C(filter plugin) for convenience
|
||||
options:
|
||||
var:
|
||||
description: The variable from which the value should be extraced
|
||||
|
@ -55,29 +55,26 @@ EXAMPLES = r"""
|
|||
|
||||
- name: Retrieve a value deep inside a using a path
|
||||
ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.get_path', a, path) }}"
|
||||
as_filter: "{{ a|ansible.utils.get_path(path) }}"
|
||||
value: "{{ lookup('ansible.utils.get_path', a, path) }}"
|
||||
vars:
|
||||
path: b.c.d[0]
|
||||
|
||||
# TASK [ansible.builtin.set_fact] *************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# TASK [Retrieve a value deep inside a using a path] ******************
|
||||
# ok: [localhost] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
# as_lookup: '0'
|
||||
# value: '0'
|
||||
|
||||
|
||||
#### Working with hostvars
|
||||
|
||||
- name: Retrieve a value deep inside all of the host's vars
|
||||
ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.get_path', look_in, look_for) }}"
|
||||
as_filter: "{{ look_in|ansible.utils.get_path(look_for) }}"
|
||||
value: "{{ lookup('ansible.utils.get_path', look_in, look_for) }}"
|
||||
vars:
|
||||
look_in: "{{ hostvars[inventory_hostname] }}"
|
||||
look_for: a.b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] **********
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] ********
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
|
@ -88,7 +85,7 @@ EXAMPLES = r"""
|
|||
|
||||
- name: Get the paths for the object
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a, prepend='a') }}"
|
||||
|
||||
- name: Retrieve the value of each path from vars
|
||||
ansible.builtin.debug:
|
||||
|
@ -98,9 +95,9 @@ EXAMPLES = r"""
|
|||
label: "{{ item }}"
|
||||
vars:
|
||||
path: "{{ item }}"
|
||||
value: "{{ vars|ansible.utils.get_path(item) }}"
|
||||
value: "{{ lookup('ansible.utils.get_path', hostvars[inventory_hostname], item) }}"
|
||||
|
||||
# TASK [Get the paths for the object] *********************************
|
||||
# TASK [Get the paths for the object] *******************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
|
@ -109,7 +106,7 @@ EXAMPLES = r"""
|
|||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
# TASK [Retrieve the value of each path from vars] ********************
|
||||
# TASK [Retrieve the value of each path from vars] ******************
|
||||
# ok: [nxos101] => (item=a.b.c.d[0]) =>
|
||||
# msg: The value of path a.b.c.d[0] in vars is 0
|
||||
# ok: [nxos101] => (item=a.b.c.d[1]) =>
|
||||
|
@ -120,7 +117,7 @@ EXAMPLES = r"""
|
|||
# msg: The value of path a.b.c.e[1] in vars is False
|
||||
|
||||
|
||||
#### Working with complex structures
|
||||
#### Working with complex structures and transforming results
|
||||
|
||||
- name: Retrieve the current interface config
|
||||
cisco.nxos.nxos_interfaces:
|
||||
|
@ -129,19 +126,23 @@ EXAMPLES = r"""
|
|||
|
||||
- name: Get the description of several interfaces
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ rekeyed|ansible.utils.get_path(item) }}"
|
||||
msg: "{{ lookup('ansible.utils.get_path', rekeyed, item) }}"
|
||||
vars:
|
||||
rekeyed:
|
||||
by_name: "{{ interfaces.gathered|ansible.builtin.rekey_on_member('name') }}"
|
||||
loop:
|
||||
- by_name['Ethernet1/1'].description
|
||||
- by_name['Ethernet1/2'].description
|
||||
- by_name['Ethernet1/2'].description|upper
|
||||
- by_name['Ethernet1/3'].description|default('')
|
||||
|
||||
# TASK [Get the description of several interfaces] ********************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) =>
|
||||
# msg: Configured by Ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description) =>
|
||||
# msg: Configured by Ansible Network
|
||||
|
||||
# TASK [Get the description of several interfaces] ******************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) => changed=false
|
||||
# msg: Configured by ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description|upper) => changed=false
|
||||
# msg: CONFIGURED BY ANSIBLE
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/3'].description|default('')) => changed=false
|
||||
# msg: ''
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ DOCUMENTATION = """
|
|||
version_added: "1.0"
|
||||
short_description: Find the indicies of items in a list matching some criteria
|
||||
description:
|
||||
- This lookup returns the indicies of items matching some criteria in a list
|
||||
- This plugin returns the indicies of items matching some criteria in a list
|
||||
- When working with a list of dictionaries, the key to evaluate can be specified
|
||||
- C(index_of) is also available as a C(filter_plugin) for convenience
|
||||
- C(index_of) is also available as a C(filter plugin) for convenience
|
||||
options:
|
||||
data:
|
||||
description: A list of items to enumerate and test against
|
||||
|
@ -61,7 +61,7 @@ DOCUMENTATION = """
|
|||
|
||||
EXAMPLES = r"""
|
||||
|
||||
#### Simple examples using a list of values
|
||||
#### Simple examples
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
|
@ -69,66 +69,41 @@ EXAMPLES = r"""
|
|||
- 2
|
||||
- 3
|
||||
|
||||
- name: Find the index of 2, lookup or filter
|
||||
- name: Find the index of 2
|
||||
set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 2) }}"
|
||||
indices: "{{ lookup('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
|
||||
# TASK [Find the index of 2, lookup or filter] *******************************
|
||||
# ok: [sw01] => changed=false
|
||||
# TASK [Find the index of 2] *************************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '1'
|
||||
# as_lookup: '1'
|
||||
# indices: '1'
|
||||
|
||||
- name: Any test can be negated using not or !
|
||||
- name: Find the index of 2, ensure list is returned
|
||||
set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'not in', [1,2]) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('!in', [1,2]) }}"
|
||||
indices: "{{ lookup('ansible.utils.index_of', data, 'eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Any test can be negated using not or !] ******************************
|
||||
# ok: [localhost] => changed=false
|
||||
# TASK [Find the index of 2, ensure list is returned] ************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '2'
|
||||
# as_lookup: '2'
|
||||
|
||||
- name: Find the index of 2, lookup or filter, ensure list is returned
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 2, wantlist=True) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Find the index of 2, lookup or filter, ensure list is returned] ******
|
||||
# ok: [sw01] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 1
|
||||
# as_lookup:
|
||||
# - 1
|
||||
# as_query:
|
||||
# indices:
|
||||
# - 1
|
||||
|
||||
- name: Find the index of 3 using the long format
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data=data, test='eq', value=value) }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data=data, test='eq',value =value, wantlist=True) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of(test='eq', value=value, wantlist=True) }}"
|
||||
indices: "{{ lookup('ansible.utils.index_of', data=data, test='eq', value=value, wantlist=True) }}"
|
||||
vars:
|
||||
value: 3
|
||||
|
||||
# TASK [Find the index of 3 using the long format] ***************************
|
||||
# ok: [sw01] => changed=false
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 2
|
||||
# as_lookup:
|
||||
# - 2
|
||||
# as_query:
|
||||
# indices:
|
||||
# - 2
|
||||
|
||||
- name: Find numbers greater than 1, using loop
|
||||
debug:
|
||||
msg: "{{ data[item] }} is {{ test }} than {{ value }}"
|
||||
loop: "{{ data|ansible.utils.index_of(test, value) }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, test, value) }}"
|
||||
vars:
|
||||
test: '>'
|
||||
value: 1
|
||||
|
@ -150,13 +125,12 @@ EXAMPLES = r"""
|
|||
value: 1
|
||||
|
||||
# TASK [Find numbers greater than 1, using with] *****************************
|
||||
# ok: [sw01] => (item=1) =>
|
||||
# ok: [nxos101] => (item=1) =>
|
||||
# msg: 2 is > than 1
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: 3 is > than 1
|
||||
|
||||
|
||||
|
||||
#### Working with lists of dictionaries
|
||||
|
||||
- set_fact:
|
||||
|
@ -172,52 +146,43 @@ EXAMPLES = r"""
|
|||
|
||||
- name: Find the index of all firewalls using the type key
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 'firewall', 'type') }}"
|
||||
firewalls: "{{ lookup('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
|
||||
# TASK [Find the index of all firewalls using the type key] ******************
|
||||
# ok: [sw01] => changed=false
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 2
|
||||
# - 3
|
||||
# as_lookup:
|
||||
# - 2
|
||||
# - 3
|
||||
# as_query:
|
||||
# firewalls:
|
||||
# - 2
|
||||
# - 3
|
||||
|
||||
- name: Find the index of all firewalls, use in a loop, as a filter
|
||||
- name: Find the index of all firewalls, use in a loop
|
||||
debug:
|
||||
msg: "The type of {{ device_type }} at index {{ item }} has name {{ data[item].name }}."
|
||||
loop: "{{ data|ansible.utils.index_of('eq', device_type, 'type') }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'eq', device_type, 'type') }}"
|
||||
vars:
|
||||
device_type: firewall
|
||||
|
||||
# TASK [Find the index of all firewalls, use in a loop] **********************
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp
|
||||
# ok: [sw01] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp
|
||||
# TASK [Find the index of all firewalls, use in a loop, as a filter] *********
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp.
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp.
|
||||
|
||||
- name: Find the index of all devices with a .corp name, as a lookup
|
||||
- name: Find the index of all devices with a .corp name
|
||||
debug:
|
||||
msg: "The device named {{ data[item].name }} is a {{ data[item].type }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'regex', regex, 'name') }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'regex', expression, 'name') }}"
|
||||
vars:
|
||||
regex: '\.corp$' # ends with .corp
|
||||
expression: '\.corp$' # ends with .corp
|
||||
|
||||
# TASK [Find the index of all devices with a .corp name, as a lookup] **********
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# TASK [Find the index of all devices with a .corp name] *********************
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The device named fw01.example.corp is a firewall
|
||||
# ok: [sw01] => (item=3) =>
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The device named fw02.example.corp is a firewall
|
||||
|
||||
|
||||
|
||||
#### Working with data from resource modules
|
||||
#### Working with complex structures from resource modules
|
||||
|
||||
- name: Retrieve the current L3 interface configuration
|
||||
cisco.nxos.nxos_l3_interfaces:
|
||||
|
@ -235,14 +200,14 @@ EXAMPLES = r"""
|
|||
# - address: 192.168.101.14/24
|
||||
# name: mgmt0
|
||||
|
||||
- name: Find the index of the interface and address with a 192.168.101.xx ip address
|
||||
- name: Find the indices interfaces with a 192.168.101.xx ip address
|
||||
set_fact:
|
||||
found: "{{ found + entry }}"
|
||||
with_indexed_items: "{{ current_l3.gathered }}"
|
||||
vars:
|
||||
found: []
|
||||
ip: '192.168.101.'
|
||||
address: "{{ item.1.ipv4|d([])|ansible.utils.index_of('search', ip, 'address', wantlist=True) }}"
|
||||
address: "{{ lookup('ansible.utils.index_of', item.1.ipv4|d([]), 'search', ip, 'address', wantlist=True) }}"
|
||||
entry:
|
||||
- interface_idx: "{{ item.0 }}"
|
||||
address_idxs: "{{ address }}"
|
||||
|
@ -263,13 +228,12 @@ EXAMPLES = r"""
|
|||
interface: "{{ current_l3.gathered[item.0.interface_idx|int] }}"
|
||||
address: "{{ interface.ipv4[item.1].address }}"
|
||||
|
||||
# TASK [debug] ***************************************************************
|
||||
# ok: [sw01] => (item=[{'interface_idx': '128', 'address_idx': [0]}, 0]) =>
|
||||
# TASK [Show all interfaces and their address] *******************************
|
||||
# ok: [nxos101] => (item=[{'interface_idx': '128', 'address_idxs': [0]}, 0]) =>
|
||||
# msg: mgmt0 has ip 192.168.101.14/24
|
||||
|
||||
|
||||
|
||||
#### Working with complex structures
|
||||
#### Working with deeply nested data
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
|
@ -329,19 +293,17 @@ EXAMPLES = r"""
|
|||
sub_index: 10
|
||||
# retrieve the index in each nested list
|
||||
int_idx: |
|
||||
{{ data.interfaces.interface|
|
||||
ansible.utils.index_of('eq', int_name, 'name') }}
|
||||
{{ lookup('ansible.utils.index_of',
|
||||
data.interfaces.interface,
|
||||
'eq', int_name, 'name') }}
|
||||
subint_idx: |
|
||||
{{ data.interfaces.interface[int_idx|int]
|
||||
.subinterfaces.subinterface|
|
||||
ansible.utils.index_of('eq', sub_index, 'index') }}
|
||||
{{ lookup('ansible.utils.index_of',
|
||||
data.interfaces.interface[int_idx|int].subinterfaces.subinterface,
|
||||
'eq', sub_index, 'index') }}
|
||||
|
||||
# TASK [Find the description of loopback111, subinterface index 10] ************
|
||||
# ok: [sw01] =>
|
||||
# msg: subinterface configured by Ansible - 3
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
|
|
|
@ -57,19 +57,12 @@ EXAMPLES = r"""
|
|||
- False
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.to_paths', a) }}"
|
||||
as_filter: "{{ a|ansible.utils.to_paths }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a) }}"
|
||||
|
||||
# TASK [set_fact] *****************************************************
|
||||
# task path: /home/brad/github/dotbracket/site.yaml:17
|
||||
# ok: [localhost] => changed=false
|
||||
# TASK [ansible.builtin.set_fact] ********************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
# b.c.e[1]: false
|
||||
# as_lookup:
|
||||
# paths:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
|
@ -77,18 +70,12 @@ EXAMPLES = r"""
|
|||
|
||||
- name: Use prepend to add the initial variable name
|
||||
ansible.builtin.set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.to_paths', a, prepend=('a')) }}"
|
||||
as_filter: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a, prepend='a') }}"
|
||||
|
||||
# TASK [Use prepend to add the initial variable name] *****************
|
||||
# TASK [Use prepend to add the initial variable name] **************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
# as_lookup:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
|
@ -110,12 +97,12 @@ EXAMPLES = r"""
|
|||
|
||||
- name: Flatten the complex object
|
||||
set_fact:
|
||||
flattened: "{{ result.json|ansible.utils.to_paths }}"
|
||||
paths: "{{ lookup('ansible.utils.to_paths', result.json) }}"
|
||||
|
||||
# TASK [Flatten the complex object] ********************
|
||||
# TASK [Flatten the complex object] ******************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# flattened:
|
||||
# paths:
|
||||
# interfaces.interface[0].config.enabled: 'true'
|
||||
# interfaces.interface[0].config.mtu: '1500'
|
||||
# interfaces.interface[0].config.name: eth1/71
|
||||
|
@ -124,7 +111,8 @@ EXAMPLES = r"""
|
|||
# interfaces.interface[0].ethernet.state.counters['in-crc-errors']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-fragment-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-jabber-frames']: '0'
|
||||
|
||||
# interfaces.interface[0].ethernet.state.counters['in-mac-control-frames']: '0'
|
||||
# <...>
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- name: Retrieve a value deep inside a using a path
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ a|ansible.utils.get_path(path) }}"
|
||||
vars:
|
||||
path: b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside a using a path] ******************
|
||||
# ok: [localhost] => changed=false
|
||||
# ansible_facts:
|
||||
# value: '0'
|
||||
|
||||
|
||||
#### Working with hostvars
|
||||
|
||||
- name: Retrieve a value deep inside all of the host's vars
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ look_in|ansible.utils.get_path(look_for) }}"
|
||||
vars:
|
||||
look_in: "{{ hostvars[inventory_hostname] }}"
|
||||
look_for: a.b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] ********
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
# as_lookup: '0'
|
||||
|
||||
|
||||
#### Used alongside ansible.utils.to_paths
|
||||
|
||||
- name: Get the paths for the object
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
|
||||
- name: Retrieve the value of each path from vars
|
||||
ansible.builtin.debug:
|
||||
msg: "The value of path {{ path }} in vars is {{ value }}"
|
||||
loop: "{{ paths.keys()|list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
vars:
|
||||
path: "{{ item }}"
|
||||
value: "{{ vars|ansible.utils.get_path(item) }}"
|
||||
|
||||
# TASK [Get the paths for the object] *******************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
# TASK [Retrieve the value of each path from vars] ******************
|
||||
# ok: [nxos101] => (item=a.b.c.d[0]) =>
|
||||
# msg: The value of path a.b.c.d[0] in vars is 0
|
||||
# ok: [nxos101] => (item=a.b.c.d[1]) =>
|
||||
# msg: The value of path a.b.c.d[1] in vars is 1
|
||||
# ok: [nxos101] => (item=a.b.c.e[0]) =>
|
||||
# msg: The value of path a.b.c.e[0] in vars is True
|
||||
# ok: [nxos101] => (item=a.b.c.e[1]) =>
|
||||
# msg: The value of path a.b.c.e[1] in vars is False
|
||||
|
||||
|
||||
#### Working with complex structures and transforming results
|
||||
|
||||
# - name: Retrieve the current interface config
|
||||
# cisco.nxos.nxos_interfaces:
|
||||
# state: gathered
|
||||
# register: interfaces
|
||||
|
||||
# - name: Get the description of several interfaces
|
||||
# ansible.builtin.debug:
|
||||
# msg: "{{ rekeyed|ansible.utils.get_path(item) }}"
|
||||
# vars:
|
||||
# rekeyed:
|
||||
# by_name: "{{ interfaces.gathered|ansible.builtin.rekey_on_member('name') }}"
|
||||
# loop:
|
||||
# - by_name['Ethernet1/1'].description
|
||||
# - by_name['Ethernet1/2'].description|upper
|
||||
# - by_name['Ethernet1/3'].description|default('')
|
||||
|
||||
|
||||
# TASK [Get the description of several interfaces] ******************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) => changed=false
|
||||
# msg: Configured by ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description|upper) => changed=false
|
||||
# msg: CONFIGURED BY ANSIBLE
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/3'].description|default('')) => changed=false
|
||||
# msg: ''
|
|
@ -0,0 +1,101 @@
|
|||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- name: Retrieve a value deep inside a using a path
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ lookup('ansible.utils.get_path', a, path) }}"
|
||||
vars:
|
||||
path: b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside a using a path] ******************
|
||||
# ok: [localhost] => changed=false
|
||||
# ansible_facts:
|
||||
# value: '0'
|
||||
|
||||
|
||||
#### Working with hostvars
|
||||
|
||||
- name: Retrieve a value deep inside all of the host's vars
|
||||
ansible.builtin.set_fact:
|
||||
value: "{{ lookup('ansible.utils.get_path', look_in, look_for) }}"
|
||||
vars:
|
||||
look_in: "{{ hostvars[inventory_hostname] }}"
|
||||
look_for: a.b.c.d[0]
|
||||
|
||||
# TASK [Retrieve a value deep inside all of the host's vars] ********
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '0'
|
||||
# as_lookup: '0'
|
||||
|
||||
|
||||
#### Used alongside ansible.utils.to_paths
|
||||
|
||||
- name: Get the paths for the object
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a, prepend='a') }}"
|
||||
|
||||
- name: Retrieve the value of each path from vars
|
||||
ansible.builtin.debug:
|
||||
msg: "The value of path {{ path }} in vars is {{ value }}"
|
||||
loop: "{{ paths.keys()|list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
vars:
|
||||
path: "{{ item }}"
|
||||
value: "{{ lookup('ansible.utils.get_path', hostvars[inventory_hostname], item) }}"
|
||||
|
||||
# TASK [Get the paths for the object] *******************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
# TASK [Retrieve the value of each path from vars] ******************
|
||||
# ok: [nxos101] => (item=a.b.c.d[0]) =>
|
||||
# msg: The value of path a.b.c.d[0] in vars is 0
|
||||
# ok: [nxos101] => (item=a.b.c.d[1]) =>
|
||||
# msg: The value of path a.b.c.d[1] in vars is 1
|
||||
# ok: [nxos101] => (item=a.b.c.e[0]) =>
|
||||
# msg: The value of path a.b.c.e[0] in vars is True
|
||||
# ok: [nxos101] => (item=a.b.c.e[1]) =>
|
||||
# msg: The value of path a.b.c.e[1] in vars is False
|
||||
|
||||
|
||||
#### Working with complex structures and transforming results
|
||||
|
||||
# - name: Retrieve the current interface config
|
||||
# cisco.nxos.nxos_interfaces:
|
||||
# state: gathered
|
||||
# register: interfaces
|
||||
|
||||
# - name: Get the description of several interfaces
|
||||
# ansible.builtin.debug:
|
||||
# msg: "{{ lookup('ansible.utils.get_path', rekeyed, item) }}"
|
||||
# vars:
|
||||
# rekeyed:
|
||||
# by_name: "{{ interfaces.gathered|ansible.builtin.rekey_on_member('name') }}"
|
||||
# loop:
|
||||
# - by_name['Ethernet1/1'].description
|
||||
# - by_name['Ethernet1/2'].description|upper
|
||||
# - by_name['Ethernet1/3'].description|default('')
|
||||
|
||||
|
||||
# TASK [Get the description of several interfaces] ******************
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/1'].description) => changed=false
|
||||
# msg: Configured by ansible
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/2'].description|upper) => changed=false
|
||||
# msg: CONFIGURED BY ANSIBLE
|
||||
# ok: [nxos101] => (item=by_name['Ethernet1/3'].description|default('')) => changed=false
|
||||
# msg: ''
|
|
@ -1,7 +1,4 @@
|
|||
# These are the examples for the lookup plugin
|
||||
# here for future use if needed
|
||||
# Note: the cisco example has been commented out
|
||||
# to eliminate a cross collection dependancy
|
||||
#### Simple examples
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
|
@ -9,49 +6,35 @@
|
|||
- 2
|
||||
- 3
|
||||
|
||||
- name: Find the index of 2, lookup or filter
|
||||
- name: Find the index of 2
|
||||
set_fact:
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 2) }}"
|
||||
indices: "{{ data|ansible.utils.index_of('eq', 2) }}"
|
||||
|
||||
# TASK [Find the index of 2, lookup or filter] *******************************
|
||||
# ok: [sw01] => changed=false
|
||||
# TASK [Find the index of 2] *************************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter: '1'
|
||||
# as_lookup: '1'
|
||||
# indices: '1'
|
||||
|
||||
- name: Find the index of 2, lookup or filter, ensure list is returned
|
||||
- name: Find the index of 2, ensure list is returned
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 2, wantlist=True) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 2, wantlist=True) }}"
|
||||
indices: "{{ data|ansible.utils.index_of('eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Find the index of 2, lookup or filter, ensure list is returned] ******
|
||||
# ok: [sw01] => changed=false
|
||||
# TASK [Find the index of 2, ensure list is returned] ************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 1
|
||||
# as_lookup:
|
||||
# - 1
|
||||
# as_query:
|
||||
# indices:
|
||||
# - 1
|
||||
|
||||
- name: Find the index of 3 using the long format
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data=data, test='eq', value=value) }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data=data, test='eq',value =value, wantlist=True) }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of(test='eq', value=value, wantlist=True) }}"
|
||||
indices: "{{ data|ansible.utils.index_of(test='eq', value=value, wantlist=True) }}"
|
||||
vars:
|
||||
value: 3
|
||||
|
||||
# TASK [Find the index of 3 using the long format] ***************************
|
||||
# ok: [sw01] => changed=false
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 2
|
||||
# as_lookup:
|
||||
# - 2
|
||||
# as_query:
|
||||
# indices:
|
||||
# - 2
|
||||
|
||||
- name: Find numbers greater than 1, using loop
|
||||
|
@ -68,16 +51,8 @@
|
|||
# ok: [sw01] => (item=2) =>
|
||||
# msg: 3 is > than 1
|
||||
|
||||
- name: Find numbers greater than 1, using with
|
||||
debug:
|
||||
msg: "{{ data[item] }} is {{ params.test }} than {{ params.value }}"
|
||||
with_ansible.utils.index_of: "{{ params }}"
|
||||
vars:
|
||||
params:
|
||||
data: "{{ data }}"
|
||||
test: '>'
|
||||
value: 1
|
||||
|
||||
#### Working with lists of dictionaries
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
|
@ -92,50 +67,44 @@
|
|||
|
||||
- name: Find the index of all firewalls using the type key
|
||||
set_fact:
|
||||
as_query: "{{ query('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
as_lookup: "{{ lookup('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
as_filter: "{{ data|ansible.utils.index_of('eq', 'firewall', 'type') }}"
|
||||
firewalls: "{{ data|ansible.utils.index_of('eq', 'firewall', 'type') }}"
|
||||
|
||||
# TASK [Find the index of all firewalls using the type key] ******************
|
||||
# ok: [sw01] => changed=false
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# as_filter:
|
||||
# - 2
|
||||
# - 3
|
||||
# as_lookup:
|
||||
# - 2
|
||||
# - 3
|
||||
# as_query:
|
||||
# firewalls:
|
||||
# - 2
|
||||
# - 3
|
||||
|
||||
- name: Find the index of all firewalls, use in a loop, as a filter
|
||||
- name: Find the index of all firewalls, use in a loop
|
||||
debug:
|
||||
msg: "The type of {{ device_type }} at index {{ item }} has name {{ data[item].name }}."
|
||||
loop: "{{ data|ansible.utils.index_of('eq', device_type, 'type') }}"
|
||||
vars:
|
||||
device_type: firewall
|
||||
|
||||
# TASK [Find the index of all firewalls, use in a loop] **********************
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.
|
||||
# ok: [sw01] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.
|
||||
# TASK [Find the index of all firewalls, use in a loop, as a filter] *********
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp.
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp.
|
||||
|
||||
|
||||
- name: Find the index of all devices with a .corp name, as a lookup
|
||||
- name: Find the index of all devices with a .corp name
|
||||
debug:
|
||||
msg: "The device named {{ data[item].name }} is a {{ data[item].type }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'regex', regex, 'name') }}"
|
||||
loop: "{{ data|ansible.utils.index_of('regex', expression, 'name') }}"
|
||||
vars:
|
||||
regex: '\.corp$' # ends with .corp
|
||||
expression: '\.corp$' # ends with .corp
|
||||
|
||||
# TASK [Find the index of all devices with a .corp name, as a lookup] **********
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# TASK [Find the index of all devices with a .corp name] *********************
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The device named fw01.example.corp is a firewall
|
||||
# ok: [sw01] => (item=3) =>
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The device named fw02.example.corp is a firewall
|
||||
|
||||
|
||||
#### Working with complex structures from resource modules
|
||||
|
||||
# - name: Retrieve the current L3 interface configuration
|
||||
# cisco.nxos.nxos_l3_interfaces:
|
||||
# state: gathered
|
||||
|
@ -152,7 +121,7 @@
|
|||
# - address: 192.168.101.14/24
|
||||
# name: mgmt0
|
||||
|
||||
# - name: Find the index of the interface and address with a 192.168.101.xx ip address
|
||||
# - name: Find the indices interfaces with a 192.168.101.xx ip address
|
||||
# set_fact:
|
||||
# found: "{{ found + entry }}"
|
||||
# with_indexed_items: "{{ current_l3.gathered }}"
|
||||
|
@ -180,10 +149,13 @@
|
|||
# interface: "{{ current_l3.gathered[item.0.interface_idx|int] }}"
|
||||
# address: "{{ interface.ipv4[item.1].address }}"
|
||||
|
||||
# TASK [debug] ***************************************************************
|
||||
# ok: [sw01] => (item=[{'interface_idx': '128', 'address_idx': [0]}, 0]) =>
|
||||
# TASK [Show all interfaces and their address] *******************************
|
||||
# ok: [nxos101] => (item=[{'interface_idx': '128', 'address_idxs': [0]}, 0]) =>
|
||||
# msg: mgmt0 has ip 192.168.101.14/24
|
||||
|
||||
|
||||
#### Working with deeply nested data
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
interfaces:
|
|
@ -0,0 +1,243 @@
|
|||
#### Simple examples
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
- name: Find the index of 2
|
||||
set_fact:
|
||||
indices: "{{ lookup('ansible.utils.index_of', data, 'eq', 2) }}"
|
||||
|
||||
# TASK [Find the index of 2] *************************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices: '1'
|
||||
|
||||
- name: Find the index of 2, ensure list is returned
|
||||
set_fact:
|
||||
indices: "{{ lookup('ansible.utils.index_of', data, 'eq', 2, wantlist=True) }}"
|
||||
|
||||
# TASK [Find the index of 2, ensure list is returned] ************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices:
|
||||
# - 1
|
||||
|
||||
- name: Find the index of 3 using the long format
|
||||
set_fact:
|
||||
indices: "{{ lookup('ansible.utils.index_of', data=data, test='eq', value=value, wantlist=True) }}"
|
||||
vars:
|
||||
value: 3
|
||||
|
||||
# TASK [Find the index of 3 using the long format] ***************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# indices:
|
||||
# - 2
|
||||
|
||||
- name: Find numbers greater than 1, using loop
|
||||
debug:
|
||||
msg: "{{ data[item] }} is {{ test }} than {{ value }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, test, value) }}"
|
||||
vars:
|
||||
test: '>'
|
||||
value: 1
|
||||
|
||||
# TASK [Find numbers great than 1, using loop] *******************************
|
||||
# ok: [sw01] => (item=1) =>
|
||||
# msg: 2 is > than 1
|
||||
# ok: [sw01] => (item=2) =>
|
||||
# msg: 3 is > than 1
|
||||
|
||||
- name: Find numbers greater than 1, using with
|
||||
debug:
|
||||
msg: "{{ data[item] }} is {{ params.test }} than {{ params.value }}"
|
||||
with_ansible.utils.index_of: "{{ params }}"
|
||||
vars:
|
||||
params:
|
||||
data: "{{ data }}"
|
||||
test: '>'
|
||||
value: 1
|
||||
|
||||
# TASK [Find numbers greater than 1, using with] *****************************
|
||||
# ok: [nxos101] => (item=1) =>
|
||||
# msg: 2 is > than 1
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: 3 is > than 1
|
||||
|
||||
|
||||
#### Working with lists of dictionaries
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
- name: sw01.example.lan
|
||||
type: switch
|
||||
- name: rtr01.example.lan
|
||||
type: router
|
||||
- name: fw01.example.corp
|
||||
type: firewall
|
||||
- name: fw02.example.corp
|
||||
type: firewall
|
||||
|
||||
- name: Find the index of all firewalls using the type key
|
||||
set_fact:
|
||||
firewalls: "{{ lookup('ansible.utils.index_of', data, 'eq', 'firewall', 'type') }}"
|
||||
|
||||
# TASK [Find the index of all firewalls using the type key] ******************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# firewalls:
|
||||
# - 2
|
||||
# - 3
|
||||
|
||||
- name: Find the index of all firewalls, use in a loop
|
||||
debug:
|
||||
msg: "The type of {{ device_type }} at index {{ item }} has name {{ data[item].name }}."
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'eq', device_type, 'type') }}"
|
||||
vars:
|
||||
device_type: firewall
|
||||
|
||||
# TASK [Find the index of all firewalls, use in a loop, as a filter] *********
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The type of firewall at index 2 has name fw01.example.corp.
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The type of firewall at index 3 has name fw02.example.corp.
|
||||
|
||||
- name: Find the index of all devices with a .corp name
|
||||
debug:
|
||||
msg: "The device named {{ data[item].name }} is a {{ data[item].type }}"
|
||||
loop: "{{ lookup('ansible.utils.index_of', data, 'regex', expression, 'name') }}"
|
||||
vars:
|
||||
expression: '\.corp$' # ends with .corp
|
||||
|
||||
# TASK [Find the index of all devices with a .corp name] *********************
|
||||
# ok: [nxos101] => (item=2) =>
|
||||
# msg: The device named fw01.example.corp is a firewall
|
||||
# ok: [nxos101] => (item=3) =>
|
||||
# msg: The device named fw02.example.corp is a firewall
|
||||
|
||||
|
||||
#### Working with complex structures from resource modules
|
||||
|
||||
# - name: Retrieve the current L3 interface configuration
|
||||
# cisco.nxos.nxos_l3_interfaces:
|
||||
# state: gathered
|
||||
# register: current_l3
|
||||
|
||||
# TASK [Retrieve the current L3 interface configuration] *********************
|
||||
# ok: [sw01] => changed=false
|
||||
# gathered:
|
||||
# - name: Ethernet1/1
|
||||
# - name: Ethernet1/2
|
||||
# <...>
|
||||
# - name: Ethernet1/128
|
||||
# - ipv4:
|
||||
# - address: 192.168.101.14/24
|
||||
# name: mgmt0
|
||||
|
||||
# - name: Find the indices interfaces with a 192.168.101.xx ip address
|
||||
# set_fact:
|
||||
# found: "{{ found + entry }}"
|
||||
# with_indexed_items: "{{ current_l3.gathered }}"
|
||||
# vars:
|
||||
# found: []
|
||||
# ip: '192.168.101.'
|
||||
# address: "{{ lookup('ansible.utils.index_of', item.1.ipv4|d([]), 'search', ip, 'address', wantlist=True) }}"
|
||||
# entry:
|
||||
# - interface_idx: "{{ item.0 }}"
|
||||
# address_idxs: "{{ address }}"
|
||||
# when: address
|
||||
|
||||
# TASK [debug] ***************************************************************
|
||||
# ok: [sw01] =>
|
||||
# found:
|
||||
# - address_idxs:
|
||||
# - 0
|
||||
# interface_idx: '128'
|
||||
|
||||
# - name: Show all interfaces and their address
|
||||
# debug:
|
||||
# msg: "{{ interface.name }} has ip {{ address }}"
|
||||
# loop: "{{ found|subelements('address_idxs') }}"
|
||||
# vars:
|
||||
# interface: "{{ current_l3.gathered[item.0.interface_idx|int] }}"
|
||||
# address: "{{ interface.ipv4[item.1].address }}"
|
||||
|
||||
# TASK [Show all interfaces and their address] *******************************
|
||||
# ok: [nxos101] => (item=[{'interface_idx': '128', 'address_idxs': [0]}, 0]) =>
|
||||
# msg: mgmt0 has ip 192.168.101.14/24
|
||||
|
||||
|
||||
#### Working with deeply nested data
|
||||
|
||||
- set_fact:
|
||||
data:
|
||||
interfaces:
|
||||
interface:
|
||||
- config:
|
||||
description: configured by Ansible - 1
|
||||
enabled: True
|
||||
loopback-mode: False
|
||||
mtu: 1024
|
||||
name: loopback0000
|
||||
type: eth
|
||||
name: loopback0000
|
||||
subinterfaces:
|
||||
subinterface:
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 1
|
||||
enabled: True
|
||||
index: 5
|
||||
index: 5
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 2
|
||||
enabled: False
|
||||
index: 2
|
||||
index: 2
|
||||
- config:
|
||||
description: configured by Ansible - 2
|
||||
enabled: False
|
||||
loopback-mode: False
|
||||
mtu: 2048
|
||||
name: loopback1111
|
||||
type: virt
|
||||
name: loopback1111
|
||||
subinterfaces:
|
||||
subinterface:
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 3
|
||||
enabled: True
|
||||
index: 10
|
||||
index: 10
|
||||
- config:
|
||||
description: subinterface configured by Ansible - 4
|
||||
enabled: False
|
||||
index: 3
|
||||
index: 3
|
||||
|
||||
|
||||
- name: Find the description of loopback111, subinterface index 10
|
||||
debug:
|
||||
msg: |-
|
||||
{{ data.interfaces.interface[int_idx|int]
|
||||
.subinterfaces.subinterface[subint_idx|int]
|
||||
.config.description }}
|
||||
vars:
|
||||
# the values to search for
|
||||
int_name: loopback1111
|
||||
sub_index: 10
|
||||
# retrieve the index in each nested list
|
||||
int_idx: |
|
||||
{{ lookup('ansible.utils.index_of',
|
||||
data.interfaces.interface,
|
||||
'eq', int_name, 'name') }}
|
||||
subint_idx: |
|
||||
{{ lookup('ansible.utils.index_of',
|
||||
data.interfaces.interface[int_idx|int].subinterfaces.subinterface,
|
||||
'eq', sub_index, 'index') }}
|
||||
|
||||
# TASK [Find the description of loopback111, subinterface index 10] ************
|
||||
# ok: [sw01] =>
|
||||
# msg: subinterface configured by Ansible - 3
|
|
@ -0,0 +1,70 @@
|
|||
#### Simple examples
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths }}"
|
||||
|
||||
# TASK [ansible.builtin.set_fact] ********************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
# b.c.e[1]: false
|
||||
|
||||
- name: Use prepend to add the initial variable name
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ a|ansible.utils.to_paths(prepend='a') }}"
|
||||
|
||||
# TASK [Use prepend to add the initial variable name] **************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
|
||||
#### Using a complex object
|
||||
|
||||
# - name: Make an API call
|
||||
# uri:
|
||||
# url: "https://nxos101/restconf/data/openconfig-interfaces:interfaces"
|
||||
# headers:
|
||||
# accept: "application/yang.data+json"
|
||||
# url_password: password
|
||||
# url_username: admin
|
||||
# validate_certs: False
|
||||
# register: result
|
||||
# delegate_to: localhost
|
||||
|
||||
# - name: Flatten the complex object
|
||||
# set_fact:
|
||||
# paths: "{{ result.json|ansible.utils.to_paths }}"
|
||||
|
||||
# TASK [Flatten the complex object] ******************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# interfaces.interface[0].config.enabled: 'true'
|
||||
# interfaces.interface[0].config.mtu: '1500'
|
||||
# interfaces.interface[0].config.name: eth1/71
|
||||
# interfaces.interface[0].config.type: ethernetCsmacd
|
||||
# interfaces.interface[0].ethernet.config['auto-negotiate']: 'true'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-crc-errors']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-fragment-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-jabber-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-mac-control-frames']: '0'
|
||||
# <...>
|
|
@ -0,0 +1,70 @@
|
|||
#### Simple examples
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d:
|
||||
- 0
|
||||
- 1
|
||||
e:
|
||||
- True
|
||||
- False
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a) }}"
|
||||
|
||||
# TASK [ansible.builtin.set_fact] ********************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# b.c.d[0]: 0
|
||||
# b.c.d[1]: 1
|
||||
# b.c.e[0]: true
|
||||
# b.c.e[1]: false
|
||||
|
||||
- name: Use prepend to add the initial variable name
|
||||
ansible.builtin.set_fact:
|
||||
paths: "{{ lookup('ansible.utils.to_paths', a, prepend='a') }}"
|
||||
|
||||
# TASK [Use prepend to add the initial variable name] **************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# a.b.c.d[0]: 0
|
||||
# a.b.c.d[1]: 1
|
||||
# a.b.c.e[0]: true
|
||||
# a.b.c.e[1]: false
|
||||
|
||||
|
||||
#### Using a complex object
|
||||
|
||||
# - name: Make an API call
|
||||
# uri:
|
||||
# url: "https://nxos101/restconf/data/openconfig-interfaces:interfaces"
|
||||
# headers:
|
||||
# accept: "application/yang.data+json"
|
||||
# url_password: password
|
||||
# url_username: admin
|
||||
# validate_certs: False
|
||||
# register: result
|
||||
# delegate_to: localhost
|
||||
|
||||
# - name: Flatten the complex object
|
||||
# set_fact:
|
||||
# paths: "{{ lookup('ansible.utils.to_paths', result.json) }}"
|
||||
|
||||
# TASK [Flatten the complex object] ******************************************
|
||||
# ok: [nxos101] => changed=false
|
||||
# ansible_facts:
|
||||
# paths:
|
||||
# interfaces.interface[0].config.enabled: 'true'
|
||||
# interfaces.interface[0].config.mtu: '1500'
|
||||
# interfaces.interface[0].config.name: eth1/71
|
||||
# interfaces.interface[0].config.type: ethernetCsmacd
|
||||
# interfaces.interface[0].ethernet.config['auto-negotiate']: 'true'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-crc-errors']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-fragment-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-jabber-frames']: '0'
|
||||
# interfaces.interface[0].ethernet.state.counters['in-mac-control-frames']: '0'
|
||||
# <...>
|
|
@ -1,4 +1 @@
|
|||
plugins/module_utils/common/index_of.py pylint:ansible-bad-module-import # file's use is limited to filter and lookups on control node
|
||||
plugins/filter/index_of.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
plugins/filter/get_path.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
plugins/filter/to_paths.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
plugins/module_utils/common/index_of.py pylint:ansible-bad-module-import # file's use is limited to filter and lookups on control node
|
||||
plugins/filter/index_of.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
plugins/filter/get_path.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
plugins/filter/to_paths.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
plugins/module_utils/common/index_of.py pylint:ansible-bad-module-import # file's use is limited to filter and lookups on control node
|
||||
plugins/filter/index_of.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
plugins/filter/get_path.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
plugins/filter/to_paths.py pep8:E501 # ignore line length for filter doc string w/ url
|
||||
|
|
Loading…
Reference in New Issue