diff --git a/docs/configuration/system.md b/docs/configuration/system.md index 25c724bc922..3cc277660e8 100644 --- a/docs/configuration/system.md +++ b/docs/configuration/system.md @@ -219,3 +219,11 @@ The time zone NetBox will use when dealing with dates and times. It is recommend Default: True Enables language translation for the user interface. (This parameter maps to Django's [USE_I18N](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-USE_I18N) setting.) + +--- + +## SCRIPT_CONTEXT_MANAGERS + +Default: [] + +The dotted path to any additional context managers to use when running scripts. diff --git a/netbox/extras/jobs.py b/netbox/extras/jobs.py index 190166b5be0..ee4b00ca423 100644 --- a/netbox/extras/jobs.py +++ b/netbox/extras/jobs.py @@ -1,8 +1,11 @@ import logging import traceback -from contextlib import nullcontext +from contextlib import ExitStack, nullcontext +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured from django.db import transaction +from django.utils.module_loading import import_string from django.utils.translation import gettext as _ from core.signals import clear_events @@ -88,6 +91,7 @@ def run(self, data, request=None, commit=True, **kwargs): commit: Passed through to Script.run() """ script = ScriptModel.objects.get(pk=self.job.object_id).python_class() + logger = logging.getLogger(f"netbox.scripts.{script.full_name}") # Add files to form data if request: @@ -98,7 +102,23 @@ def run(self, data, request=None, commit=True, **kwargs): # Add the current request as a property of the script script.request = request + context_managers = [] + for context_manager_str in settings.SCRIPT_CONTEXT_MANAGERS: + try: + context_managers.append(import_string(context_manager_str)) + except AttributeError: + message = _("Failed to import configured SCRIPT_CONTEXT_MANAGERS: ") + context_manager_str + logger.error(message) + raise ImproperlyConfigured(message) + # Execute the script. If commit is True, wrap it with the event_tracking context manager to ensure we process # change logging, event rules, etc. with event_tracking(request) if commit else nullcontext(): - self.run_script(script, request, data, commit) + if context_managers: + with ExitStack() as stack: + for cm in context_managers: + stack.enter_context(cm(request)) + + self.run_script(script, request, data, commit) + else: + self.run_script(script, request, data, commit) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index a8ac68d4dc2..83450efc39e 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -179,6 +179,7 @@ STORAGE_CONFIG = getattr(configuration, 'STORAGE_CONFIG', {}) TIME_ZONE = getattr(configuration, 'TIME_ZONE', 'UTC') TRANSLATION_ENABLED = getattr(configuration, 'TRANSLATION_ENABLED', True) +SCRIPT_CONTEXT_MANAGERS = getattr(configuration, 'SCRIPT_CONTEXT_MANAGERS', []) # Load any dynamic configuration parameters which have been hard-coded in the configuration file for param in CONFIG_PARAMS: