mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-21 10:43:36 +00:00
feat: comprehensive alert system simplification and UI improvements
- Simplified alert rules: removed warning/critical levels, now one rule per metric type - Unified alert editing: all rules (built-in and custom) use same modal template - Enhanced UI: show actual thresholds/conditions in rules list without clicking edit - Fixed Create Rule button: changed from event listener to direct onclick approach - Fixed disabled rules visibility: disabled rules now stay in list with toggle off - Removed redundant labels: eliminated "Enabled/Disabled" badges (toggle shows state) - Updated alert summary cards: replaced Critical/Warning/Info with Active/Acknowledged/Rules/Status - Improved UX: consistent editing experience across all alert types - Cleaned up duplicate code: removed separate modal templates for system vs custom alerts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+218
-293
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"guest_down_endpoint_2_pi_102": {
|
||||
"id": "alert_1749383901524_ii0r1wvj6",
|
||||
"id": "alert_1749506759853_8lji2gh42",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
@@ -18,110 +18,77 @@
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"maxmem": 536870912,
|
||||
"status": "stopped",
|
||||
"mem": 0,
|
||||
"cpus": 1,
|
||||
"swap": 0,
|
||||
"tags": "proxmox-helper-scripts",
|
||||
"cpu": 0,
|
||||
"diskwrite": 0,
|
||||
"netout": 0,
|
||||
"vmid": 102,
|
||||
"maxswap": 536870912,
|
||||
"type": "lxc",
|
||||
"diskread": 0,
|
||||
"uptime": 0,
|
||||
"netin": 0,
|
||||
"maxdisk": 4401922048,
|
||||
"disk": 0,
|
||||
"name": "pi-docker",
|
||||
"node": "pi",
|
||||
"endpointId": "endpoint_2",
|
||||
"id": "endpoint_2-pi-102",
|
||||
"nodeDisplayName": "pimox"
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383916078,
|
||||
"triggeredAt": 1749383901523,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "web-user",
|
||||
"acknowledgedAt": 1749383916175,
|
||||
"acknowledgeNote": "Acknowledged via web interface",
|
||||
"note": "Acknowledged via web interface"
|
||||
},
|
||||
"guest_down_primary_desktop_400": {
|
||||
"id": "alert_1749383901523_u7e6l7r1v",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
"description": "Virtual machine or container has stopped unexpectedly",
|
||||
"metric": "status",
|
||||
"condition": "equals",
|
||||
"threshold": "stopped",
|
||||
"duration": 60000,
|
||||
"severity": "critical",
|
||||
"enabled": true,
|
||||
"tags": [
|
||||
"availability",
|
||||
"guest"
|
||||
],
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
},
|
||||
"guest": {
|
||||
"diskread": 0,
|
||||
"name": "ubuntu-gpu-vm",
|
||||
"maxmem": 2147483648,
|
||||
"diskwrite": 0,
|
||||
"disk": 0,
|
||||
"mem": 0,
|
||||
"vmid": 400,
|
||||
"node": "pi",
|
||||
"vmid": 102,
|
||||
"name": "pi-docker",
|
||||
"type": "lxc",
|
||||
"status": "stopped",
|
||||
"cpus": 2,
|
||||
"uptime": 0,
|
||||
"netin": 0,
|
||||
"maxdisk": 34359738368,
|
||||
"cpu": 0,
|
||||
"netout": 0,
|
||||
"node": "desktop",
|
||||
"endpointId": "primary",
|
||||
"type": "qemu",
|
||||
"id": "primary-desktop-400",
|
||||
"nodeDisplayName": "homelab - desktop"
|
||||
"maxmem": 536870912,
|
||||
"maxdisk": 4401922048
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383922611,
|
||||
"triggeredAt": 1749383901523,
|
||||
"startTime": 1749506759851,
|
||||
"lastUpdate": 1749506768059,
|
||||
"triggeredAt": 1749506759851,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749383923304,
|
||||
"acknowledgedAt": 1749506768114,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
"guest_down_primary_desktop_400": {
|
||||
"id": "alert_1749506759852_1huz9md0u",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
"description": "Virtual machine or container has stopped unexpectedly",
|
||||
"metric": "status",
|
||||
"condition": "equals",
|
||||
"threshold": "stopped",
|
||||
"duration": 60000,
|
||||
"severity": "critical",
|
||||
"enabled": true,
|
||||
"tags": [
|
||||
"availability",
|
||||
"guest"
|
||||
],
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"endpointId": "primary",
|
||||
"node": "desktop",
|
||||
"vmid": 400,
|
||||
"name": "ubuntu-gpu-vm",
|
||||
"type": "qemu",
|
||||
"status": "stopped",
|
||||
"maxmem": 2147483648,
|
||||
"maxdisk": 34359738368
|
||||
},
|
||||
"startTime": 1749506759851,
|
||||
"lastUpdate": 1749506768059,
|
||||
"triggeredAt": 1749506759851,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749506768076,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
"guest_down_primary_desktop_102": {
|
||||
"id": "alert_1749383901524_5sdux0hpp",
|
||||
"id": "alert_1749569747925_cr09csaa4",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
@@ -139,49 +106,33 @@
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"diskwrite": 0,
|
||||
"name": "windows11",
|
||||
"maxmem": 8589934592,
|
||||
"diskread": 0,
|
||||
"vmid": 102,
|
||||
"disk": 0,
|
||||
"mem": 0,
|
||||
"cpus": 4,
|
||||
"status": "stopped",
|
||||
"serial": 1,
|
||||
"cpu": 0,
|
||||
"netout": 0,
|
||||
"maxdisk": 68719476736,
|
||||
"netin": 0,
|
||||
"uptime": 0,
|
||||
"node": "desktop",
|
||||
"endpointId": "primary",
|
||||
"node": "desktop",
|
||||
"vmid": 102,
|
||||
"name": "windows11",
|
||||
"type": "qemu",
|
||||
"id": "primary-desktop-102",
|
||||
"nodeDisplayName": "homelab - desktop"
|
||||
"status": "stopped",
|
||||
"maxmem": 8589934592,
|
||||
"maxdisk": 68719476736
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383922611,
|
||||
"triggeredAt": 1749383901523,
|
||||
"startTime": 1749569747925,
|
||||
"lastUpdate": 1749569831486,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749383923312,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
"triggeredAt": 1749569809584,
|
||||
"acknowledgedBy": "web-user",
|
||||
"acknowledgedAt": 1749569832402,
|
||||
"acknowledgeNote": "Acknowledged via web interface",
|
||||
"note": "Acknowledged via web interface"
|
||||
},
|
||||
"guest_down_primary_desktop_200": {
|
||||
"id": "alert_1749383901524_wc8c7l96a",
|
||||
"id": "alert_1749569747925_g5yxjcnmv",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
@@ -199,48 +150,33 @@
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"diskread": 0,
|
||||
"maxmem": 8589934592,
|
||||
"name": "UnraidServer",
|
||||
"diskwrite": 0,
|
||||
"mem": 0,
|
||||
"disk": 0,
|
||||
"vmid": 200,
|
||||
"cpus": 6,
|
||||
"status": "stopped",
|
||||
"uptime": 0,
|
||||
"netin": 0,
|
||||
"maxdisk": 0,
|
||||
"netout": 0,
|
||||
"cpu": 0,
|
||||
"node": "desktop",
|
||||
"endpointId": "primary",
|
||||
"node": "desktop",
|
||||
"vmid": 200,
|
||||
"name": "UnraidServer",
|
||||
"type": "qemu",
|
||||
"id": "primary-desktop-200",
|
||||
"nodeDisplayName": "homelab - desktop"
|
||||
"status": "stopped",
|
||||
"maxmem": 8589934592,
|
||||
"maxdisk": 0
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383922611,
|
||||
"triggeredAt": 1749383901523,
|
||||
"startTime": 1749569747925,
|
||||
"lastUpdate": 1749569829318,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749383923314,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
"triggeredAt": 1749569809584,
|
||||
"acknowledgedBy": "web-user",
|
||||
"acknowledgedAt": 1749569829548,
|
||||
"acknowledgeNote": "Acknowledged via web interface",
|
||||
"note": "Acknowledged via web interface"
|
||||
},
|
||||
"guest_down_primary_desktop_109": {
|
||||
"id": "alert_1749383901524_884o95b7f",
|
||||
"id": "alert_1749506759852_h7fxa1ycd",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
@@ -258,51 +194,33 @@
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"vmid": 109,
|
||||
"mem": 0,
|
||||
"disk": 0,
|
||||
"type": "lxc",
|
||||
"maxswap": 536870912,
|
||||
"diskwrite": 0,
|
||||
"maxmem": 4294967296,
|
||||
"name": "pbs2",
|
||||
"diskread": 0,
|
||||
"netout": 0,
|
||||
"cpu": 0,
|
||||
"maxdisk": 10737418240,
|
||||
"tags": "backup;community-script",
|
||||
"netin": 0,
|
||||
"uptime": 0,
|
||||
"status": "stopped",
|
||||
"cpus": 4,
|
||||
"swap": 0,
|
||||
"node": "desktop",
|
||||
"endpointId": "primary",
|
||||
"id": "primary-desktop-109",
|
||||
"nodeDisplayName": "homelab - desktop"
|
||||
"node": "desktop",
|
||||
"vmid": 109,
|
||||
"name": "pbs2",
|
||||
"type": "lxc",
|
||||
"status": "stopped",
|
||||
"maxmem": 4294967296,
|
||||
"maxdisk": 10737418240
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383922611,
|
||||
"triggeredAt": 1749383901523,
|
||||
"startTime": 1749506759851,
|
||||
"lastUpdate": 1749506768059,
|
||||
"triggeredAt": 1749506759851,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749383923317,
|
||||
"acknowledgedAt": 1749506768101,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
"guest_down_primary_desktop_112": {
|
||||
"id": "alert_1749383901524_e6h94me1n",
|
||||
"id": "alert_1749506759852_xx9hn6622",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
@@ -320,51 +238,33 @@
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"status": "stopped",
|
||||
"cpus": 1,
|
||||
"swap": 0,
|
||||
"tags": "community-script;monitoring;proxmox",
|
||||
"maxdisk": 4294967296,
|
||||
"cpu": 0,
|
||||
"netout": 0,
|
||||
"uptime": 0,
|
||||
"netin": 0,
|
||||
"diskwrite": 0,
|
||||
"maxswap": 536870912,
|
||||
"type": "lxc",
|
||||
"diskread": 0,
|
||||
"name": "pulse",
|
||||
"maxmem": 1073741824,
|
||||
"disk": 0,
|
||||
"mem": 0,
|
||||
"vmid": 112,
|
||||
"node": "desktop",
|
||||
"endpointId": "primary",
|
||||
"id": "primary-desktop-112",
|
||||
"nodeDisplayName": "homelab - desktop"
|
||||
"node": "desktop",
|
||||
"vmid": 112,
|
||||
"name": "pulse",
|
||||
"type": "lxc",
|
||||
"status": "stopped",
|
||||
"maxmem": 1073741824,
|
||||
"maxdisk": 4294967296
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383922611,
|
||||
"triggeredAt": 1749383901523,
|
||||
"startTime": 1749506759851,
|
||||
"lastUpdate": 1749506768059,
|
||||
"triggeredAt": 1749506759851,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749383923320,
|
||||
"acknowledgedAt": 1749506768098,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
"guest_down_endpoint_2_pi_101": {
|
||||
"id": "alert_1749383901524_ew3vhj38x",
|
||||
"id": "alert_1749506759853_fqm539ogq",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
@@ -382,51 +282,33 @@
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"diskwrite": 0,
|
||||
"cpu": 0,
|
||||
"tags": "alpine;community-script;os",
|
||||
"swap": 0,
|
||||
"cpus": 1,
|
||||
"mem": 0,
|
||||
"maxmem": 536870912,
|
||||
"status": "stopped",
|
||||
"disk": 0,
|
||||
"name": "pi-influxdb",
|
||||
"maxdisk": 2254438400,
|
||||
"netin": 0,
|
||||
"diskread": 0,
|
||||
"uptime": 0,
|
||||
"type": "lxc",
|
||||
"maxswap": 536870912,
|
||||
"vmid": 101,
|
||||
"netout": 0,
|
||||
"node": "pi",
|
||||
"endpointId": "endpoint_2",
|
||||
"id": "endpoint_2-pi-101",
|
||||
"nodeDisplayName": "pimox"
|
||||
"node": "pi",
|
||||
"vmid": 101,
|
||||
"name": "pi-influxdb",
|
||||
"type": "lxc",
|
||||
"status": "stopped",
|
||||
"maxmem": 536870912,
|
||||
"maxdisk": 2254438400
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383922611,
|
||||
"triggeredAt": 1749383901523,
|
||||
"startTime": 1749506759851,
|
||||
"lastUpdate": 1749506768059,
|
||||
"triggeredAt": 1749506759851,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749383923322,
|
||||
"acknowledgedAt": 1749506768110,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
"guest_down_endpoint_2_pi_100": {
|
||||
"id": "alert_1749383901524_z3xuybdjm",
|
||||
"id": "alert_1749506759853_efv9jpkmk",
|
||||
"rule": {
|
||||
"id": "guest_down",
|
||||
"name": "Guest System Down",
|
||||
@@ -444,46 +326,28 @@
|
||||
"group": "availability_alerts",
|
||||
"escalationTime": 600000,
|
||||
"autoResolve": true,
|
||||
"suppressionTime": 120000,
|
||||
"notificationChannels": [
|
||||
"default",
|
||||
"urgent"
|
||||
]
|
||||
"suppressionTime": 120000
|
||||
},
|
||||
"guest": {
|
||||
"tags": "proxmox-helper-scripts",
|
||||
"swap": 0,
|
||||
"cpus": 1,
|
||||
"mem": 0,
|
||||
"endpointId": "endpoint_2",
|
||||
"node": "pi",
|
||||
"vmid": 100,
|
||||
"name": "pihole",
|
||||
"type": "lxc",
|
||||
"status": "stopped",
|
||||
"maxmem": 536870912,
|
||||
"diskwrite": 0,
|
||||
"cpu": 0,
|
||||
"type": "lxc",
|
||||
"maxswap": 536870912,
|
||||
"vmid": 100,
|
||||
"netout": 0,
|
||||
"disk": 0,
|
||||
"name": "pihole",
|
||||
"maxdisk": 6442450944,
|
||||
"netin": 0,
|
||||
"diskread": 0,
|
||||
"uptime": 0,
|
||||
"node": "pi",
|
||||
"endpointId": "endpoint_2",
|
||||
"id": "endpoint_2-pi-100",
|
||||
"nodeDisplayName": "pimox"
|
||||
"maxdisk": 6442450944
|
||||
},
|
||||
"startTime": 1749383901523,
|
||||
"lastUpdate": 1749383922611,
|
||||
"triggeredAt": 1749383901523,
|
||||
"startTime": 1749506759851,
|
||||
"lastUpdate": 1749506768059,
|
||||
"triggeredAt": 1749506759851,
|
||||
"currentValue": "stopped",
|
||||
"effectiveThreshold": "stopped",
|
||||
"state": "active",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749383923326,
|
||||
"acknowledgedAt": 1749506768116,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
@@ -1100,7 +964,7 @@
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
"compound_1749471240848_s7tobb06w_primary_desktop_100": {
|
||||
"id": "alert_1749502225872_hi8xpxptm",
|
||||
"id": "alert_1749506911287_7s6evevo5",
|
||||
"rule": {
|
||||
"id": "compound_1749471240848_s7tobb06w",
|
||||
"name": "Custom Alert",
|
||||
@@ -1134,10 +998,10 @@
|
||||
"maxmem": 2147483648,
|
||||
"maxdisk": 10464022528
|
||||
},
|
||||
"startTime": 1749502225871,
|
||||
"lastUpdate": 1749502234638,
|
||||
"startTime": 1749506911287,
|
||||
"lastUpdate": 1749506917939,
|
||||
"currentValue": {
|
||||
"cpu": 9.7
|
||||
"cpu": 4.6
|
||||
},
|
||||
"effectiveThreshold": [
|
||||
{
|
||||
@@ -1149,10 +1013,10 @@
|
||||
"state": "resolved",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"triggeredAt": 1749502232450,
|
||||
"resolvedAt": 1749502236824,
|
||||
"triggeredAt": 1749506917939,
|
||||
"resolvedAt": 1749506920164,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749503811808,
|
||||
"acknowledgedAt": 1749506987457,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
@@ -1267,8 +1131,7 @@
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
},
|
||||
"compound_1749471240848_s7tobb06w_primary_desktop_111": {
|
||||
"id": "alert_1749502224406_5r7jkmoga",
|
||||
"ruleId": "compound_1749471240848_s7tobb06w",
|
||||
"id": "alert_1749568238371_r7qnu045w",
|
||||
"rule": {
|
||||
"id": "compound_1749471240848_s7tobb06w",
|
||||
"name": "Custom Alert",
|
||||
@@ -1302,21 +1165,83 @@
|
||||
"maxmem": 2147483648,
|
||||
"maxdisk": 4152066048
|
||||
},
|
||||
"severity": "warning",
|
||||
"message": "Dynamic threshold rule \"Custom Alert\" triggered for debian: CPU: 10.5% (≥ 4%)",
|
||||
"startTime": 1749502224405,
|
||||
"lastUpdate": 1749502224405,
|
||||
"triggeredAt": 1749502224405,
|
||||
"startTime": 1749568238370,
|
||||
"lastUpdate": 1749568244956,
|
||||
"currentValue": {
|
||||
"cpu": 10.5
|
||||
"cpu": 4
|
||||
},
|
||||
"effectiveThreshold": [
|
||||
{
|
||||
"metric": "cpu",
|
||||
"condition": "greater_than",
|
||||
"threshold": 4
|
||||
}
|
||||
],
|
||||
"state": "resolved",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"resolvedAt": 1749502225871,
|
||||
"acknowledgedBy": "bulk-operation",
|
||||
"acknowledgedAt": 1749503811814,
|
||||
"acknowledgeNote": "Bulk acknowledged via dropdown",
|
||||
"note": "Bulk acknowledged via dropdown"
|
||||
"triggeredAt": 1749568244956,
|
||||
"resolvedAt": 1749568247148,
|
||||
"acknowledgedBy": "web-user",
|
||||
"acknowledgedAt": 1749568251499,
|
||||
"acknowledgeNote": "Acknowledged via web interface",
|
||||
"note": "Acknowledged via web interface"
|
||||
},
|
||||
"compound_1749471240848_s7tobb06w_primary_delly_101": {
|
||||
"id": "alert_1749505855170_5srfusl2c",
|
||||
"rule": {
|
||||
"id": "compound_1749471240848_s7tobb06w",
|
||||
"name": "Custom Alert",
|
||||
"condition": "greater_than",
|
||||
"duration": 5000,
|
||||
"severity": "warning",
|
||||
"enabled": true,
|
||||
"tags": [],
|
||||
"group": "compound_threshold",
|
||||
"escalationTime": 900000,
|
||||
"autoResolve": false,
|
||||
"suppressionTime": 300000,
|
||||
"type": "compound_threshold",
|
||||
"thresholds": [
|
||||
{
|
||||
"metric": "cpu",
|
||||
"condition": "greater_than",
|
||||
"threshold": 4
|
||||
}
|
||||
],
|
||||
"sendEmail": true,
|
||||
"sendWebhook": false
|
||||
},
|
||||
"guest": {
|
||||
"endpointId": "primary",
|
||||
"node": "delly",
|
||||
"vmid": 101,
|
||||
"name": "homeassistant",
|
||||
"type": "lxc",
|
||||
"status": "running",
|
||||
"maxmem": 2147483648,
|
||||
"maxdisk": 14687412224
|
||||
},
|
||||
"startTime": 1749505855169,
|
||||
"lastUpdate": 1749505863903,
|
||||
"currentValue": {
|
||||
"cpu": 4.4
|
||||
},
|
||||
"effectiveThreshold": [
|
||||
{
|
||||
"metric": "cpu",
|
||||
"condition": "greater_than",
|
||||
"threshold": 4
|
||||
}
|
||||
],
|
||||
"state": "resolved",
|
||||
"escalated": false,
|
||||
"acknowledged": true,
|
||||
"triggeredAt": 1749505861716,
|
||||
"resolvedAt": 1749505866083,
|
||||
"acknowledgedBy": "web-user",
|
||||
"acknowledgedAt": 1749506285411,
|
||||
"acknowledgeNote": "Acknowledged via web interface",
|
||||
"note": "Acknowledged via web interface"
|
||||
}
|
||||
}
|
||||
+131
-79
@@ -130,9 +130,9 @@ class AlertManager extends EventEmitter {
|
||||
|
||||
const defaultRules = [
|
||||
{
|
||||
id: 'high_cpu',
|
||||
name: 'High CPU Usage',
|
||||
description: 'Triggers when CPU usage exceeds threshold for specified duration',
|
||||
id: 'cpu',
|
||||
name: 'CPU Usage',
|
||||
description: 'Monitors CPU usage across all VMs and containers',
|
||||
metric: 'cpu',
|
||||
condition: 'greater_than',
|
||||
threshold: cpuThreshold,
|
||||
@@ -146,25 +146,9 @@ class AlertManager extends EventEmitter {
|
||||
suppressionTime: 300000, // 5 minutes
|
||||
},
|
||||
{
|
||||
id: 'critical_cpu',
|
||||
name: 'Critical CPU Usage',
|
||||
description: 'Critical CPU usage requiring immediate attention',
|
||||
metric: 'cpu',
|
||||
condition: 'greater_than',
|
||||
threshold: this.parseEnvInt('ALERT_CPU_CRITICAL_THRESHOLD', 95, 1, 100),
|
||||
duration: this.parseEnvInt('ALERT_CPU_CRITICAL_DURATION', 60000, 1000),
|
||||
severity: 'critical',
|
||||
enabled: process.env.ALERT_CPU_CRITICAL_ENABLED !== 'false',
|
||||
tags: ['performance', 'cpu', 'critical'],
|
||||
group: 'critical_alerts',
|
||||
escalationTime: 300000, // 5 minutes
|
||||
autoResolve: true,
|
||||
suppressionTime: 0, // No suppression for critical
|
||||
},
|
||||
{
|
||||
id: 'high_memory',
|
||||
name: 'High Memory Usage',
|
||||
description: 'Memory usage exceeds safe operating levels',
|
||||
id: 'memory',
|
||||
name: 'Memory Usage',
|
||||
description: 'Monitors memory usage across all VMs and containers',
|
||||
metric: 'memory',
|
||||
condition: 'greater_than',
|
||||
threshold: memThreshold,
|
||||
@@ -178,25 +162,9 @@ class AlertManager extends EventEmitter {
|
||||
suppressionTime: 300000,
|
||||
},
|
||||
{
|
||||
id: 'critical_memory',
|
||||
name: 'Critical Memory Usage',
|
||||
description: 'Memory usage at critical levels - system stability at risk',
|
||||
metric: 'memory',
|
||||
condition: 'greater_than',
|
||||
threshold: this.parseEnvInt('ALERT_MEMORY_CRITICAL_THRESHOLD', 98, 1, 100),
|
||||
duration: this.parseEnvInt('ALERT_MEMORY_CRITICAL_DURATION', 120000, 1000),
|
||||
severity: 'critical',
|
||||
enabled: process.env.ALERT_MEMORY_CRITICAL_ENABLED !== 'false',
|
||||
tags: ['performance', 'memory', 'critical'],
|
||||
group: 'critical_alerts',
|
||||
escalationTime: 300000, // 5 minutes
|
||||
autoResolve: true,
|
||||
suppressionTime: 0,
|
||||
},
|
||||
{
|
||||
id: 'disk_space_warning',
|
||||
name: 'Low Disk Space',
|
||||
description: 'Disk usage approaching capacity limits',
|
||||
id: 'disk',
|
||||
name: 'Disk Usage',
|
||||
description: 'Monitors disk space usage across all VMs and containers',
|
||||
metric: 'disk',
|
||||
condition: 'greater_than',
|
||||
threshold: diskThreshold,
|
||||
@@ -210,25 +178,9 @@ class AlertManager extends EventEmitter {
|
||||
suppressionTime: 600000, // 10 minutes
|
||||
},
|
||||
{
|
||||
id: 'disk_space_critical',
|
||||
name: 'Critical Disk Space',
|
||||
description: 'Disk space critically low - immediate action required',
|
||||
metric: 'disk',
|
||||
condition: 'greater_than',
|
||||
threshold: this.parseEnvInt('ALERT_DISK_CRITICAL_THRESHOLD', 95, 1, 100),
|
||||
duration: this.parseEnvInt('ALERT_DISK_CRITICAL_DURATION', 60000, 1000),
|
||||
severity: 'critical',
|
||||
enabled: process.env.ALERT_DISK_CRITICAL_ENABLED !== 'false',
|
||||
tags: ['storage', 'disk', 'critical'],
|
||||
group: 'critical_alerts',
|
||||
escalationTime: 300000, // 5 minutes
|
||||
autoResolve: true,
|
||||
suppressionTime: 0,
|
||||
},
|
||||
{
|
||||
id: 'guest_down',
|
||||
name: 'Guest System Down',
|
||||
description: 'Virtual machine or container has stopped unexpectedly',
|
||||
id: 'down',
|
||||
name: 'System Availability',
|
||||
description: 'Monitors VM/container availability and uptime',
|
||||
metric: 'status',
|
||||
condition: 'equals',
|
||||
threshold: 'stopped',
|
||||
@@ -240,29 +192,13 @@ class AlertManager extends EventEmitter {
|
||||
escalationTime: 600000, // 10 minutes
|
||||
autoResolve: true,
|
||||
suppressionTime: 120000, // 2 minutes
|
||||
},
|
||||
{
|
||||
id: 'network_anomaly',
|
||||
name: 'Network Traffic Anomaly',
|
||||
description: 'Unusual network traffic patterns detected',
|
||||
metric: 'network_combined',
|
||||
condition: 'anomaly',
|
||||
threshold: 'auto', // Machine learning based
|
||||
duration: 180000, // 3 minutes
|
||||
severity: 'info',
|
||||
enabled: process.env.ALERT_NETWORK_ANOMALY_ENABLED === 'true',
|
||||
tags: ['network', 'anomaly'],
|
||||
group: 'network_alerts',
|
||||
escalationTime: 1800000, // 30 minutes
|
||||
autoResolve: true,
|
||||
suppressionTime: 900000, // 15 minutes
|
||||
}
|
||||
];
|
||||
|
||||
defaultRules.forEach(rule => {
|
||||
if (rule.enabled) {
|
||||
this.alertRules.set(rule.id, rule);
|
||||
}
|
||||
// Always add rules to the map, regardless of enabled state
|
||||
// This allows them to be displayed and toggled in the UI
|
||||
this.alertRules.set(rule.id, rule);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2442,6 +2378,122 @@ This alert was generated by Pulse monitoring system.
|
||||
this.emailTransporter.close();
|
||||
}
|
||||
}
|
||||
|
||||
async sendTestEmail() {
|
||||
try {
|
||||
console.log('[AlertManager] Sending test email...');
|
||||
|
||||
if (!this.emailTransporter) {
|
||||
return { success: false, error: 'Email transporter not configured' };
|
||||
}
|
||||
|
||||
const config = await this.loadEmailConfig();
|
||||
if (!config.to) {
|
||||
return { success: false, error: 'No recipient email address configured' };
|
||||
}
|
||||
|
||||
return await this.sendTestEmailWithConfig({
|
||||
ALERT_FROM_EMAIL: config.from,
|
||||
ALERT_TO_EMAIL: config.to,
|
||||
SMTP_HOST: config.host,
|
||||
SMTP_PORT: config.port,
|
||||
SMTP_USER: config.user,
|
||||
SMTP_SECURE: config.secure
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[AlertManager] Error sending test email:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async sendTestEmailWithConfig(config) {
|
||||
try {
|
||||
console.log('[AlertManager] Sending test email with provided config...');
|
||||
|
||||
if (!this.emailTransporter) {
|
||||
return { success: false, error: 'Email transporter not configured' };
|
||||
}
|
||||
|
||||
if (!config.ALERT_TO_EMAIL) {
|
||||
return { success: false, error: 'No recipient email address configured' };
|
||||
}
|
||||
|
||||
const testEmailOptions = {
|
||||
from: config.ALERT_FROM_EMAIL || 'noreply@pulse.local',
|
||||
to: config.ALERT_TO_EMAIL,
|
||||
subject: 'Pulse Alert System - Test Email',
|
||||
text: `This is a test email from your Pulse monitoring system.
|
||||
|
||||
Sent at: ${new Date().toISOString()}
|
||||
From: ${require('os').hostname()}
|
||||
|
||||
If you received this email, your email configuration is working correctly!
|
||||
|
||||
Configuration used:
|
||||
- SMTP Host: ${config.SMTP_HOST}
|
||||
- SMTP Port: ${config.SMTP_PORT}
|
||||
- From: ${config.ALERT_FROM_EMAIL}
|
||||
- To: ${config.ALERT_TO_EMAIL}
|
||||
|
||||
Best regards,
|
||||
Pulse Monitoring System`,
|
||||
html: `<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2 style="color: #3b82f6;">Pulse Alert System - Test Email</h2>
|
||||
<p>This is a test email from your Pulse monitoring system.</p>
|
||||
|
||||
<div style="background-color: #f3f4f6; padding: 15px; border-radius: 5px; margin: 20px 0;">
|
||||
<strong>Test Details:</strong><br>
|
||||
<strong>Sent at:</strong> ${new Date().toISOString()}<br>
|
||||
<strong>From:</strong> ${require('os').hostname()}<br><br>
|
||||
<strong>Configuration used:</strong><br>
|
||||
<strong>SMTP Host:</strong> ${config.SMTP_HOST}<br>
|
||||
<strong>SMTP Port:</strong> ${config.SMTP_PORT}<br>
|
||||
<strong>From:</strong> ${config.ALERT_FROM_EMAIL}<br>
|
||||
<strong>To:</strong> ${config.ALERT_TO_EMAIL}
|
||||
</div>
|
||||
|
||||
<p style="color: #16a34a;"><strong>✅ Success!</strong> If you received this email, your email configuration is working correctly!</p>
|
||||
|
||||
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;">
|
||||
<p style="color: #6b7280; font-size: 12px;">
|
||||
Best regards,<br>
|
||||
Pulse Monitoring System
|
||||
</p>
|
||||
</div>`
|
||||
};
|
||||
|
||||
await this.emailTransporter.sendMail(testEmailOptions);
|
||||
console.log('[AlertManager] Test email sent successfully');
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('[AlertManager] Error sending test email:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async loadEmailConfig() {
|
||||
try {
|
||||
// Load email configuration from environment or config
|
||||
const { loadConfiguration } = require('./configLoader');
|
||||
const config = await loadConfiguration();
|
||||
|
||||
console.log('[AlertManager] Loading email config, ALERT_TO_EMAIL:', config.ALERT_TO_EMAIL);
|
||||
|
||||
return {
|
||||
from: config.ALERT_FROM_EMAIL,
|
||||
to: config.ALERT_TO_EMAIL,
|
||||
host: config.SMTP_HOST,
|
||||
port: config.SMTP_PORT,
|
||||
user: config.SMTP_USER,
|
||||
secure: config.SMTP_SECURE === 'true'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[AlertManager] Error loading email config:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AlertManager;
|
||||
@@ -466,6 +466,47 @@ app.get('/api/alerts/metrics', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Test email configuration
|
||||
app.post('/api/alerts/test-email', async (req, res) => {
|
||||
try {
|
||||
console.log('[Test Email] Sending test email...');
|
||||
|
||||
// Get email configuration from process.env (loaded by configLoader)
|
||||
const config = {
|
||||
ALERT_TO_EMAIL: process.env.ALERT_TO_EMAIL,
|
||||
ALERT_FROM_EMAIL: process.env.ALERT_FROM_EMAIL,
|
||||
SMTP_HOST: process.env.SMTP_HOST,
|
||||
SMTP_PORT: process.env.SMTP_PORT,
|
||||
SMTP_USER: process.env.SMTP_USER,
|
||||
SMTP_SECURE: process.env.SMTP_SECURE
|
||||
};
|
||||
|
||||
console.log('[Test Email] Config loaded, ALERT_TO_EMAIL:', config.ALERT_TO_EMAIL);
|
||||
|
||||
if (!config.ALERT_TO_EMAIL) {
|
||||
return res.status(400).json({ success: false, error: 'No recipient email address configured' });
|
||||
}
|
||||
|
||||
if (!config.SMTP_HOST) {
|
||||
return res.status(400).json({ success: false, error: 'SMTP server not configured' });
|
||||
}
|
||||
|
||||
// Use the alert manager to send a test email with the config
|
||||
const testResult = await stateManager.alertManager.sendTestEmailWithConfig(config);
|
||||
|
||||
if (testResult.success) {
|
||||
console.log('[Test Email] Test email sent successfully');
|
||||
res.json({ success: true, message: 'Test email sent successfully' });
|
||||
} else {
|
||||
console.error('[Test Email] Failed to send test email:', testResult.error);
|
||||
res.status(400).json({ success: false, error: testResult.error || 'Failed to send test email' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Test Email] Error sending test email:', error);
|
||||
res.status(500).json({ success: false, error: 'Internal server error while sending test email' });
|
||||
}
|
||||
});
|
||||
|
||||
// Alert rules management with filtering
|
||||
app.get('/api/alerts/rules', (req, res) => {
|
||||
try {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user