mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
fix combine filter using undefined vars (#55840)
* Check variables are defined before using combine filter * Add tests for the combine filter * Remove dependencies that should already be installed * relocate the function to recursively check for undefined vars add another test * changelog
This commit is contained in:
parent
c4004b5fb1
commit
11279a909d
4 changed files with 53 additions and 0 deletions
|
@ -0,0 +1,2 @@
|
|||
bugfixes:
|
||||
- combine filter - Validate that undefined variables aren't used (https://github.com/ansible/ansible/issues/55810).
|
|
@ -48,6 +48,7 @@ from ansible.module_utils.common.collections import is_sequence
|
|||
from ansible.module_utils.common._collections_compat import Mapping, MutableMapping
|
||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
||||
from ansible.template import recursive_check_defined
|
||||
from ansible.utils.display import Display
|
||||
from ansible.utils.encrypt import passlib_or_crypt
|
||||
from ansible.utils.hashing import md5s, checksum_s
|
||||
|
@ -300,8 +301,10 @@ def combine(*terms, **kwargs):
|
|||
dicts = []
|
||||
for t in terms:
|
||||
if isinstance(t, MutableMapping):
|
||||
recursive_check_defined(t)
|
||||
dicts.append(t)
|
||||
elif isinstance(t, list):
|
||||
recursive_check_defined(t)
|
||||
dicts.append(combine(*t, **kwargs))
|
||||
else:
|
||||
raise AnsibleFilterError("|combine expects dictionaries, got " + repr(t))
|
||||
|
|
|
@ -178,6 +178,20 @@ def _count_newlines_from_end(in_str):
|
|||
return i
|
||||
|
||||
|
||||
def recursive_check_defined(item):
|
||||
from jinja2.runtime import Undefined
|
||||
|
||||
if isinstance(item, MutableMapping):
|
||||
for key in item:
|
||||
recursive_check_defined(item[key])
|
||||
elif isinstance(item, list):
|
||||
for i in item:
|
||||
recursive_check_defined(i)
|
||||
else:
|
||||
if isinstance(item, Undefined):
|
||||
raise AnsibleFilterError("{0} is undefined".format(item))
|
||||
|
||||
|
||||
class AnsibleUndefined(StrictUndefined):
|
||||
'''
|
||||
A custom Undefined class, which returns further Undefined objects on access,
|
||||
|
|
|
@ -277,3 +277,37 @@
|
|||
loop: "{{ hostvars|dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
|
||||
- name: Ensure combining two dictionaries containing undefined variables provides a helpful error
|
||||
block:
|
||||
- set_fact:
|
||||
foo:
|
||||
key1: value1
|
||||
|
||||
- set_fact:
|
||||
combined: "{{ foo | combine({'key2': undef_variable}) }}"
|
||||
ignore_errors: yes
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "result.msg.startswith('The task includes an option with an undefined variable')"
|
||||
|
||||
- set_fact:
|
||||
combined: "{{ foo | combine({'key2': {'nested': [undef_variable]}})}}"
|
||||
ignore_errors: yes
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "result.msg.startswith('The task includes an option with an undefined variable')"
|
||||
|
||||
- set_fact:
|
||||
key2: is_defined
|
||||
|
||||
- set_fact:
|
||||
combined: "{{ foo | combine({'key2': key2}) }}"
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "combined.key2 == 'is_defined'"
|
||||
|
|
Loading…
Reference in a new issue