Files
MikrotikManager/backend/scripts/acceptance/external-jobs-availability.mjs
T

35 lines
3.4 KiB
JavaScript

import assert from 'node:assert/strict';
import fs from 'node:fs';
import { createHash } from 'node:crypto';
const { pool } = await import('/app/backend/dist/db/index.js');
const { MikrotikClient } = await import('/app/backend/dist/services/mikrotik.js');
const { getAcmeSettingsPublic } = await import('/app/backend/dist/services/certificates-service.js');
const rows = (await pool.query("SELECT * FROM servers WHERE host IN ('194.226.121.150','104.165.244.7') ORDER BY host")).rows;
assert.equal(rows.length, 2); assert(rows.every(s => s.enabled && s.port === 80 && !s.use_ssl));
const report = { date: '2026-10-14', block: '12.5.243', scope: 'Read-only availability, not container lifecycle or ACME issuance', hosts: [], requests: [], routerosWrites: 0, databaseWrites: 0, dnsWrites: 0, passwordChanges: 0 };
async function read(client, host, endpoint) {
try { const result = await client.get(endpoint, 8000); report.requests.push({ host, path: endpoint, status: 200 }); return result; }
catch (e) { report.requests.push({ host, path: endpoint, status: e.statusCode ?? null, errorName: e.name, errorBodySha256: e.body ? createHash('sha256').update(e.body).digest('hex') : null }); return undefined; }
}
try {
for (const server of rows) {
const client = new MikrotikClient({ host: server.host, port: 80, useSsl: false, verifySsl: false, username: server.username, password: server.password });
const packages = await read(client, server.host, '/system/package');
const resource = await read(client, server.host, '/system/resource');
const mode = await read(client, server.host, '/system/device-mode');
const disks = await read(client, server.host, '/disk');
const containers = await read(client, server.host, '/container');
const m = Array.isArray(mode) ? mode[0] : mode;
report.hosts.push({ host: server.host, packages: Array.isArray(packages) ? packages.map(p => ({ name: p.name, version: p.version, disabled: p.disabled })) : null, resource: resource ? { version: resource.version, architecture: resource['architecture-name'], boardName: resource['board-name'], freeHddSpace: resource['free-hdd-space'], totalHddSpace: resource['total-hdd-space'], freeMemory: resource['free-memory'] } : null, deviceMode: m ? { mode: m.mode ?? null, container: m.container ?? null, flagged: m.flagged ?? null } : null, disks: Array.isArray(disks) ? disks.length : null, containers: Array.isArray(containers) ? { count: containers.length, statuses: containers.map(c => c.status ?? null) } : null });
}
const acme = await getAcmeSettingsPublic();
report.acme = { tokenConfigured: acme.tokenConfigured, defaultZoneConfigured: Boolean(acme.defaultZoneId), directoryHost: null, directoryStatus: null };
const directory = new URL(acme.directoryUrl);
assert(!directory.username && !directory.password);
report.acme.directoryHost = directory.hostname;
if (directory.protocol === 'https:' && ['acme-v02.api.letsencrypt.org','acme-staging-v02.api.letsencrypt.org'].includes(directory.hostname) && directory.pathname === '/directory') {
const r = await fetch(directory, { signal: AbortSignal.timeout(8000) }); report.acme.directoryStatus = r.status;
if (r.ok) { const data = await r.json(); report.acme.directoryKeys = Object.keys(data).sort(); }
}
} finally { await pool.end(); fs.writeFileSync('/checks/external-jobs243-availability.json', JSON.stringify(report, null, 2) + '\n'); console.log(JSON.stringify(report)); }