diff --git a/netbox/core/api/serializers_/tasks.py b/netbox/core/api/serializers_/tasks.py index 5f39eab8d..adeb71e5a 100644 --- a/netbox/core/api/serializers_/tasks.py +++ b/netbox/core/api/serializers_/tasks.py @@ -59,7 +59,8 @@ class BackgroundQueueSerializer(serializers.Serializer): class BackgroundWorkerSerializer(serializers.Serializer): - name = serializers.CharField() + name = serializers.HyperlinkedIdentityField(view_name='core-api:rqworker-detail', lookup_field='name') + state = serializers.SerializerMethodField() birth_date = serializers.CharField() queue_names = serializers.ListField(child=serializers.CharField()) diff --git a/netbox/core/api/urls.py b/netbox/core/api/urls.py index 964653e19..936b885b1 100644 --- a/netbox/core/api/urls.py +++ b/netbox/core/api/urls.py @@ -12,16 +12,17 @@ router.register('data-sources', views.DataSourceViewSet) router.register('data-files', views.DataFileViewSet) router.register('jobs', views.JobViewSet) router.register('object-changes', views.ObjectChangeViewSet) -router.register('background-queues', views.QueueViewSet, basename='RQQueue') -router.register('background-workers', views.WorkerViewSet, basename='RQWorker') +router.register('background-queues', views.QueueViewSet, basename='rqqueue') +router.register('background-workers', views.WorkerViewSet, basename='rqworker') +router.register('background-tasks/(?P.+)/', views.TaskViewSet, basename='rqtask') urlpatterns = ( - path('background-tasks//', views.TaskListView.as_view(), name="background_task_list"), - path('background-tasks//deferred/', views.DeferredTaskListView.as_view(), name="background_tasks_deferred"), - path('background-tasks//failed/', views.FailedTaskListView.as_view(), name="background_tasks_failed"), - path('background-tasks//finished/', views.FinishedTaskListView.as_view(), name="background_tasks_finished"), - path('background-tasks//started/', views.StartedTaskListView.as_view(), name="background_tasks_started"), - path('background-tasks//queued/', views.QueuedTaskListView.as_view(), name="background_tasks_queued"), + # path('background-tasks//', views.TaskListView.as_view(), name="background_task_list"), + # path('background-tasks//deferred/', views.DeferredTaskListView.as_view(), name="background_tasks_deferred"), + # path('background-tasks//failed/', views.FailedTaskListView.as_view(), name="background_tasks_failed"), + # path('background-tasks//finished/', views.FinishedTaskListView.as_view(), name="background_tasks_finished"), + # path('background-tasks//started/', views.StartedTaskListView.as_view(), name="background_tasks_started"), + # path('background-tasks//queued/', views.QueuedTaskListView.as_view(), name="background_tasks_queued"), path('background-task//', views.TaskDetailView.as_view(), name="background_task_detail"), path('background-task//delete/', views.TaskDeleteView.as_view(), name="background_task_delete"), path('background-task//requeue/', views.TaskRequeueView.as_view(), name="background_task_requeue"), diff --git a/netbox/core/api/views.py b/netbox/core/api/views.py index 2d7be346f..8f234ce9b 100644 --- a/netbox/core/api/views.py +++ b/netbox/core/api/views.py @@ -124,7 +124,7 @@ class BaseRQListView(viewsets.ViewSet): paginator = LimitOffsetListPagination() data = paginator.paginate_list(data, request) - serializer = self.serializer_class(data, many=True) + serializer = self.serializer_class(data, many=True, context={'request': request}) return paginator.get_paginated_response(serializer.data) @@ -133,6 +133,7 @@ class QueueViewSet(BaseRQListView): Retrieve a list of RQ Queues. """ serializer_class = serializers.BackgroundQueueSerializer + lookup_field = 'name' def get_view_name(self): return "Background Queues" @@ -146,6 +147,7 @@ class WorkerViewSet(BaseRQListView): Retrieve a list of RQ Workers. """ serializer_class = serializers.BackgroundWorkerSerializer + lookup_field = 'name' def get_view_name(self): return "Background Workers" @@ -154,18 +156,18 @@ class WorkerViewSet(BaseRQListView): config = QUEUES_LIST[0] return Worker.all(get_redis_connection(config['connection_config'])) - def retrieve(self, request, pk=None): + def retrieve(self, request, name=None): # all the RQ queues should use the same connection - if not pk: + if not name: raise Http404 config = QUEUES_LIST[0] workers = Worker.all(get_redis_connection(config['connection_config'])) - worker = next((item for item in workers if item.name == pk), None) + worker = next((item for item in workers if item.name == name), None) if not worker: raise Http404 - serializer = serializers.BackgroundWorkerSerializer(worker) + serializer = serializers.BackgroundWorkerSerializer(worker, context={'request': request}) return Response(serializer.data) @@ -186,7 +188,7 @@ class TaskListView(APIView): raise Http404 data = queue.get_jobs() - serializer = serializers.BackgroundTaskSerializer(data, many=True) + serializer = serializers.BackgroundTaskSerializer(data, many=True, context={'request': request}) return Response(serializer.data) @@ -217,7 +219,7 @@ class TaskDetailView(BaseTaskView): @extend_schema(responses={200: OpenApiTypes.OBJECT}) def get(self, request, task_id, format=None): task = self.get_task_from_id(task_id) - serializer = serializers.BackgroundTaskSerializer(task) + serializer = serializers.BackgroundTaskSerializer(task, context={'request': request}) return Response(serializer.data) @@ -284,78 +286,46 @@ class TaskStopView(APIView): return HttpResponse(status=204) -class BaseTaskListView(APIView): +class TaskViewSet(viewsets.ViewSet): permission_classes = [IsAdminUser] - registry = None + registry = "default" def get_view_name(self): return "Background Tasks" - @extend_schema(responses={200: OpenApiTypes.OBJECT}) - def get(self, request, queue_name, format=None): + def get_response(self, request, queue_name, status=None): try: queue = get_queue(queue_name) except KeyError: raise Http404 - data = get_rq_jobs_from_status(queue, self.registry) - serializer = serializers.BackgroundTaskSerializer(data, many=True) + if not status: + data = queue.get_jobs() + + data = get_rq_jobs_from_status(queue, status) + + paginator = LimitOffsetListPagination() + data = paginator.paginate_list(data, request) + + serializer = serializers.BackgroundTaskSerializer(data, many=True, context={'request': request}) return Response(serializer.data) - -class DeferredTaskListView(BaseTaskListView): - """ - Retrieve a list of Deferred RQ Tasks in the specified Queue. - """ - registry = "deferred" - - def get_view_name(self): - return "Deferred Tasks" - - -class FailedTaskListView(BaseTaskListView): - """ - Retrieve a list of Failed RQ Tasks in the specified Queue. - """ - registry = "failed" - - def get_view_name(self): - return "Failed Tasks" - - -class FinishedTaskListView(BaseTaskListView): - """ - Retrieve a list of Finished RQ Tasks in the specified Queue. - """ - registry = "finished" - - def get_view_name(self): - return "Finished Tasks" - - -class StartedTaskListView(BaseTaskListView): - """ - Retrieve a list of Started RQ Tasks in the specified Queue. - """ - registry = "started" - - def get_view_name(self): - return "Started Tasks" - - -class QueuedTaskListView(BaseTaskListView): - """ - Retrieve a list of Queued RQ Tasks in the specified Queue. - """ - registry = "queued" - @extend_schema(responses={200: OpenApiTypes.OBJECT}) - def get(self, request, queue_name, format=None): - try: - queue = get_queue(queue_name) - except KeyError: - raise Http404 + def list(self, request, queue_name): + return self.get_response(request, queue_name, None) - data = queue.get_jobs() - serializer = serializers.BackgroundTaskSerializer(data, many=True) - return Response(serializer.data) + @action(methods=["GET"], detail=False) + def deferred(self, request, queue_name): + return self.get_response(request, queue_name, "deferred") + + @action(methods=["GET"], detail=False) + def finished(self, request, queue_name): + return self.get_response(request, queue_name, "finished") + + @action(methods=["GET"], detail=False) + def started(self, request, queue_name): + return self.get_response(request, queue_name, "started") + + @action(methods=["GET"], detail=False) + def queued(self, request, queue_name): + return self.cget_response(request, queue_name, None) diff --git a/netbox/core/tests/test_api.py b/netbox/core/tests/test_api.py index d2be9ae2f..7e046725e 100644 --- a/netbox/core/tests/test_api.py +++ b/netbox/core/tests/test_api.py @@ -134,7 +134,7 @@ class BackgroundTaskTestCase(TestCase): get_queue('low').connection.flushall() def test_background_queue_list(self): - url = reverse('core-api:background_queue_list') + url = reverse('core-api:rqqueue-list') # Attempt to load view without permission self.user.is_staff = False @@ -155,7 +155,7 @@ class BackgroundTaskTestCase(TestCase): queue = get_queue('default') queue.enqueue(self.dummy_job_default) - response = self.client.get(reverse('core-api:background_task_list', args=["default",]), **self.header) + response = self.client.get(reverse('core-api:rqtask-list', args=["default",]), **self.header) self.assertEqual(response.status_code, 200) self.assertIn('BackgroundTaskTestCase.dummy_job_default', str(response.content)) @@ -165,7 +165,7 @@ class BackgroundTaskTestCase(TestCase): registry = FinishedJobRegistry(queue.name, queue.connection) registry.add(job, 2) - response = self.client.get(reverse('core-api:background_tasks_finished', args=["default",]), **self.header) + response = self.client.get(reverse('core-api:rqtask-finished', args=["default",]), **self.header) self.assertEqual(response.status_code, 200) self.assertIn(job.id, str(response.content)) @@ -175,7 +175,7 @@ class BackgroundTaskTestCase(TestCase): registry = FailedJobRegistry(queue.name, queue.connection) registry.add(job, 2) - response = self.client.get(reverse('core-api:background_tasks_failed', args=["default"]), **self.header) + response = self.client.get(reverse('core-api:rqtask-failed', args=["default"]), **self.header) self.assertEqual(response.status_code, 200) self.assertIn(job.id, str(response.content)) @@ -185,7 +185,7 @@ class BackgroundTaskTestCase(TestCase): registry = DeferredJobRegistry(queue.name, queue.connection) registry.add(job, 2) - response = self.client.get(reverse('core-api:background_tasks_deferred', args=["default",]), **self.header) + response = self.client.get(reverse('core-api:rqtask-deferred', args=["default",]), **self.header) self.assertEqual(response.status_code, 200) self.assertIn(job.id, str(response.content))