mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Implements #2006 - run reports and scripts in the background
This commit is contained in:
@ -12,9 +12,15 @@ from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
from django.utils.decorators import classproperty
|
||||
from django_rq import job
|
||||
from mptt.forms import TreeNodeChoiceField, TreeNodeMultipleChoiceField
|
||||
from mptt.models import MPTTModel
|
||||
|
||||
from extras.api.serializers import ScriptOutputSerializer
|
||||
from extras.choices import JobResultStatusChoices
|
||||
from extras.models import JobResult
|
||||
from ipam.formfields import IPAddressFormField, IPNetworkFormField
|
||||
from ipam.validators import MaxPrefixLengthValidator, MinPrefixLengthValidator, prefix_validator
|
||||
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
|
||||
@ -269,6 +275,10 @@ class BaseScript:
|
||||
def __str__(self):
|
||||
return getattr(self.Meta, 'name', self.__class__.__name__)
|
||||
|
||||
@classproperty
|
||||
def full_name(self):
|
||||
return '.'.join([self.__module__, self.__name__])
|
||||
|
||||
@classmethod
|
||||
def module(cls):
|
||||
return cls.__module__
|
||||
@ -375,7 +385,8 @@ def is_variable(obj):
|
||||
return isinstance(obj, ScriptVariable)
|
||||
|
||||
|
||||
def run_script(script, data, request, commit=True):
|
||||
@job('default')
|
||||
def run_script(data, request, commit=True, *args, **kwargs):
|
||||
"""
|
||||
A wrapper for calling Script.run(). This performs error handling and provides a hook for committing changes. It
|
||||
exists outside of the Script class to ensure it cannot be overridden by a script author.
|
||||
@ -384,8 +395,15 @@ def run_script(script, data, request, commit=True):
|
||||
start_time = None
|
||||
end_time = None
|
||||
|
||||
script_name = script.__class__.__name__
|
||||
logger = logging.getLogger(f"netbox.scripts.{script.module()}.{script_name}")
|
||||
job_result = kwargs.pop('job_result')
|
||||
module, script_name = job_result.name.split('.', 1)
|
||||
|
||||
script = get_script(module, script_name)()
|
||||
|
||||
job_result.status = JobResultStatusChoices.STATUS_RUNNING
|
||||
job_result.save()
|
||||
|
||||
logger = logging.getLogger(f"netbox.scripts.{module}.{script_name}")
|
||||
logger.info(f"Running script (commit={commit})")
|
||||
|
||||
# Add files to form data
|
||||
@ -405,9 +423,8 @@ def run_script(script, data, request, commit=True):
|
||||
|
||||
try:
|
||||
with transaction.atomic():
|
||||
start_time = time.time()
|
||||
output = script.run(**kwargs)
|
||||
end_time = time.time()
|
||||
script.output = script.run(**kwargs)
|
||||
job_result.status = JobResultStatusChoices.STATUS_COMPLETED
|
||||
if not commit:
|
||||
raise AbortTransaction()
|
||||
except AbortTransaction:
|
||||
@ -419,6 +436,7 @@ def run_script(script, data, request, commit=True):
|
||||
)
|
||||
logger.error(f"Exception raised during script execution: {e}")
|
||||
commit = False
|
||||
job_result.status = JobResultStatusChoices.STATUS_FAILED
|
||||
finally:
|
||||
if not commit:
|
||||
# Delete all pending changelog entries
|
||||
@ -427,14 +445,19 @@ def run_script(script, data, request, commit=True):
|
||||
"Database changes have been reverted automatically."
|
||||
)
|
||||
|
||||
# Calculate execution time
|
||||
if end_time is not None:
|
||||
execution_time = end_time - start_time
|
||||
logger.info(f"Script completed in {execution_time:.4f} seconds")
|
||||
else:
|
||||
execution_time = None
|
||||
job_result.data = ScriptOutputSerializer(script).data
|
||||
job_result.completed = timezone.now()
|
||||
job_result.save()
|
||||
|
||||
return output, execution_time
|
||||
logger.info(f"Script completed in {job_result.duration}")
|
||||
|
||||
# Delete any previous terminal state results
|
||||
JobResult.objects.filter(
|
||||
obj_type=job_result.obj_type,
|
||||
status=JobResultStatusChoices.TERMINAL_STATE_CHOICES
|
||||
).exclude(
|
||||
pk=job_result.pk
|
||||
).delete()
|
||||
|
||||
|
||||
def get_scripts(use_names=False):
|
||||
|
Reference in New Issue
Block a user