summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changelogs/fragments/75131-fix-rekey_on_member-lazy-evaluation.yaml2
-rw-r--r--docs/docsite/rst/dev_guide/developing_plugins.rst25
-rw-r--r--lib/ansible/plugins/filter/mathstuff.py3
-rw-r--r--test/integration/targets/filter_mathstuff/host_vars/localhost.yml1
-rw-r--r--test/integration/targets/filter_mathstuff/tasks/main.yml12
-rw-r--r--test/integration/targets/filter_mathstuff/vars/defined_later.yml3
-rw-r--r--test/integration/targets/filter_mathstuff/vars/main.yml1
7 files changed, 47 insertions, 0 deletions
diff --git a/changelogs/fragments/75131-fix-rekey_on_member-lazy-evaluation.yaml b/changelogs/fragments/75131-fix-rekey_on_member-lazy-evaluation.yaml
new file mode 100644
index 0000000000..23585033f0
--- /dev/null
+++ b/changelogs/fragments/75131-fix-rekey_on_member-lazy-evaluation.yaml
@@ -0,0 +1,2 @@
+bugfixes:
+ - rekey_on_member - handle undefined positional arguments better.
diff --git a/docs/docsite/rst/dev_guide/developing_plugins.rst b/docs/docsite/rst/dev_guide/developing_plugins.rst
index 08aec93f6c..7d941f58b3 100644
--- a/docs/docsite/rst/dev_guide/developing_plugins.rst
+++ b/docs/docsite/rst/dev_guide/developing_plugins.rst
@@ -36,7 +36,10 @@ You should return errors encountered during plugin execution by raising ``Ansibl
except Exception as e:
raise AnsibleError('Something happened, this was original exception: %s' % to_native(e))
+Since Ansible evaluates variables only when they are needed, filter and test plugins should propagate the exceptions ``jinja2.exceptions.UndefinedError`` and ``AnsibleUndefinedVariable`` to ensure undefined variables are only fatal when necessary.
+
Check the different `AnsibleError objects <https://github.com/ansible/ansible/blob/devel/lib/ansible/errors/__init__.py>`_ and see which one applies best to your situation.
+Check the section on the specific plugin type you're developing for type-specific error handling details.
String encoding
===============
@@ -306,6 +309,17 @@ Filter plugins manipulate data. They are a feature of Jinja2 and are also availa
Filter plugins do not use the standard configuration and documentation system described above.
+Since Ansible evaluates variables only when they are needed, filter plugins should propagate the exceptions ``jinja2.exceptions.UndefinedError`` and ``AnsibleUndefinedVariable`` to ensure undefined variables are only fatal when necessary.
+
+.. code-block:: python
+
+ try:
+ cause_an_exception(with_undefined_variable)
+ except jinja2.exceptions.UndefinedError as e:
+ raise AnsibleUndefinedVariable("Something happened, this was the original exception: %s" % to_native(e))
+ except Exception as e:
+ raise AnsibleFilterError("Something happened, this was the original exception: %s" % to_native(e))
+
For example filter plugins, see the source code for the `filter plugins included with Ansible Core <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/filter>`_.
.. _developing_inventory_plugins:
@@ -433,6 +447,17 @@ Test plugins verify data. They are a feature of Jinja2 and are also available in
Test plugins do not use the standard configuration and documentation system described above.
+Since Ansible evaluates variables only when they are needed, test plugins should propagate the exceptions ``jinja2.exceptions.UndefinedError`` and ``AnsibleUndefinedVariable`` to ensure undefined variables are only fatal when necessary.
+
+.. code-block:: python
+
+ try:
+ cause_an_exception(with_undefined_variable)
+ except jinja2.exceptions.UndefinedError as e:
+ raise AnsibleUndefinedVariable("Something happened, this was the original exception: %s" % to_native(e))
+ except Exception as e:
+ raise AnsibleFilterError("Something happened, this was the original exception: %s" % to_native(e))
+
For example test plugins, see the source code for the `test plugins included with Ansible Core <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/test>`_.
.. _developing_vars_plugins:
diff --git a/lib/ansible/plugins/filter/mathstuff.py b/lib/ansible/plugins/filter/mathstuff.py
index 1a54553889..d2ea3f6df5 100644
--- a/lib/ansible/plugins/filter/mathstuff.py
+++ b/lib/ansible/plugins/filter/mathstuff.py
@@ -210,6 +210,9 @@ def rekey_on_member(data, key, duplicates='error'):
new_obj = {}
+ # Ensure the positional args are defined - raise jinja2.exceptions.UndefinedError if not
+ bool(data) and bool(key)
+
if isinstance(data, Mapping):
iterate_over = data.values()
elif isinstance(data, Iterable) and not isinstance(data, (text_type, binary_type)):
diff --git a/test/integration/targets/filter_mathstuff/host_vars/localhost.yml b/test/integration/targets/filter_mathstuff/host_vars/localhost.yml
new file mode 100644
index 0000000000..1f5a9e0319
--- /dev/null
+++ b/test/integration/targets/filter_mathstuff/host_vars/localhost.yml
@@ -0,0 +1 @@
+foo: test
diff --git a/test/integration/targets/filter_mathstuff/tasks/main.yml b/test/integration/targets/filter_mathstuff/tasks/main.yml
index 93a65727f0..019f00e4c2 100644
--- a/test/integration/targets/filter_mathstuff/tasks/main.yml
+++ b/test/integration/targets/filter_mathstuff/tasks/main.yml
@@ -301,6 +301,18 @@
- rekey_on_member_exc5_res is failed
- '"is not unique, cannot correctly turn into dict" in rekey_on_member_exc5_res.msg'
+- name: test undefined positional args for rekey_on_member are properly handled
+ vars:
+ all_vars: "{{ hostvars[inventory_hostname] }}"
+ test_var: "{{ all_vars.foo }}"
+ block:
+ - include_vars:
+ file: defined_later.yml
+ - assert:
+ that: "test_var == 'test'"
+ - assert:
+ that: "rekeyed == {'value': {'test': 'value'}}"
+
# TODO: For some reason, the coverage tool isn't accounting for the last test
# so add another "last test" to fake it...
- assert:
diff --git a/test/integration/targets/filter_mathstuff/vars/defined_later.yml b/test/integration/targets/filter_mathstuff/vars/defined_later.yml
new file mode 100644
index 0000000000..dfb2421b61
--- /dev/null
+++ b/test/integration/targets/filter_mathstuff/vars/defined_later.yml
@@ -0,0 +1,3 @@
+do_rekey:
+ - test: value
+rekeyed: "{{ do_rekey | rekey_on_member(defined_later) }}"
diff --git a/test/integration/targets/filter_mathstuff/vars/main.yml b/test/integration/targets/filter_mathstuff/vars/main.yml
new file mode 100644
index 0000000000..bb61e12ee3
--- /dev/null
+++ b/test/integration/targets/filter_mathstuff/vars/main.yml
@@ -0,0 +1 @@
+defined_later: "{{ test_var }}"