mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-09-07 09:51:57 +00:00
![Matthew Nickson](/assets/img/avatar_default.png)
* Added JSDoc to eslint rules Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com> * Fixed JSDoc eslint errors Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com> * Update the check-linters workflow to Node.js 20 --------- Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com> Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
96 lines
3.8 KiB
JavaScript
96 lines
3.8 KiB
JavaScript
const { MonitorType } = require("./monitor-type");
|
|
const { UP, log } = require("../../src/util");
|
|
const exec = require("child_process").exec;
|
|
|
|
/**
|
|
* A TailscalePing class extends the MonitorType.
|
|
* It runs Tailscale ping to monitor the status of a specific node.
|
|
*/
|
|
class TailscalePing extends MonitorType {
|
|
|
|
name = "tailscale-ping";
|
|
|
|
/**
|
|
* Checks the ping status of the URL associated with the monitor.
|
|
* It then parses the Tailscale ping command output to update the heatrbeat.
|
|
* @param {object} monitor The monitor object associated with the check.
|
|
* @param {object} heartbeat The heartbeat object to update.
|
|
* @returns {Promise<void>}
|
|
* @throws Will throw an error if checking Tailscale ping encounters any error
|
|
*/
|
|
async check(monitor, heartbeat) {
|
|
try {
|
|
let tailscaleOutput = await this.runTailscalePing(monitor.hostname, monitor.interval);
|
|
this.parseTailscaleOutput(tailscaleOutput, heartbeat);
|
|
} catch (err) {
|
|
log.debug("Tailscale", err);
|
|
// trigger log function somewhere to display a notification or alert to the user (but how?)
|
|
throw new Error(`Error checking Tailscale ping: ${err}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Runs the Tailscale ping command to the given URL.
|
|
* @param {string} hostname The hostname to ping.
|
|
* @param {number} interval Interval to send ping
|
|
* @returns {Promise<string>} A Promise that resolves to the output of the Tailscale ping command
|
|
* @throws Will throw an error if the command execution encounters any error.
|
|
*/
|
|
async runTailscalePing(hostname, interval) {
|
|
let cmd = `tailscale ping ${hostname}`;
|
|
|
|
log.debug("Tailscale", cmd);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
let timeout = interval * 1000 * 0.8;
|
|
exec(cmd, { timeout: timeout }, (error, stdout, stderr) => {
|
|
// we may need to handle more cases if tailscale reports an error that isn't necessarily an error (such as not-logged in or DERP health-related issues)
|
|
if (error) {
|
|
reject(`Execution error: ${error.message}`);
|
|
return;
|
|
}
|
|
if (stderr) {
|
|
reject(`Error in output: ${stderr}`);
|
|
return;
|
|
}
|
|
|
|
resolve(stdout);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Parses the output of the Tailscale ping command to update the heartbeat.
|
|
* @param {string} tailscaleOutput The output of the Tailscale ping command.
|
|
* @param {object} heartbeat The heartbeat object to update.
|
|
* @returns {void}
|
|
* @throws Will throw an eror if the output contains any unexpected string.
|
|
*/
|
|
parseTailscaleOutput(tailscaleOutput, heartbeat) {
|
|
let lines = tailscaleOutput.split("\n");
|
|
|
|
for (let line of lines) {
|
|
if (line.includes("pong from")) {
|
|
heartbeat.status = UP;
|
|
let time = line.split(" in ")[1].split(" ")[0];
|
|
heartbeat.ping = parseInt(time);
|
|
heartbeat.msg = line;
|
|
break;
|
|
} else if (line.includes("timed out")) {
|
|
throw new Error(`Ping timed out: "${line}"`);
|
|
// Immediately throws upon "timed out" message, the server is expected to re-call the check function
|
|
} else if (line.includes("no matching peer")) {
|
|
throw new Error(`Nonexistant or inaccessible due to ACLs: "${line}"`);
|
|
} else if (line.includes("is local Tailscale IP")) {
|
|
throw new Error(`Tailscale only works if used on other machines: "${line}"`);
|
|
} else if (line !== "") {
|
|
throw new Error(`Unexpected output: "${line}"`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
TailscalePing,
|
|
};
|