778 lines
21 KiB
JSON
778 lines
21 KiB
JSON
{
|
|
"name": "Homelab Health Monitor",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"rule": {
|
|
"interval": [
|
|
{
|
|
"field": "minutes",
|
|
"minutesInterval": 15
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "schedule-trigger",
|
|
"name": "Every 15 Minutes",
|
|
"type": "n8n-nodes-base.scheduleTrigger",
|
|
"typeVersion": 1.2,
|
|
"position": [
|
|
250,
|
|
300
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "health-check",
|
|
"responseMode": "responseNode",
|
|
"options": {}
|
|
},
|
|
"id": "webhook-trigger",
|
|
"name": "Manual Trigger Webhook",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
250,
|
|
500
|
|
],
|
|
"webhookId": "homelab-health"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://www.google.com",
|
|
"options": {
|
|
"timeout": 5000
|
|
}
|
|
},
|
|
"id": "check-internet-dns",
|
|
"name": "Check Google DNS",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
500,
|
|
200
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://1.1.1.1",
|
|
"options": {
|
|
"timeout": 5000
|
|
}
|
|
},
|
|
"id": "check-cloudflare",
|
|
"name": "Check Cloudflare DNS",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
500,
|
|
350
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=http://192.168.1.196:80",
|
|
"options": {
|
|
"timeout": 3000
|
|
}
|
|
},
|
|
"id": "check-internal-dns-1",
|
|
"name": "Check Pi-hole .196",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
500,
|
|
500
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=http://192.168.1.245:80",
|
|
"options": {
|
|
"timeout": 3000
|
|
}
|
|
},
|
|
"id": "check-internal-dns-2",
|
|
"name": "Check Pi-hole .245",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
500,
|
|
650
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=http://192.168.1.62:80",
|
|
"options": {
|
|
"timeout": 3000
|
|
}
|
|
},
|
|
"id": "check-internal-dns-3",
|
|
"name": "Check Pi-hole .62",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
500,
|
|
800
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "docker service ls --format '{{json .}}'"
|
|
},
|
|
"id": "docker-service-list",
|
|
"name": "Get Docker Services",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
750,
|
|
300
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "docker node ls --format '{{json .}}'"
|
|
},
|
|
"id": "docker-node-list",
|
|
"name": "Get Swarm Nodes",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
750,
|
|
450
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://komodo.sj98.duckdns.org",
|
|
"options": {
|
|
"timeout": 5000
|
|
}
|
|
},
|
|
"id": "check-komodo",
|
|
"name": "Check Komodo",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1000,
|
|
200
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://ai.sj98.duckdns.org/health",
|
|
"options": {
|
|
"timeout": 5000
|
|
}
|
|
},
|
|
"id": "check-openwebui",
|
|
"name": "Check OpenWebUI",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1000,
|
|
350
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://paperless.sj98.duckdns.org/api",
|
|
"options": {
|
|
"timeout": 5000
|
|
}
|
|
},
|
|
"id": "check-paperless",
|
|
"name": "Check Paperless",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1000,
|
|
500
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://prometheus.sj98.duckdns.org/-/healthy",
|
|
"options": {
|
|
"timeout": 5000
|
|
}
|
|
},
|
|
"id": "check-prometheus",
|
|
"name": "Check Prometheus",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1000,
|
|
650
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "curl -sf http://192.168.1.1 > /dev/null && echo '{\"node\": \"Gateway\", \"status\": \"healthy\"}' || echo '{\"node\": \"Gateway\", \"error\": \"unreachable\"}'"
|
|
},
|
|
"id": "check-gateway",
|
|
"name": "Check Gateway",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
500,
|
|
950
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"command": "metrics=$(curl -s --connect-timeout 2 http://192.168.1.57:9100/metrics | grep -E \"node_load1 |node_memory_MemAvailable_bytes |node_memory_MemTotal_bytes \" | tr '\\n' ',' || echo \"failed\"); echo \"{\\\"node\\\": \\\"Proxmox Host\\\", \\\"metrics\\\": \\\"$metrics\\\"}\""
|
|
},
|
|
"id": "check-proxmox",
|
|
"name": "Check Proxmox",
|
|
"type": "n8n-nodes-base.executeCommand",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
1000,
|
|
950
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=http://lm-studio:1234/v1/models",
|
|
"options": {
|
|
"timeout": 5000
|
|
}
|
|
},
|
|
"id": "check-lm-studio",
|
|
"name": "Check LM Studio",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1000,
|
|
800
|
|
],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const items = $input.all();\n\nconst healthData = {\n timestamp: new Date().toISOString(),\n network: {\n internet: [],\n internal: [],\n gateway: {}\n },\n docker: {\n services: [],\n nodes: []\n },\n infrastructure: {\n proxmox: {}\n },\n services: []\n};\n\n// Process all health check results\nfor (const item of items) {\n let nodeName = item.json.node || 'unknown';\n const success = !item.json.error;\n \n // Handle Execute Command JSON output (Gateway/Proxmox)\n if (item.json.stdout && item.json.stdout.trim().startsWith('{')) {\n try {\n const parsed = JSON.parse(item.json.stdout);\n if (parsed.node) nodeName = parsed.node;\n if (parsed.metrics) item.json.metrics = parsed.metrics;\n if (parsed.status) item.json.status = parsed.status;\n } catch (e) {}\n }\n\n if (nodeName.includes('DNS') || nodeName.includes('Cloudflare')) {\n healthData.network.internet.push({\n name: nodeName,\n status: success ? 'healthy' : 'unhealthy',\n error: item.json.error || null\n });\n } else if (nodeName.includes('Gateway')) {\n healthData.network.gateway = {\n status: item.json.status || 'unhealthy',\n error: item.json.error || null\n };\n } else if (nodeName.includes('Pi-hole')) {\n healthData.network.internal.push({\n name: nodeName,\n status: success ? 'healthy' : 'unhealthy',\n error: item.json.error || null\n });\n } else if (nodeName.includes('Proxmox')) {\n healthData.infrastructure.proxmox = {\n status: item.json.metrics ? 'healthy' : 'unhealthy',\n metrics: item.json.metrics || null,\n error: item.json.error || null\n };\n } else if (nodeName.includes('Docker')) {\n try {\n const data = JSON.parse(item.json.stdout || '[]');\n if (nodeName.includes('Services')) {\n healthData.docker.services = data;\n } else if (nodeName.includes('Nodes')) {\n healthData.docker.nodes = data;\n }\n } catch (e) {\n healthData.docker.error = e.message;\n }\n } else {\n healthData.services.push({\n name: nodeName,\n status: success ? 'healthy' : 'unhealthy',\n statusCode: item.json.statusCode,\n error: item.json.error || null\n });\n }\n}\n\n// Calculate overall health score (0-100)\nlet totalChecks = 0;\nlet passedChecks = 0;\n\nhealthData.network.internet.forEach(check => {\n totalChecks++;\n if (check.status === 'healthy') passedChecks++;\n});\n\nif (healthData.network.gateway.status === 'healthy') {\n totalChecks++;\n passedChecks++;\n} else if (healthData.network.gateway.status) {\n totalChecks++;\n}\n\nhealthData.network.internal.forEach(check => {\n totalChecks++;\n if (check.status === 'healthy') passedChecks++;\n});\n\nif (healthData.infrastructure.proxmox.status === 'healthy') {\n totalChecks++;\n passedChecks++;\n} else if (healthData.infrastructure.proxmox.status) {\n totalChecks++;\n}\n\nhealthData.services.forEach(service => {\n totalChecks++;\n if (service.status === 'healthy') passedChecks++;\n});\n\nhealthData.healthScore = totalChecks > 0 ? Math.round((passedChecks / totalChecks) * 100) : 0;\nhealthData.summary = `${passedChecks}/${totalChecks} checks passed`;\n\nreturn [{ json: healthData }];"
|
|
},
|
|
"id": "aggregate-health",
|
|
"name": "Aggregate Health Data",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1250,
|
|
500
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "=http://lm-studio:1234/v1/chat/completions",
|
|
"sendBody": true,
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "model",
|
|
"value": "=deepseek-r1-distill-llama-8b"
|
|
},
|
|
{
|
|
"name": "messages",
|
|
"value": "={{ [{\"role\":\"system\",\"content\":\"You are a homelab infrastructure analyst. Analyze health check data and provide concise insights about system status, potential issues, and recommendations. Respond in JSON format with fields: overall_status, critical_issues (array), warnings (array), recommendations (array).\"}, {\"role\":\"user\",\"content\":\"Analyze this homelab health data:\\n\\n\" + JSON.stringify($json, null, 2)}] }}"
|
|
},
|
|
{
|
|
"name": "temperature",
|
|
"value": "=0.3"
|
|
},
|
|
{
|
|
"name": "max_tokens",
|
|
"value": "=1000"
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"timeout": 30000
|
|
}
|
|
},
|
|
"id": "ai-analysis",
|
|
"name": "AI Health Analysis",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1500,
|
|
500
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const healthData = $('Aggregate Health Data').item.json;\nconst aiResponse = $json.choices[0].message.content;\n\nlet analysis;\ntry {\n // Try to parse AI response as JSON\n analysis = JSON.parse(aiResponse);\n} catch (e) {\n // If not JSON, structure it\n analysis = {\n overall_status: aiResponse.includes('healthy') ? 'healthy' : 'needs attention',\n raw_response: aiResponse\n };\n}\n\nconst report = {\n generated_at: new Date().toISOString(),\n health_score: healthData.healthScore,\n summary: healthData.summary,\n network_status: {\n internet: healthData.network.internet,\n internal_dns: healthData.network.internal\n },\n docker_swarm: {\n nodes: healthData.docker.nodes.length || 0,\n services: healthData.docker.services.length || 0,\n services_list: healthData.docker.services\n },\n service_endpoints: healthData.services,\n ai_analysis: analysis,\n alert_level: healthData.healthScore < 70 ? 'critical' : healthData.healthScore < 90 ? 'warning' : 'normal'\n};\n\nreturn [{ json: report }];"
|
|
},
|
|
"id": "build-report",
|
|
"name": "Build Final Report",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1750,
|
|
500
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"leftValue": "",
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict"
|
|
},
|
|
"combinator": "or",
|
|
"conditions": [
|
|
{
|
|
"id": "alert-critical",
|
|
"leftValue": "={{ $json.alert_level }}",
|
|
"rightValue": "critical",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
}
|
|
},
|
|
{
|
|
"id": "alert-warning",
|
|
"leftValue": "={{ $json.health_score }}",
|
|
"rightValue": 80,
|
|
"operator": {
|
|
"type": "number",
|
|
"operation": "lt"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "should-alert",
|
|
"name": "Should Alert?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2000,
|
|
500
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "🚨 **Homelab Health Alert**\\n\\n**Health Score:** {{ $json.health_score }}/100\\n**Status:** {{ $json.alert_level }}\\n**Time:** {{ $json.generated_at }}\\n\\n**Summary:** {{ $json.summary }}\\n\\n**AI Analysis:**\\n{{ $json.ai_analysis.overall_status }}\\n\\n{% if $json.ai_analysis.critical_issues %}**Critical Issues:**\\n{% for issue in $json.ai_analysis.critical_issues %}- {{ issue }}\\n{% endfor %}{% endif %}\\n\\n{% if $json.ai_analysis.recommendations %}**Recommendations:**\\n{% for rec in $json.ai_analysis.recommendations %}- {{ rec }}\\n{% endfor %}{% endif %}",
|
|
"options": {}
|
|
},
|
|
"id": "format-alert",
|
|
"name": "Format Alert Message",
|
|
"type": "n8n-nodes-base.markdown",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
2250,
|
|
400
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "json",
|
|
"responseBody": "={{ $json }}"
|
|
},
|
|
"id": "webhook-response",
|
|
"name": "Webhook Response",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
2250,
|
|
600
|
|
]
|
|
}
|
|
],
|
|
"pinData": {},
|
|
"connections": {
|
|
"Every 15 Minutes": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Check Google DNS",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Cloudflare DNS",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Pi-hole .196",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Pi-hole .245",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Pi-hole .62",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get Docker Services",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get Swarm Nodes",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Komodo",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check OpenWebUI",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Paperless",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Prometheus",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check LM Studio",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Gateway",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Proxmox",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Manual Trigger Webhook": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Check Google DNS",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Cloudflare DNS",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Pi-hole .196",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Pi-hole .245",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Pi-hole .62",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get Docker Services",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Get Swarm Nodes",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Komodo",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check OpenWebUI",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Paperless",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Prometheus",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check LM Studio",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Gateway",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Check Proxmox",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Google DNS": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Cloudflare DNS": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Pi-hole .196": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Pi-hole .245": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Pi-hole .62": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Docker Services": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Swarm Nodes": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Komodo": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check OpenWebUI": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Paperless": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Prometheus": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Gateway": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Proxmox": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check LM Studio": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Health Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Aggregate Health Data": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AI Health Analysis",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AI Health Analysis": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Build Final Report",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Build Final Report": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Should Alert?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Should Alert?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Format Alert Message",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Webhook Response",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Format Alert Message": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Webhook Response",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"active": false,
|
|
"settings": {
|
|
"executionOrder": "v1"
|
|
},
|
|
"versionId": "1",
|
|
"meta": {
|
|
"templateCredsSetupCompleted": true,
|
|
"instanceId": "homelab"
|
|
},
|
|
"id": "homelab-health-monitor",
|
|
"tags": []
|
|
} |