Add a get_nested filter

When accessing nested facts, such as in ansible_local sections, guard
statements in the when clause can get quite long, due to having to
repeate the 'in/not in' logic for every key at every level.

The get_nested filter attempts to instead to move the guard into a
single line, making the conditions easier to write and maintain.

As example,

   ('openstack_ansible' not in ansible_local or
    'swift' not in ansible_local['openstack_ansible'] or
    'venv_tag' not in ansible_local['openstack_ansible']['swift'] or
    ansible_local['openstack_ansible']['swift']['venv_tag'] == swift_venv_tag)

 could be rewritten as

     get_nested(ansible_local, 'openstack_ansible.swift.venv_tag') == swift_venv_tag

Change-Id: I3b43c25c8783c43cf5285f2b3e7267b2c5712ea0
This commit is contained in:
Nolan Brubaker 2017-07-06 17:09:14 -04:00
parent ca87421e46
commit 80a1262252
3 changed files with 52 additions and 1 deletions

View File

@ -317,6 +317,34 @@ def git_link_parse_name(repo):
return git_link_parse(repo)['name']
def get_nested(target_dict, keys):
"""Retrieves values through a nested dictionary.
If any key on the path is missing, return None
This helps solves convoluted guards in roles/plays such as the following:
('openstack_ansible' not in ansible_local or
'swift' not in ansible_local['openstack_ansible'] or
'venv_tag' not in ansible_local['openstack_ansible']['swift'] or
ansible_local['openstack_ansible']['swift']['venv_tag'] == swift_venv_tag)
With this filter, it could be instead written:
ansible_local|get_nested('openstack_ansible.swift.venv_tag') == swift_venv_tag
"""
try:
key, next_keys = keys.split('.', 1)
except ValueError:
return target_dict.get(keys, None)
try:
next_dict = target_dict[key]
except KeyError:
return None
return get_nested(next_dict, next_keys)
class FilterModule(object):
"""Ansible jinja2 filters."""
@ -335,5 +363,6 @@ class FilterModule(object):
'filtered_list': filtered_list,
'git_link_parse': git_link_parse,
'git_link_parse_name': git_link_parse_name,
'deprecated': _deprecated
'deprecated': _deprecated,
'get_nested': get_nested
}

View File

@ -0,0 +1,7 @@
---
features:
- The `get_nested` filter has been added, allowing for simplified
value lookups inside of nested dictionaries.
`ansible_local|get_nested('openstack_ansible.swift')`, for example,
will look 2 levels down and return the result.

View File

@ -120,3 +120,18 @@
- name: Validate deprecated filter
assert:
that: "deprecated_value == old_var"
- name: Set test_dict fact
set_fact:
test_dict:
a:
b:
c: d
- name: Validate get_nested returns value
assert:
that: "{{ test_dict|get_nested('a.b.c') == 'd' }}"
- name: Validate get_nested returns None on missing key
assert:
that: "{{ test_dict|get_nested('a.c') == None }}"