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 rest_framework.routers import APIRootView
from core import filtersets from core import filtersets
from core.models import * from core.models import *
from extras.models import JobResult
from netbox.api.viewsets import NetBoxModelViewSet from netbox.api.viewsets import NetBoxModelViewSet
from utilities.utils import count_related from utilities.utils import count_related
from . import serializers from . import serializers
@ -26,6 +33,20 @@ class DataSourceViewSet(NetBoxModelViewSet):
serializer_class = serializers.DataSourceSerializer serializer_class = serializers.DataSourceSerializer
filterset_class = filtersets.DataSourceFilterSet 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): class DataFileViewSet(NetBoxModelViewSet):
queryset = DataFile.objects.defer('data').prefetch_related('source') queryset = DataFile.objects.defer('data').prefetch_related('source')

View File

@ -5,11 +5,14 @@ import tempfile
from fnmatch import fnmatchcase from fnmatch import fnmatchcase
from urllib.parse import quote, urlunparse, urlparse from urllib.parse import quote, urlunparse, urlparse
from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.module_loading import import_string
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from extras.models import JobResult
from netbox.models import ChangeLoggedModel from netbox.models import ChangeLoggedModel
from utilities.files import sha256_hash from utilities.files import sha256_hash
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
@ -88,6 +91,30 @@ class DataSource(ChangeLoggedModel):
def get_status_color(self): def get_status_color(self):
return DataSourceStatusChoices.colors.get(self.status) 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): def sync(self):
""" """
Create/update/delete child DataFiles as necessary to synchronize with the remote source. 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): def post(self, request, pk):
datasource = get_object_or_404(self.queryset, pk=pk) datasource = get_object_or_404(self.queryset, pk=pk)
job_result = datasource.enqueue_sync_job(request)
# 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,
)
messages.success(request, f"Queued job #{job_result.pk} to sync {datasource}") messages.success(request, f"Queued job #{job_result.pk} to sync {datasource}")
return redirect(datasource.get_absolute_url()) return redirect(datasource.get_absolute_url())

View File

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