v0.3.2
This commit is contained in:
parent
54d14fad18
commit
a35c064aeb
|
|
@ -33,7 +33,7 @@ MVP - Minimum Viable Product Task List
|
||||||
- [x] Create SDL Worker Install to $SDL_HOME
|
- [x] Create SDL Worker Install to $SDL_HOME
|
||||||
- [x] SDL Install Script
|
- [x] SDL Install Script
|
||||||
- [ ] Create SDL Worker Auto Update Process
|
- [ ] Create SDL Worker Auto Update Process
|
||||||
- [ ] Create Worker Join Process
|
- [x] Create Worker Join Process
|
||||||
- [ ] Create Worker Telementry Process
|
- [ ] Create Worker Telementry Process
|
||||||
- [ ] Data Storage Organizational Structure
|
- [ ] Data Storage Organizational Structure
|
||||||
- [ ] MinIO S3 Storage Server
|
- [ ] MinIO S3 Storage Server
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const config = load_config();
|
const config = load_config();
|
||||||
|
|
||||||
log(`Loaded module: ${module}`);
|
log(`Loaded module: ${module}`);
|
||||||
|
|
@ -343,6 +344,32 @@ function startSDLStatusPub() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function publishStatus(client, topic) {
|
function publishStatus(client, topic) {
|
||||||
|
//get ip addr
|
||||||
|
const interfaces = os.networkInterfaces();
|
||||||
|
let ip_addr = null;
|
||||||
|
|
||||||
|
for (const [iface, addrs] of Object.entries(interfaces)) {
|
||||||
|
for (const addr of addrs) {
|
||||||
|
// --- FILTERS ---
|
||||||
|
|
||||||
|
// IPv4 only
|
||||||
|
if (addr.family !== 'IPv4') continue;
|
||||||
|
|
||||||
|
// Skip loopback
|
||||||
|
if (addr.internal === true) continue;
|
||||||
|
|
||||||
|
// Skip /32 networks (no broadcast: e.g. Tailscale)
|
||||||
|
const cidr = Number(addr.cidr?.split('/')[1]);
|
||||||
|
if (!Number.isInteger(cidr) || cidr >= 32) continue;
|
||||||
|
|
||||||
|
// Compute broadcast address
|
||||||
|
const broadcastAddr = computeBroadcast(addr.address, addr.netmask);
|
||||||
|
if (!broadcastAddr) continue;
|
||||||
|
|
||||||
|
ip_addr = addr.address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const status = {
|
const status = {
|
||||||
ts: new Date().toISOString(),
|
ts: new Date().toISOString(),
|
||||||
sdl_id: config.identity.sdl_id,
|
sdl_id: config.identity.sdl_id,
|
||||||
|
|
@ -352,7 +379,8 @@ function publishStatus(client, topic) {
|
||||||
msg: {
|
msg: {
|
||||||
sdl: {
|
sdl: {
|
||||||
version: config.package.version,
|
version: config.package.version,
|
||||||
uptime: getUptimeDHMS()
|
uptime: getUptimeDHMS(),
|
||||||
|
update_cmd: `curl -s http://${ip_addr}:${config.modules.web.port}/dist/install-sdl-wkr.sh | bash -s ${ip_addr}`
|
||||||
},
|
},
|
||||||
cluster: config.cluster,
|
cluster: config.cluster,
|
||||||
modules: Object.fromEntries(
|
modules: Object.fromEntries(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import { load_config, log } from '../nwa-lib/index.js';
|
||||||
import dgram from 'dgram';
|
import dgram from 'dgram';
|
||||||
import mqtt from 'mqtt';
|
import mqtt from 'mqtt';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
|
||||||
|
|
||||||
const config = load_config();
|
const config = load_config();
|
||||||
|
|
||||||
|
|
@ -12,8 +14,10 @@ log(`Loaded module: ${module}`);
|
||||||
// Worker state
|
// Worker state
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
let joined = false;
|
let joined = false;
|
||||||
|
let authorized = false;
|
||||||
let mqttClient = null;
|
let mqttClient = null;
|
||||||
let clusterConfig = null;
|
let clusterConfig = null;
|
||||||
|
let updating = false;
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Start UDP discovery
|
// Start UDP discovery
|
||||||
|
|
@ -172,13 +176,23 @@ function joinCluster(mqttInfo, cluster) {
|
||||||
// Handle MQTT messages
|
// Handle MQTT messages
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
function handleMqttMessage(topic, message) {
|
function handleMqttMessage(topic, message) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = JSON.parse(message.toString());
|
const payload = JSON.parse(message.toString());
|
||||||
const mqttTopics = clusterConfig.modules.mqtt.topics[module];
|
const mqttTopics = clusterConfig.modules.mqtt.topics[module];
|
||||||
|
|
||||||
if (topic === mqttTopics.sub['sdl_join-authz']) {
|
if (topic === mqttTopics.sub['sdl_join-authz']) {
|
||||||
handleJoinAuthz(payload);
|
handleJoinAuthz(payload);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
authorized &&
|
||||||
|
topic === mqttTopics.sub['sdl_cluster-status']
|
||||||
|
) {
|
||||||
|
handleClusterStatus(payload);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log(`${module}: failed to parse MQTT message: ${err}`);
|
log(`${module}: failed to parse MQTT message: ${err}`);
|
||||||
}
|
}
|
||||||
|
|
@ -195,11 +209,63 @@ function handleJoinAuthz(payload) {
|
||||||
|
|
||||||
if (payload.msg?.authorized === true) {
|
if (payload.msg?.authorized === true) {
|
||||||
log(`${module}: join authorized by cluster`);
|
log(`${module}: join authorized by cluster`);
|
||||||
|
authorized = true;
|
||||||
|
|
||||||
|
const mqttTopics = clusterConfig.modules.mqtt.topics[module];
|
||||||
|
const statusTopic = mqttTopics.sub['sdl_cluster-status'];
|
||||||
|
|
||||||
|
mqttClient.subscribe(statusTopic, { qos: 1 }, err => {
|
||||||
|
if (err) {
|
||||||
|
log(`${module}: failed to subscribe to ${statusTopic}: ${err}`);
|
||||||
|
} else {
|
||||||
|
log(`${module}: subscribed to ${statusTopic}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
log(`${module}: join denied: ${payload.msg?.reason || 'unknown'}`);
|
log(`${module}: join denied: ${payload.msg?.reason || 'unknown'}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleClusterStatus(payload) {
|
||||||
|
const clusterVersion = payload.msg?.sdl?.version;
|
||||||
|
const updateCmd = payload.msg?.sdl?.update_cmd;
|
||||||
|
const localVersion = config.package.version;
|
||||||
|
|
||||||
|
if (!clusterVersion) return;
|
||||||
|
|
||||||
|
if (clusterVersion !== localVersion) {
|
||||||
|
log(
|
||||||
|
`${module}: version mismatch detected (cluster=${clusterVersion}, local=${localVersion})`
|
||||||
|
);
|
||||||
|
triggerWorkerUpdate(clusterVersion, updateCmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function triggerWorkerUpdate(targetVersion, updateCmd) {
|
||||||
|
if (updating) return;
|
||||||
|
updating = true;
|
||||||
|
|
||||||
|
log(
|
||||||
|
`${module}: triggering self-update to SDL version ${targetVersion}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Stop reacting to further control messages
|
||||||
|
authorized = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
exec(updateCmd, { stdio: 'inherit' });
|
||||||
|
} catch (err) {
|
||||||
|
log(`${module}: failed to exec update command: ${err}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`${module}: exiting for self-update`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Entry point
|
// Entry point
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue