diff --git a/changelogs/fragments/51136-fix-ansible-inventory-tracebacks.yml b/changelogs/fragments/51136-fix-ansible-inventory-tracebacks.yml new file mode 100644 index 00000000000..6a53b522edb --- /dev/null +++ b/changelogs/fragments/51136-fix-ansible-inventory-tracebacks.yml @@ -0,0 +1,2 @@ +bugfixes: + - Fix bug where some inventory parsing tracebacks were missing or reported under the wrong plugin. diff --git a/lib/ansible/errors/__init__.py b/lib/ansible/errors/__init__.py index 379a7ac3d34..6bbc0e66110 100644 --- a/lib/ansible/errors/__init__.py +++ b/lib/ansible/errors/__init__.py @@ -20,8 +20,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from collections import Sequence -import traceback -import sys from ansible.errors.yaml_strings import ( YAML_COMMON_DICT_ERROR, @@ -70,8 +68,6 @@ class AnsibleError(Exception): if orig_exc: self.orig_exc = orig_exc - self.tb = ''.join(traceback.format_tb(sys.exc_info()[2])) - def __str__(self): return self.message diff --git a/lib/ansible/inventory/manager.py b/lib/ansible/inventory/manager.py index 7bd4abd9ee6..f15adf98e60 100644 --- a/lib/ansible/inventory/manager.py +++ b/lib/ansible/inventory/manager.py @@ -21,8 +21,10 @@ __metaclass__ = type import fnmatch import os +import sys import re import itertools +import traceback from operator import attrgetter from random import shuffle @@ -276,10 +278,12 @@ class InventoryManager(object): break except AnsibleParserError as e: display.debug('%s was not parsable by %s' % (source, plugin_name)) - failures.append({'src': source, 'plugin': plugin_name, 'exc': e}) + tb = ''.join(traceback.format_tb(sys.exc_info()[2])) + failures.append({'src': source, 'plugin': plugin_name, 'exc': e, 'tb': tb}) except Exception as e: - display.debug('%s failed to parse %s' % (plugin_name, source)) - failures.append({'src': source, 'plugin': plugin_name, 'exc': AnsibleError(e)}) + display.debug('%s failed while attempting to parse %s' % (plugin_name, source)) + tb = ''.join(traceback.format_tb(sys.exc_info()[2])) + failures.append({'src': source, 'plugin': plugin_name, 'exc': AnsibleError(e), 'tb': tb}) else: display.v('%s did not meet %s requirements, check plugin documentation if this is unexpected' % (source, plugin_name)) else: @@ -287,8 +291,8 @@ class InventoryManager(object): # only if no plugin processed files should we show errors. for fail in failures: display.warning(u'\n* Failed to parse %s with %s plugin: %s' % (to_text(fail['src']), fail['plugin'], to_text(fail['exc']))) - if hasattr(fail['exc'], 'tb'): - display.vvv(to_text(fail['exc'].tb)) + if 'tb' in fail: + display.vvv(to_text(fail['tb'])) if C.INVENTORY_ANY_UNPARSED_IS_FAILED: raise AnsibleError(u'Completely failed to parse inventory source %s' % (source)) if not parsed: