From 10c81bbfd3d8cf0d396fff2ce4759fcf21bd6a70 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 13:51:47 +0100 Subject: [PATCH 01/17] Added new columns to monitor table for configuring advanced ping behavior: - ping_count: number of packets to send - ping_deadline: maximum total duration - ping_timeout: time to wait for each response - ping_numeric: output IP addresses instead of hostnames --- db/knex_init_db.js | 14 ++++++++++++++ .../patch-add-ping-advanced-options.sql | 7 +++++++ 2 files changed, 21 insertions(+) create mode 100644 db/old_migrations/patch-add-ping-advanced-options.sql diff --git a/db/knex_init_db.js b/db/knex_init_db.js index 46bff4bfa..c5a542e29 100644 --- a/db/knex_init_db.js +++ b/db/knex_init_db.js @@ -548,6 +548,20 @@ ALTER TABLE monitor table.double("timeout").defaultTo(0).notNullable(); }); + /* + patch-add-ping-advanced-options.sql + ALTER TABLE monitor ADD ping_count INTEGER default 1 not null; + ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null; + ALTER TABLE monitor ADD ping_deadline INTEGER default 10 not null; + ALTER TABLE monitor ADD ping_timeout INTEGER default 2 not null; + */ + await knex.schema.table("monitor", function (table) { + table.integer("ping_count").defaultTo(1).notNullable(); + table.boolean("ping_numeric").defaultTo(true).notNullable(); + table.integer("ping_deadline").defaultTo(10).notNullable(); + table.integer("ping_timeout").defaultTo(2).notNullable(); + }); + /* patch-add-gamedig-given-port.sql ALTER TABLE monitor diff --git a/db/old_migrations/patch-add-ping-advanced-options.sql b/db/old_migrations/patch-add-ping-advanced-options.sql new file mode 100644 index 000000000..9ce76b072 --- /dev/null +++ b/db/old_migrations/patch-add-ping-advanced-options.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; +ALTER TABLE monitor ADD ping_count INTEGER default 1 not null; +ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null; +ALTER TABLE monitor ADD ping_deadline INTEGER default 10 not null; +ALTER TABLE monitor ADD ping_timeout INTEGER default 2 not null; +COMMIT; From ffd0157474b8d0563a842c797b75b0def1ebd52b Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 13:58:30 +0100 Subject: [PATCH 02/17] added ping options patch to patchList --- server/database.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/database.js b/server/database.js index 0e6a7405d..415624b9f 100644 --- a/server/database.js +++ b/server/database.js @@ -111,7 +111,8 @@ class Database { "patch-notification-config.sql": true, "patch-fix-kafka-producer-booleans.sql": true, "patch-timeout.sql": true, - "patch-monitor-tls-info-add-fk.sql": true, // The last file so far converted to a knex migration file + "patch-monitor-tls-info-add-fk.sql": true, + "patch-add-ping-advanced-options.sql": true, // The last file so far converted to a knex migration file }; /** From 55075f10bd4bdd750f11b21c2543d7ed324ee4ab Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 14:02:55 +0100 Subject: [PATCH 03/17] build: added constants for ping advanced options and rebuilt util.js Added MIN/MAX/DEFAULT constants for: - ping count - ping deadline - ping timeout - and packet size, too. --- src/util.js | 42 +++++++++++++++++++++++++++++++++++------- src/util.ts | 20 ++++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/util.js b/src/util.js index df89cf92b..a116d16ee 100644 --- a/src/util.js +++ b/src/util.js @@ -8,17 +8,34 @@ // Backend uses the compiled file util.js // Frontend uses util.ts */ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); -exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0; -exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = void 0; -exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = void 0; +exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.PING_TIMEOUT_DEFAULT = exports.PING_TIMEOUT_MAX = exports.PING_TIMEOUT_MIN = exports.PING_COUNT_DEFAULT = exports.PING_COUNT_MAX = exports.PING_COUNT_MIN = exports.PING_DEADLINE_DEFAULT = exports.PING_DEADLINE_MAX = exports.PING_DEADLINE_MIN = exports.PING_DEFAULT_PACKET_SIZE = exports.PING_MAX_PACKET_SIZE = exports.PING_MIN_PACKET_SIZE = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0; +exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = void 0; const dayjs_1 = __importDefault(require("dayjs")); -const dayjs = require("dayjs"); -const jsonata = require("jsonata"); +const jsonata = __importStar(require("jsonata")); exports.isDev = process.env.NODE_ENV === "development"; exports.isNode = typeof process !== "undefined" && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node); exports.appName = "Uptime Kuma"; @@ -35,6 +52,18 @@ exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; exports.MAX_INTERVAL_SECOND = 2073600; exports.MIN_INTERVAL_SECOND = 20; +exports.PING_MIN_PACKET_SIZE = 1; +exports.PING_MAX_PACKET_SIZE = 65500; +exports.PING_DEFAULT_PACKET_SIZE = 56; +exports.PING_DEADLINE_MIN = 0; +exports.PING_DEADLINE_MAX = 300; +exports.PING_DEADLINE_DEFAULT = 0; +exports.PING_COUNT_MIN = 1; +exports.PING_COUNT_MAX = 100; +exports.PING_COUNT_DEFAULT = 3; +exports.PING_TIMEOUT_MIN = 0; +exports.PING_TIMEOUT_MAX = 60; +exports.PING_TIMEOUT_DEFAULT = 0; exports.CONSOLE_STYLE_Reset = "\x1b[0m"; exports.CONSOLE_STYLE_Bright = "\x1b[1m"; exports.CONSOLE_STYLE_Dim = "\x1b[2m"; @@ -66,7 +95,6 @@ exports.CONSOLE_STYLE_BgMagenta = "\x1b[45m"; exports.CONSOLE_STYLE_BgCyan = "\x1b[46m"; exports.CONSOLE_STYLE_BgWhite = "\x1b[47m"; exports.CONSOLE_STYLE_BgGray = "\x1b[100m"; - const consoleModuleColors = [ exports.CONSOLE_STYLE_FgCyan, exports.CONSOLE_STYLE_FgGreen, @@ -458,4 +486,4 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`); } } -exports.evaluateJsonQuery = evaluateJsonQuery; \ No newline at end of file +exports.evaluateJsonQuery = evaluateJsonQuery; diff --git a/src/util.ts b/src/util.ts index b3bab4fff..4d215e94e 100644 --- a/src/util.ts +++ b/src/util.ts @@ -39,6 +39,26 @@ export const SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; export const MAX_INTERVAL_SECOND = 2073600; // 24 days export const MIN_INTERVAL_SECOND = 20; // 20 seconds +// Packet Size limits +export const PING_PACKET_SIZE_MIN = 1; +export const PING_PACKET_SIZE_MAX = 65500; +export const PING_PACKET_SIZE_DEFAULT = 56; + +// Deadline limits (in seconds) +export const PING_DEADLINE_MIN = 1; +export const PING_DEADLINE_MAX = 300; +export const PING_DEADLINE_DEFAULT = 10; + +// Ping count limits +export const PING_COUNT_MIN = 1; +export const PING_COUNT_MAX = 100; +export const PING_COUNT_DEFAULT = 1; + +// Timeout limits (in seconds) +export const PING_TIMEOUT_MIN = 1; +export const PING_TIMEOUT_MAX = 60; +export const PING_TIMEOUT_DEFAULT = 2; + // Console colors // https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color export const CONSOLE_STYLE_Reset = "\x1b[0m"; From 4bd775e4bef9a049fb38d574a53aedc924e55800 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 14:08:07 +0100 Subject: [PATCH 04/17] added advanced ping options to server and monitor and also added validation using ping MIN/MAX constants in monitor --- server/model/monitor.js | 33 ++++++++++++++++++++++++++++++++- server/server.js | 6 ++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 3ad8cfafc..67c295f68 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -2,7 +2,8 @@ const dayjs = require("dayjs"); const axios = require("axios"); const { Prometheus } = require("../prometheus"); const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, - SQL_DATETIME_FORMAT, evaluateJsonQuery + SQL_DATETIME_FORMAT, evaluateJsonQuery, PING_PACKET_SIZE_MIN, PING_PACKET_SIZE_MAX, + PING_DEADLINE_MIN, PING_DEADLINE_MAX, PING_COUNT_MIN, PING_COUNT_MAX, PING_TIMEOUT_MIN, PING_TIMEOUT_MAX } = require("../../src/util"); const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery, redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal @@ -155,6 +156,12 @@ class Monitor extends BeanModel { snmpVersion: this.snmpVersion, rabbitmqNodes: JSON.parse(this.rabbitmqNodes), conditions: JSON.parse(this.conditions), + + // ping advanced options + ping_numeric: this.isPingNumeric(), + ping_count: this.ping_count, + ping_deadline: this.ping_deadline, + ping_timeout: this.ping_timeout, }; if (includeSensitiveData) { @@ -247,6 +254,14 @@ class Monitor extends BeanModel { return Boolean(this.expiryNotification); } + /** + * Check if ping should use numeric output only + * @returns {boolean} True if IP addresses will be output instead of symbolic hostnames + */ + isPingNumeric() { + return Boolean(this.ping_numeric); + } + /** * Parse to boolean * @returns {boolean} Should TLS errors be ignored? @@ -1500,6 +1515,22 @@ class Monitor extends BeanModel { if (this.interval < MIN_INTERVAL_SECOND) { throw new Error(`Interval cannot be less than ${MIN_INTERVAL_SECOND} seconds`); } + + if (this.packetSize && (this.packetSize < PING_PACKET_SIZE_MIN || this.packetSize > PING_PACKET_SIZE_MAX)) { + throw new Error(`Packet size must be between ${PING_PACKET_SIZE_MIN} and ${PING_PACKET_SIZE_MAX}`); + } + + if (this.ping_deadline && (this.ping_deadline < PING_DEADLINE_MIN || this.ping_deadline > PING_DEADLINE_MAX)) { + throw new Error(`Deadline must be between ${PING_DEADLINE_MIN} and ${PING_DEADLINE_MAX} seconds`); + } + + if (this.ping_count && (this.ping_count < PING_COUNT_MIN || this.ping_count > PING_COUNT_MAX)) { + throw new Error(`Echo requests count must be between ${PING_COUNT_MIN} and ${PING_COUNT_MAX}`); + } + + if (this.ping_timeout && (this.ping_timeout < PING_TIMEOUT_MIN || this.ping_timeout > PING_TIMEOUT_MAX)) { + throw new Error(`Timeout must be between ${PING_TIMEOUT_MIN} and ${PING_TIMEOUT_MAX} seconds`); + } } /** diff --git a/server/server.js b/server/server.js index ec5ad49f6..38b93acf9 100644 --- a/server/server.js +++ b/server/server.js @@ -875,6 +875,12 @@ let needSetup = false; bean.rabbitmqPassword = monitor.rabbitmqPassword; bean.conditions = JSON.stringify(monitor.conditions); + // ping advanced options + bean.ping_numeric = monitor.ping_numeric; + bean.ping_count = monitor.ping_count; + bean.ping_deadline = monitor.ping_deadline; + bean.ping_timeout = monitor.ping_timeout; + bean.validate(); await R.store(bean); From e1bdc53ba5e8e0c9fcb6fbdefc5b6146e1ee2f1e Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 14:11:12 +0100 Subject: [PATCH 05/17] refactor: enhanced ping function with advanced options and docs - Added advanced parameters (count, deadline, timeout) - Updated parameter names for clarity - Used constants for default values - Improved method and parameter documentation --- server/util-server.js | 57 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/server/util-server.js b/server/util-server.js index 5ebc62ac5..187872589 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -1,7 +1,11 @@ const tcpp = require("tcp-ping"); const ping = require("@louislam/ping"); const { R } = require("redbean-node"); -const { log, genSecret, badgeConstants } = require("../src/util"); +const { + log, genSecret, badgeConstants, + PING_PACKET_SIZE_DEFAULT, PING_DEADLINE_DEFAULT, + PING_COUNT_DEFAULT, PING_TIMEOUT_DEFAULT +} = require("../src/util"); const passwordHash = require("./password-hash"); const { Resolver } = require("dns"); const iconv = require("iconv-lite"); @@ -118,20 +122,33 @@ exports.tcping = function (hostname, port) { /** * Ping the specified machine - * @param {string} hostname Hostname / address of machine - * @param {number} size Size of packet to send + * @param {string} dest_address Hostname / IP address of machine to ping + * @param {number} count Number of packets to send before stopping + * @param {string} source_address Source address for sending/receiving echo requests + * @param {boolean} numeric If true, IP addresses will be output instead of symbolic hostnames + * @param {number} size Size (in bytes) of echo request to send + * @param {number} deadline Maximum time in seconds before ping stops, regardless of packets sent + * @param {number} timeout Maximum time in seconds to wait for each response * @returns {Promise<number>} Time for ping in ms rounded to nearest integer */ -exports.ping = async (hostname, size = 56) => { +exports.ping = async ( + dest_address, + count = PING_COUNT_DEFAULT, + source_address = '', + numeric = true, + size = PING_PACKET_SIZE_DEFAULT, + deadline = PING_DEADLINE_DEFAULT, + timeout = PING_TIMEOUT_DEFAULT, +) => { try { - return await exports.pingAsync(hostname, false, size); + return await exports.pingAsync(dest_address, false, count, source_address, numeric, size, deadline, timeout); } catch (e) { // If the host cannot be resolved, try again with ipv6 log.debug("ping", "IPv6 error message: " + e.message); // As node-ping does not report a specific error for this, try again if it is an empty message with ipv6 no matter what. if (!e.message) { - return await exports.pingAsync(hostname, true, size); + return await exports.pingAsync(dest_address, true, count, source_address, numeric, size, deadline, timeout); } else { throw e; } @@ -140,18 +157,34 @@ exports.ping = async (hostname, size = 56) => { /** * Ping the specified machine - * @param {string} hostname Hostname / address of machine to ping + * @param {string} dest_address Hostname / IP address of machine to ping * @param {boolean} ipv6 Should IPv6 be used? - * @param {number} size Size of ping packet to send + * @param {number} count Number of packets to send before stopping + * @param {string} source_address Source address for sending/receiving echo requests + * @param {boolean} numeric If true, IP addresses will be output instead of symbolic hostnames + * @param {number} size Size (in bytes) of echo request to send + * @param {number} deadline Maximum time in seconds before ping stops, regardless of packets sent + * @param {number} timeout Maximum time in seconds to wait for each response * @returns {Promise<number>} Time for ping in ms rounded to nearest integer */ -exports.pingAsync = function (hostname, ipv6 = false, size = 56) { +exports.pingAsync = function ( + dest_address, + ipv6 = false, + count = PING_COUNT_DEFAULT, + source_address = '', + numeric = true, + size = PING_PACKET_SIZE_DEFAULT, + deadline = PING_DEADLINE_DEFAULT, + timeout = PING_TIMEOUT_DEFAULT, +) { return new Promise((resolve, reject) => { - ping.promise.probe(hostname, { + ping.promise.probe(dest_address, { v6: ipv6, - min_reply: 1, - deadline: 10, + min_reply: count, + sourceAddr: source_address, packetSize: size, + deadline: deadline, + timeout: timeout }).then((res) => { // If ping failed, it will set field to unknown if (res.alive) { From 7371cefc27cb7169427c40791bd2e105439a3d46 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 14:12:54 +0100 Subject: [PATCH 06/17] added UI for advanced ping configuration Added form fields to configure: - packet count - timeout - deadline - numeric output option in monitor creation/edit view --- src/pages/EditMonitor.vue | 82 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index a83f91cab..3d3f3ca13 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -660,12 +660,54 @@ </div> </div> - <!-- Ping packet size --> + <!-- Max Packets / Count --> + <div v-if="monitor.type === 'ping'" class="my-3"> + <label for="ping-count" class="form-label">{{ $t("Max Packets") }}</label> + <input id="ping-count" v-model="monitor.ping_count" type="number" class="form-control" required :min="ping_count_min" :max="ping_count_max" step="1"> + <div class="form-text"> + {{ $t("Number of packets to send before stopping") }} + </div> + </div> + + <!-- Numeric Output --> + <div v-if="monitor.type === 'ping'" class="my-3 form-check"> + <input id="ping_numeric" v-model="monitor.ping_numeric" type="checkbox" class="form-check-input" + :checked="monitor.ping_numeric"> + <label class="form-check-label" for="ping_numeric"> + {{ $t("Numeric Output") }} + </label> + <div class="form-text"> + {{ $t("If checked, IP addresses will be output instead of symbolic hostnames") }} + </div> + </div> + + <!-- Packet size --> <div v-if="monitor.type === 'ping'" class="my-3"> <label for="packet-size" class="form-label">{{ $t("Packet Size") }}</label> - <input id="packet-size" v-model="monitor.packetSize" type="number" class="form-control" required min="1" max="65500" step="1"> + <input id="packet-size" v-model="monitor.packetSize" type="number" class="form-control" + required :min="packetSize_min" :max="packetSize_max" step="1"> </div> + <!-- Max Duration / Deadline --> + <div v-if="monitor.type === 'ping'" class="my-3"> + <label for="ping_deadline" class="form-label">{{ $t("Max Duration") }}</label> + <input id="ping_deadline" v-model="monitor.ping_deadline" type="number" class="form-control" + required :min="ping_deadline_min" :max="ping_deadline_max" step="1"> + <div class="form-text"> + {{ $t("Total time in seconds before ping stops, regardless of packets sent") }} + </div> + </div> + + <!-- Response Timeout --> + <div v-if="monitor.type === 'ping'" class="my-3"> + <label for="ping_timeout" class="form-label">{{ $t("Response Timeout") }}</label> + <input id="ping_timeout" v-model="monitor.ping_timeout" type="number" class="form-control" required :min="ping_timeout_min" :max="ping_timeout_max" step="1"> + <div class="form-text"> + {{ $t("Maximum time in seconds to wait for each response") }} + </div> + </div> + + <!-- HTTP / Keyword only --> <template v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' || monitor.type === 'grpc-keyword' "> <div class="my-3"> @@ -1060,7 +1102,25 @@ import DockerHostDialog from "../components/DockerHostDialog.vue"; import RemoteBrowserDialog from "../components/RemoteBrowserDialog.vue"; import ProxyDialog from "../components/ProxyDialog.vue"; import TagsManager from "../components/TagsManager.vue"; -import { genSecret, isDev, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, sleep } from "../util.ts"; +import { + genSecret, + isDev, + MAX_INTERVAL_SECOND, + MIN_INTERVAL_SECOND, + sleep, + PING_PACKET_SIZE_MIN, + PING_PACKET_SIZE_MAX, + PING_PACKET_SIZE_DEFAULT, + PING_DEADLINE_MIN, + PING_DEADLINE_MAX, + PING_DEADLINE_DEFAULT, + PING_COUNT_MIN, + PING_COUNT_MAX, + PING_COUNT_DEFAULT, + PING_TIMEOUT_MIN, + PING_TIMEOUT_MAX, + PING_TIMEOUT_DEFAULT +} from "../util.ts"; import { hostNameRegexPattern } from "../util-frontend"; import HiddenInput from "../components/HiddenInput.vue"; import EditMonitorConditions from "../components/EditMonitorConditions.vue"; @@ -1082,7 +1142,6 @@ const monitorDefaults = { notificationIDList: {}, ignoreTls: false, upsideDown: false, - packetSize: 56, expiryNotification: false, maxredirects: 10, accepted_statuscodes: [ "200-299" ], @@ -1133,6 +1192,14 @@ export default { return { minInterval: MIN_INTERVAL_SECOND, maxInterval: MAX_INTERVAL_SECOND, + ping_count_min: PING_COUNT_MIN, + ping_count_max: PING_COUNT_MAX, + packetSize_min: PING_PACKET_SIZE_MIN, + packetSize_max: PING_PACKET_SIZE_MAX, + ping_deadline_min: PING_DEADLINE_MIN, + ping_deadline_max: PING_DEADLINE_MAX, + ping_timeout_min: PING_TIMEOUT_MIN, + ping_timeout_max: PING_TIMEOUT_MAX, processing: false, monitor: { notificationIDList: {}, @@ -1564,7 +1631,12 @@ message HealthCheckResponse { if (this.isAdd) { this.monitor = { - ...monitorDefaults + ...monitorDefaults, + ping_count: PING_COUNT_DEFAULT, + ping_numeric: true, + packetSize: PING_PACKET_SIZE_DEFAULT, + ping_deadline: PING_DEADLINE_DEFAULT, + ping_timeout: PING_TIMEOUT_DEFAULT, }; if (this.$root.proxyList && !this.monitor.proxyId) { From e661b9f801661532ae55d3ebb1a0a291abd8e37a Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 14:29:38 +0100 Subject: [PATCH 07/17] fixed ESLint issues and regenerated util.js --- server/database.js | 2 +- server/model/monitor.js | 6 +++--- server/util-server.js | 26 +++++++++++++------------- src/util.js | 10 +++++----- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/server/database.js b/server/database.js index 415624b9f..db31c2d9e 100644 --- a/server/database.js +++ b/server/database.js @@ -111,7 +111,7 @@ class Database { "patch-notification-config.sql": true, "patch-fix-kafka-producer-booleans.sql": true, "patch-timeout.sql": true, - "patch-monitor-tls-info-add-fk.sql": true, + "patch-monitor-tls-info-add-fk.sql": true, "patch-add-ping-advanced-options.sql": true, // The last file so far converted to a knex migration file }; diff --git a/server/model/monitor.js b/server/model/monitor.js index 67c295f68..73612bd0b 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -1519,15 +1519,15 @@ class Monitor extends BeanModel { if (this.packetSize && (this.packetSize < PING_PACKET_SIZE_MIN || this.packetSize > PING_PACKET_SIZE_MAX)) { throw new Error(`Packet size must be between ${PING_PACKET_SIZE_MIN} and ${PING_PACKET_SIZE_MAX}`); } - + if (this.ping_deadline && (this.ping_deadline < PING_DEADLINE_MIN || this.ping_deadline > PING_DEADLINE_MAX)) { throw new Error(`Deadline must be between ${PING_DEADLINE_MIN} and ${PING_DEADLINE_MAX} seconds`); } - + if (this.ping_count && (this.ping_count < PING_COUNT_MIN || this.ping_count > PING_COUNT_MAX)) { throw new Error(`Echo requests count must be between ${PING_COUNT_MIN} and ${PING_COUNT_MAX}`); } - + if (this.ping_timeout && (this.ping_timeout < PING_TIMEOUT_MIN || this.ping_timeout > PING_TIMEOUT_MAX)) { throw new Error(`Timeout must be between ${PING_TIMEOUT_MIN} and ${PING_TIMEOUT_MAX} seconds`); } diff --git a/server/util-server.js b/server/util-server.js index 187872589..33d2d78e6 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -1,7 +1,7 @@ const tcpp = require("tcp-ping"); const ping = require("@louislam/ping"); const { R } = require("redbean-node"); -const { +const { log, genSecret, badgeConstants, PING_PACKET_SIZE_DEFAULT, PING_DEADLINE_DEFAULT, PING_COUNT_DEFAULT, PING_TIMEOUT_DEFAULT @@ -122,9 +122,9 @@ exports.tcping = function (hostname, port) { /** * Ping the specified machine - * @param {string} dest_address Hostname / IP address of machine to ping + * @param {string} destAddr Hostname / IP address of machine to ping * @param {number} count Number of packets to send before stopping - * @param {string} source_address Source address for sending/receiving echo requests + * @param {string} sourceAddr Source address for sending/receiving echo requests * @param {boolean} numeric If true, IP addresses will be output instead of symbolic hostnames * @param {number} size Size (in bytes) of echo request to send * @param {number} deadline Maximum time in seconds before ping stops, regardless of packets sent @@ -132,23 +132,23 @@ exports.tcping = function (hostname, port) { * @returns {Promise<number>} Time for ping in ms rounded to nearest integer */ exports.ping = async ( - dest_address, + destAddr, count = PING_COUNT_DEFAULT, - source_address = '', + sourceAddr = "", numeric = true, size = PING_PACKET_SIZE_DEFAULT, deadline = PING_DEADLINE_DEFAULT, timeout = PING_TIMEOUT_DEFAULT, ) => { try { - return await exports.pingAsync(dest_address, false, count, source_address, numeric, size, deadline, timeout); + return await exports.pingAsync(destAddr, false, count, sourceAddr, numeric, size, deadline, timeout); } catch (e) { // If the host cannot be resolved, try again with ipv6 log.debug("ping", "IPv6 error message: " + e.message); // As node-ping does not report a specific error for this, try again if it is an empty message with ipv6 no matter what. if (!e.message) { - return await exports.pingAsync(dest_address, true, count, source_address, numeric, size, deadline, timeout); + return await exports.pingAsync(destAddr, true, count, sourceAddr, numeric, size, deadline, timeout); } else { throw e; } @@ -157,10 +157,10 @@ exports.ping = async ( /** * Ping the specified machine - * @param {string} dest_address Hostname / IP address of machine to ping + * @param {string} destAddr Hostname / IP address of machine to ping * @param {boolean} ipv6 Should IPv6 be used? * @param {number} count Number of packets to send before stopping - * @param {string} source_address Source address for sending/receiving echo requests + * @param {string} sourceAddr Source address for sending/receiving echo requests * @param {boolean} numeric If true, IP addresses will be output instead of symbolic hostnames * @param {number} size Size (in bytes) of echo request to send * @param {number} deadline Maximum time in seconds before ping stops, regardless of packets sent @@ -168,20 +168,20 @@ exports.ping = async ( * @returns {Promise<number>} Time for ping in ms rounded to nearest integer */ exports.pingAsync = function ( - dest_address, + destAddr, ipv6 = false, count = PING_COUNT_DEFAULT, - source_address = '', + sourceAddr = "", numeric = true, size = PING_PACKET_SIZE_DEFAULT, deadline = PING_DEADLINE_DEFAULT, timeout = PING_TIMEOUT_DEFAULT, ) { return new Promise((resolve, reject) => { - ping.promise.probe(dest_address, { + ping.promise.probe(destAddr, { v6: ipv6, min_reply: count, - sourceAddr: source_address, + sourceAddr: sourceAddr, packetSize: size, deadline: deadline, timeout: timeout diff --git a/src/util.js b/src/util.js index a116d16ee..644914472 100644 --- a/src/util.js +++ b/src/util.js @@ -32,7 +32,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); -exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.PING_TIMEOUT_DEFAULT = exports.PING_TIMEOUT_MAX = exports.PING_TIMEOUT_MIN = exports.PING_COUNT_DEFAULT = exports.PING_COUNT_MAX = exports.PING_COUNT_MIN = exports.PING_DEADLINE_DEFAULT = exports.PING_DEADLINE_MAX = exports.PING_DEADLINE_MIN = exports.PING_DEFAULT_PACKET_SIZE = exports.PING_MAX_PACKET_SIZE = exports.PING_MIN_PACKET_SIZE = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0; +exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.PING_TIMEOUT_DEFAULT = exports.PING_TIMEOUT_MAX = exports.PING_TIMEOUT_MIN = exports.PING_COUNT_DEFAULT = exports.PING_COUNT_MAX = exports.PING_COUNT_MIN = exports.PING_DEADLINE_DEFAULT = exports.PING_DEADLINE_MAX = exports.PING_DEADLINE_MIN = exports.PING_PACKET_SIZE_DEFAULT = exports.PING_PACKET_SIZE_MAX = exports.PING_PACKET_SIZE_MIN = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0; exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = void 0; const dayjs_1 = __importDefault(require("dayjs")); const jsonata = __importStar(require("jsonata")); @@ -52,16 +52,16 @@ exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; exports.MAX_INTERVAL_SECOND = 2073600; exports.MIN_INTERVAL_SECOND = 20; -exports.PING_MIN_PACKET_SIZE = 1; -exports.PING_MAX_PACKET_SIZE = 65500; -exports.PING_DEFAULT_PACKET_SIZE = 56; +exports.PING_PACKET_SIZE_MIN = 1; +exports.PING_PACKET_SIZE_MAX = 65500; +exports.PING_PACKET_SIZE_DEFAULT = 56; exports.PING_DEADLINE_MIN = 0; exports.PING_DEADLINE_MAX = 300; exports.PING_DEADLINE_DEFAULT = 0; exports.PING_COUNT_MIN = 1; exports.PING_COUNT_MAX = 100; exports.PING_COUNT_DEFAULT = 3; -exports.PING_TIMEOUT_MIN = 0; +exports.PING_TIMEOUT_MIN_TIMEOU = 0; exports.PING_TIMEOUT_MAX = 60; exports.PING_TIMEOUT_DEFAULT = 0; exports.CONSOLE_STYLE_Reset = "\x1b[0m"; From c58c76ccf1e754a42702d6bf3cc074141aa6847d Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 31 Jan 2025 14:57:03 +0100 Subject: [PATCH 08/17] Fixed check-linters errors --- src/pages/EditMonitor.vue | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 3d3f3ca13..079bc4fca 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -671,8 +671,7 @@ <!-- Numeric Output --> <div v-if="monitor.type === 'ping'" class="my-3 form-check"> - <input id="ping_numeric" v-model="monitor.ping_numeric" type="checkbox" class="form-check-input" - :checked="monitor.ping_numeric"> + <input id="ping_numeric" v-model="monitor.ping_numeric" type="checkbox" class="form-check-input" :checked="monitor.ping_numeric"> <label class="form-check-label" for="ping_numeric"> {{ $t("Numeric Output") }} </label> @@ -684,15 +683,13 @@ <!-- Packet size --> <div v-if="monitor.type === 'ping'" class="my-3"> <label for="packet-size" class="form-label">{{ $t("Packet Size") }}</label> - <input id="packet-size" v-model="monitor.packetSize" type="number" class="form-control" - required :min="packetSize_min" :max="packetSize_max" step="1"> + <input id="packet-size" v-model="monitor.packetSize" type="number" class="form-control" required :min="packetSize_min" :max="packetSize_max" step="1"> </div> <!-- Max Duration / Deadline --> <div v-if="monitor.type === 'ping'" class="my-3"> <label for="ping_deadline" class="form-label">{{ $t("Max Duration") }}</label> - <input id="ping_deadline" v-model="monitor.ping_deadline" type="number" class="form-control" - required :min="ping_deadline_min" :max="ping_deadline_max" step="1"> + <input id="ping_deadline" v-model="monitor.ping_deadline" type="number" class="form-control" required :min="ping_deadline_min" :max="ping_deadline_max" step="1"> <div class="form-text"> {{ $t("Total time in seconds before ping stops, regardless of packets sent") }} </div> @@ -707,7 +704,6 @@ </div> </div> - <!-- HTTP / Keyword only --> <template v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' || monitor.type === 'grpc-keyword' "> <div class="my-3"> @@ -1102,11 +1098,11 @@ import DockerHostDialog from "../components/DockerHostDialog.vue"; import RemoteBrowserDialog from "../components/RemoteBrowserDialog.vue"; import ProxyDialog from "../components/ProxyDialog.vue"; import TagsManager from "../components/TagsManager.vue"; -import { - genSecret, - isDev, - MAX_INTERVAL_SECOND, - MIN_INTERVAL_SECOND, +import { + genSecret, + isDev, + MAX_INTERVAL_SECOND, + MIN_INTERVAL_SECOND, sleep, PING_PACKET_SIZE_MIN, PING_PACKET_SIZE_MAX, From e0166f5eca6041f0cd46b2067a0b91b9b041ff78 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Tue, 4 Mar 2025 10:11:34 +0100 Subject: [PATCH 09/17] migrated from old to new migration system based on knex --- db/knex_init_db.js | 14 ---------- .../2025-03-04-0000-ping-advanced-options.js | 27 +++++++++++++++++++ .../patch-add-ping-advanced-options.sql | 7 ----- server/database.js | 3 +-- 4 files changed, 28 insertions(+), 23 deletions(-) create mode 100644 db/knex_migrations/2025-03-04-0000-ping-advanced-options.js delete mode 100644 db/old_migrations/patch-add-ping-advanced-options.sql diff --git a/db/knex_init_db.js b/db/knex_init_db.js index c5a542e29..46bff4bfa 100644 --- a/db/knex_init_db.js +++ b/db/knex_init_db.js @@ -548,20 +548,6 @@ ALTER TABLE monitor table.double("timeout").defaultTo(0).notNullable(); }); - /* - patch-add-ping-advanced-options.sql - ALTER TABLE monitor ADD ping_count INTEGER default 1 not null; - ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null; - ALTER TABLE monitor ADD ping_deadline INTEGER default 10 not null; - ALTER TABLE monitor ADD ping_timeout INTEGER default 2 not null; - */ - await knex.schema.table("monitor", function (table) { - table.integer("ping_count").defaultTo(1).notNullable(); - table.boolean("ping_numeric").defaultTo(true).notNullable(); - table.integer("ping_deadline").defaultTo(10).notNullable(); - table.integer("ping_timeout").defaultTo(2).notNullable(); - }); - /* patch-add-gamedig-given-port.sql ALTER TABLE monitor diff --git a/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js new file mode 100644 index 000000000..319fb18ef --- /dev/null +++ b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js @@ -0,0 +1,27 @@ +/* SQL: +ALTER TABLE monitor ADD ping_count INTEGER default 1 not null; +ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null; +ALTER TABLE monitor ADD ping_deadline INTEGER default 10 not null; +ALTER TABLE monitor ADD ping_timeout INTEGER default 2 not null; +*/ +exports.up = function (knex) { + // Add new columns to table monitor + return knex.schema + .alterTable("monitor", function (table) { + table.integer("ping_count").defaultTo(1).notNullable(); + table.boolean("ping_numeric").defaultTo(true).notNullable(); + table.integer("ping_deadline").defaultTo(10).notNullable(); + table.integer("ping_timeout").defaultTo(2).notNullable(); + }); + +}; + +exports.down = function (knex) { + return knex.schema + .alterTable("monitor", function (table) { + table.dropColumn("ping_count"); + table.dropColumn("ping_numeric"); + table.dropColumn("ping_deadline"); + table.dropColumn("ping_timeout"); + }); +}; diff --git a/db/old_migrations/patch-add-ping-advanced-options.sql b/db/old_migrations/patch-add-ping-advanced-options.sql deleted file mode 100644 index 9ce76b072..000000000 --- a/db/old_migrations/patch-add-ping-advanced-options.sql +++ /dev/null @@ -1,7 +0,0 @@ --- You should not modify if this have pushed to Github, unless it does serious wrong with the db. -BEGIN TRANSACTION; -ALTER TABLE monitor ADD ping_count INTEGER default 1 not null; -ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null; -ALTER TABLE monitor ADD ping_deadline INTEGER default 10 not null; -ALTER TABLE monitor ADD ping_timeout INTEGER default 2 not null; -COMMIT; diff --git a/server/database.js b/server/database.js index db31c2d9e..0e6a7405d 100644 --- a/server/database.js +++ b/server/database.js @@ -111,8 +111,7 @@ class Database { "patch-notification-config.sql": true, "patch-fix-kafka-producer-booleans.sql": true, "patch-timeout.sql": true, - "patch-monitor-tls-info-add-fk.sql": true, - "patch-add-ping-advanced-options.sql": true, // The last file so far converted to a knex migration file + "patch-monitor-tls-info-add-fk.sql": true, // The last file so far converted to a knex migration file }; /** From 0bb2756f9cb4b023bfc8974e931fd4fe02dc54b6 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Tue, 4 Mar 2025 11:01:23 +0100 Subject: [PATCH 10/17] added/fixed translations --- src/lang/en.json | 10 +++++++++- src/pages/EditMonitor.vue | 16 ++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index e215f1031..28bca7d87 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1051,5 +1051,13 @@ "RabbitMQ Password": "RabbitMQ Password", "rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.", "SendGrid API Key": "SendGrid API Key", - "Separate multiple email addresses with commas": "Separate multiple email addresses with commas" + "Separate multiple email addresses with commas": "Separate multiple email addresses with commas", + "pingCountLabel": "Max Packets", + "pingCountDescription": "Number of packets to send before stopping", + "pingNumericLabel": "Numeric Output", + "pingNumericDescription": "If checked, IP addresses will be output instead of symbolic hostnames", + "pingDeadlineLabel": "Max Duration", + "pingDeadlineDescription": "Total time in seconds before ping stops, regardless of packets sent", + "pingTimeoutLabel": "Response Timeout", + "pingTimeoutDescription": "Maximum time in seconds to wait for each response" } diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 079bc4fca..767e79b30 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -662,10 +662,10 @@ <!-- Max Packets / Count --> <div v-if="monitor.type === 'ping'" class="my-3"> - <label for="ping-count" class="form-label">{{ $t("Max Packets") }}</label> + <label for="ping-count" class="form-label">{{ $t("pingCountLabel") }}</label> <input id="ping-count" v-model="monitor.ping_count" type="number" class="form-control" required :min="ping_count_min" :max="ping_count_max" step="1"> <div class="form-text"> - {{ $t("Number of packets to send before stopping") }} + {{ $t("pingCountDescription") }} </div> </div> @@ -673,10 +673,10 @@ <div v-if="monitor.type === 'ping'" class="my-3 form-check"> <input id="ping_numeric" v-model="monitor.ping_numeric" type="checkbox" class="form-check-input" :checked="monitor.ping_numeric"> <label class="form-check-label" for="ping_numeric"> - {{ $t("Numeric Output") }} + {{ $t("pingNumericLabel") }} </label> <div class="form-text"> - {{ $t("If checked, IP addresses will be output instead of symbolic hostnames") }} + {{ $t("pingNumericDescription") }} </div> </div> @@ -688,19 +688,19 @@ <!-- Max Duration / Deadline --> <div v-if="monitor.type === 'ping'" class="my-3"> - <label for="ping_deadline" class="form-label">{{ $t("Max Duration") }}</label> + <label for="ping_deadline" class="form-label">{{ $t("pingDeadlineLabel") }}</label> <input id="ping_deadline" v-model="monitor.ping_deadline" type="number" class="form-control" required :min="ping_deadline_min" :max="ping_deadline_max" step="1"> <div class="form-text"> - {{ $t("Total time in seconds before ping stops, regardless of packets sent") }} + {{ $t("pingDeadlineDescription") }} </div> </div> <!-- Response Timeout --> <div v-if="monitor.type === 'ping'" class="my-3"> - <label for="ping_timeout" class="form-label">{{ $t("Response Timeout") }}</label> + <label for="ping_timeout" class="form-label">{{ $t("pingTimeoutLabel") }}</label> <input id="ping_timeout" v-model="monitor.ping_timeout" type="number" class="form-control" required :min="ping_timeout_min" :max="ping_timeout_max" step="1"> <div class="form-text"> - {{ $t("Maximum time in seconds to wait for each response") }} + {{ $t("pingTimeoutDescription") }} </div> </div> From f275d5611bc9fe14590cc183a259c8a7a1866078 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Tue, 4 Mar 2025 12:11:51 +0100 Subject: [PATCH 11/17] fix: numeric flag now properly passed to the underlying function --- server/util-server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/util-server.js b/server/util-server.js index 33d2d78e6..5efe9116a 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -182,6 +182,7 @@ exports.pingAsync = function ( v6: ipv6, min_reply: count, sourceAddr: sourceAddr, + numeric: numeric, packetSize: size, deadline: deadline, timeout: timeout From d12a0b31781609556ac73d025489c7478a638c4a Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Thu, 6 Mar 2025 16:32:20 +0100 Subject: [PATCH 12/17] inline ping validation constants --- server/model/monitor.js | 15 +++++++++------ src/pages/EditMonitor.vue | 36 ++++++++---------------------------- src/util.js | 10 +++++----- 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 73612bd0b..86f53f3b3 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -2,8 +2,11 @@ const dayjs = require("dayjs"); const axios = require("axios"); const { Prometheus } = require("../prometheus"); const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, - SQL_DATETIME_FORMAT, evaluateJsonQuery, PING_PACKET_SIZE_MIN, PING_PACKET_SIZE_MAX, - PING_DEADLINE_MIN, PING_DEADLINE_MAX, PING_COUNT_MIN, PING_COUNT_MAX, PING_TIMEOUT_MIN, PING_TIMEOUT_MAX + SQL_DATETIME_FORMAT, evaluateJsonQuery, + PING_PACKET_SIZE_MIN, PING_PACKET_SIZE_MAX, PING_PACKET_SIZE_DEFAULT, + PING_DEADLINE_MIN, PING_DEADLINE_MAX, PING_DEADLINE_DEFAULT, + PING_COUNT_MIN, PING_COUNT_MAX, PING_COUNT_DEFAULT, + PING_TIMEOUT_MIN, PING_TIMEOUT_MAX, PING_TIMEOUT_DEFAULT } = require("../../src/util"); const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery, redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal @@ -1517,19 +1520,19 @@ class Monitor extends BeanModel { } if (this.packetSize && (this.packetSize < PING_PACKET_SIZE_MIN || this.packetSize > PING_PACKET_SIZE_MAX)) { - throw new Error(`Packet size must be between ${PING_PACKET_SIZE_MIN} and ${PING_PACKET_SIZE_MAX}`); + throw new Error(`Packet size must be between ${PING_PACKET_SIZE_MIN} and ${PING_PACKET_SIZE_MAX} (default: ${PING_PACKET_SIZE_DEFAULT})`); } if (this.ping_deadline && (this.ping_deadline < PING_DEADLINE_MIN || this.ping_deadline > PING_DEADLINE_MAX)) { - throw new Error(`Deadline must be between ${PING_DEADLINE_MIN} and ${PING_DEADLINE_MAX} seconds`); + throw new Error(`Deadline must be between ${PING_DEADLINE_MIN} and ${PING_DEADLINE_MAX} seconds (default: ${PING_DEADLINE_DEFAULT})`); } if (this.ping_count && (this.ping_count < PING_COUNT_MIN || this.ping_count > PING_COUNT_MAX)) { - throw new Error(`Echo requests count must be between ${PING_COUNT_MIN} and ${PING_COUNT_MAX}`); + throw new Error(`Echo requests count must be between ${PING_COUNT_MIN} and ${PING_COUNT_MAX} (default: ${PING_COUNT_DEFAULT})`); } if (this.ping_timeout && (this.ping_timeout < PING_TIMEOUT_MIN || this.ping_timeout > PING_TIMEOUT_MAX)) { - throw new Error(`Timeout must be between ${PING_TIMEOUT_MIN} and ${PING_TIMEOUT_MAX} seconds`); + throw new Error(`Timeout must be between ${PING_TIMEOUT_MIN} and ${PING_TIMEOUT_MAX} seconds (default: ${PING_TIMEOUT_DEFAULT})`); } } diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 767e79b30..19d7c2a9e 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -663,7 +663,7 @@ <!-- Max Packets / Count --> <div v-if="monitor.type === 'ping'" class="my-3"> <label for="ping-count" class="form-label">{{ $t("pingCountLabel") }}</label> - <input id="ping-count" v-model="monitor.ping_count" type="number" class="form-control" required :min="ping_count_min" :max="ping_count_max" step="1"> + <input id="ping-count" v-model="monitor.ping_count" type="number" class="form-control" required min="1" max="100" step="1"> <div class="form-text"> {{ $t("pingCountDescription") }} </div> @@ -683,13 +683,13 @@ <!-- Packet size --> <div v-if="monitor.type === 'ping'" class="my-3"> <label for="packet-size" class="form-label">{{ $t("Packet Size") }}</label> - <input id="packet-size" v-model="monitor.packetSize" type="number" class="form-control" required :min="packetSize_min" :max="packetSize_max" step="1"> + <input id="packet-size" v-model="monitor.packetSize" type="number" class="form-control" required min="1" :max="65500" step="1"> </div> <!-- Max Duration / Deadline --> <div v-if="monitor.type === 'ping'" class="my-3"> <label for="ping_deadline" class="form-label">{{ $t("pingDeadlineLabel") }}</label> - <input id="ping_deadline" v-model="monitor.ping_deadline" type="number" class="form-control" required :min="ping_deadline_min" :max="ping_deadline_max" step="1"> + <input id="ping_deadline" v-model="monitor.ping_deadline" type="number" class="form-control" required min="0" max="300" step="1"> <div class="form-text"> {{ $t("pingDeadlineDescription") }} </div> @@ -698,7 +698,7 @@ <!-- Response Timeout --> <div v-if="monitor.type === 'ping'" class="my-3"> <label for="ping_timeout" class="form-label">{{ $t("pingTimeoutLabel") }}</label> - <input id="ping_timeout" v-model="monitor.ping_timeout" type="number" class="form-control" required :min="ping_timeout_min" :max="ping_timeout_max" step="1"> + <input id="ping_timeout" v-model="monitor.ping_timeout" type="number" class="form-control" required min="1" max="60" step="1"> <div class="form-text"> {{ $t("pingTimeoutDescription") }} </div> @@ -1104,18 +1104,6 @@ import { MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, sleep, - PING_PACKET_SIZE_MIN, - PING_PACKET_SIZE_MAX, - PING_PACKET_SIZE_DEFAULT, - PING_DEADLINE_MIN, - PING_DEADLINE_MAX, - PING_DEADLINE_DEFAULT, - PING_COUNT_MIN, - PING_COUNT_MAX, - PING_COUNT_DEFAULT, - PING_TIMEOUT_MIN, - PING_TIMEOUT_MAX, - PING_TIMEOUT_DEFAULT } from "../util.ts"; import { hostNameRegexPattern } from "../util-frontend"; import HiddenInput from "../components/HiddenInput.vue"; @@ -1188,14 +1176,6 @@ export default { return { minInterval: MIN_INTERVAL_SECOND, maxInterval: MAX_INTERVAL_SECOND, - ping_count_min: PING_COUNT_MIN, - ping_count_max: PING_COUNT_MAX, - packetSize_min: PING_PACKET_SIZE_MIN, - packetSize_max: PING_PACKET_SIZE_MAX, - ping_deadline_min: PING_DEADLINE_MIN, - ping_deadline_max: PING_DEADLINE_MAX, - ping_timeout_min: PING_TIMEOUT_MIN, - ping_timeout_max: PING_TIMEOUT_MAX, processing: false, monitor: { notificationIDList: {}, @@ -1628,11 +1608,11 @@ message HealthCheckResponse { this.monitor = { ...monitorDefaults, - ping_count: PING_COUNT_DEFAULT, + ping_count: 3, ping_numeric: true, - packetSize: PING_PACKET_SIZE_DEFAULT, - ping_deadline: PING_DEADLINE_DEFAULT, - ping_timeout: PING_TIMEOUT_DEFAULT, + packetSize: 56, + ping_deadline: 10, + ping_timeout: 2, }; if (this.$root.proxyList && !this.monitor.proxyId) { diff --git a/src/util.js b/src/util.js index 644914472..62ebba01c 100644 --- a/src/util.js +++ b/src/util.js @@ -55,15 +55,15 @@ exports.MIN_INTERVAL_SECOND = 20; exports.PING_PACKET_SIZE_MIN = 1; exports.PING_PACKET_SIZE_MAX = 65500; exports.PING_PACKET_SIZE_DEFAULT = 56; -exports.PING_DEADLINE_MIN = 0; +exports.PING_DEADLINE_MIN = 1; exports.PING_DEADLINE_MAX = 300; -exports.PING_DEADLINE_DEFAULT = 0; +exports.PING_DEADLINE_DEFAULT = 10; exports.PING_COUNT_MIN = 1; exports.PING_COUNT_MAX = 100; -exports.PING_COUNT_DEFAULT = 3; -exports.PING_TIMEOUT_MIN_TIMEOU = 0; +exports.PING_COUNT_DEFAULT = 1; +exports.PING_TIMEOUT_MIN = 1; exports.PING_TIMEOUT_MAX = 60; -exports.PING_TIMEOUT_DEFAULT = 0; +exports.PING_TIMEOUT_DEFAULT = 2; exports.CONSOLE_STYLE_Reset = "\x1b[0m"; exports.CONSOLE_STYLE_Bright = "\x1b[1m"; exports.CONSOLE_STYLE_Dim = "\x1b[2m"; From 7110c6d30ed75f49e7987358397af1da8699ac80 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Tue, 11 Mar 2025 11:55:27 +0100 Subject: [PATCH 13/17] added binding between ping model parameters and the new ping implementation --- server/model/monitor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 86f53f3b3..40ca4e384 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -635,7 +635,7 @@ class Monitor extends BeanModel { bean.status = UP; } else if (this.type === "ping") { - bean.ping = await ping(this.hostname, this.packetSize); + bean.ping = await ping(this.hostname, this.ping_count, "", this.ping_numeric, this.packetSize, this.ping_deadline, this.ping_timeout); bean.msg = ""; bean.status = UP; } else if (this.type === "push") { // Type: Push @@ -707,7 +707,7 @@ class Monitor extends BeanModel { bean.msg = res.data.response.servers[0].name; try { - bean.ping = await ping(this.hostname, this.packetSize); + bean.ping = await ping(this.hostname, PING_COUNT_DEFAULT, "", true, this.packetSize, PING_DEADLINE_DEFAULT, PING_TIMEOUT_DEFAULT); } catch (_) { } } else { throw new Error("Server not found on Steam"); From e8207fed97639304026411eff09d0630c060f822 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Tue, 11 Mar 2025 11:59:02 +0100 Subject: [PATCH 14/17] add ping to timeout field and alphabetically sort monitor types --- src/pages/EditMonitor.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 19d7c2a9e..abc96bdf7 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -595,8 +595,8 @@ <input id="retry-interval" v-model="monitor.retryInterval" type="number" class="form-control" required :min="minInterval" step="1"> </div> - <!-- Timeout: HTTP / Keyword / SNMP only --> - <div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' || monitor.type === 'snmp' || monitor.type === 'rabbitmq'" class="my-3"> + <!-- Timeout: HTTP / JSON query / Keyword / Ping / RabbitMQ / SNMP only --> + <div v-if="monitor.type === 'http' || monitor.type === 'json-query' || monitor.type === 'keyword' || monitor.type === 'ping' || monitor.type === 'rabbitmq' || monitor.type === 'snmp'" class="my-3"> <label for="timeout" class="form-label">{{ $t("Request Timeout") }} ({{ $t("timeoutAfter", [ monitor.timeout || clampTimeout(monitor.interval) ]) }})</label> <input id="timeout" v-model="monitor.timeout" type="number" class="form-control" required min="0" step="0.1"> </div> From a769a2d0e0556139e98d90685861b9be241c0b42 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Wed, 12 Mar 2025 12:15:37 +0100 Subject: [PATCH 15/17] removed ping_timeout field in favor of common timeout field --- .../2025-03-04-0000-ping-advanced-options.js | 3 - server/model/monitor.js | 28 +++-- server/server.js | 1 - src/lang/en.json | 3 +- src/pages/EditMonitor.vue | 119 ++++++++++++++---- 5 files changed, 118 insertions(+), 36 deletions(-) diff --git a/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js index 319fb18ef..58b86036a 100644 --- a/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js +++ b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js @@ -2,7 +2,6 @@ ALTER TABLE monitor ADD ping_count INTEGER default 1 not null; ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null; ALTER TABLE monitor ADD ping_deadline INTEGER default 10 not null; -ALTER TABLE monitor ADD ping_timeout INTEGER default 2 not null; */ exports.up = function (knex) { // Add new columns to table monitor @@ -11,7 +10,6 @@ exports.up = function (knex) { table.integer("ping_count").defaultTo(1).notNullable(); table.boolean("ping_numeric").defaultTo(true).notNullable(); table.integer("ping_deadline").defaultTo(10).notNullable(); - table.integer("ping_timeout").defaultTo(2).notNullable(); }); }; @@ -22,6 +20,5 @@ exports.down = function (knex) { table.dropColumn("ping_count"); table.dropColumn("ping_numeric"); table.dropColumn("ping_deadline"); - table.dropColumn("ping_timeout"); }); }; diff --git a/server/model/monitor.js b/server/model/monitor.js index 40ca4e384..5f9d08786 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -164,7 +164,6 @@ class Monitor extends BeanModel { ping_numeric: this.isPingNumeric(), ping_count: this.ping_count, ping_deadline: this.ping_deadline, - ping_timeout: this.ping_timeout, }; if (includeSensitiveData) { @@ -635,7 +634,7 @@ class Monitor extends BeanModel { bean.status = UP; } else if (this.type === "ping") { - bean.ping = await ping(this.hostname, this.ping_count, "", this.ping_numeric, this.packetSize, this.ping_deadline, this.ping_timeout); + bean.ping = await ping(this.hostname, this.ping_count, "", this.ping_numeric, this.packetSize, this.ping_deadline, this.timeout); bean.msg = ""; bean.status = UP; } else if (this.type === "push") { // Type: Push @@ -1523,16 +1522,25 @@ class Monitor extends BeanModel { throw new Error(`Packet size must be between ${PING_PACKET_SIZE_MIN} and ${PING_PACKET_SIZE_MAX} (default: ${PING_PACKET_SIZE_DEFAULT})`); } - if (this.ping_deadline && (this.ping_deadline < PING_DEADLINE_MIN || this.ping_deadline > PING_DEADLINE_MAX)) { - throw new Error(`Deadline must be between ${PING_DEADLINE_MIN} and ${PING_DEADLINE_MAX} seconds (default: ${PING_DEADLINE_DEFAULT})`); - } + if (this.type === "ping") { + // ping parameters validation + if (this.ping_deadline && (this.ping_deadline < PING_DEADLINE_MIN || this.ping_deadline > PING_DEADLINE_MAX)) { + throw new Error(`Deadline must be between ${PING_DEADLINE_MIN} and ${PING_DEADLINE_MAX} seconds (default: ${PING_DEADLINE_DEFAULT})`); + } - if (this.ping_count && (this.ping_count < PING_COUNT_MIN || this.ping_count > PING_COUNT_MAX)) { - throw new Error(`Echo requests count must be between ${PING_COUNT_MIN} and ${PING_COUNT_MAX} (default: ${PING_COUNT_DEFAULT})`); - } + if (this.ping_count && (this.ping_count < PING_COUNT_MIN || this.ping_count > PING_COUNT_MAX)) { + throw new Error(`Echo requests count must be between ${PING_COUNT_MIN} and ${PING_COUNT_MAX} (default: ${PING_COUNT_DEFAULT})`); + } - if (this.ping_timeout && (this.ping_timeout < PING_TIMEOUT_MIN || this.ping_timeout > PING_TIMEOUT_MAX)) { - throw new Error(`Timeout must be between ${PING_TIMEOUT_MIN} and ${PING_TIMEOUT_MAX} seconds (default: ${PING_TIMEOUT_DEFAULT})`); + if (this.timeout) { + const pingTimeout = Math.round(Number(this.timeout)); + + if (pingTimeout < PING_TIMEOUT_MIN || pingTimeout > PING_TIMEOUT_MAX) { + throw new Error(`Timeout must be between ${PING_TIMEOUT_MIN} and ${PING_TIMEOUT_MAX} seconds (default: ${PING_TIMEOUT_DEFAULT})`); + } + + this.timeout = pingTimeout; + } } } diff --git a/server/server.js b/server/server.js index 38b93acf9..41a730b68 100644 --- a/server/server.js +++ b/server/server.js @@ -879,7 +879,6 @@ let needSetup = false; bean.ping_numeric = monitor.ping_numeric; bean.ping_count = monitor.ping_count; bean.ping_deadline = monitor.ping_deadline; - bean.ping_timeout = monitor.ping_timeout; bean.validate(); diff --git a/src/lang/en.json b/src/lang/en.json index 28bca7d87..9a01491c4 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1059,5 +1059,6 @@ "pingDeadlineLabel": "Max Duration", "pingDeadlineDescription": "Total time in seconds before ping stops, regardless of packets sent", "pingTimeoutLabel": "Response Timeout", - "pingTimeoutDescription": "Maximum time in seconds to wait for each response" + "pingTimeoutDescription": "Maximum time in seconds to wait for each response", + "pingIntervalAdjusted": "Interval has been adjusted according to deadline, timeout and packet count" } diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index abc96bdf7..fdd87ff26 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -597,8 +597,11 @@ <!-- Timeout: HTTP / JSON query / Keyword / Ping / RabbitMQ / SNMP only --> <div v-if="monitor.type === 'http' || monitor.type === 'json-query' || monitor.type === 'keyword' || monitor.type === 'ping' || monitor.type === 'rabbitmq' || monitor.type === 'snmp'" class="my-3"> - <label for="timeout" class="form-label">{{ $t("Request Timeout") }} ({{ $t("timeoutAfter", [ monitor.timeout || clampTimeout(monitor.interval) ]) }})</label> - <input id="timeout" v-model="monitor.timeout" type="number" class="form-control" required min="0" step="0.1"> + <label for="timeout" class="form-label"> + {{ timeoutLabel }} ({{ monitor.type === 'ping' ? $t("timeoutAfter", [monitor.timeout]) : $t("timeoutAfter", [monitor.timeout || clampTimeout(monitor.interval)]) }}) + </label> + <input id="timeout" v-model="monitor.timeout" type="number" class="form-control" :min="timeoutMin" :max="timeoutMax" :step="timeoutStep" required> + <div class="form-text">{{ timeoutDescription }}</div> </div> <div class="my-3"> @@ -695,15 +698,6 @@ </div> </div> - <!-- Response Timeout --> - <div v-if="monitor.type === 'ping'" class="my-3"> - <label for="ping_timeout" class="form-label">{{ $t("pingTimeoutLabel") }}</label> - <input id="ping_timeout" v-model="monitor.ping_timeout" type="number" class="form-control" required min="1" max="60" step="1"> - <div class="form-text"> - {{ $t("pingTimeoutDescription") }} - </div> - </div> - <!-- HTTP / Keyword only --> <template v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' || monitor.type === 'grpc-keyword' "> <div class="my-3"> @@ -1200,6 +1194,29 @@ export default { }, computed: { + timeoutStep() { + return this.monitor.type === "ping" ? 1 : 0.1; + }, + + timeoutMin() { + return this.monitor.type === "ping" ? 1 : 0; + }, + + timeoutMax() { + return this.monitor.type === "ping" ? 60 : undefined; + }, + + timeoutLabel() { + return this.monitor.type === "ping" ? this.$t("pingTimeoutLabel") : this.$t("Request Timeout"); + }, + + timeoutDescription() { + if (this.monitor.type === "ping") { + return this.$t("pingTimeoutDescription"); + } + return ""; + }, + ipRegex() { // Allow to test with simple dns server with port (127.0.0.1:5300) @@ -1458,9 +1475,25 @@ message HealthCheckResponse { }, "monitor.timeout"(value, oldValue) { - // keep timeout within 80% range - if (value && value !== oldValue) { - this.monitor.timeout = this.clampTimeout(value); + if (this.monitor.type === "ping") { + this.finishUpdateInterval(); + } else { + // keep timeout within 80% range + if (value && value !== oldValue) { + this.monitor.timeout = this.clampTimeout(value); + } + } + }, + + "monitor.ping_count"() { + if (this.monitor.type === "ping") { + this.finishUpdateInterval(); + } + }, + + "monitor.ping_deadline"() { + if (this.monitor.type === "ping") { + this.finishUpdateInterval(); } }, @@ -1489,8 +1522,10 @@ message HealthCheckResponse { // Set a default timeout if the monitor type has changed or if it's a new monitor if (oldType || this.isAdd) { if (this.monitor.type === "snmp") { - // snmp is not expected to be executed via the internet => we can choose a lower default timeout + // snmp is not expected to be executed via the internet => we can choose a lower default timeout this.monitor.timeout = 5; + } else if (this.monitor.type === "ping") { + this.monitor.timeout = 2; } else { this.monitor.timeout = 48; } @@ -1612,7 +1647,6 @@ message HealthCheckResponse { ping_numeric: true, packetSize: 56, ping_deadline: 10, - ping_timeout: 2, }; if (this.$root.proxyList && !this.monitor.proxyId) { @@ -1675,7 +1709,12 @@ message HealthCheckResponse { } // Handling for monitors that are missing/zeroed timeout if (!this.monitor.timeout) { - this.monitor.timeout = ~~(this.monitor.interval * 8) / 10; + if (this.monitor.type === "ping") { + // set to default + this.monitor.timeout = 2; + } else { + this.monitor.timeout = ~~(this.monitor.interval * 8) / 10; + } } } else { this.$root.toastError(res.msg); @@ -1888,11 +1927,49 @@ message HealthCheckResponse { return Number.isFinite(clamped) ? clamped : maxTimeout; }, + calculatePingInterval() { + // If monitor.type is not "ping", simply return the configured interval + if (this.monitor.type !== "ping") { + return this.monitor.interval; + } + + // Calculate the maximum theoretical time needed if all ping requests time out + const theoreticalTotal = this.monitor.ping_count * this.monitor.timeout; + + // The deadline forces ping to terminate, so the effective limit + // is the smaller value between deadline and theoreticalTotal + const effectiveLimit = Math.min(this.monitor.ping_deadline, theoreticalTotal); + + // Add a 10% margin to the effective limit to ensure proper handling + const adjustedLimit = Math.ceil(effectiveLimit * 1.1); + + // If the calculated limit is less than the minimum allowed interval, + // use the minimum interval to ensure stability + if (adjustedLimit < this.minInterval) { + return this.minInterval; + } + + return adjustedLimit; + }, + finishUpdateInterval() { - // Update timeout if it is greater than the clamp timeout - let clampedValue = this.clampTimeout(this.monitor.interval); - if (this.monitor.timeout > clampedValue) { - this.monitor.timeout = clampedValue; + if (this.monitor.type === "ping") { + // Calculate the minimum required interval based on ping configuration + const calculatedPingInterval = this.calculatePingInterval(); + + // If the configured interval is too small, adjust it to the minimum required value + if (this.monitor.interval < calculatedPingInterval) { + this.monitor.interval = calculatedPingInterval; + + // Notify the user that the interval has been automatically adjusted + toast.info(this.$t("pingIntervalAdjusted")); + } + } else { + // Update timeout if it is greater than the clamp timeout + let clampedValue = this.clampTimeout(this.monitor.interval); + if (this.monitor.timeout > clampedValue) { + this.monitor.timeout = clampedValue; + } } }, From 59c379ade1b195648bfff963da56b681d32266dc Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Fri, 14 Mar 2025 15:11:06 +0100 Subject: [PATCH 16/17] clarify ping timeout labels and descriptions --- src/lang/en.json | 5 +++-- src/pages/EditMonitor.vue | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index 9a01491c4..4538d8728 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1058,7 +1058,8 @@ "pingNumericDescription": "If checked, IP addresses will be output instead of symbolic hostnames", "pingDeadlineLabel": "Max Duration", "pingDeadlineDescription": "Total time in seconds before ping stops, regardless of packets sent", - "pingTimeoutLabel": "Response Timeout", - "pingTimeoutDescription": "Maximum time in seconds to wait for each response", + "pingTimeoutLabel": "Per-Ping Timeout", + "pingTimeoutDescription": "applies to each individual ping packet sent", + "pingTimeoutHelp": "This is the maximum waiting time (in seconds) before considering a single ping packet lost", "pingIntervalAdjusted": "Interval has been adjusted according to deadline, timeout and packet count" } diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index fdd87ff26..30ce5459b 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -598,10 +598,11 @@ <!-- Timeout: HTTP / JSON query / Keyword / Ping / RabbitMQ / SNMP only --> <div v-if="monitor.type === 'http' || monitor.type === 'json-query' || monitor.type === 'keyword' || monitor.type === 'ping' || monitor.type === 'rabbitmq' || monitor.type === 'snmp'" class="my-3"> <label for="timeout" class="form-label"> - {{ timeoutLabel }} ({{ monitor.type === 'ping' ? $t("timeoutAfter", [monitor.timeout]) : $t("timeoutAfter", [monitor.timeout || clampTimeout(monitor.interval)]) }}) + {{ monitor.type === 'ping' ? $t("pingTimeoutLabel") : $t("Request Timeout") }} + ({{ monitor.type === 'ping' ? $t("pingTimeoutDescription") : $t("timeoutAfter", [monitor.timeout || clampTimeout(monitor.interval)]) }}) </label> <input id="timeout" v-model="monitor.timeout" type="number" class="form-control" :min="timeoutMin" :max="timeoutMax" :step="timeoutStep" required> - <div class="form-text">{{ timeoutDescription }}</div> + <div v-if="monitor.type === 'ping'" class="form-text">{{ $t("pingTimeoutHelp") }}</div> </div> <div class="my-3"> From ab8d6dda75b8a3bd7056c52cc3273199326f8592 Mon Sep 17 00:00:00 2001 From: filippolauria <filippo.lauria@iit.cnr.it> Date: Mon, 17 Mar 2025 16:15:36 +0100 Subject: [PATCH 17/17] remove deadline field and repurpose timeout semantics --- .../2025-03-04-0000-ping-advanced-options.js | 6 ++-- server/model/monitor.js | 30 ++++++++-------- server/server.js | 2 +- server/util-server.js | 12 +++---- src/lang/en.json | 11 +++--- src/pages/EditMonitor.vue | 35 +++++++++---------- src/util.js | 14 ++++---- src/util.ts | 16 ++++----- 8 files changed, 62 insertions(+), 64 deletions(-) diff --git a/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js index 58b86036a..e8bd03e53 100644 --- a/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js +++ b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js @@ -1,7 +1,7 @@ /* SQL: ALTER TABLE monitor ADD ping_count INTEGER default 1 not null; ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null; -ALTER TABLE monitor ADD ping_deadline INTEGER default 10 not null; +ALTER TABLE monitor ADD ping_per_request_timeout INTEGER default 2 not null; */ exports.up = function (knex) { // Add new columns to table monitor @@ -9,7 +9,7 @@ exports.up = function (knex) { .alterTable("monitor", function (table) { table.integer("ping_count").defaultTo(1).notNullable(); table.boolean("ping_numeric").defaultTo(true).notNullable(); - table.integer("ping_deadline").defaultTo(10).notNullable(); + table.integer("ping_per_request_timeout").defaultTo(2).notNullable(); }); }; @@ -19,6 +19,6 @@ exports.down = function (knex) { .alterTable("monitor", function (table) { table.dropColumn("ping_count"); table.dropColumn("ping_numeric"); - table.dropColumn("ping_deadline"); + table.dropColumn("ping_per_request_timeout"); }); }; diff --git a/server/model/monitor.js b/server/model/monitor.js index bb303cbec..b9cceaa87 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -4,9 +4,9 @@ const { Prometheus } = require("../prometheus"); const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, SQL_DATETIME_FORMAT, evaluateJsonQuery, PING_PACKET_SIZE_MIN, PING_PACKET_SIZE_MAX, PING_PACKET_SIZE_DEFAULT, - PING_DEADLINE_MIN, PING_DEADLINE_MAX, PING_DEADLINE_DEFAULT, + PING_GLOBAL_TIMEOUT_MIN, PING_GLOBAL_TIMEOUT_MAX, PING_GLOBAL_TIMEOUT_DEFAULT, PING_COUNT_MIN, PING_COUNT_MAX, PING_COUNT_DEFAULT, - PING_TIMEOUT_MIN, PING_TIMEOUT_MAX, PING_TIMEOUT_DEFAULT + PING_PER_REQUEST_TIMEOUT_MIN, PING_PER_REQUEST_TIMEOUT_MAX, PING_PER_REQUEST_TIMEOUT_DEFAULT } = require("../../src/util"); const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery, redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal @@ -163,7 +163,7 @@ class Monitor extends BeanModel { // ping advanced options ping_numeric: this.isPingNumeric(), ping_count: this.ping_count, - ping_deadline: this.ping_deadline, + ping_per_request_timeout: this.ping_per_request_timeout, }; if (includeSensitiveData) { @@ -634,7 +634,7 @@ class Monitor extends BeanModel { bean.status = UP; } else if (this.type === "ping") { - bean.ping = await ping(this.hostname, this.ping_count, "", this.ping_numeric, this.packetSize, this.ping_deadline, this.timeout); + bean.ping = await ping(this.hostname, this.ping_count, "", this.ping_numeric, this.packetSize, this.timeout, this.ping_per_request_timeout); bean.msg = ""; bean.status = UP; } else if (this.type === "push") { // Type: Push @@ -706,7 +706,7 @@ class Monitor extends BeanModel { bean.msg = res.data.response.servers[0].name; try { - bean.ping = await ping(this.hostname, PING_COUNT_DEFAULT, "", true, this.packetSize, PING_DEADLINE_DEFAULT, PING_TIMEOUT_DEFAULT); + bean.ping = await ping(this.hostname, PING_COUNT_DEFAULT, "", true, this.packetSize, PING_GLOBAL_TIMEOUT_DEFAULT, PING_PER_REQUEST_TIMEOUT_DEFAULT); } catch (_) { } } else { throw new Error("Server not found on Steam"); @@ -1518,14 +1518,14 @@ class Monitor extends BeanModel { throw new Error(`Interval cannot be less than ${MIN_INTERVAL_SECOND} seconds`); } - if (this.packetSize && (this.packetSize < PING_PACKET_SIZE_MIN || this.packetSize > PING_PACKET_SIZE_MAX)) { - throw new Error(`Packet size must be between ${PING_PACKET_SIZE_MIN} and ${PING_PACKET_SIZE_MAX} (default: ${PING_PACKET_SIZE_DEFAULT})`); - } - if (this.type === "ping") { // ping parameters validation - if (this.ping_deadline && (this.ping_deadline < PING_DEADLINE_MIN || this.ping_deadline > PING_DEADLINE_MAX)) { - throw new Error(`Deadline must be between ${PING_DEADLINE_MIN} and ${PING_DEADLINE_MAX} seconds (default: ${PING_DEADLINE_DEFAULT})`); + if (this.packetSize && (this.packetSize < PING_PACKET_SIZE_MIN || this.packetSize > PING_PACKET_SIZE_MAX)) { + throw new Error(`Packet size must be between ${PING_PACKET_SIZE_MIN} and ${PING_PACKET_SIZE_MAX} (default: ${PING_PACKET_SIZE_DEFAULT})`); + } + + if (this.ping_per_request_timeout && (this.ping_per_request_timeout < PING_PER_REQUEST_TIMEOUT_MIN || this.ping_per_request_timeout > PING_PER_REQUEST_TIMEOUT_MAX)) { + throw new Error(`Per-ping timeout must be between ${PING_PER_REQUEST_TIMEOUT_MIN} and ${PING_PER_REQUEST_TIMEOUT_MAX} seconds (default: ${PING_PER_REQUEST_TIMEOUT_DEFAULT})`); } if (this.ping_count && (this.ping_count < PING_COUNT_MIN || this.ping_count > PING_COUNT_MAX)) { @@ -1533,13 +1533,13 @@ class Monitor extends BeanModel { } if (this.timeout) { - const pingTimeout = Math.round(Number(this.timeout)); + const pingGlobalTimeout = Math.round(Number(this.timeout)); - if (pingTimeout < PING_TIMEOUT_MIN || pingTimeout > PING_TIMEOUT_MAX) { - throw new Error(`Timeout must be between ${PING_TIMEOUT_MIN} and ${PING_TIMEOUT_MAX} seconds (default: ${PING_TIMEOUT_DEFAULT})`); + if (pingGlobalTimeout < this.ping_per_request_timeout || pingGlobalTimeout < PING_GLOBAL_TIMEOUT_MIN || pingGlobalTimeout > PING_GLOBAL_TIMEOUT_MAX) { + throw new Error(`Timeout must be between ${PING_GLOBAL_TIMEOUT_MIN} and ${PING_GLOBAL_TIMEOUT_MAX} seconds (default: ${PING_GLOBAL_TIMEOUT_DEFAULT})`); } - this.timeout = pingTimeout; + this.timeout = pingGlobalTimeout; } } } diff --git a/server/server.js b/server/server.js index 41a730b68..e1a877fa9 100644 --- a/server/server.js +++ b/server/server.js @@ -878,7 +878,7 @@ let needSetup = false; // ping advanced options bean.ping_numeric = monitor.ping_numeric; bean.ping_count = monitor.ping_count; - bean.ping_deadline = monitor.ping_deadline; + bean.ping_per_request_timeout = monitor.ping_per_request_timeout; bean.validate(); diff --git a/server/util-server.js b/server/util-server.js index 5efe9116a..08df728ed 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -3,8 +3,8 @@ const ping = require("@louislam/ping"); const { R } = require("redbean-node"); const { log, genSecret, badgeConstants, - PING_PACKET_SIZE_DEFAULT, PING_DEADLINE_DEFAULT, - PING_COUNT_DEFAULT, PING_TIMEOUT_DEFAULT + PING_PACKET_SIZE_DEFAULT, PING_GLOBAL_TIMEOUT_DEFAULT, + PING_COUNT_DEFAULT, PING_PER_REQUEST_TIMEOUT_DEFAULT } = require("../src/util"); const passwordHash = require("./password-hash"); const { Resolver } = require("dns"); @@ -137,8 +137,8 @@ exports.ping = async ( sourceAddr = "", numeric = true, size = PING_PACKET_SIZE_DEFAULT, - deadline = PING_DEADLINE_DEFAULT, - timeout = PING_TIMEOUT_DEFAULT, + deadline = PING_GLOBAL_TIMEOUT_DEFAULT, + timeout = PING_PER_REQUEST_TIMEOUT_DEFAULT, ) => { try { return await exports.pingAsync(destAddr, false, count, sourceAddr, numeric, size, deadline, timeout); @@ -174,8 +174,8 @@ exports.pingAsync = function ( sourceAddr = "", numeric = true, size = PING_PACKET_SIZE_DEFAULT, - deadline = PING_DEADLINE_DEFAULT, - timeout = PING_TIMEOUT_DEFAULT, + deadline = PING_GLOBAL_TIMEOUT_DEFAULT, + timeout = PING_PER_REQUEST_TIMEOUT_DEFAULT, ) { return new Promise((resolve, reject) => { ping.promise.probe(destAddr, { diff --git a/src/lang/en.json b/src/lang/en.json index ce21769e6..2000d4e99 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1059,12 +1059,11 @@ "pingCountDescription": "Number of packets to send before stopping", "pingNumericLabel": "Numeric Output", "pingNumericDescription": "If checked, IP addresses will be output instead of symbolic hostnames", - "pingDeadlineLabel": "Max Duration", - "pingDeadlineDescription": "Total time in seconds before ping stops, regardless of packets sent", - "pingTimeoutLabel": "Per-Ping Timeout", - "pingTimeoutDescription": "applies to each individual ping packet sent", - "pingTimeoutHelp": "This is the maximum waiting time (in seconds) before considering a single ping packet lost", - "pingIntervalAdjusted": "Interval has been adjusted according to deadline, timeout and packet count", + "pingGlobalTimeoutLabel": "Global Timeout", + "pingGlobalTimeoutDescription": "Total time in seconds before ping stops, regardless of packets sent", + "pingPerRequestTimeoutLabel": "Per-Ping Timeout", + "pingPerRequestTimeoutDescription": "This is the maximum waiting time (in seconds) before considering a single ping packet lost", + "pingIntervalAdjustedInfo": "Interval adjusted based on packet count, global timeout and per-ping timeout", "YZJ Webhook URL": "YZJ Webhook URL", "YZJ Robot Token": "YZJ Robot token", "Plain Text": "Plain Text", diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 30ce5459b..63225ee6f 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -598,11 +598,11 @@ <!-- Timeout: HTTP / JSON query / Keyword / Ping / RabbitMQ / SNMP only --> <div v-if="monitor.type === 'http' || monitor.type === 'json-query' || monitor.type === 'keyword' || monitor.type === 'ping' || monitor.type === 'rabbitmq' || monitor.type === 'snmp'" class="my-3"> <label for="timeout" class="form-label"> - {{ monitor.type === 'ping' ? $t("pingTimeoutLabel") : $t("Request Timeout") }} - ({{ monitor.type === 'ping' ? $t("pingTimeoutDescription") : $t("timeoutAfter", [monitor.timeout || clampTimeout(monitor.interval)]) }}) + {{ monitor.type === 'ping' ? $t("pingGlobalTimeoutLabel") : $t("Request Timeout") }} + <span v-if="monitor.type !== 'ping'">({{ $t("timeoutAfter", [monitor.timeout || clampTimeout(monitor.interval)]) }})</span> </label> <input id="timeout" v-model="monitor.timeout" type="number" class="form-control" :min="timeoutMin" :max="timeoutMax" :step="timeoutStep" required> - <div v-if="monitor.type === 'ping'" class="form-text">{{ $t("pingTimeoutHelp") }}</div> + <div v-if="monitor.type === 'ping'" class="form-text">{{ $t("pingGlobalTimeoutDescription") }}</div> </div> <div class="my-3"> @@ -690,12 +690,12 @@ <input id="packet-size" v-model="monitor.packetSize" type="number" class="form-control" required min="1" :max="65500" step="1"> </div> - <!-- Max Duration / Deadline --> + <!-- per-request timeout --> <div v-if="monitor.type === 'ping'" class="my-3"> - <label for="ping_deadline" class="form-label">{{ $t("pingDeadlineLabel") }}</label> - <input id="ping_deadline" v-model="monitor.ping_deadline" type="number" class="form-control" required min="0" max="300" step="1"> + <label for="ping_per_request_timeout" class="form-label">{{ $t("pingPerRequestTimeoutLabel") }}</label> + <input id="ping_per_request_timeout" v-model="monitor.ping_per_request_timeout" type="number" class="form-control" required min="0" max="300" step="1"> <div class="form-text"> - {{ $t("pingDeadlineDescription") }} + {{ $t("pingPerRequestTimeoutDescription") }} </div> </div> @@ -1492,7 +1492,7 @@ message HealthCheckResponse { } }, - "monitor.ping_deadline"() { + "monitor.ping_per_request_timeout"() { if (this.monitor.type === "ping") { this.finishUpdateInterval(); } @@ -1526,7 +1526,7 @@ message HealthCheckResponse { // snmp is not expected to be executed via the internet => we can choose a lower default timeout this.monitor.timeout = 5; } else if (this.monitor.type === "ping") { - this.monitor.timeout = 2; + this.monitor.timeout = 10; } else { this.monitor.timeout = 48; } @@ -1647,7 +1647,7 @@ message HealthCheckResponse { ping_count: 3, ping_numeric: true, packetSize: 56, - ping_deadline: 10, + ping_per_request_timeout: 2, }; if (this.$root.proxyList && !this.monitor.proxyId) { @@ -1712,7 +1712,7 @@ message HealthCheckResponse { if (!this.monitor.timeout) { if (this.monitor.type === "ping") { // set to default - this.monitor.timeout = 2; + this.monitor.timeout = 10; } else { this.monitor.timeout = ~~(this.monitor.interval * 8) / 10; } @@ -1934,18 +1934,17 @@ message HealthCheckResponse { return this.monitor.interval; } - // Calculate the maximum theoretical time needed if all ping requests time out - const theoreticalTotal = this.monitor.ping_count * this.monitor.timeout; + // Calculate the maximum theoretical time needed if every ping request times out + const theoreticalTotal = this.monitor.ping_count * this.monitor.ping_per_request_timeout; - // The deadline forces ping to terminate, so the effective limit + // The global timeout (aka deadline) forces ping to terminate, so the effective limit // is the smaller value between deadline and theoreticalTotal - const effectiveLimit = Math.min(this.monitor.ping_deadline, theoreticalTotal); + const effectiveLimit = Math.min(this.monitor.timeout, theoreticalTotal); // Add a 10% margin to the effective limit to ensure proper handling const adjustedLimit = Math.ceil(effectiveLimit * 1.1); - // If the calculated limit is less than the minimum allowed interval, - // use the minimum interval to ensure stability + // If the calculated limit is lower than the minimum allowed interval, use the minimum interval if (adjustedLimit < this.minInterval) { return this.minInterval; } @@ -1963,7 +1962,7 @@ message HealthCheckResponse { this.monitor.interval = calculatedPingInterval; // Notify the user that the interval has been automatically adjusted - toast.info(this.$t("pingIntervalAdjusted")); + toast.info(this.$t("pingIntervalAdjustedInfo")); } } else { // Update timeout if it is greater than the clamp timeout diff --git a/src/util.js b/src/util.js index 62ebba01c..f094cdd63 100644 --- a/src/util.js +++ b/src/util.js @@ -32,7 +32,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); -exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.PING_TIMEOUT_DEFAULT = exports.PING_TIMEOUT_MAX = exports.PING_TIMEOUT_MIN = exports.PING_COUNT_DEFAULT = exports.PING_COUNT_MAX = exports.PING_COUNT_MIN = exports.PING_DEADLINE_DEFAULT = exports.PING_DEADLINE_MAX = exports.PING_DEADLINE_MIN = exports.PING_PACKET_SIZE_DEFAULT = exports.PING_PACKET_SIZE_MAX = exports.PING_PACKET_SIZE_MIN = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0; +exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.PING_PER_REQUEST_TIMEOUT_DEFAULT = exports.PING_PER_REQUEST_TIMEOUT_MAX = exports.PING_PER_REQUEST_TIMEOUT_MIN = exports.PING_COUNT_DEFAULT = exports.PING_COUNT_MAX = exports.PING_COUNT_MIN = exports.PING_GLOBAL_TIMEOUT_DEFAULT = exports.PING_GLOBAL_TIMEOUT_MAX = exports.PING_GLOBAL_TIMEOUT_MIN = exports.PING_PACKET_SIZE_DEFAULT = exports.PING_PACKET_SIZE_MAX = exports.PING_PACKET_SIZE_MIN = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0; exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = void 0; const dayjs_1 = __importDefault(require("dayjs")); const jsonata = __importStar(require("jsonata")); @@ -55,15 +55,15 @@ exports.MIN_INTERVAL_SECOND = 20; exports.PING_PACKET_SIZE_MIN = 1; exports.PING_PACKET_SIZE_MAX = 65500; exports.PING_PACKET_SIZE_DEFAULT = 56; -exports.PING_DEADLINE_MIN = 1; -exports.PING_DEADLINE_MAX = 300; -exports.PING_DEADLINE_DEFAULT = 10; +exports.PING_GLOBAL_TIMEOUT_MIN = 1; +exports.PING_GLOBAL_TIMEOUT_MAX = 300; +exports.PING_GLOBAL_TIMEOUT_DEFAULT = 10; exports.PING_COUNT_MIN = 1; exports.PING_COUNT_MAX = 100; exports.PING_COUNT_DEFAULT = 1; -exports.PING_TIMEOUT_MIN = 1; -exports.PING_TIMEOUT_MAX = 60; -exports.PING_TIMEOUT_DEFAULT = 2; +exports.PING_PER_REQUEST_TIMEOUT_MIN = 1; +exports.PING_PER_REQUEST_TIMEOUT_MAX = 60; +exports.PING_PER_REQUEST_TIMEOUT_DEFAULT = 2; exports.CONSOLE_STYLE_Reset = "\x1b[0m"; exports.CONSOLE_STYLE_Bright = "\x1b[1m"; exports.CONSOLE_STYLE_Dim = "\x1b[2m"; diff --git a/src/util.ts b/src/util.ts index 4d215e94e..277d860f4 100644 --- a/src/util.ts +++ b/src/util.ts @@ -44,20 +44,20 @@ export const PING_PACKET_SIZE_MIN = 1; export const PING_PACKET_SIZE_MAX = 65500; export const PING_PACKET_SIZE_DEFAULT = 56; -// Deadline limits (in seconds) -export const PING_DEADLINE_MIN = 1; -export const PING_DEADLINE_MAX = 300; -export const PING_DEADLINE_DEFAULT = 10; +// Global timeout (aka deadline) limits in seconds +export const PING_GLOBAL_TIMEOUT_MIN = 1; +export const PING_GLOBAL_TIMEOUT_MAX = 300; +export const PING_GLOBAL_TIMEOUT_DEFAULT = 10; // Ping count limits export const PING_COUNT_MIN = 1; export const PING_COUNT_MAX = 100; export const PING_COUNT_DEFAULT = 1; -// Timeout limits (in seconds) -export const PING_TIMEOUT_MIN = 1; -export const PING_TIMEOUT_MAX = 60; -export const PING_TIMEOUT_DEFAULT = 2; +// per-request timeout (aka timeout) limits in seconds +export const PING_PER_REQUEST_TIMEOUT_MIN = 1; +export const PING_PER_REQUEST_TIMEOUT_MAX = 60; +export const PING_PER_REQUEST_TIMEOUT_DEFAULT = 2; // Console colors // https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color