1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Closes #13334: Record error message on failed jobs (#14106)

This commit is contained in:
Jeremy Stretch
2023-10-31 08:34:57 -04:00
committed by GitHub
parent edc4a35296
commit 7323668dd0
9 changed files with 40 additions and 9 deletions

View File

@ -69,5 +69,5 @@ class JobSerializer(BaseModelSerializer):
model = Job model = Job
fields = [ fields = [
'id', 'url', 'display', 'object_type', 'object_id', 'name', 'status', 'created', 'scheduled', 'interval', 'id', 'url', 'display', 'object_type', 'object_id', 'name', 'status', 'created', 'scheduled', 'interval',
'started', 'completed', 'user', 'data', 'job_id', 'started', 'completed', 'user', 'data', 'error', 'job_id',
] ]

View File

@ -25,7 +25,7 @@ def sync_datasource(job, *args, **kwargs):
job.terminate() job.terminate()
except Exception as e: except Exception as e:
job.terminate(status=JobStatusChoices.STATUS_ERRORED) job.terminate(status=JobStatusChoices.STATUS_ERRORED, error=str(e))
DataSource.objects.filter(pk=datasource.pk).update(status=DataSourceStatusChoices.FAILED) DataSource.objects.filter(pk=datasource.pk).update(status=DataSourceStatusChoices.FAILED)
if type(e) in (SyncError, JobTimeoutException): if type(e) in (SyncError, JobTimeoutException):
logging.error(e) logging.error(e)

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.6 on 2023-10-23 20:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0005_job_created_auto_now'),
]
operations = [
migrations.AddField(
model_name='job',
name='error',
field=models.TextField(blank=True, editable=False),
),
]

View File

@ -92,6 +92,11 @@ class Job(models.Model):
null=True, null=True,
blank=True blank=True
) )
error = models.TextField(
verbose_name=_('error'),
editable=False,
blank=True
)
job_id = models.UUIDField( job_id = models.UUIDField(
verbose_name=_('job ID'), verbose_name=_('job ID'),
unique=True unique=True
@ -158,7 +163,7 @@ class Job(models.Model):
# Handle webhooks # Handle webhooks
self.trigger_webhooks(event=EVENT_JOB_START) self.trigger_webhooks(event=EVENT_JOB_START)
def terminate(self, status=JobStatusChoices.STATUS_COMPLETED): def terminate(self, status=JobStatusChoices.STATUS_COMPLETED, error=None):
""" """
Mark the job as completed, optionally specifying a particular termination status. Mark the job as completed, optionally specifying a particular termination status.
""" """
@ -168,6 +173,8 @@ class Job(models.Model):
# Mark the job as completed # Mark the job as completed
self.status = status self.status = status
if error:
self.error = error
self.completed = timezone.now() self.completed = timezone.now()
self.save() self.save()

View File

@ -47,7 +47,7 @@ class JobTable(NetBoxTable):
model = Job model = Job
fields = ( fields = (
'pk', 'id', 'object_type', 'object', 'name', 'status', 'created', 'scheduled', 'interval', 'started', 'pk', 'id', 'object_type', 'object', 'name', 'status', 'created', 'scheduled', 'interval', 'started',
'completed', 'user', 'job_id', 'completed', 'user', 'error', 'job_id',
) )
default_columns = ( default_columns = (
'pk', 'id', 'object_type', 'object', 'name', 'status', 'created', 'started', 'completed', 'user', 'pk', 'id', 'object_type', 'object', 'name', 'status', 'created', 'started', 'completed', 'user',

View File

@ -59,7 +59,7 @@ class Command(BaseCommand):
logger.error(f"Exception raised during script execution: {e}") logger.error(f"Exception raised during script execution: {e}")
clear_webhooks.send(request) clear_webhooks.send(request)
job.data = ScriptOutputSerializer(script).data job.data = ScriptOutputSerializer(script).data
job.terminate(status=JobStatusChoices.STATUS_ERRORED) job.terminate(status=JobStatusChoices.STATUS_ERRORED, error=str(e))
logger.info(f"Script completed in {job.duration}") logger.info(f"Script completed in {job.duration}")

View File

@ -40,8 +40,8 @@ def run_report(job, *args, **kwargs):
try: try:
report.run(job) report.run(job)
except Exception: except Exception as e:
job.terminate(status=JobStatusChoices.STATUS_ERRORED) job.terminate(status=JobStatusChoices.STATUS_ERRORED, error=str(e))
logging.error(f"Error during execution of report {job.name}") logging.error(f"Error during execution of report {job.name}")
finally: finally:
# Schedule the next job if an interval has been set # Schedule the next job if an interval has been set
@ -230,7 +230,7 @@ class Report(object):
stacktrace = traceback.format_exc() stacktrace = traceback.format_exc()
self.log_failure(None, f"An exception occurred: {type(e).__name__}: {e} <pre>{stacktrace}</pre>") self.log_failure(None, f"An exception occurred: {type(e).__name__}: {e} <pre>{stacktrace}</pre>")
logger.error(f"Exception raised during report execution: {e}") logger.error(f"Exception raised during report execution: {e}")
job.terminate(status=JobStatusChoices.STATUS_ERRORED) job.terminate(status=JobStatusChoices.STATUS_ERRORED, error=str(e))
# Perform any post-run tasks # Perform any post-run tasks
self.post_run() self.post_run()

View File

@ -519,7 +519,7 @@ def run_script(data, request, job, commit=True, **kwargs):
logger.error(f"Exception raised during script execution: {e}") logger.error(f"Exception raised during script execution: {e}")
script.log_info("Database changes have been reverted due to error.") script.log_info("Database changes have been reverted due to error.")
job.data = ScriptOutputSerializer(script).data job.data = ScriptOutputSerializer(script).data
job.terminate(status=JobStatusChoices.STATUS_ERRORED) job.terminate(status=JobStatusChoices.STATUS_ERRORED, error=str(e))
clear_webhooks.send(request) clear_webhooks.send(request)
logger.info(f"Script completed in {job.duration}") logger.info(f"Script completed in {job.duration}")

View File

@ -35,6 +35,12 @@
<th scope="row">{% trans "Status" %}</th> <th scope="row">{% trans "Status" %}</th>
<td>{% badge object.get_status_display object.get_status_color %}</td> <td>{% badge object.get_status_display object.get_status_color %}</td>
</tr> </tr>
{% if object.error %}
<tr>
<th scope="row">{% trans "Error" %}</th>
<td>{{ object.error }}</td>
</tr>
{% endif %}
<tr> <tr>
<th scope="row">{% trans "Created By" %}</th> <th scope="row">{% trans "Created By" %}</th>
<td>{{ object.user|placeholder }}</td> <td>{{ object.user|placeholder }}</td>