Implement all vendor integrations, WAN graphs, and FortiGate health panel
- Wire up 26 vendor providers: Atlassian Statuspage API, Status.io, Instatus, AWS RSS feeds, Apple/Google JSON feeds, M365 Graph API, and synthetic checks - Add 11 new providers: AWS, Cloudflare, SmartPass, School Dismissal Manager, SherpaDesk, Classkick, ClassDojo, Savvas, Study Island, Promethean, RAZ-Kids - Rename Local Infrastructure → Internet (TCP check to 8.8.8.8:53) - Add WAN throughput graph section: dual-link canvas graphs (Crown Castle + Comcast) polling FortiGate REST API every 30s with 30-min rolling history - Add FortiGate health card: uptime, CPU %, memory % from FortiOS API - Add /api/throughput and /api/fortigate-health endpoints - Add README with setup instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
export const name = "Amazon AWS";
|
||||
export const url = "https://health.aws.amazon.com/health/status";
|
||||
|
||||
// Core services in both Pittsburgh-adjacent regions + global services.
|
||||
// Expand this list if you discover specific services your vendors rely on.
|
||||
const FEEDS = [
|
||||
{ url: "https://status.aws.amazon.com/rss/ec2-us-east-1.rss", label: "EC2 (N. Virginia)" },
|
||||
{ url: "https://status.aws.amazon.com/rss/ec2-us-east-2.rss", label: "EC2 (Ohio)" },
|
||||
{ url: "https://status.aws.amazon.com/rss/s3-us-east-1.rss", label: "S3 (N. Virginia)" },
|
||||
{ url: "https://status.aws.amazon.com/rss/cloudfront.rss", label: "CloudFront" },
|
||||
{ url: "https://status.aws.amazon.com/rss/route53.rss", label: "Route 53" },
|
||||
];
|
||||
|
||||
const SEVERITY_ORDER = ["operational", "degraded", "outage"];
|
||||
|
||||
function worstStatus(a, b) {
|
||||
return SEVERITY_ORDER.indexOf(a) >= SEVERITY_ORDER.indexOf(b) ? a : b;
|
||||
}
|
||||
|
||||
// Extract the text of the first <title> inside the first <item>.
|
||||
// Returns null if there are no items (clean feed = all clear).
|
||||
function parseFirstItemTitle(xml) {
|
||||
const itemMatch = xml.match(/<item[\s>][\s\S]*?<\/item>/i);
|
||||
if (!itemMatch) return null;
|
||||
const titleMatch = itemMatch[0].match(/<title>([\s\S]*?)<\/title>/i);
|
||||
return titleMatch ? titleMatch[1].trim() : null;
|
||||
}
|
||||
|
||||
function titleToStatus(title) {
|
||||
if (!title) return "operational"; // no items = clean feed
|
||||
const t = title.toLowerCase();
|
||||
if (t.includes("operating normally") || t.includes("informational")) return "operational";
|
||||
if (t.includes("performance issues") || t.includes("degraded")) return "degraded";
|
||||
if (t.includes("service disruption") || t.includes("disruption")) return "outage";
|
||||
return "degraded"; // unknown incident title — assume degraded
|
||||
}
|
||||
|
||||
async function checkFeed({ url, label }) {
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`${label}: HTTP ${res.status}`);
|
||||
const xml = await res.text();
|
||||
const title = parseFirstItemTitle(xml);
|
||||
const status = titleToStatus(title);
|
||||
return { label, status, title };
|
||||
}
|
||||
|
||||
export async function checkStatus() {
|
||||
const results = await Promise.allSettled(FEEDS.map(checkFeed));
|
||||
|
||||
let overall = "operational";
|
||||
const issues = [];
|
||||
|
||||
for (const result of results) {
|
||||
if (result.status === "rejected") {
|
||||
overall = worstStatus(overall, "degraded");
|
||||
issues.push(`Check failed: ${result.reason?.message ?? "unknown error"}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const { label, status, title } = result.value;
|
||||
overall = worstStatus(overall, status);
|
||||
|
||||
if (status !== "operational") {
|
||||
issues.push(`${label}: ${title ?? "unknown issue"}`);
|
||||
}
|
||||
}
|
||||
|
||||
const message =
|
||||
issues.length > 0 ? issues.join(" | ") : "All monitored services operating normally.";
|
||||
|
||||
return {
|
||||
name,
|
||||
status: overall,
|
||||
message,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user