from rest_framework import status from rest_framework.decorators import action from rest_framework.response import Response from netbox.api.viewsets import NetBoxModelViewSet from ..engine.resolver import Resolver from ..models import Service, ServiceTemplate from .serializers import ServiceSerializer, ServiceTemplateSerializer class ServiceTemplateViewSet(NetBoxModelViewSet): queryset = ServiceTemplate.objects.all() serializer_class = ServiceTemplateSerializer class ServiceViewSet(NetBoxModelViewSet): queryset = Service.objects.all() serializer_class = ServiceSerializer @action(detail=True, methods=["post"]) def resolve(self, request, pk=None): """Resolve a service's requirement tree. Request body: ``{"mode": "dry_run" | "commit"}`` """ service = self.get_object() mode = request.data.get("mode", "dry_run") resolver = Resolver() try: result = resolver.resolve(service, mode=mode, user=request.user) except Exception as exc: return Response( {"error": str(exc)}, status=status.HTTP_400_BAD_REQUEST, ) planned_data = [] for node_name, obj in result.planned_objects: ct = obj.__class__._meta planned_data.append({ "node": node_name, "object_type": f"{ct.app_label}.{ct.model_name}", "object_id": obj.pk, "object": str(obj), }) response_data = { "mode": mode, "succeeded": result.succeeded, "total_planned": result.total_planned, "total_current": result.total_current, "to_add": len(result.to_add), "to_remove": len(result.to_remove), "planned": planned_data, "errors": result.errors, "warnings": result.warnings, "summary": result.summary, } return Response(response_data)