From f0badf89705d894fdd5c2e93169695baa77845b0 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Mon, 30 Sep 2024 10:38:07 -0400 Subject: [PATCH] Ansible Errors, Don't hide stacked messages when yaml (#83933) (#83999) Also remove redundant msg now that we fixed yaml case So no more need to %s % e. Co-authored-by: Abhijeet Kasurde (cherry picked from commit 0c8efa29b2c1d891f6a2c12f78bc2cdff9b70bd2) --- changelogs/fragments/fix_errors.yml | 2 ++ lib/ansible/errors/__init__.py | 8 ++++++-- lib/ansible/playbook/base.py | 10 +++++----- test/integration/targets/template/tasks/main.yml | 4 +++- 4 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 changelogs/fragments/fix_errors.yml diff --git a/changelogs/fragments/fix_errors.yml b/changelogs/fragments/fix_errors.yml new file mode 100644 index 00000000000..995cc28ffda --- /dev/null +++ b/changelogs/fragments/fix_errors.yml @@ -0,0 +1,2 @@ +bugfixes: + - Errors now preserve stacked error messages even when YAML is involved. diff --git a/lib/ansible/errors/__init__.py b/lib/ansible/errors/__init__.py index 8e33bef120b..c26c06ab26e 100644 --- a/lib/ansible/errors/__init__.py +++ b/lib/ansible/errors/__init__.py @@ -66,14 +66,18 @@ class AnsibleError(Exception): from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject message = [self._message] + + # Add from previous exceptions + if self.orig_exc: + message.append('. %s' % to_native(self.orig_exc)) + + # Add from yaml to give specific file/line no if isinstance(self.obj, AnsibleBaseYAMLObject): extended_error = self._get_extended_error() if extended_error and not self._suppress_extended_error: message.append( '\n\n%s' % to_native(extended_error) ) - elif self.orig_exc: - message.append('. %s' % to_native(self.orig_exc)) return ''.join(message) diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py index df18ecb61ad..e2c97a493e2 100644 --- a/lib/ansible/playbook/base.py +++ b/lib/ansible/playbook/base.py @@ -18,7 +18,7 @@ from ansible import context from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleAssertionError from ansible.module_utils.six import string_types from ansible.module_utils.parsing.convert_bool import boolean -from ansible.module_utils.common.text.converters import to_text, to_native +from ansible.module_utils.common.text.converters import to_text from ansible.parsing.dataloader import DataLoader from ansible.playbook.attribute import Attribute, FieldAttribute, ConnectionFieldAttribute, NonInheritableFieldAttribute from ansible.plugins.loader import module_loader, action_loader @@ -560,14 +560,14 @@ class FieldAttributeBase: setattr(self, name, value) except (TypeError, ValueError) as e: value = getattr(self, name) - raise AnsibleParserError("the field '%s' has an invalid value (%s), and could not be converted to %s. " - "The error was: %s" % (name, value, attribute.isa, e), obj=self.get_ds(), orig_exc=e) + raise AnsibleParserError(f"the field '{name}' has an invalid value ({value!r}), and could not be converted to {attribute.isa}.", + obj=self.get_ds(), orig_exc=e) except (AnsibleUndefinedVariable, UndefinedError) as e: if templar._fail_on_undefined_errors and name != 'name': if name == 'args': - msg = "The task includes an option with an undefined variable. The error was: %s" % (to_native(e)) + msg = "The task includes an option with an undefined variable." else: - msg = "The field '%s' has an invalid value, which includes an undefined variable. The error was: %s" % (name, to_native(e)) + msg = f"The field '{name}' has an invalid value, which includes an undefined variable." raise AnsibleParserError(msg, obj=self.get_ds(), orig_exc=e) self._finalized = True diff --git a/test/integration/targets/template/tasks/main.yml b/test/integration/targets/template/tasks/main.yml index d96941fd32d..8a45494033f 100644 --- a/test/integration/targets/template/tasks/main.yml +++ b/test/integration/targets/template/tasks/main.yml @@ -714,7 +714,9 @@ - name: check that proper error message is emitted when in operator is used assert: - that: "\"The error was: 'y' is undefined\n\n\" in error.msg" + that: + - '"The task includes an option with an undefined variable" in error.msg' + - "\"'y' is undefined\n\n\" in error.msg" - template: src: template_import_macro_globals.j2