Add API endpoint to sync data sources

This commit is contained in:
jeremystretch 2023-01-27 10:27:33 -05:00
parent 15ca5e2326
commit 685e457d6f
4 changed files with 50 additions and 13 deletions

View File

@ -1,7 +1,14 @@
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
from rest_framework.routers import APIRootView
from core import filtersets
from core.models import *
from extras.models import JobResult
from netbox.api.viewsets import NetBoxModelViewSet
from utilities.utils import count_related
from . import serializers
@ -26,6 +33,20 @@ class DataSourceViewSet(NetBoxModelViewSet):
serializer_class = serializers.DataSourceSerializer
filterset_class = filtersets.DataSourceFilterSet
@action(detail=True, methods=['post'])
def sync(self, request, pk):
"""
Enqueue a job to synchronize the DataSource.
"""
if not request.user.has_perm('extras.sync_datasource'):
raise PermissionDenied("Syncing data sources requires the core.sync_datasource permission.")
datasource = get_object_or_404(DataSource, pk=pk)
datasource.enqueue_sync_job(request)
serializer = serializers.DataSourceSerializer(datasource, context={'request': request})
return Response(serializer.data)
class DataFileViewSet(NetBoxModelViewSet):
queryset = DataFile.objects.defer('data').prefetch_related('source')

View File

@ -5,11 +5,14 @@ import tempfile
from fnmatch import fnmatchcase
from urllib.parse import quote, urlunparse, urlparse
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.utils.module_loading import import_string
from django.utils.translation import gettext as _
from extras.models import JobResult
from netbox.models import ChangeLoggedModel
from utilities.files import sha256_hash
from utilities.querysets import RestrictedQuerySet
@ -88,6 +91,30 @@ class DataSource(ChangeLoggedModel):
def get_status_color(self):
return DataSourceStatusChoices.colors.get(self.status)
@property
def ready_for_sync(self):
return self.enabled and self.status not in (
DataSourceStatusChoices.QUEUED,
DataSourceStatusChoices.SYNCING
)
def enqueue_sync_job(self, request):
"""
Enqueue a background job to synchronize the DataSource by calling sync().
"""
# Set the status to "syncing"
self.status = DataSourceStatusChoices.QUEUED
# Enqueue a sync job
job_result = JobResult.enqueue_job(
import_string('core.jobs.sync_datasource'),
name=self.name,
obj_type=ContentType.objects.get_for_model(DataSource),
user=request.user,
)
return job_result
def sync(self):
"""
Create/update/delete child DataFiles as necessary to synchronize with the remote source.

View File

@ -44,18 +44,7 @@ class DataSourceSyncView(BaseObjectView):
def post(self, request, pk):
datasource = get_object_or_404(self.queryset, pk=pk)
# Set the status to "syncing"
datasource.status = DataSourceStatusChoices.QUEUED
datasource.save()
# Enqueue a sync job
job_result = JobResult.enqueue_job(
jobs.sync_datasource,
name=datasource.name,
obj_type=ContentType.objects.get_for_model(DataSource),
user=request.user,
)
job_result = datasource.enqueue_sync_job(request)
messages.success(request, f"Queued job #{job_result.pk} to sync {datasource}")
return redirect(datasource.get_absolute_url())

View File

@ -6,7 +6,7 @@
{% block extra_controls %}
{% if perms.core.sync_datasource %}
{% if object.enabled %}
{% if object.ready_for_sync %}
<form action="{% url 'core:datasource_sync' pk=object.pk %}" method="post">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-primary">