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)