#!/usr/bin/env python3 """ AWS Lambda Function Simulation: On-Call Incident Dispatcher. In AWS Production: - Triggered by Amazon SNS topic subscription or EventBridge rule. - Parses the alert payload. - Invokes AWS ECS / Fargate run_task API to launch an ephemeral container. """ import json import logging import os import subprocess import sys import time logging.basicConfig(level=logging.INFO, format="%(asctime)s [LAMBDA] %(message)s") logger = logging.getLogger("lambda-dispatcher") def lambda_handler(event, context=None): logger.info("Lambda invocation started with event payload.") # 1. Parse Event from SNS or direct EventBridge invocation alert_data = {} if "Records" in event and len(event["Records"]) > 0: sns_record = event["Records"][0].get("Sns", {}) raw_msg = sns_record.get("Message", "{}") if isinstance(raw_msg, str): try: alert_data = json.loads(raw_msg) except json.JSONDecodeError: alert_data = {"summary": raw_msg} else: alert_data = raw_msg elif "detail" in event: alert_data = event["detail"] else: alert_data = event alert_name = alert_data.get("alert_name", alert_data.get("alertname", "HighHttpErrorRate")) severity = alert_data.get("severity", "critical") service_name = alert_data.get("service_name", alert_data.get("service", "api-backend")) ts = int(time.time()) incident_id = f"INC-{ts}-{alert_name}" logger.info(f"Processed alert: '{alert_name}' [{severity}] for service '{service_name}' -> Incident ID: {incident_id}") # 2. Mimic ECS run_task API # In cloud: ecs_client.run_task(cluster='on-call-cluster', taskDefinition='on-call-agent:1', launchType='FARGATE', overrides={...}) # In local simulation: runs an ephemeral Docker container using amazon/aws-cli:latest or docker runner s3_endpoint = os.environ.get("S3_ENDPOINT_URL", "http://personal-lifecycle-cloud-emulator:4566") s3_bucket = os.environ.get("S3_BUCKET", "lifecycle-on-call-incidents") script_dir = os.path.dirname(os.path.abspath(__file__)) sim_dir = os.path.dirname(script_dir) fargate_script = os.path.join(sim_dir, "fargate-task", "task-runner.sh") logger.info("Dispatching AWS ECS / Fargate ephemeral container task...") docker_cmd = [ "docker", "run", "--rm", "--name", f"fargate-task-{incident_id.lower()}", "--network", "personal-lifecycle-observability-net", "-e", f"INCIDENT_ID={incident_id}", "-e", f"ALERT_NAME={alert_name}", "-e", f"SEVERITY={severity}", "-e", f"SERVICE_NAME={service_name}", "-e", f"S3_ENDPOINT_URL={s3_endpoint}", "-e", f"S3_BUCKET={s3_bucket}", "-e", "AWS_DEFAULT_REGION=us-east-1", "-e", "AWS_ACCESS_KEY_ID=test", "-e", "AWS_SECRET_ACCESS_KEY=test", "-v", f"{fargate_script}:/task-runner.sh:ro", "--entrypoint", "/task-runner.sh", "amazon/aws-cli:latest" ] proc = subprocess.run(docker_cmd, capture_output=True, text=True) if proc.stdout: for line in proc.stdout.strip().split("\n"): logger.info(f"[FARGATE-STDOUT] {line}") if proc.stderr: for line in proc.stderr.strip().split("\n"): logger.warning(f"[FARGATE-STDERR] {line}") if proc.returncode != 0: logger.error(f"Fargate task exited with non-zero code {proc.returncode}") return { "statusCode": 500, "incidentId": incident_id, "error": proc.stderr } task_arn = f"arn:aws:ecs:us-east-1:000000000000:task/{incident_id}" logger.info(f"Fargate container task completed and terminated immediately. Task ARN: {task_arn}") return { "statusCode": 200, "incidentId": incident_id, "taskArn": task_arn, "s3AuditLocation": f"s3://{s3_bucket}/{incident_id}/" } if __name__ == "__main__": sample_sns_event = { "Records": [ { "Sns": { "Message": json.dumps({ "alert_name": "HighHttpErrorRate", "severity": "critical", "service_name": "api-backend", "summary": "Elevated HTTP 5xx error rate", "observed_value": 100.0, "timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) }) } } ] } result = lambda_handler(sample_sns_event) print(json.dumps(result, indent=2))