Updates
This commit is contained in:
411
ETB-API/automation_orchestration/views/automation.py
Normal file
411
ETB-API/automation_orchestration/views/automation.py
Normal file
@@ -0,0 +1,411 @@
|
||||
"""
|
||||
Views for Automation & Orchestration models
|
||||
"""
|
||||
from rest_framework import viewsets, status, permissions
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework.filters import SearchFilter, OrderingFilter
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q
|
||||
|
||||
from ..models import (
|
||||
Runbook,
|
||||
RunbookExecution,
|
||||
Integration,
|
||||
ChatOpsIntegration,
|
||||
ChatOpsCommand,
|
||||
AutoRemediation,
|
||||
AutoRemediationExecution,
|
||||
MaintenanceWindow,
|
||||
WorkflowTemplate,
|
||||
WorkflowExecution,
|
||||
)
|
||||
from ..serializers.automation import (
|
||||
RunbookSerializer,
|
||||
RunbookExecutionSerializer,
|
||||
IntegrationSerializer,
|
||||
ChatOpsIntegrationSerializer,
|
||||
ChatOpsCommandSerializer,
|
||||
AutoRemediationSerializer,
|
||||
AutoRemediationExecutionSerializer,
|
||||
MaintenanceWindowSerializer,
|
||||
WorkflowTemplateSerializer,
|
||||
WorkflowExecutionSerializer,
|
||||
)
|
||||
|
||||
|
||||
class RunbookViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for Runbook model"""
|
||||
|
||||
queryset = Runbook.objects.all()
|
||||
serializer_class = RunbookSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status', 'trigger_type', 'category', 'is_public']
|
||||
search_fields = ['name', 'description', 'category']
|
||||
ordering_fields = ['name', 'created_at', 'updated_at', 'execution_count', 'success_rate']
|
||||
ordering = ['-created_at']
|
||||
|
||||
def get_queryset(self):
|
||||
"""Filter runbooks based on user permissions"""
|
||||
queryset = super().get_queryset()
|
||||
|
||||
# Filter by public runbooks or user's own runbooks
|
||||
if not self.request.user.is_staff:
|
||||
queryset = queryset.filter(
|
||||
Q(is_public=True) | Q(created_by=self.request.user)
|
||||
)
|
||||
|
||||
return queryset
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating a runbook"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
"""Set the last modifier when updating a runbook"""
|
||||
serializer.save(last_modified_by=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def execute(self, request, pk=None):
|
||||
"""Execute a runbook"""
|
||||
runbook = self.get_object()
|
||||
|
||||
if not runbook.can_be_triggered_by(request.user):
|
||||
return Response(
|
||||
{'error': 'You do not have permission to execute this runbook'},
|
||||
status=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
# Create execution record
|
||||
execution = RunbookExecution.objects.create(
|
||||
runbook=runbook,
|
||||
triggered_by=request.user,
|
||||
trigger_type='MANUAL',
|
||||
trigger_data=request.data.get('trigger_data', {}),
|
||||
total_steps=len(runbook.steps)
|
||||
)
|
||||
|
||||
# TODO: Start actual execution in background task
|
||||
|
||||
serializer = RunbookExecutionSerializer(execution, context={'request': request})
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def available_for_trigger(self, request):
|
||||
"""Get runbooks available for triggering by current user"""
|
||||
queryset = self.get_queryset().filter(status='ACTIVE')
|
||||
available_runbooks = [rb for rb in queryset if rb.can_be_triggered_by(request.user)]
|
||||
|
||||
serializer = self.get_serializer(available_runbooks, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class RunbookExecutionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for RunbookExecution model (read-only)"""
|
||||
|
||||
queryset = RunbookExecution.objects.all()
|
||||
serializer_class = RunbookExecutionSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status', 'trigger_type', 'runbook', 'incident']
|
||||
search_fields = ['runbook__name']
|
||||
ordering_fields = ['started_at', 'completed_at', 'duration']
|
||||
ordering = ['-started_at']
|
||||
|
||||
def get_queryset(self):
|
||||
"""Filter executions based on user permissions"""
|
||||
queryset = super().get_queryset()
|
||||
|
||||
# Users can only see executions they triggered or for incidents they have access to
|
||||
if not self.request.user.is_staff:
|
||||
queryset = queryset.filter(
|
||||
Q(triggered_by=self.request.user) |
|
||||
Q(incident__assigned_to=self.request.user) |
|
||||
Q(incident__reporter=self.request.user)
|
||||
)
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
class IntegrationViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for Integration model"""
|
||||
|
||||
queryset = Integration.objects.all()
|
||||
serializer_class = IntegrationSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['integration_type', 'status', 'health_status']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'created_at', 'last_used_at']
|
||||
ordering = ['name']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating an integration"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def test_connection(self, request, pk=None):
|
||||
"""Test integration connection"""
|
||||
integration = self.get_object()
|
||||
|
||||
# TODO: Implement actual connection testing
|
||||
# For now, just return a mock response
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Connection test for {integration.name} completed',
|
||||
'health_status': 'HEALTHY'
|
||||
})
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def health_check(self, request, pk=None):
|
||||
"""Perform health check on integration"""
|
||||
integration = self.get_object()
|
||||
|
||||
# TODO: Implement actual health check
|
||||
# For now, just update the timestamp
|
||||
integration.last_health_check = timezone.now()
|
||||
integration.health_status = 'HEALTHY'
|
||||
integration.save()
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'health_status': integration.health_status,
|
||||
'last_health_check': integration.last_health_check
|
||||
})
|
||||
|
||||
|
||||
class ChatOpsIntegrationViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for ChatOpsIntegration model"""
|
||||
|
||||
queryset = ChatOpsIntegration.objects.all()
|
||||
serializer_class = ChatOpsIntegrationSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['platform', 'is_active']
|
||||
search_fields = ['name']
|
||||
ordering_fields = ['name', 'created_at', 'last_activity']
|
||||
ordering = ['name']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating a ChatOps integration"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def test_webhook(self, request, pk=None):
|
||||
"""Test ChatOps webhook"""
|
||||
integration = self.get_object()
|
||||
|
||||
# TODO: Implement actual webhook testing
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Webhook test for {integration.name} completed'
|
||||
})
|
||||
|
||||
|
||||
class ChatOpsCommandViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for ChatOpsCommand model (read-only)"""
|
||||
|
||||
queryset = ChatOpsCommand.objects.all()
|
||||
serializer_class = ChatOpsCommandSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status', 'chatops_integration', 'command']
|
||||
search_fields = ['command', 'user_id']
|
||||
ordering_fields = ['executed_at', 'completed_at']
|
||||
ordering = ['-executed_at']
|
||||
|
||||
|
||||
class AutoRemediationViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for AutoRemediation model"""
|
||||
|
||||
queryset = AutoRemediation.objects.all()
|
||||
serializer_class = AutoRemediationSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['remediation_type', 'trigger_condition_type', 'is_active', 'requires_approval']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'created_at', 'execution_count', 'success_count']
|
||||
ordering = ['name']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating an auto-remediation"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def test_trigger(self, request, pk=None):
|
||||
"""Test auto-remediation trigger conditions"""
|
||||
remediation = self.get_object()
|
||||
|
||||
# TODO: Implement actual trigger testing
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Trigger test for {remediation.name} completed',
|
||||
'trigger_conditions': remediation.trigger_conditions
|
||||
})
|
||||
|
||||
|
||||
class AutoRemediationExecutionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for AutoRemediationExecution model (read-only)"""
|
||||
|
||||
queryset = AutoRemediationExecution.objects.all()
|
||||
serializer_class = AutoRemediationExecutionSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status', 'auto_remediation', 'incident']
|
||||
search_fields = ['auto_remediation__name', 'incident__title']
|
||||
ordering_fields = ['triggered_at', 'started_at', 'completed_at']
|
||||
ordering = ['-triggered_at']
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def approve(self, request, pk=None):
|
||||
"""Approve a pending auto-remediation execution"""
|
||||
execution = self.get_object()
|
||||
|
||||
if execution.status != 'PENDING':
|
||||
return Response(
|
||||
{'error': 'Only pending remediations can be approved'},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
if not execution.auto_remediation.requires_approval:
|
||||
return Response(
|
||||
{'error': 'This remediation does not require approval'},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
if request.user not in execution.auto_remediation.approval_users.all():
|
||||
return Response(
|
||||
{'error': 'You do not have permission to approve this remediation'},
|
||||
status=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
execution.status = 'APPROVED'
|
||||
execution.approved_by = request.user
|
||||
execution.approved_at = timezone.now()
|
||||
execution.approval_notes = request.data.get('approval_notes', '')
|
||||
execution.save()
|
||||
|
||||
# TODO: Start actual remediation execution
|
||||
|
||||
serializer = self.get_serializer(execution)
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def reject(self, request, pk=None):
|
||||
"""Reject a pending auto-remediation execution"""
|
||||
execution = self.get_object()
|
||||
|
||||
if execution.status != 'PENDING':
|
||||
return Response(
|
||||
{'error': 'Only pending remediations can be rejected'},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
execution.status = 'REJECTED'
|
||||
execution.approved_by = request.user
|
||||
execution.approved_at = timezone.now()
|
||||
execution.approval_notes = request.data.get('rejection_notes', '')
|
||||
execution.save()
|
||||
|
||||
serializer = self.get_serializer(execution)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class MaintenanceWindowViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for MaintenanceWindow model"""
|
||||
|
||||
queryset = MaintenanceWindow.objects.all()
|
||||
serializer_class = MaintenanceWindowSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'start_time', 'end_time', 'created_at']
|
||||
ordering = ['start_time']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating a maintenance window"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def active(self, request):
|
||||
"""Get currently active maintenance windows"""
|
||||
now = timezone.now()
|
||||
active_windows = self.get_queryset().filter(
|
||||
start_time__lte=now,
|
||||
end_time__gte=now,
|
||||
status='ACTIVE'
|
||||
)
|
||||
|
||||
serializer = self.get_serializer(active_windows, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def upcoming(self, request):
|
||||
"""Get upcoming maintenance windows"""
|
||||
now = timezone.now()
|
||||
upcoming_windows = self.get_queryset().filter(
|
||||
start_time__gt=now,
|
||||
status='SCHEDULED'
|
||||
)
|
||||
|
||||
serializer = self.get_serializer(upcoming_windows, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class WorkflowTemplateViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for WorkflowTemplate model"""
|
||||
|
||||
queryset = WorkflowTemplate.objects.all()
|
||||
serializer_class = WorkflowTemplateSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['template_type', 'is_public']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'created_at', 'usage_count']
|
||||
ordering = ['name']
|
||||
|
||||
def get_queryset(self):
|
||||
"""Filter templates based on user permissions"""
|
||||
queryset = super().get_queryset()
|
||||
|
||||
# Filter by public templates or user's own templates
|
||||
if not self.request.user.is_staff:
|
||||
queryset = queryset.filter(
|
||||
Q(is_public=True) | Q(created_by=self.request.user)
|
||||
)
|
||||
|
||||
return queryset
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating a workflow template"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
|
||||
class WorkflowExecutionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for WorkflowExecution model (read-only)"""
|
||||
|
||||
queryset = WorkflowExecution.objects.all()
|
||||
serializer_class = WorkflowExecutionSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status', 'workflow_template', 'trigger_type']
|
||||
search_fields = ['name', 'workflow_template__name']
|
||||
ordering_fields = ['started_at', 'completed_at', 'duration']
|
||||
ordering = ['-started_at']
|
||||
|
||||
def get_queryset(self):
|
||||
"""Filter executions based on user permissions"""
|
||||
queryset = super().get_queryset()
|
||||
|
||||
# Users can only see executions they triggered or for incidents they have access to
|
||||
if not self.request.user.is_staff:
|
||||
queryset = queryset.filter(
|
||||
Q(triggered_by=self.request.user) |
|
||||
Q(related_incident__assigned_to=self.request.user) |
|
||||
Q(related_incident__reporter=self.request.user)
|
||||
)
|
||||
|
||||
return queryset
|
||||
Reference in New Issue
Block a user