From b500a451d3379f8ef0a0e272ce27e457ca2df203 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 23 Oct 2024 12:05:12 +0800 Subject: [PATCH 1/8] disc -> disk --- Server/db/models/HardwareCheck.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/db/models/HardwareCheck.js b/Server/db/models/HardwareCheck.js index b710087bf..8ff615ec6 100644 --- a/Server/db/models/HardwareCheck.js +++ b/Server/db/models/HardwareCheck.js @@ -16,7 +16,7 @@ const memorySchema = mongoose.Schema({ usage_percent: { type: Number, default: 0 }, }); -const discSchema = mongoose.Schema({ +const diskSchema = mongoose.Schema({ read_speed_bytes: { type: Number, default: 0 }, write_speed_bytes: { type: Number, default: 0 }, total_bytes: { type: Number, default: 0 }, @@ -46,7 +46,7 @@ const HardwareCheckSchema = mongoose.Schema( default: () => ({}), }, disk: { - type: [discSchema], + type: [diskSchema], default: () => [], }, host: { From d392317f13b88a666ac6221367b695173f0beefc Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 23 Oct 2024 12:05:50 +0800 Subject: [PATCH 2/8] Add optional threshold fields to Monitor for hardware monitoring --- Server/db/models/Monitor.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Server/db/models/Monitor.js b/Server/db/models/Monitor.js index 6d718e9cd..c4dcb649c 100644 --- a/Server/db/models/Monitor.js +++ b/Server/db/models/Monitor.js @@ -1,5 +1,4 @@ import mongoose from "mongoose"; -import Notification from "./Notification.js"; const MonitorSchema = mongoose.Schema( { @@ -48,6 +47,14 @@ const MonitorSchema = mongoose.Schema( type: Number, default: undefined, }, + thresholds: { + type: { + usage_cpu: { type: Number }, + usage_memory: { type: Number }, + usage_disk: { type: Number }, + }, + _id: false, + }, notifications: [ { type: mongoose.Schema.Types.ObjectId, From 7d8c0d298b97f5184f8dbedde8aadaa948850dcf Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 23 Oct 2024 12:06:05 +0800 Subject: [PATCH 3/8] update monitor validation to allow for threshold values --- Server/validation/joi.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Server/validation/joi.js b/Server/validation/joi.js index d1ba107bc..0b85a4557 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -222,6 +222,11 @@ const createMonitorBodyValidation = joi.object({ url: joi.string().required(), isActive: joi.boolean(), interval: joi.number(), + thresholds: joi.object().keys({ + usage_cpu: joi.number(), + usage_memory: joi.number(), + usage_disk: joi.number(), + }), notifications: joi.array().items(joi.object()), }); From 2ae5fb6008a6f172704fd741038d85a3a78d09ec Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 23 Oct 2024 13:45:28 +0800 Subject: [PATCH 4/8] Added email template for threshold violation --- Server/templates/thresholdViolated.mjml | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Server/templates/thresholdViolated.mjml diff --git a/Server/templates/thresholdViolated.mjml b/Server/templates/thresholdViolated.mjml new file mode 100644 index 000000000..a3d4344e4 --- /dev/null +++ b/Server/templates/thresholdViolated.mjml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + Message from BlueWave Uptime Service + + + + + {{message}} + + + {{#if cpu}} + {{cpu}} + {{/if}} + + + {{#if disk}} + {{disk}} + {{/if}} + + + {{#if memory}} + {{memory}} + {{/if}} + + + + + + \ No newline at end of file From 55111ba4c959b24f8f27b60dd046c4a500014883 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 23 Oct 2024 13:45:53 +0800 Subject: [PATCH 5/8] Add new template to emailService templateLookup --- Server/service/emailService.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Server/service/emailService.js b/Server/service/emailService.js index 519162ba0..9bdc4f4a3 100644 --- a/Server/service/emailService.js +++ b/Server/service/emailService.js @@ -63,6 +63,7 @@ class EmailService { serverIsDownTemplate: this.loadTemplate("serverIsDown"), serverIsUpTemplate: this.loadTemplate("serverIsUp"), passwordResetTemplate: this.loadTemplate("passwordReset"), + thresholdViolatedTemplate: this.loadTemplate("thresholdViolated"), }; /** From 8d9803fef0099a2b26b42d54d7bbfd6bebd583a0 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 23 Oct 2024 13:46:27 +0800 Subject: [PATCH 6/8] Added methods for handleHardwareUpdates, refactored sending notifications to allow for arbitrary templates --- Server/service/networkService.js | 96 ++++++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/Server/service/networkService.js b/Server/service/networkService.js index e90180835..3e9582fd6 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -34,24 +34,24 @@ class NetworkService { } /** - * Handles the notification process for a monitor. + * Handles notifications for a given monitor configuration. * - * @param {Object} monitor - The monitor object containing monitor details. - * @param {boolean} isAlive - The status of the monitor (true if up, false if down). - * @returns {Promise} - */ async handleNotification(monitor, isAlive) { + * @param {Object} config - The configuration object for the notification. + * @param {Object} config.monitor - The monitor object containing the monitor ID. + * @param {string} config.template - The email template to be used. + * @param {Object} config.context - The context for the email template. + * @param {string} config.subject - The subject of the email. + */ + async handleNotification(config) { try { - let template = isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate"; - let status = isAlive === true ? "up" : "down"; - - const notifications = await this.db.getNotificationsByMonitorId(monitor._id); + const notifications = await this.db.getNotificationsByMonitorId(config.monitor._id); for (const notification of notifications) { if (notification.type === "email") { await this.emailService.buildAndSendEmail( - template, - { monitorName: monitor.name, monitorUrl: monitor.url }, + config.template, + config.context, notification.address, - `Monitor ${monitor.name} is ${status}` + config.subject ); } } @@ -69,9 +69,10 @@ class NetworkService { * * @param {Object} job - The job object containing job details. * @param {boolean} isAlive - The status of the monitor (true if up, false if down). + * @param {Object} [hardwareData] - The hardware data for the monitor. * @returns {Promise} */ - async handleStatusUpdate(job, isAlive) { + async handleStatusUpdate(job, isAlive, hardwareData) { let monitor; const { _id } = job.data; @@ -98,9 +99,19 @@ class NetworkService { await monitor.save(); if (oldStatus !== undefined && oldStatus !== isAlive) { - this.handleNotification(monitor, isAlive); + const config = { + monitor: monitor, + template: isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate", + context: { monitorName: monitor.name, monitorUrl: monitor.url }, + subject: + (subject = `Monitor ${monitor.name} is ${isAlive === true ? "up" : "down"}`), + }; + this.handleNotification(config); } } + if (monitor.type === this.TYPE_HARDWARE) { + this.handleHardwareUpdate(monitor, hardwareData); + } } catch (error) { this.logger.error(error.message, { method: "handleStatusUpdate", @@ -110,6 +121,55 @@ class NetworkService { } } + async handleHardwareUpdate(monitor, hardwareData) { + //Get Thresholds + const thresholds = monitor?.thresholds; + if (thresholds === undefined) { + return; + } + //Get Values + const cpuUsage = hardwareData?.cpu?.usage_percent; + const memoryUsage = hardwareData?.memory?.usage_percent; + const diskUsage = hardwareData?.disk[0]?.usage_percent; + + // Return early if no values + if (cpuUsage === undefined && memoryUsage === undefined && diskUsage === undefined) { + return; + } + + // Return early if all values are below thresholds + if ( + cpuUsage < thresholds.usage_cpu && + memoryUsage < thresholds.usage_memory && + diskUsage < thresholds.usage_disk + ) { + return; + } + + let context = { + message: "Threshold(s) exceeded:", + }; + if (cpuUsage > thresholds.usage_cpu) { + context.cpu = `CPU USAGE: ${cpuUsage * 100}% > ${thresholds.usage_cpu * 100}%`; + } + + if (memoryUsage > thresholds.usage_memory) { + context.memory = `MEMORY USAGE: ${memoryUsage * 100}% > ${thresholds.usage_memory * 100}%`; + } + + if (diskUsage > thresholds.usage_disk) { + context.disk = `DISK USAGE: ${diskUsage * 100}% > ${thresholds.usage_disk * 100}%`; + } + + const config = { + monitor: monitor, + template: "thresholdViolatedTemplate", + context: context, + subject: `Threshold Violated for ${monitor.name}`, + }; + this.handleNotification(config); + } + /** * Measures the response time of an asynchronous operation. * @param {Function} operation - An asynchronous operation to measure. @@ -308,13 +368,13 @@ class NetworkService { frequency: 266, temperature: null, free_percent: null, - usage_percent: null, + usage_percent: 1, }, memory: { total_bytes: 4, available_bytes: 4, used_bytes: 2, - usage_percent: 0.5, + usage_percent: 1, }, disk: [ { @@ -322,7 +382,7 @@ class NetworkService { write_speed_bytes: 3, total_bytes: 10, free_bytes: 2, - usage_percent: 0.8, + usage_percent: 1, }, ], host: { @@ -369,7 +429,7 @@ class NetworkService { }; this.logAndStoreCheck(nullData, this.db.createHardwareCheck); } finally { - this.handleStatusUpdate(job, isAlive); + this.handleStatusUpdate(job, isAlive, hardwareData); } } From 70872c368d2739a56f2b08ca33ebfc0fe5088310 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 25 Oct 2024 10:48:37 +0800 Subject: [PATCH 7/8] Add status to hardware check model --- Server/db/models/HardwareCheck.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Server/db/models/HardwareCheck.js b/Server/db/models/HardwareCheck.js index 8ff615ec6..5e7f53329 100644 --- a/Server/db/models/HardwareCheck.js +++ b/Server/db/models/HardwareCheck.js @@ -37,6 +37,10 @@ const HardwareCheckSchema = mongoose.Schema( ref: "Monitor", immutable: true, }, + status: { + type: Boolean, + index: true, + }, cpu: { type: cpuSchema, default: () => ({}), From 50c6e32d6e1b6130f70e35fbbf01adf3b3b8bb03 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 25 Oct 2024 10:49:08 +0800 Subject: [PATCH 8/8] Fix variable assignment in --- Server/service/networkService.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Server/service/networkService.js b/Server/service/networkService.js index 2fa470df1..157a29006 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -104,8 +104,7 @@ class NetworkService { monitor: monitor, template: isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate", context: { monitorName: monitor.name, monitorUrl: monitor.url }, - subject: - (subject = `Monitor ${monitor.name} is ${isAlive === true ? "up" : "down"}`), + subject: `Monitor ${monitor.name} is ${isAlive === true ? "up" : "down"}`, }; this.handleNotification(config); }