1
0
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:
John Anderson
2020-06-29 03:50:05 -04:00
parent eb8c0539c5
commit 3777fbccc3
29 changed files with 953 additions and 192 deletions

View File

@ -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):