UNPKG

@porosys/pss

Version:

Porosys Server Setup (pss): General-purpose server setup and automation tool (including Netdata management)

170 lines (155 loc) 5.5 kB
import path from 'path'; import { input, select, confirm } from '@inquirer/prompts'; import chalk from 'chalk'; import { loadConfig, saveConfig } from '../config/config.helper'; import { setupUfwAlert } from '../alerts/setup-ufw-alert'; import { setupSshConfigAlert } from '../alerts/setup-ssh-config-alert'; import { setupMongodServiceDeactiveAlert } from '../alerts/setup-mongod-service-deactive-alert'; import { setupMockServiceDeactiveAlert } from '../alerts/setup-mock-service-deactive-alert'; import { setupPasswdAlert } from '../alerts/setup-passwd-alert'; import { setupShadowAlert } from '../alerts/setup-shadow-alert'; import { setupSudoersAlert } from '../alerts/setup-sudoers-alert'; import { setupSshBruteforceAlert } from '../alerts/setup-ssh-bruteforce-alert'; export const netdataAddAlertCommand = async () => { console.log(chalk.green.bold('\n📦 Updating Netdata Alarm Config')); const config = await loadConfig(); if (!config) { console.log( chalk.yellow('⚠️ No config found. Run `pss netdata install` first.'), ); return; } if (!config.healthdPath) { const possiblePaths = [ '/opt/netdata/etc/netdata/health.d', '/etc/netdata/health.d', ]; let detectedPath = ''; for (const p of possiblePaths) { try { await import('fs') .then((fs) => fs.promises.access(p)) .then(() => { detectedPath = p; }); if (detectedPath) break; } catch {} } if (detectedPath) { console.log(chalk.gray(`Detected health.d path: ${detectedPath}`)); config.healthdPath = detectedPath; } else { const healthdPath = await input({ message: 'Enter the path to your Netdata health.d folder: ', }); config.healthdPath = healthdPath; } } // Compute and store healthScriptsPath as sibling to healthdPath const computedHealthScriptsPath = path.join( path.dirname(config.healthdPath), 'health-scripts', ); if (!config.healthScriptsPath) { config.healthScriptsPath = computedHealthScriptsPath; await saveConfig(config); } let done = false; while (!done) { const alertCategory = await select({ message: 'Which alert category would you like to set up?', choices: [ { name: 'Sensitive Change', value: 'sensitive-change' }, { name: 'Service Deactivation', value: 'service-deactivation' }, { name: 'Attack Detection', value: 'attack-detection' }, { name: 'Exit', value: 'exit' }, ], }); if (alertCategory === 'exit') return; let alertType; let backToCategory = false; while (!alertType && !backToCategory) { if (alertCategory === 'sensitive-change') { alertType = await select({ message: 'Which sensitive change would you like to monitor?', choices: [ { name: 'ufw', value: 'ufw-change' }, { name: 'sshd-config', value: 'sshd-config-change' }, { name: 'passwd', value: 'passwd-change' }, { name: 'sudoers', value: 'sudoers-change' }, { name: 'shadow', value: 'shadow-change' }, { name: '⬅️ Back', value: 'back' }, ], }); } else if (alertCategory === 'service-deactivation') { alertType = await select({ message: 'Which service deactivation would you like to monitor?', choices: [ { name: 'mongod', value: 'mongod-service-deactive' }, { name: 'mock-service', value: 'mock-service-deactive' }, { name: '⬅️ Back', value: 'back' }, ], }); } else if (alertCategory === 'attack-detection') { alertType = await select({ message: 'Which attack detection would you like to monitor?', choices: [{ name: 'ssh-bruteforce', value: 'ssh-bruteforce-attack' }], }); } if (alertType === 'back') { backToCategory = true; break; } } if (backToCategory) continue; switch (alertType) { case 'ufw-change': await setupUfwAlert(); break; case 'sshd-config-change': await setupSshConfigAlert(); break; case 'passwd-change': await setupPasswdAlert(); break; case 'sudoers-change': await setupSudoersAlert(); break; case 'shadow-change': await setupShadowAlert(); break; case 'mongod-service-deactive': await setupMongodServiceDeactiveAlert(); break; case 'mock-service-deactive': await setupMockServiceDeactiveAlert(); break; case 'ssh-bruteforce-attack': await setupSshBruteforceAlert(); break; default: console.log(chalk.yellow('⚠️ Alert type not found.')); } // Ask if user wants to add another alert or apply changes const addAnother = await confirm({ message: 'Would you like to add another alert?', default: false, }); if (!addAnother) { done = true; } } // Reload Netdata health after all alerts are set up const { execa } = await import('execa'); try { await execa('/opt/netdata/bin/netdatacli', ['reload-health'], { stdio: 'inherit', }); console.log(chalk.green('✅ Netdata health reloaded.')); } catch (err) { console.log(chalk.red('❌ Failed to reload Netdata health.')); if (err instanceof Error) { console.error(err.message); } } };