p3x-systemd-manager
Version:
⌚ SystemD Manager, watchdog, notifier and service
176 lines (157 loc) • 5.39 kB
JavaScript
const exec = require('child_process').exec;
const ms = require('millisecond');
const Mail = require('./mail')
const moment = require('moment');
const lib = require('./lib');
const parseRow = /^([^\s]+)([\s]+)([^\s]+)([\s]+)([^\s]+)([\s]+)([^\s]+)([\s]+)(.+)$/;
module.exports = (settings) => {
/**
* Parses systemctl services
* @param input
* @returns {{}}
*/
const parseStatus = (input) => {
const lines = input.split("\n");
lines.pop();
const dbUpdate = {};
lines.forEach((line) => {
const [, unit, , load, , active, , sub, , description] = parseRow.exec(line);
dbUpdate[unit] = {
unit: unit,
load: load,
active: active,
sub: sub,
description: new String(description).trim()
};
})
return dbUpdate;
}
/**
* Runs an update of getting current services and parses and returns at once.
* @returns {Promise}
*/
const update = async () => {
return new Promise((resolve, reject) => {
exec(command, {
maxBuffer: 10 * 1024 * 1024
}, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
if (stderr !== '') {
reject(new Error({
stderr: stderr,
stout: stdout,
}));
return;
}
resolve(parseStatus(stdout));
});
})
}
/**
* The watch program.
*/
const watch = async () => {
try {
const dbUpdate = await update();
if (db === undefined) {
db = dbUpdate;
/*
const notFound = [];
Object.keys(db).forEach((key) => {
if (db[key].load == 'not-found') {
notFound.push(db[key]);
}
})
if (notFound.length > 0) {
mail.send(`NOT FOUND`, notFound);
}
*/
return;
}
const watchUpdate = {
changes: {},
added: {},
removed: {}
}
Object.keys(dbUpdate).forEach((unit) => {
if (db[unit] === undefined && filter.isValid(unit)) {
watchUpdate.added[unit] = lib.clone(dbUpdate[unit]);
} else if (JSON.stringify(db[unit]) !== JSON.stringify(dbUpdate[unit]) && filter.isValid(unit)) {
watchUpdate.changes[unit] = {
'old': lib.clone(db[unit]),
'new': lib.clone(dbUpdate[unit]),
};
}
delete db[unit];
});
watchUpdate.removed = {};
Object.keys(db).forEach((unit) => {
if (filter.isValid(unit)) {
watchUpdate.removed[unit] = lib.clone(db[unit]);
}
})
db = dbUpdate;
let sendChanges = false;
Object.keys(watchUpdate).forEach((watchUpdateKey) => {
if (Object.keys(watchUpdate[watchUpdateKey]).length > 0) {
sendChanges = true;
}
})
if (sendChanges === true) {
watchUpdate.moment = moment().format(settings.moment);
mail.send(`CHANGED`, watchUpdate);
}
} catch (error) {
mail.send(`ERROR`, error);
}
if (timeLastPing == undefined || Date.now() - timeLastPing > timePing) {
console.log(`ping - ${Object.keys(db).length} items - every ${timePingString}`);
//console.log(db);
timeLastPing = Date.now();
}
}
const mail = Mail(settings);
const filter = lib.filter(settings);
//const command = 'sudo systemctl -all --full --plain --no-pager --no-legend ';
let types = '';
if (settings.filter.type.length > 0) {
types = `--type=${settings.filter.type.join(',')}`;
}
const options = settings.options || '';
const command = `${settings.sudo ? 'sudo ' : ''}systemctl --plain --no-pager --no-legend ${options} ${types}`;
// systemctl --state=not-found --all
let db;
let timeLastPing;
let timePing = ms(settings.ping);
let timePingString = settings.ping;
let interval = ms(settings.interval)
let intervalString = settings.interval;
const showStatus = () => {
if (settings.filter.type.length === 0) {
console.log(`watchdog all`)
} else {
console.log(`watchdog type(s): ${settings.filter.type.join(',')}`)
}
console.log(`ping: ${timePingString}`);
console.log(`interval: ${intervalString}`);
console.log(`command: ${command}`);
}
console.log(`started`);
if (settings.test) {
interval = 3000;
intervalString = interval + ' ms';
timePing = 3000;
timePingString = 3000 + ' ms';
status(`TEST MODE`);
}
showStatus();
return {
run: () => {
watch();
setInterval(watch, interval);
}
}
}