Files
ETB/ETB-API/collaboration_war_rooms/services/automation_commands.py
Iliyan Angelov 6b247e5b9f Updates
2025-09-19 11:58:53 +03:00

367 lines
14 KiB
Python

"""
Automation Commands Service for ChatOps Integration
Handles execution of automation commands via chat interface
"""
from django.utils import timezone
from django.contrib.auth import get_user_model
from typing import Dict, Any, Optional, List
from ..models import ChatCommand, WarRoomMessage
from automation_orchestration.models import Runbook, RunbookExecution, AutoRemediation, AutoRemediationExecution
from incident_intelligence.models import Incident
User = get_user_model()
class AutomationCommandService:
"""Service for handling automation commands in chat"""
@staticmethod
def execute_runbook_command(chat_command: ChatCommand, runbook_name: str, user: User) -> Dict[str, Any]:
"""Execute a runbook via chat command"""
try:
incident = chat_command.message.war_room.incident
# Find the runbook
runbook = Runbook.objects.filter(
name__icontains=runbook_name,
is_active=True
).first()
if not runbook:
return {
'error': f'Runbook "{runbook_name}" not found or inactive',
'suggestions': AutomationCommandService._get_runbook_suggestions(runbook_name)
}
# Check if runbook applies to this incident
if not AutomationCommandService._runbook_applies_to_incident(runbook, incident):
return {
'error': f'Runbook "{runbook.name}" does not apply to this incident type',
'incident_category': incident.category,
'incident_severity': incident.severity
}
# Execute the runbook
execution = RunbookExecution.objects.create(
runbook=runbook,
incident=incident,
triggered_by=user,
trigger_type='CHAT_COMMAND',
trigger_data={
'chat_command_id': str(chat_command.id),
'command_text': chat_command.command_text
}
)
# Update chat command with execution reference
chat_command.automation_execution = execution
chat_command.save()
# Create status message in chat
AutomationCommandService._create_execution_status_message(
chat_command.message.war_room,
f"🚀 **Runbook Execution Started**\n\n"
f"**Runbook:** {runbook.name}\n"
f"**Execution ID:** {execution.id}\n"
f"**Triggered by:** {user.username}\n"
f"**Status:** {execution.status}\n\n"
f"Monitor progress in the automation dashboard."
)
return {
'success': True,
'execution_id': str(execution.id),
'runbook_name': runbook.name,
'status': execution.status,
'message': f'Runbook "{runbook.name}" execution started successfully'
}
except Exception as e:
return {
'error': f'Failed to execute runbook: {str(e)}'
}
@staticmethod
def execute_auto_remediation_command(chat_command: ChatCommand, remediation_name: str, user: User) -> Dict[str, Any]:
"""Execute auto-remediation via chat command"""
try:
incident = chat_command.message.war_room.incident
# Find the auto-remediation
remediation = AutoRemediation.objects.filter(
name__icontains=remediation_name,
is_active=True
).first()
if not remediation:
return {
'error': f'Auto-remediation "{remediation_name}" not found or inactive',
'suggestions': AutomationCommandService._get_remediation_suggestions(remediation_name)
}
# Check if remediation applies to this incident
if not AutomationCommandService._remediation_applies_to_incident(remediation, incident):
return {
'error': f'Auto-remediation "{remediation.name}" does not apply to this incident type',
'incident_category': incident.category,
'incident_severity': incident.severity
}
# Execute the auto-remediation
execution = AutoRemediationExecution.objects.create(
auto_remediation=remediation,
incident=incident,
triggered_by=user,
trigger_type='CHAT_COMMAND',
trigger_data={
'chat_command_id': str(chat_command.id),
'command_text': chat_command.command_text
}
)
# Create status message in chat
AutomationCommandService._create_execution_status_message(
chat_command.message.war_room,
f"🔧 **Auto-Remediation Started**\n\n"
f"**Remediation:** {remediation.name}\n"
f"**Execution ID:** {execution.id}\n"
f"**Triggered by:** {user.username}\n"
f"**Status:** {execution.status}\n\n"
f"Monitor progress in the automation dashboard."
)
return {
'success': True,
'execution_id': str(execution.id),
'remediation_name': remediation.name,
'status': execution.status,
'message': f'Auto-remediation "{remediation.name}" execution started successfully'
}
except Exception as e:
return {
'error': f'Failed to execute auto-remediation: {str(e)}'
}
@staticmethod
def get_incident_status(chat_command: ChatCommand) -> Dict[str, Any]:
"""Get comprehensive incident status"""
try:
incident = chat_command.message.war_room.incident
# Get SLA status
from .sla_notifications import SLANotificationService
sla_status = SLANotificationService.get_sla_status_for_incident(incident)
# Get recent runbook executions
recent_executions = RunbookExecution.objects.filter(
incident=incident
).order_by('-created_at')[:5]
executions_data = []
for execution in recent_executions:
executions_data.append({
'id': str(execution.id),
'runbook_name': execution.runbook.name,
'status': execution.status,
'started_at': execution.started_at.isoformat() if execution.started_at else None,
'completed_at': execution.completed_at.isoformat() if execution.completed_at else None
})
return {
'incident_id': str(incident.id),
'title': incident.title,
'status': incident.status,
'severity': incident.severity,
'priority': incident.priority,
'category': incident.category,
'assigned_to': incident.assigned_to.username if incident.assigned_to else None,
'reporter': incident.reporter.username if incident.reporter else None,
'created_at': incident.created_at.isoformat(),
'updated_at': incident.updated_at.isoformat(),
'resolution_time': str(incident.resolution_time) if incident.resolution_time else None,
'sla_status': sla_status,
'recent_executions': executions_data,
'automation_enabled': incident.automation_enabled,
'runbook_suggested': incident.runbook_suggested,
'auto_remediation_attempted': incident.auto_remediation_attempted
}
except Exception as e:
return {
'error': f'Failed to get incident status: {str(e)}'
}
@staticmethod
def list_available_runbooks(incident: Incident) -> List[Dict[str, Any]]:
"""List runbooks available for the incident"""
try:
runbooks = Runbook.objects.filter(is_active=True)
available_runbooks = []
for runbook in runbooks:
if AutomationCommandService._runbook_applies_to_incident(runbook, incident):
available_runbooks.append({
'id': str(runbook.id),
'name': runbook.name,
'description': runbook.description,
'category': runbook.category,
'severity_levels': runbook.severity_levels,
'estimated_duration': runbook.estimated_duration
})
return available_runbooks
except Exception as e:
return []
@staticmethod
def list_available_remediations(incident: Incident) -> List[Dict[str, Any]]:
"""List auto-remediations available for the incident"""
try:
remediations = AutoRemediation.objects.filter(is_active=True)
available_remediations = []
for remediation in remediations:
if AutomationCommandService._remediation_applies_to_incident(remediation, incident):
available_remediations.append({
'id': str(remediation.id),
'name': remediation.name,
'description': remediation.description,
'category': remediation.category,
'severity_levels': remediation.severity_levels,
'estimated_duration': remediation.estimated_duration
})
return available_remediations
except Exception as e:
return []
@staticmethod
def _runbook_applies_to_incident(runbook: Runbook, incident: Incident) -> bool:
"""Check if runbook applies to the incident"""
# Check categories
if runbook.categories and incident.category not in runbook.categories:
return False
# Check severity levels
if runbook.severity_levels and incident.severity not in runbook.severity_levels:
return False
# Check if runbook is active
if not runbook.is_active:
return False
return True
@staticmethod
def _remediation_applies_to_incident(remediation: AutoRemediation, incident: Incident) -> bool:
"""Check if auto-remediation applies to the incident"""
# Check categories
if remediation.categories and incident.category not in remediation.categories:
return False
# Check severity levels
if remediation.severity_levels and incident.severity not in remediation.severity_levels:
return False
# Check if remediation is active
if not remediation.is_active:
return False
return True
@staticmethod
def _get_runbook_suggestions(partial_name: str) -> List[str]:
"""Get runbook name suggestions based on partial input"""
try:
runbooks = Runbook.objects.filter(
name__icontains=partial_name,
is_active=True
).values_list('name', flat=True)[:5]
return list(runbooks)
except:
return []
@staticmethod
def _get_remediation_suggestions(partial_name: str) -> List[str]:
"""Get auto-remediation name suggestions based on partial input"""
try:
remediations = AutoRemediation.objects.filter(
name__icontains=partial_name,
is_active=True
).values_list('name', flat=True)[:5]
return list(remediations)
except:
return []
@staticmethod
def _create_execution_status_message(war_room: 'WarRoom', content: str):
"""Create a status message in the war room"""
try:
WarRoomMessage.objects.create(
war_room=war_room,
content=content,
message_type='SYSTEM',
sender=None,
sender_name='Automation System',
external_data={
'message_type': 'automation_status'
}
)
except Exception as e:
print(f"Error creating status message: {e}")
@staticmethod
def update_execution_status(execution_id: str, status: str, result: Dict[str, Any] = None):
"""Update execution status and notify chat room"""
try:
# Find the chat command that triggered this execution
chat_command = ChatCommand.objects.filter(
automation_execution_id=execution_id
).first()
if not chat_command:
return False
# Update chat command status
chat_command.execution_status = status
if result:
chat_command.execution_result = result
chat_command.save()
# Create status update message
status_emoji = {
'SUCCESS': '',
'FAILED': '',
'RUNNING': '🔄',
'CANCELLED': '⏹️'
}.get(status, '📊')
message_content = (
f"{status_emoji} **Execution Status Update**\n\n"
f"**Status:** {status}\n"
f"**Execution ID:** {execution_id}\n"
)
if result:
if 'error' in result:
message_content += f"**Error:** {result['error']}\n"
if 'output' in result:
message_content += f"**Output:** {result['output'][:200]}...\n"
AutomationCommandService._create_execution_status_message(
chat_command.message.war_room,
message_content
)
return True
except Exception as e:
print(f"Error updating execution status: {e}")
return False