Files
ETB/ETB-API/knowledge_learning/management/commands/generate_postmortems.py
Iliyan Angelov 6b247e5b9f Updates
2025-09-19 11:58:53 +03:00

122 lines
4.2 KiB
Python

from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone
from datetime import timedelta
from incident_intelligence.models import Incident
from knowledge_learning.services.postmortem_generator import PostmortemGenerator
from knowledge_learning.models import Postmortem
class Command(BaseCommand):
help = 'Generate automated postmortems for resolved incidents'
def add_arguments(self, parser):
parser.add_argument(
'--days',
type=int,
default=7,
help='Number of days back to look for resolved incidents (default: 7)'
)
parser.add_argument(
'--severity',
type=str,
choices=['LOW', 'MEDIUM', 'HIGH', 'CRITICAL', 'EMERGENCY'],
help='Only generate postmortems for incidents with specific severity'
)
parser.add_argument(
'--force',
action='store_true',
help='Force generation even if postmortem already exists'
)
parser.add_argument(
'--dry-run',
action='store_true',
help='Show what would be generated without actually creating postmortems'
)
def handle(self, *args, **options):
days = options['days']
severity = options['severity']
force = options['force']
dry_run = options['dry_run']
# Calculate date range
end_date = timezone.now()
start_date = end_date - timedelta(days=days)
self.stdout.write(
self.style.SUCCESS(f'Looking for resolved incidents from {start_date.date()} to {end_date.date()}')
)
# Build queryset for resolved incidents
queryset = Incident.objects.filter(
status__in=['RESOLVED', 'CLOSED'],
resolved_at__gte=start_date,
resolved_at__lte=end_date
)
if severity:
queryset = queryset.filter(severity=severity)
# Filter out incidents that already have postmortems (unless force is used)
if not force:
existing_postmortem_incidents = Postmortem.objects.values_list('incident_id', flat=True)
queryset = queryset.exclude(id__in=existing_postmortem_incidents)
incidents = list(queryset)
if not incidents:
self.stdout.write(
self.style.WARNING('No resolved incidents found matching criteria')
)
return
self.stdout.write(
self.style.SUCCESS(f'Found {len(incidents)} incidents to process')
)
if dry_run:
self.stdout.write(self.style.WARNING('DRY RUN - No postmortems will be created'))
for incident in incidents:
self.stdout.write(f' - {incident.title} ({incident.severity}) - {incident.resolved_at}')
return
# Initialize postmortem generator
generator = PostmortemGenerator()
success_count = 0
error_count = 0
for incident in incidents:
try:
self.stdout.write(f'Generating postmortem for: {incident.title}')
result = generator.generate_postmortem_for_incident(
incident_id=str(incident.id),
include_timeline=True,
include_logs=True,
trigger='management_command'
)
self.stdout.write(
self.style.SUCCESS(f' ✓ Generated postmortem {result["postmortem_id"]}')
)
success_count += 1
except Exception as e:
self.stdout.write(
self.style.ERROR(f' ✗ Failed to generate postmortem: {str(e)}')
)
error_count += 1
# Summary
self.stdout.write('\n' + '='*50)
self.stdout.write(
self.style.SUCCESS(f'Postmortem generation completed:')
)
self.stdout.write(f' Successfully generated: {success_count}')
if error_count > 0:
self.stdout.write(
self.style.ERROR(f' Failed: {error_count}')
)
self.stdout.write('='*50)