Updates
This commit is contained in:
480
ETB-API/monitoring/views.py
Normal file
480
ETB-API/monitoring/views.py
Normal file
@@ -0,0 +1,480 @@
|
||||
"""
|
||||
Views for monitoring system
|
||||
"""
|
||||
import logging
|
||||
from rest_framework import viewsets, status, permissions
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework.filters import SearchFilter, OrderingFilter
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
|
||||
from monitoring.models import (
|
||||
MonitoringTarget, HealthCheck, SystemMetric, MetricMeasurement,
|
||||
AlertRule, Alert, MonitoringDashboard, SystemStatus
|
||||
)
|
||||
from monitoring.serializers import (
|
||||
MonitoringTargetSerializer, HealthCheckSerializer, SystemMetricSerializer,
|
||||
MetricMeasurementSerializer, AlertRuleSerializer, AlertSerializer,
|
||||
MonitoringDashboardSerializer, SystemStatusSerializer,
|
||||
HealthCheckSummarySerializer, MetricTrendSerializer, AlertSummarySerializer,
|
||||
SystemOverviewSerializer
|
||||
)
|
||||
from monitoring.services.health_checks import HealthCheckService
|
||||
from monitoring.services.metrics_collector import MetricsCollector, MetricsAggregator
|
||||
from monitoring.services.alerting import AlertingService
|
||||
from monitoring.tasks import (
|
||||
execute_health_checks, collect_metrics, evaluate_alerts,
|
||||
generate_system_status_report
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MonitoringTargetViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for MonitoringTarget model"""
|
||||
|
||||
queryset = MonitoringTarget.objects.all()
|
||||
serializer_class = MonitoringTargetSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['target_type', 'status', 'last_status', 'related_module']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'created_at', 'last_checked']
|
||||
ordering = ['name']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating a monitoring target"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def test_connection(self, request, pk=None):
|
||||
"""Test connection to monitoring target"""
|
||||
target = self.get_object()
|
||||
|
||||
try:
|
||||
health_service = HealthCheckService()
|
||||
result = health_service.execute_health_check(target, 'HTTP')
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'result': result
|
||||
})
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def enable_monitoring(self, request, pk=None):
|
||||
"""Enable monitoring for a target"""
|
||||
target = self.get_object()
|
||||
target.status = 'ACTIVE'
|
||||
target.save()
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Monitoring enabled for {target.name}'
|
||||
})
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def disable_monitoring(self, request, pk=None):
|
||||
"""Disable monitoring for a target"""
|
||||
target = self.get_object()
|
||||
target.status = 'INACTIVE'
|
||||
target.save()
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Monitoring disabled for {target.name}'
|
||||
})
|
||||
|
||||
|
||||
class HealthCheckViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for HealthCheck model (read-only)"""
|
||||
|
||||
queryset = HealthCheck.objects.all()
|
||||
serializer_class = HealthCheckSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['target', 'check_type', 'status']
|
||||
ordering_fields = ['checked_at', 'response_time_ms']
|
||||
ordering = ['-checked_at']
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def summary(self, request):
|
||||
"""Get health check summary"""
|
||||
try:
|
||||
health_service = HealthCheckService()
|
||||
summary = health_service.get_system_health_summary()
|
||||
|
||||
serializer = HealthCheckSummarySerializer(summary)
|
||||
return Response(serializer.data)
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@action(detail=False, methods=['post'])
|
||||
def run_all_checks(self, request):
|
||||
"""Run health checks for all targets"""
|
||||
try:
|
||||
# Execute health checks asynchronously
|
||||
task = execute_health_checks.delay()
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': 'Health checks started',
|
||||
'task_id': task.id
|
||||
})
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
||||
class SystemMetricViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for SystemMetric model"""
|
||||
|
||||
queryset = SystemMetric.objects.all()
|
||||
serializer_class = SystemMetricSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['metric_type', 'category', 'is_active', 'related_module']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'created_at']
|
||||
ordering = ['name']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating a metric"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['get'])
|
||||
def measurements(self, request, pk=None):
|
||||
"""Get measurements for a metric"""
|
||||
metric = self.get_object()
|
||||
|
||||
# Get query parameters
|
||||
hours = int(request.query_params.get('hours', 24))
|
||||
limit = int(request.query_params.get('limit', 100))
|
||||
|
||||
since = timezone.now() - timedelta(hours=hours)
|
||||
measurements = MetricMeasurement.objects.filter(
|
||||
metric=metric,
|
||||
timestamp__gte=since
|
||||
).order_by('-timestamp')[:limit]
|
||||
|
||||
serializer = MetricMeasurementSerializer(measurements, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(detail=True, methods=['get'])
|
||||
def trends(self, request, pk=None):
|
||||
"""Get metric trends"""
|
||||
metric = self.get_object()
|
||||
days = int(request.query_params.get('days', 7))
|
||||
|
||||
try:
|
||||
aggregator = MetricsAggregator()
|
||||
trends = aggregator.get_metric_trends(metric, days)
|
||||
|
||||
serializer = MetricTrendSerializer(trends)
|
||||
return Response(serializer.data)
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
||||
class MetricMeasurementViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for MetricMeasurement model (read-only)"""
|
||||
|
||||
queryset = MetricMeasurement.objects.all()
|
||||
serializer_class = MetricMeasurementSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, OrderingFilter]
|
||||
filterset_fields = ['metric']
|
||||
ordering_fields = ['timestamp', 'value']
|
||||
ordering = ['-timestamp']
|
||||
|
||||
|
||||
class AlertRuleViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for AlertRule model"""
|
||||
|
||||
queryset = AlertRule.objects.all()
|
||||
serializer_class = AlertRuleSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['alert_type', 'severity', 'status', 'is_enabled']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'created_at']
|
||||
ordering = ['name']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating an alert rule"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def test_rule(self, request, pk=None):
|
||||
"""Test an alert rule"""
|
||||
rule = self.get_object()
|
||||
|
||||
try:
|
||||
alerting_service = AlertingService()
|
||||
# This would test the rule without creating an alert
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Alert rule {rule.name} test completed'
|
||||
})
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def enable_rule(self, request, pk=None):
|
||||
"""Enable an alert rule"""
|
||||
rule = self.get_object()
|
||||
rule.is_enabled = True
|
||||
rule.save()
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Alert rule {rule.name} enabled'
|
||||
})
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def disable_rule(self, request, pk=None):
|
||||
"""Disable an alert rule"""
|
||||
rule = self.get_object()
|
||||
rule.is_enabled = False
|
||||
rule.save()
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'Alert rule {rule.name} disabled'
|
||||
})
|
||||
|
||||
|
||||
class AlertViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for Alert model"""
|
||||
|
||||
queryset = Alert.objects.all()
|
||||
serializer_class = AlertSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['rule', 'severity', 'status']
|
||||
search_fields = ['title', 'description']
|
||||
ordering_fields = ['triggered_at', 'severity']
|
||||
ordering = ['-triggered_at']
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def acknowledge(self, request, pk=None):
|
||||
"""Acknowledge an alert"""
|
||||
alert = self.get_object()
|
||||
|
||||
try:
|
||||
alerting_service = AlertingService()
|
||||
result = alerting_service.acknowledge_alert(str(alert.id), request.user)
|
||||
|
||||
return Response(result)
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def resolve(self, request, pk=None):
|
||||
"""Resolve an alert"""
|
||||
alert = self.get_object()
|
||||
|
||||
try:
|
||||
alerting_service = AlertingService()
|
||||
result = alerting_service.resolve_alert(str(alert.id), request.user)
|
||||
|
||||
return Response(result)
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def summary(self, request):
|
||||
"""Get alert summary"""
|
||||
try:
|
||||
alerting_service = AlertingService()
|
||||
active_alerts = alerting_service.get_active_alerts()
|
||||
|
||||
# Calculate summary
|
||||
total_alerts = Alert.objects.count()
|
||||
critical_alerts = Alert.objects.filter(severity='CRITICAL', status='TRIGGERED').count()
|
||||
high_alerts = Alert.objects.filter(severity='HIGH', status='TRIGGERED').count()
|
||||
medium_alerts = Alert.objects.filter(severity='MEDIUM', status='TRIGGERED').count()
|
||||
low_alerts = Alert.objects.filter(severity='LOW', status='TRIGGERED').count()
|
||||
acknowledged_alerts = Alert.objects.filter(status='ACKNOWLEDGED').count()
|
||||
resolved_alerts = Alert.objects.filter(status='RESOLVED').count()
|
||||
|
||||
summary = {
|
||||
'total_alerts': total_alerts,
|
||||
'critical_alerts': critical_alerts,
|
||||
'high_alerts': high_alerts,
|
||||
'medium_alerts': medium_alerts,
|
||||
'low_alerts': low_alerts,
|
||||
'acknowledged_alerts': acknowledged_alerts,
|
||||
'resolved_alerts': resolved_alerts
|
||||
}
|
||||
|
||||
serializer = AlertSummarySerializer(summary)
|
||||
return Response(serializer.data)
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
||||
class MonitoringDashboardViewSet(viewsets.ModelViewSet):
|
||||
"""ViewSet for MonitoringDashboard model"""
|
||||
|
||||
queryset = MonitoringDashboard.objects.all()
|
||||
serializer_class = MonitoringDashboardSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['dashboard_type', 'is_active', 'is_public']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name', 'created_at']
|
||||
ordering = ['name']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the creator when creating a dashboard"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
def get_queryset(self):
|
||||
"""Filter dashboards based on user access"""
|
||||
queryset = super().get_queryset()
|
||||
|
||||
if not self.request.user.is_staff:
|
||||
# Non-staff users can only see public dashboards or dashboards they have access to
|
||||
queryset = queryset.filter(
|
||||
models.Q(is_public=True) |
|
||||
models.Q(allowed_users=self.request.user)
|
||||
).distinct()
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
class SystemStatusViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""ViewSet for SystemStatus model (read-only)"""
|
||||
|
||||
queryset = SystemStatus.objects.all()
|
||||
serializer_class = SystemStatusSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
ordering = ['-started_at']
|
||||
|
||||
|
||||
class SystemOverviewView(APIView):
|
||||
"""System overview endpoint"""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
"""Get system overview"""
|
||||
try:
|
||||
# Get current system status
|
||||
current_status = SystemStatus.objects.filter(
|
||||
resolved_at__isnull=True
|
||||
).order_by('-started_at').first()
|
||||
|
||||
if not current_status:
|
||||
# Create default operational status
|
||||
current_status = SystemStatus.objects.create(
|
||||
status='OPERATIONAL',
|
||||
message='All systems operational',
|
||||
created_by=request.user
|
||||
)
|
||||
|
||||
# Get health summary
|
||||
health_service = HealthCheckService()
|
||||
health_summary = health_service.get_system_health_summary()
|
||||
|
||||
# Get alert summary
|
||||
alerting_service = AlertingService()
|
||||
active_alerts = alerting_service.get_active_alerts()
|
||||
|
||||
alert_summary = {
|
||||
'total_alerts': len(active_alerts),
|
||||
'critical_alerts': len([a for a in active_alerts if a['severity'] == 'CRITICAL']),
|
||||
'high_alerts': len([a for a in active_alerts if a['severity'] == 'HIGH']),
|
||||
'medium_alerts': len([a for a in active_alerts if a['severity'] == 'MEDIUM']),
|
||||
'low_alerts': len([a for a in active_alerts if a['severity'] == 'LOW']),
|
||||
'acknowledged_alerts': 0, # Would be calculated from database
|
||||
'resolved_alerts': 0 # Would be calculated from database
|
||||
}
|
||||
|
||||
# Get recent incidents (mock data for now)
|
||||
recent_incidents = []
|
||||
|
||||
# Get top metrics (mock data for now)
|
||||
top_metrics = []
|
||||
|
||||
# Get system resources
|
||||
import psutil
|
||||
system_resources = {
|
||||
'cpu_percent': psutil.cpu_percent(interval=1),
|
||||
'memory_percent': psutil.virtual_memory().percent,
|
||||
'disk_percent': psutil.disk_usage('/').percent
|
||||
}
|
||||
|
||||
overview = {
|
||||
'system_status': current_status,
|
||||
'health_summary': health_summary,
|
||||
'alert_summary': alert_summary,
|
||||
'recent_incidents': recent_incidents,
|
||||
'top_metrics': top_metrics,
|
||||
'system_resources': system_resources
|
||||
}
|
||||
|
||||
serializer = SystemOverviewSerializer(overview)
|
||||
return Response(serializer.data)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get system overview: {e}")
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
||||
class MonitoringTasksView(APIView):
|
||||
"""Monitoring tasks management"""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
"""Execute monitoring tasks"""
|
||||
task_type = request.data.get('task_type')
|
||||
|
||||
try:
|
||||
if task_type == 'health_checks':
|
||||
task = execute_health_checks.delay()
|
||||
elif task_type == 'metrics_collection':
|
||||
task = collect_metrics.delay()
|
||||
elif task_type == 'alert_evaluation':
|
||||
task = evaluate_alerts.delay()
|
||||
elif task_type == 'system_status_report':
|
||||
task = generate_system_status_report.delay()
|
||||
else:
|
||||
return Response({
|
||||
'error': 'Invalid task type'
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return Response({
|
||||
'status': 'success',
|
||||
'message': f'{task_type} task started',
|
||||
'task_id': task.id
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return Response({
|
||||
'error': str(e)
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
Reference in New Issue
Block a user