This commit is contained in:
Arthur Hanson
2025-12-02 14:37:53 +00:00
committed by GitHub

View File

@@ -2,11 +2,13 @@ import logging
import traceback import traceback
from contextlib import ExitStack from contextlib import ExitStack
from django.db import transaction from django.db import router, transaction
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from core.signals import clear_events from core.signals import clear_events
from dcim.models import Device
from extras.models import Script as ScriptModel from extras.models import Script as ScriptModel
from netbox.context_managers import event_tracking
from netbox.jobs import JobRunner from netbox.jobs import JobRunner
from netbox.registry import registry from netbox.registry import registry
from utilities.exceptions import AbortScript, AbortTransaction from utilities.exceptions import AbortScript, AbortTransaction
@@ -42,10 +44,18 @@ class ScriptJob(JobRunner):
# A script can modify multiple models so need to do an atomic lock on # A script can modify multiple models so need to do an atomic lock on
# both the default database (for non ChangeLogged models) and potentially # both the default database (for non ChangeLogged models) and potentially
# any other database (for ChangeLogged models) # any other database (for ChangeLogged models)
with transaction.atomic(): branch_db = router.db_for_write(Device)
script.output = script.run(data, commit) with transaction.atomic(using='default'):
if not commit: # If branch database is different from default, wrap in a second atomic transaction
raise AbortTransaction() if branch_db != 'default':
with transaction.atomic(using=branch_db):
script.output = script.run(data, commit)
if not commit:
raise AbortTransaction()
else:
script.output = script.run(data, commit)
if not commit:
raise AbortTransaction()
except AbortTransaction: except AbortTransaction:
script.log_info(message=_("Database changes have been reverted automatically.")) script.log_info(message=_("Database changes have been reverted automatically."))
if script.failed: if script.failed:
@@ -108,14 +118,14 @@ class ScriptJob(JobRunner):
script.request = request script.request = request
self.logger.debug(f"Request ID: {request.id if request else None}") self.logger.debug(f"Request ID: {request.id if request else None}")
# Execute the script. If commit is True, wrap it with the event_tracking context manager to ensure we process
# change logging, event rules, etc.
if commit: if commit:
self.logger.info("Executing script (commit enabled)") self.logger.info("Executing script (commit enabled)")
with ExitStack() as stack:
for request_processor in registry['request_processors']:
stack.enter_context(request_processor(request))
self.run_script(script, request, data, commit)
else: else:
self.logger.warning("Executing script (commit disabled)") self.logger.warning("Executing script (commit disabled)")
with ExitStack() as stack:
for request_processor in registry['request_processors']:
if not commit and request_processor is event_tracking:
continue
stack.enter_context(request_processor(request))
self.run_script(script, request, data, commit) self.run_script(script, request, data, commit)