feat(appliance): initial release of MERICA standalone appliance v1.0.0
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
Router for Testing and Managing Multi-Channel Alerting (Telegram, Slack, Discord, SITOMAT).
|
||||
Adheres to Dokumen 34 Architectural Blueprint.
|
||||
"""
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
import urllib.request
|
||||
from typing import Optional, Dict, Any, List
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/alerts", tags=["Alerting & Notifications"])
|
||||
|
||||
|
||||
class AlertTestRequest(BaseModel):
|
||||
channel: str = Field(..., description="Channel to test: 'telegram', 'slack', 'discord', 'sitomat'")
|
||||
webhook_url: Optional[str] = Field(None, description="Webhook URL for Slack, Discord, or SITOMAT")
|
||||
bot_token: Optional[str] = Field(None, description="Telegram Bot Token")
|
||||
chat_id: Optional[str] = Field(None, description="Telegram Chat ID")
|
||||
message: Optional[str] = Field(None, description="Custom test message content")
|
||||
|
||||
|
||||
class AlertChannelsStatusResponse(BaseModel):
|
||||
telegram_configured: bool
|
||||
slack_configured: bool
|
||||
discord_configured: bool
|
||||
sitomat_configured: bool
|
||||
default_coalescing_window_seconds: int = 300
|
||||
|
||||
|
||||
@router.get("/status", response_model=AlertChannelsStatusResponse)
|
||||
def get_alert_channels_status():
|
||||
"""
|
||||
Menampilkan status konfigurasi saluran alerting pada environment runtime.
|
||||
"""
|
||||
return AlertChannelsStatusResponse(
|
||||
telegram_configured=bool(os.getenv("ALERT_TELEGRAM_BOT_TOKEN") and os.getenv("ALERT_TELEGRAM_CHAT_ID")),
|
||||
slack_configured=bool(os.getenv("ALERT_SLACK_WEBHOOK_URL")),
|
||||
discord_configured=bool(os.getenv("ALERT_DISCORD_WEBHOOK_URL")),
|
||||
sitomat_configured=bool(os.getenv("ALERT_SITOMAT_GATEWAY_URL")),
|
||||
default_coalescing_window_seconds=300
|
||||
)
|
||||
|
||||
|
||||
@router.post("/test", status_code=status.HTTP_200_OK)
|
||||
def test_alert_dispatch(req: AlertTestRequest):
|
||||
"""
|
||||
Menguji konektivitas pengiriman notifikasi ke saluran target (Telegram, Slack, Discord, atau SITOMAT).
|
||||
"""
|
||||
channel = req.channel.lower().strip()
|
||||
msg_text = req.message or "🧪 MERICA Test Alert: Multi-Channel Webhook Connectivity Verified."
|
||||
|
||||
if channel == "telegram":
|
||||
token = req.bot_token or os.getenv("ALERT_TELEGRAM_BOT_TOKEN")
|
||||
chat_id = req.chat_id or os.getenv("ALERT_TELEGRAM_CHAT_ID")
|
||||
if not token or not chat_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Telegram Bot Token and Chat ID must be provided or configured in environment."
|
||||
)
|
||||
url = f"https://api.telegram.org/bot{token}/sendMessage"
|
||||
payload = {"chat_id": chat_id, "text": f"<b>{msg_text}</b>", "parse_mode": "HTML"}
|
||||
|
||||
elif channel == "slack":
|
||||
url = req.webhook_url or os.getenv("ALERT_SLACK_WEBHOOK_URL")
|
||||
if not url:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Slack Webhook URL must be provided or configured in environment."
|
||||
)
|
||||
payload = {
|
||||
"text": msg_text,
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {"type": "mrkdwn", "text": f"🧪 *MERICA Studio Test Alert*\n{msg_text}"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
elif channel == "discord":
|
||||
url = req.webhook_url or os.getenv("ALERT_DISCORD_WEBHOOK_URL")
|
||||
if not url:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Discord Webhook URL must be provided or configured in environment."
|
||||
)
|
||||
payload = {
|
||||
"content": f"🧪 **MERICA Test Alert**\n{msg_text}"
|
||||
}
|
||||
|
||||
elif channel == "sitomat":
|
||||
url = req.webhook_url or os.getenv("ALERT_SITOMAT_GATEWAY_URL")
|
||||
if not url:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="SITOMAT Gateway URL must be provided or configured in environment."
|
||||
)
|
||||
payload = {
|
||||
"incidentType": "TEST_CONNECTIVITY",
|
||||
"message": msg_text,
|
||||
"source": "MERICA Studio UI Inspector"
|
||||
}
|
||||
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Unsupported alert channel '{channel}'. Supported: 'telegram', 'slack', 'discord', 'sitomat'."
|
||||
)
|
||||
|
||||
# Dispatch HTTP POST
|
||||
try:
|
||||
http_req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode("utf-8"),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST"
|
||||
)
|
||||
with urllib.request.urlopen(http_req, timeout=5) as resp:
|
||||
status_code = getattr(resp, "status", 200)
|
||||
return {
|
||||
"status": "success",
|
||||
"channel": channel,
|
||||
"http_status": status_code,
|
||||
"message": f"Successfully delivered test alert to {channel}."
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Failed to test alert for channel %s: %s", channel, e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_502_BAD_GATEWAY,
|
||||
detail=f"Failed to deliver test alert to {channel}: {str(e)}"
|
||||
)
|
||||
Reference in New Issue
Block a user