229 lines
6.4 KiB
JavaScript
Executable File
229 lines
6.4 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
"use strict";
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
function findModuleDirectory(root, moduleName, depth = 0) {
|
|
if (depth > 5) {
|
|
return "";
|
|
}
|
|
let entries;
|
|
try {
|
|
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
} catch (_error) {
|
|
return "";
|
|
}
|
|
|
|
for (const entry of entries) {
|
|
if (!entry.isDirectory()) {
|
|
continue;
|
|
}
|
|
const fullPath = path.join(root, entry.name);
|
|
if (entry.name === moduleName && fs.existsSync(path.join(fullPath, "package.json"))) {
|
|
return fullPath;
|
|
}
|
|
}
|
|
|
|
for (const entry of entries) {
|
|
if (!entry.isDirectory()) {
|
|
continue;
|
|
}
|
|
const fullPath = path.join(root, entry.name);
|
|
const found = findModuleDirectory(fullPath, moduleName, depth + 1);
|
|
if (found) {
|
|
return found;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
function loadDatabaseModule() {
|
|
const candidates = [
|
|
"better-sqlite3",
|
|
"/app/node_modules/better-sqlite3",
|
|
"/app/server/node_modules/better-sqlite3",
|
|
"/app/src/node_modules/better-sqlite3"
|
|
];
|
|
|
|
for (const root of ["/app/node_modules", "/app/server/node_modules", "/app/src/node_modules"]) {
|
|
const found = findModuleDirectory(root, "better-sqlite3");
|
|
if (found) {
|
|
candidates.push(found);
|
|
}
|
|
}
|
|
|
|
for (const moduleName of candidates) {
|
|
try {
|
|
return require(moduleName);
|
|
} catch (_error) {
|
|
// Try the next location used by the upstream Uptime Kuma image.
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function nowSql() {
|
|
return new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
}
|
|
|
|
function defaultForColumn(column, monitor, userId) {
|
|
const accepted = monitor.accepted_statuscodes || ["200-399"];
|
|
const defaults = {
|
|
name: monitor.name,
|
|
type: monitor.type,
|
|
active: 1,
|
|
user_id: userId,
|
|
interval: monitor.interval || 60,
|
|
retry_interval: monitor.retry_interval || 60,
|
|
resend_interval: monitor.resend_interval || 0,
|
|
maxretries: monitor.maxretries || 3,
|
|
accepted_statuscodes: JSON.stringify(accepted),
|
|
url: monitor.url || "",
|
|
method: monitor.method || "GET",
|
|
hostname: monitor.hostname || "",
|
|
port: monitor.port || null,
|
|
dns_resolve_type: monitor.dns_resolve_type || "A",
|
|
dns_resolve_server: monitor.dns_resolve_server || "1.1.1.1",
|
|
upside_down: 0,
|
|
weight: monitor.weight || 2000,
|
|
maxredirects: monitor.maxredirects || 10,
|
|
timeout: monitor.timeout || 48,
|
|
expiryNotification: 0,
|
|
ignoreTls: monitor.ignoreTls ? 1 : 0,
|
|
created_date: nowSql(),
|
|
modified_date: nowSql(),
|
|
body: "",
|
|
headers: "",
|
|
basic_auth_user: "",
|
|
basic_auth_pass: "",
|
|
authMethod: "",
|
|
mqtt_success_message: "",
|
|
database_connection_string: "",
|
|
database_query: "",
|
|
packet_size: 56
|
|
};
|
|
|
|
return Object.prototype.hasOwnProperty.call(defaults, column.name)
|
|
? defaults[column.name]
|
|
: "";
|
|
}
|
|
|
|
function monitorValues(monitor, columns, userId, includeCreatedDate) {
|
|
const values = {};
|
|
const supported = new Set(columns.map((column) => column.name));
|
|
|
|
const requested = {
|
|
name: monitor.name,
|
|
type: monitor.type,
|
|
active: 1,
|
|
user_id: userId,
|
|
interval: monitor.interval || 60,
|
|
retry_interval: monitor.retry_interval || 60,
|
|
resend_interval: monitor.resend_interval || 0,
|
|
maxretries: monitor.maxretries || 3,
|
|
accepted_statuscodes: JSON.stringify(monitor.accepted_statuscodes || ["200-399"]),
|
|
method: monitor.method || "GET",
|
|
url: monitor.url || "",
|
|
hostname: monitor.hostname || "",
|
|
port: monitor.port || null,
|
|
dns_resolve_type: monitor.dns_resolve_type || "A",
|
|
dns_resolve_server: monitor.dns_resolve_server || "1.1.1.1",
|
|
maxredirects: monitor.maxredirects || 10,
|
|
timeout: monitor.timeout || 48,
|
|
ignoreTls: monitor.ignoreTls ? 1 : 0,
|
|
modified_date: nowSql()
|
|
};
|
|
|
|
if (includeCreatedDate) {
|
|
requested.created_date = nowSql();
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(requested)) {
|
|
if (supported.has(key)) {
|
|
values[key] = value;
|
|
}
|
|
}
|
|
|
|
for (const column of columns) {
|
|
if (column.pk || Object.prototype.hasOwnProperty.call(values, column.name)) {
|
|
continue;
|
|
}
|
|
if (column.notnull && column.dflt_value === null) {
|
|
values[column.name] = defaultForColumn(column, monitor, userId);
|
|
}
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
function upsertMonitor(database, monitor, columns, userId) {
|
|
const existing = database
|
|
.prepare("select id from monitor where user_id = ? and name = ? limit 1")
|
|
.get(userId, monitor.name);
|
|
|
|
if (existing) {
|
|
const values = monitorValues(monitor, columns, userId, false);
|
|
delete values.name;
|
|
delete values.user_id;
|
|
const assignments = Object.keys(values).map((key) => `"${key}" = @${key}`);
|
|
database
|
|
.prepare(`update monitor set ${assignments.join(", ")} where id = @id`)
|
|
.run({ ...values, id: existing.id });
|
|
console.log(`updated ${monitor.name}`);
|
|
return;
|
|
}
|
|
|
|
const values = monitorValues(monitor, columns, userId, true);
|
|
const keys = Object.keys(values);
|
|
database
|
|
.prepare(
|
|
`insert into monitor (${keys.map((key) => `"${key}"`).join(", ")}) values (${keys
|
|
.map((key) => `@${key}`)
|
|
.join(", ")})`
|
|
)
|
|
.run(values);
|
|
console.log(`created ${monitor.name}`);
|
|
}
|
|
|
|
function main() {
|
|
const monitorFile = process.argv[2] || "/tmp/homelab-kuma-monitors.json";
|
|
const databasePath = process.argv[3] || "/app/data/kuma.db";
|
|
const monitors = JSON.parse(fs.readFileSync(monitorFile, "utf8"));
|
|
const Database = loadDatabaseModule();
|
|
if (!Database) {
|
|
console.log("Could not load better-sqlite3 from the Uptime Kuma container; skipping monitor seed");
|
|
return;
|
|
}
|
|
const database = new Database(databasePath);
|
|
|
|
const userTable = database
|
|
.prepare("select name from sqlite_master where type = 'table' and name = 'user'")
|
|
.get();
|
|
if (!userTable) {
|
|
console.log("Uptime Kuma user table is missing; skipping monitor seed");
|
|
return;
|
|
}
|
|
|
|
const user = database.prepare("select id from user order by id limit 1").get();
|
|
if (!user) {
|
|
console.log("Uptime Kuma initial setup has not been completed; skipping monitor seed");
|
|
return;
|
|
}
|
|
|
|
const columns = database.prepare("pragma table_info(monitor)").all();
|
|
if (!columns.length) {
|
|
throw new Error("Uptime Kuma monitor table is missing");
|
|
}
|
|
|
|
const transaction = database.transaction(() => {
|
|
for (const monitor of monitors) {
|
|
upsertMonitor(database, monitor, columns, user.id);
|
|
}
|
|
});
|
|
transaction();
|
|
}
|
|
|
|
main();
|