Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
32f85aa46f | |||
0a8a52f334 | |||
08f537aefd | |||
8431ef91a8 | |||
9bfb948e5c | |||
f5988dcd07 |
20
changelog.md
20
changelog.md
@ -1,5 +1,25 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-03-25 - 1.9.0 - feat(cli)
|
||||||
|
Add update command to CLI to update NUPST from repository and refresh the systemd service
|
||||||
|
|
||||||
|
- Integrate 'update' subcommand in CLI command parser
|
||||||
|
- Update documentation and help output to include new command
|
||||||
|
- Implement update process that fetches changes from git, runs install.sh/setup.sh, and refreshes systemd service if installed
|
||||||
|
|
||||||
|
## 2025-03-25 - 1.8.2 - fix(cli)
|
||||||
|
Refactor logs command to use child_process spawn for real-time log tailing
|
||||||
|
|
||||||
|
- Replaced execSync call with spawn to properly follow logs
|
||||||
|
- Forward SIGINT to the spawned process for graceful termination
|
||||||
|
- Await the child process exit to ensure clean shutdown of the CLI log command
|
||||||
|
|
||||||
|
## 2025-03-25 - 1.8.1 - fix(systemd)
|
||||||
|
Update ExecStart in systemd service template to use /opt/nupst/bin/nupst for daemon startup
|
||||||
|
|
||||||
|
- Changed ExecStart from '/usr/bin/nupst daemon-start' to '/opt/nupst/bin/nupst daemon-start' in the systemd service file
|
||||||
|
- Ensures the service uses the correct binary installation path
|
||||||
|
|
||||||
## 2025-03-25 - 1.8.0 - feat(core)
|
## 2025-03-25 - 1.8.0 - feat(core)
|
||||||
Enhance SNMP module and interactive CLI setup for UPS shutdown
|
Enhance SNMP module and interactive CLI setup for UPS shutdown
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@serve.zone/nupst",
|
"name": "@serve.zone/nupst",
|
||||||
"version": "1.8.0",
|
"version": "1.9.0",
|
||||||
"description": "Node.js UPS Shutdown Tool for SNMP-enabled UPS devices",
|
"description": "Node.js UPS Shutdown Tool for SNMP-enabled UPS devices",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/nupst',
|
name: '@serve.zone/nupst',
|
||||||
version: '1.8.0',
|
version: '1.9.0',
|
||||||
description: 'Node.js UPS Shutdown Tool for SNMP-enabled UPS devices'
|
description: 'Node.js UPS Shutdown Tool for SNMP-enabled UPS devices'
|
||||||
}
|
}
|
||||||
|
102
ts/cli.ts
102
ts/cli.ts
@ -91,6 +91,10 @@ export class NupstCli {
|
|||||||
await this.test(debugMode);
|
await this.test(debugMode);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'update':
|
||||||
|
await this.update();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'help':
|
case 'help':
|
||||||
default:
|
default:
|
||||||
this.showHelp();
|
this.showHelp();
|
||||||
@ -131,8 +135,24 @@ export class NupstCli {
|
|||||||
*/
|
*/
|
||||||
private async logs(): Promise<void> {
|
private async logs(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const logs = execSync('journalctl -u nupst.service -n 50 -f').toString();
|
// Use exec with spawn to properly follow logs in real-time
|
||||||
console.log(logs);
|
const { spawn } = await import('child_process');
|
||||||
|
console.log('Tailing nupst service logs (Ctrl+C to exit)...\n');
|
||||||
|
|
||||||
|
const journalctl = spawn('journalctl', ['-u', 'nupst.service', '-n', '50', '-f'], {
|
||||||
|
stdio: ['ignore', 'inherit', 'inherit']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Forward signals to child process
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
journalctl.kill('SIGINT');
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for process to exit
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
journalctl.on('exit', () => resolve());
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to retrieve logs:', error);
|
console.error('Failed to retrieve logs:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -343,6 +363,7 @@ Usage:
|
|||||||
nupst status - Show status of the systemd service and UPS status
|
nupst status - Show status of the systemd service and UPS status
|
||||||
nupst setup - Run the interactive setup to configure SNMP settings
|
nupst setup - Run the interactive setup to configure SNMP settings
|
||||||
nupst test - Test the current configuration by connecting to the UPS
|
nupst test - Test the current configuration by connecting to the UPS
|
||||||
|
nupst update - Update NUPST from repository and refresh systemd service (requires root)
|
||||||
nupst help - Show this help message
|
nupst help - Show this help message
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@ -351,6 +372,83 @@ Options:
|
|||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update NUPST from repository and refresh systemd service
|
||||||
|
*/
|
||||||
|
private async update(): Promise<void> {
|
||||||
|
try {
|
||||||
|
// Check if running as root
|
||||||
|
this.checkRootAccess('This command must be run as root to update NUPST and refresh the systemd service.');
|
||||||
|
|
||||||
|
console.log('┌─ NUPST Update Process ──────────────────┐');
|
||||||
|
console.log('│ Updating NUPST from repository...');
|
||||||
|
|
||||||
|
// Determine the installation directory (assuming it's either /opt/nupst or the current directory)
|
||||||
|
const { existsSync } = await import('fs');
|
||||||
|
let installDir = '/opt/nupst';
|
||||||
|
|
||||||
|
if (!existsSync(installDir)) {
|
||||||
|
// If not installed in /opt/nupst, use the current directory
|
||||||
|
const { dirname } = await import('path');
|
||||||
|
installDir = dirname(dirname(process.argv[1])); // Go up two levels from the executable
|
||||||
|
console.log(`│ Using local installation directory: ${installDir}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Update the repository
|
||||||
|
console.log('│ Pulling latest changes from git repository...');
|
||||||
|
execSync(`cd ${installDir} && git fetch origin && git reset --hard origin/main`, { stdio: 'pipe' });
|
||||||
|
|
||||||
|
// 2. Run the install.sh script
|
||||||
|
console.log('│ Running install.sh to update NUPST...');
|
||||||
|
execSync(`cd ${installDir} && bash ./install.sh`, { stdio: 'pipe' });
|
||||||
|
|
||||||
|
// 3. Run the setup.sh script
|
||||||
|
console.log('│ Running setup.sh to update dependencies...');
|
||||||
|
execSync(`cd ${installDir} && bash ./setup.sh`, { stdio: 'pipe' });
|
||||||
|
|
||||||
|
// 4. Refresh the systemd service
|
||||||
|
console.log('│ Refreshing systemd service...');
|
||||||
|
|
||||||
|
// First check if service exists
|
||||||
|
const serviceExists = execSync('systemctl list-unit-files | grep nupst.service').toString().includes('nupst.service');
|
||||||
|
|
||||||
|
if (serviceExists) {
|
||||||
|
// Stop the service if it's running
|
||||||
|
const isRunning = execSync('systemctl is-active nupst.service || true').toString().trim() === 'active';
|
||||||
|
if (isRunning) {
|
||||||
|
console.log('│ Stopping nupst service...');
|
||||||
|
execSync('systemctl stop nupst.service');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinstall the service
|
||||||
|
console.log('│ Reinstalling systemd service...');
|
||||||
|
await this.nupst.getSystemd().install();
|
||||||
|
|
||||||
|
// Restart the service if it was running
|
||||||
|
if (isRunning) {
|
||||||
|
console.log('│ Restarting nupst service...');
|
||||||
|
execSync('systemctl start nupst.service');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('│ Systemd service not installed, skipping service refresh.');
|
||||||
|
console.log('│ Run "nupst enable" to install the service.');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('│ Update completed successfully!');
|
||||||
|
console.log('└──────────────────────────────────────────┘');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('│ Error during update process:');
|
||||||
|
console.error(`│ ${error.message}`);
|
||||||
|
console.error('└──────────────────────────────────────────┘');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Update failed: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interactive setup for configuring SNMP settings
|
* Interactive setup for configuring SNMP settings
|
||||||
*/
|
*/
|
||||||
|
15
ts/daemon.ts
15
ts/daemon.ts
@ -193,11 +193,15 @@ export class NupstDaemon {
|
|||||||
console.log('Starting UPS monitoring...');
|
console.log('Starting UPS monitoring...');
|
||||||
|
|
||||||
let lastStatus: 'online' | 'onBattery' | 'unknown' = 'unknown';
|
let lastStatus: 'online' | 'onBattery' | 'unknown' = 'unknown';
|
||||||
|
let lastLogTime = 0; // Track when we last logged status
|
||||||
|
const LOG_INTERVAL = 5 * 60 * 1000; // Log at least every 5 minutes (300000ms)
|
||||||
|
|
||||||
// Monitor continuously
|
// Monitor continuously
|
||||||
while (this.isRunning) {
|
while (this.isRunning) {
|
||||||
try {
|
try {
|
||||||
const status = await this.snmp.getUpsStatus(this.config.snmp);
|
const status = await this.snmp.getUpsStatus(this.config.snmp);
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const shouldLogStatus = (currentTime - lastLogTime) >= LOG_INTERVAL;
|
||||||
|
|
||||||
// Log status changes
|
// Log status changes
|
||||||
if (status.powerStatus !== lastStatus) {
|
if (status.powerStatus !== lastStatus) {
|
||||||
@ -205,6 +209,17 @@ export class NupstDaemon {
|
|||||||
console.log(`│ Power status changed: ${lastStatus} → ${status.powerStatus}`);
|
console.log(`│ Power status changed: ${lastStatus} → ${status.powerStatus}`);
|
||||||
console.log('└──────────────────────────────────────────┘');
|
console.log('└──────────────────────────────────────────┘');
|
||||||
lastStatus = status.powerStatus;
|
lastStatus = status.powerStatus;
|
||||||
|
lastLogTime = currentTime; // Reset log timer when status changes
|
||||||
|
}
|
||||||
|
// Log status periodically (at least every 5 minutes)
|
||||||
|
else if (shouldLogStatus) {
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
console.log('┌──────────────────────────────────────────┐');
|
||||||
|
console.log(`│ [${timestamp}] Periodic Status Update`);
|
||||||
|
console.log(`│ Power Status: ${status.powerStatus}`);
|
||||||
|
console.log(`│ Battery: ${status.batteryCapacity}% | Runtime: ${status.batteryRuntime} min`);
|
||||||
|
console.log('└──────────────────────────────────────────┘');
|
||||||
|
lastLogTime = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle battery power status
|
// Handle battery power status
|
||||||
|
@ -17,7 +17,7 @@ Description=Node.js UPS Shutdown Tool
|
|||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/bin/nupst daemon-start
|
ExecStart=/opt/nupst/bin/nupst daemon-start
|
||||||
Restart=always
|
Restart=always
|
||||||
User=root
|
User=root
|
||||||
Group=root
|
Group=root
|
||||||
|
Reference in New Issue
Block a user