From 21525498a96c1fd135e8cf20f841299dafed26fb Mon Sep 17 00:00:00 2001 From: Justin Pettit <47164813+jmpettit@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:23:04 -0500 Subject: [PATCH 1/7] Refactor Jinja error handling and add stack trace --- .../plugins/tasks/dispatcher/default.py | 41 ++++++++----------- nornir_nautobot/utils/helpers.py | 7 ++++ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/nornir_nautobot/plugins/tasks/dispatcher/default.py b/nornir_nautobot/plugins/tasks/dispatcher/default.py index 44b4747..b09d437 100644 --- a/nornir_nautobot/plugins/tasks/dispatcher/default.py +++ b/nornir_nautobot/plugins/tasks/dispatcher/default.py @@ -25,7 +25,7 @@ from nornir_netmiko.tasks import netmiko_send_command from nornir_nautobot.exceptions import NornirNautobotException -from nornir_nautobot.utils.helpers import make_folder +from nornir_nautobot.utils.helpers import make_folder, format_jinja_stack_trace _logger = logging.getLogger(__name__) @@ -174,29 +174,22 @@ def generate_config( jinja_env=jinja_env, )[0].result except NornirSubTaskError as exc: - if isinstance(exc.result.exception, jinja2.exceptions.UndefinedError): # pylint: disable=no-else-raise - error_msg = ( - f"`E1010:` There was a jinja2.exceptions.UndefinedError error: ``{str(exc.result.exception)}``" - ) - logger.error(error_msg, extra={"object": obj}) - raise NornirNautobotException(error_msg) - - elif isinstance(exc.result.exception, jinja2.TemplateSyntaxError): - error_msg = (f"`E1011:` There was a jinja2.TemplateSyntaxError error: ``{str(exc.result.exception)}``",) - logger.error(error_msg, extra={"object": obj}) - raise NornirNautobotException(error_msg) - - elif isinstance(exc.result.exception, jinja2.TemplateNotFound): - error_msg = f"`E1012:` There was an issue finding the template and a jinja2.TemplateNotFound error was raised: ``{str(exc.result.exception)}``" - logger.error(error_msg, extra={"object": obj}) - raise NornirNautobotException(error_msg) - - elif isinstance(exc.result.exception, jinja2.TemplateError): - error_msg = f"`E1013:` There was an issue general Jinja error: ``{str(exc.result.exception)}``" - logger.error(error_msg, extra={"object": obj}) - raise NornirNautobotException(error_msg) - - error_msg = f"`E1014:` Failed with an unknown issue. `{exc.result.exception}`" + stack_trace = format_jinja_stack_trace(exc.result.exception) + + error_mapping = { + jinja2.exceptions.UndefinedError: ("E1010", "Undefined variable in Jinja2 template"), + jinja2.TemplateSyntaxError: ("E1011", "Syntax error in Jinja2 template"), + jinja2.TemplateNotFound: ("E1012", "Jinja2 template not found"), + jinja2.TemplateError: ("E1013", "General Jinja2 template error"), + } + + for error, (code, message) in error_mapping.items(): + if isinstance(exc.result.exception, error): + error_msg = f"`{code}:` {message} - ``{str(exc.result.exception)}``\n```\n{stack_trace}\n```" + logger.error(error_msg, extra={"object": obj}) + raise NornirNautobotException(error_msg) + + error_msg = f"`E1014:` Unknown error - {exc.result.exception}\n```\n{stack_trace}\n```" logger.error(error_msg, extra={"object": obj}) raise NornirNautobotException(error_msg) diff --git a/nornir_nautobot/utils/helpers.py b/nornir_nautobot/utils/helpers.py index 4912758..46f4a00 100644 --- a/nornir_nautobot/utils/helpers.py +++ b/nornir_nautobot/utils/helpers.py @@ -4,6 +4,7 @@ import os import logging import importlib +import traceback LOGGER = logging.getLogger(__name__) @@ -31,3 +32,9 @@ def import_string(dotted_path): return getattr(importlib.import_module(module_name), class_name) except (ModuleNotFoundError, AttributeError): return None + +def format_jinja_stack_trace(exc: Exception) -> str: + """Generate and format a stack trace string for a given Jinja exception.""" + stack_trace_lines = traceback.format_exception(type(exc), exc, exc.__traceback__) + stack_trace_lines = [line for line in stack_trace_lines if '.j2' in line or '{{' in line] + return "\n".join(stack_trace_lines) From 0fea1678ca1a421e1d8dc62bbfa4c64d524767e3 Mon Sep 17 00:00:00 2001 From: Justin Pettit <47164813+jmpettit@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:47:38 -0500 Subject: [PATCH 2/7] Fix format for E1014 --- nornir_nautobot/plugins/tasks/dispatcher/default.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nornir_nautobot/plugins/tasks/dispatcher/default.py b/nornir_nautobot/plugins/tasks/dispatcher/default.py index b09d437..e49d34e 100644 --- a/nornir_nautobot/plugins/tasks/dispatcher/default.py +++ b/nornir_nautobot/plugins/tasks/dispatcher/default.py @@ -189,7 +189,7 @@ def generate_config( logger.error(error_msg, extra={"object": obj}) raise NornirNautobotException(error_msg) - error_msg = f"`E1014:` Unknown error - {exc.result.exception}\n```\n{stack_trace}\n```" + error_msg = f"`E1014:` Unknown error - `{exc.result.exception}`" logger.error(error_msg, extra={"object": obj}) raise NornirNautobotException(error_msg) From 15076b7ca4daa527110c2e4d9910f8520885ac70 Mon Sep 17 00:00:00 2001 From: Justin Pettit <47164813+jmpettit@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:41:45 -0500 Subject: [PATCH 3/7] Include full stack trace in error logging --- nornir_nautobot/plugins/tasks/dispatcher/default.py | 6 +++--- nornir_nautobot/utils/helpers.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/nornir_nautobot/plugins/tasks/dispatcher/default.py b/nornir_nautobot/plugins/tasks/dispatcher/default.py index e49d34e..c02fea9 100644 --- a/nornir_nautobot/plugins/tasks/dispatcher/default.py +++ b/nornir_nautobot/plugins/tasks/dispatcher/default.py @@ -25,7 +25,7 @@ from nornir_netmiko.tasks import netmiko_send_command from nornir_nautobot.exceptions import NornirNautobotException -from nornir_nautobot.utils.helpers import make_folder, format_jinja_stack_trace +from nornir_nautobot.utils.helpers import make_folder, get_stack_trace _logger = logging.getLogger(__name__) @@ -174,7 +174,7 @@ def generate_config( jinja_env=jinja_env, )[0].result except NornirSubTaskError as exc: - stack_trace = format_jinja_stack_trace(exc.result.exception) + stack_trace = get_stack_trace(exc.result.exception) error_mapping = { jinja2.exceptions.UndefinedError: ("E1010", "Undefined variable in Jinja2 template"), @@ -189,7 +189,7 @@ def generate_config( logger.error(error_msg, extra={"object": obj}) raise NornirNautobotException(error_msg) - error_msg = f"`E1014:` Unknown error - `{exc.result.exception}`" + error_msg = f"`E1014:` Unknown error - `{exc.result.exception}`\n```\n{stack_trace}\n```" logger.error(error_msg, extra={"object": obj}) raise NornirNautobotException(error_msg) diff --git a/nornir_nautobot/utils/helpers.py b/nornir_nautobot/utils/helpers.py index 46f4a00..ea2df8e 100644 --- a/nornir_nautobot/utils/helpers.py +++ b/nornir_nautobot/utils/helpers.py @@ -33,8 +33,7 @@ def import_string(dotted_path): except (ModuleNotFoundError, AttributeError): return None -def format_jinja_stack_trace(exc: Exception) -> str: +def get_stack_trace(exc: Exception) -> str: """Generate and format a stack trace string for a given Jinja exception.""" stack_trace_lines = traceback.format_exception(type(exc), exc, exc.__traceback__) - stack_trace_lines = [line for line in stack_trace_lines if '.j2' in line or '{{' in line] return "\n".join(stack_trace_lines) From 201e684a465ed37992476f613692a5d8b9de6b02 Mon Sep 17 00:00:00 2001 From: Justin Pettit <47164813+jmpettit@users.noreply.github.com> Date: Thu, 21 Mar 2024 09:55:20 -0500 Subject: [PATCH 4/7] Fix Linting issues --- nornir_nautobot/utils/helpers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nornir_nautobot/utils/helpers.py b/nornir_nautobot/utils/helpers.py index ea2df8e..168a964 100644 --- a/nornir_nautobot/utils/helpers.py +++ b/nornir_nautobot/utils/helpers.py @@ -33,6 +33,7 @@ def import_string(dotted_path): except (ModuleNotFoundError, AttributeError): return None + def get_stack_trace(exc: Exception) -> str: """Generate and format a stack trace string for a given Jinja exception.""" stack_trace_lines = traceback.format_exception(type(exc), exc, exc.__traceback__) From 6fcd84c78d7e88e77c72128d95ed8d0cd357ebcd Mon Sep 17 00:00:00 2001 From: Justin Pettit <47164813+jmpettit@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:07:06 -0500 Subject: [PATCH 5/7] Update docstring on get_stack_trace --- nornir_nautobot/utils/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nornir_nautobot/utils/helpers.py b/nornir_nautobot/utils/helpers.py index 168a964..5954456 100644 --- a/nornir_nautobot/utils/helpers.py +++ b/nornir_nautobot/utils/helpers.py @@ -35,6 +35,6 @@ def import_string(dotted_path): def get_stack_trace(exc: Exception) -> str: - """Generate and format a stack trace string for a given Jinja exception.""" + """Converts the provided exception's stack trace into a string.""" stack_trace_lines = traceback.format_exception(type(exc), exc, exc.__traceback__) return "\n".join(stack_trace_lines) From 7f62f5089aa085fbd0c5143650397ee233ef7005 Mon Sep 17 00:00:00 2001 From: Justin Pettit <47164813+jmpettit@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:28:06 -0500 Subject: [PATCH 6/7] Add pylint disable comment for too-many-locals --- nornir_nautobot/plugins/tasks/dispatcher/default.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nornir_nautobot/plugins/tasks/dispatcher/default.py b/nornir_nautobot/plugins/tasks/dispatcher/default.py index c02fea9..436aa4b 100644 --- a/nornir_nautobot/plugins/tasks/dispatcher/default.py +++ b/nornir_nautobot/plugins/tasks/dispatcher/default.py @@ -149,6 +149,7 @@ def generate_config( jinja_filters: Optional[dict] = None, jinja_env: Optional[jinja2.Environment] = None, ) -> Result: + # pylint: disable=too-many-locals """A small wrapper around template_file Nornir task. Args: From 6f215d082ab3b0aebf8915b5f4af738842ec375c Mon Sep 17 00:00:00 2001 From: Justin Pettit <47164813+jmpettit@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:20:06 -0500 Subject: [PATCH 7/7] Fix stack trace formatting in get_stack_trace function --- nornir_nautobot/utils/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nornir_nautobot/utils/helpers.py b/nornir_nautobot/utils/helpers.py index 5954456..463bb53 100644 --- a/nornir_nautobot/utils/helpers.py +++ b/nornir_nautobot/utils/helpers.py @@ -37,4 +37,4 @@ def import_string(dotted_path): def get_stack_trace(exc: Exception) -> str: """Converts the provided exception's stack trace into a string.""" stack_trace_lines = traceback.format_exception(type(exc), exc, exc.__traceback__) - return "\n".join(stack_trace_lines) + return "".join(stack_trace_lines)