fix(daemon): Refactor shutdown initiation logic in daemon by moving the initiateShutdown and monitorDuringShutdown methods from the SNMP manager to the daemon, and update calls accordingly
This commit is contained in:
parent
901127f784
commit
e47f316d0a
@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-03-25 - 2.4.2 - fix(daemon)
|
||||||
|
Refactor shutdown initiation logic in daemon by moving the initiateShutdown and monitorDuringShutdown methods from the SNMP manager to the daemon, and update calls accordingly
|
||||||
|
|
||||||
|
- Moved initiateShutdown and monitorDuringShutdown to the daemon class for improved cohesion
|
||||||
|
- Updated references in the daemon to call its own shutdown method instead of the SNMP manager
|
||||||
|
- Removed redundant initiateShutdown method from the SNMP manager
|
||||||
|
|
||||||
## 2025-03-25 - 2.4.1 - fix(docs)
|
## 2025-03-25 - 2.4.1 - fix(docs)
|
||||||
Update readme with detailed legal and trademark guidance
|
Update readme with detailed legal and trademark guidance
|
||||||
|
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/nupst',
|
name: '@serve.zone/nupst',
|
||||||
version: '2.4.1',
|
version: '2.4.2',
|
||||||
description: 'Node.js UPS Shutdown Tool for SNMP-enabled UPS devices'
|
description: 'Node.js UPS Shutdown Tool for SNMP-enabled UPS devices'
|
||||||
}
|
}
|
||||||
|
88
ts/daemon.ts
88
ts/daemon.ts
@ -1,7 +1,11 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
import { promisify } from 'util';
|
||||||
import { NupstSnmp, type ISnmpConfig } from './snmp.js';
|
import { NupstSnmp, type ISnmpConfig } from './snmp.js';
|
||||||
|
|
||||||
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration interface for the daemon
|
* Configuration interface for the daemon
|
||||||
*/
|
*/
|
||||||
@ -269,7 +273,7 @@ export class NupstDaemon {
|
|||||||
if (status.batteryCapacity < this.config.thresholds.battery) {
|
if (status.batteryCapacity < this.config.thresholds.battery) {
|
||||||
console.log('⚠️ WARNING: Battery capacity below threshold');
|
console.log('⚠️ WARNING: Battery capacity below threshold');
|
||||||
console.log(`Current: ${status.batteryCapacity}% | Threshold: ${this.config.thresholds.battery}%`);
|
console.log(`Current: ${status.batteryCapacity}% | Threshold: ${this.config.thresholds.battery}%`);
|
||||||
await this.snmp.initiateShutdown('Battery capacity below threshold');
|
await this.initiateShutdown('Battery capacity below threshold');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,10 +281,90 @@ export class NupstDaemon {
|
|||||||
if (status.batteryRuntime < this.config.thresholds.runtime) {
|
if (status.batteryRuntime < this.config.thresholds.runtime) {
|
||||||
console.log('⚠️ WARNING: Runtime below threshold');
|
console.log('⚠️ WARNING: Runtime below threshold');
|
||||||
console.log(`Current: ${status.batteryRuntime} min | Threshold: ${this.config.thresholds.runtime} min`);
|
console.log(`Current: ${status.batteryRuntime} min | Threshold: ${this.config.thresholds.runtime} min`);
|
||||||
await this.snmp.initiateShutdown('Runtime below threshold');
|
await this.initiateShutdown('Runtime below threshold');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate system shutdown with UPS monitoring during shutdown
|
||||||
|
* @param reason Reason for shutdown
|
||||||
|
*/
|
||||||
|
public async initiateShutdown(reason: string): Promise<void> {
|
||||||
|
console.log(`Initiating system shutdown due to: ${reason}`);
|
||||||
|
|
||||||
|
// Set a longer delay for shutdown to allow VMs and services to close
|
||||||
|
const shutdownDelayMinutes = 5;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Execute shutdown command with delay to allow for VM graceful shutdown
|
||||||
|
const { stdout } = await execAsync(`shutdown -h +${shutdownDelayMinutes} "UPS battery critical, shutting down in ${shutdownDelayMinutes} minutes"`);
|
||||||
|
console.log('Shutdown initiated:', stdout);
|
||||||
|
console.log(`Allowing ${shutdownDelayMinutes} minutes for VMs to shut down safely`);
|
||||||
|
|
||||||
|
// Monitor UPS during shutdown and force immediate shutdown if battery gets too low
|
||||||
|
console.log('Monitoring UPS during shutdown process...');
|
||||||
|
await this.monitorDuringShutdown();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to initiate shutdown:', error);
|
||||||
|
// Try a different method if first one fails
|
||||||
|
try {
|
||||||
|
console.log('Trying alternative shutdown method...');
|
||||||
|
await execAsync('poweroff --force');
|
||||||
|
} catch (innerError) {
|
||||||
|
console.error('All shutdown methods failed:', innerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitor UPS during system shutdown
|
||||||
|
* Force immediate shutdown if battery gets critically low
|
||||||
|
*/
|
||||||
|
private async monitorDuringShutdown(): Promise<void> {
|
||||||
|
const EMERGENCY_RUNTIME_THRESHOLD = 5; // 5 minutes remaining is critical
|
||||||
|
const CHECK_INTERVAL = 30000; // Check every 30 seconds during shutdown
|
||||||
|
const MAX_MONITORING_TIME = 5 * 60 * 1000; // Max 5 minutes of monitoring
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
console.log(`Emergency shutdown threshold: ${EMERGENCY_RUNTIME_THRESHOLD} minutes remaining battery runtime`);
|
||||||
|
|
||||||
|
// Continue monitoring until max monitoring time is reached
|
||||||
|
while (Date.now() - startTime < MAX_MONITORING_TIME) {
|
||||||
|
try {
|
||||||
|
console.log('Checking UPS status during shutdown...');
|
||||||
|
const status = await this.snmp.getUpsStatus(this.config.snmp);
|
||||||
|
|
||||||
|
console.log(`Current battery: ${status.batteryCapacity}%, Runtime: ${status.batteryRuntime} minutes`);
|
||||||
|
|
||||||
|
// If battery runtime gets critically low, force immediate shutdown
|
||||||
|
if (status.batteryRuntime < EMERGENCY_RUNTIME_THRESHOLD) {
|
||||||
|
console.log('┌─ EMERGENCY SHUTDOWN ─────────────────────┐');
|
||||||
|
console.log(`│ Battery runtime critically low: ${status.batteryRuntime} minutes`);
|
||||||
|
console.log('│ Forcing immediate shutdown!');
|
||||||
|
console.log('└──────────────────────────────────────────┘');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await execAsync('shutdown -h now "EMERGENCY: UPS battery critically low, shutting down NOW"');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Emergency shutdown failed, trying alternative method...');
|
||||||
|
await execAsync('poweroff --force');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop monitoring after initiating emergency shutdown
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait before checking again
|
||||||
|
await this.sleep(CHECK_INTERVAL);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error monitoring UPS during shutdown:', error);
|
||||||
|
await this.sleep(CHECK_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('UPS monitoring during shutdown completed');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleep for the specified milliseconds
|
* Sleep for the specified milliseconds
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import { exec } from 'child_process';
|
|
||||||
import { promisify } from 'util';
|
|
||||||
import * as dgram from 'dgram';
|
import * as dgram from 'dgram';
|
||||||
import type { IOidSet, ISnmpConfig, TUpsModel, IUpsStatus } from './types.js';
|
import type { IOidSet, ISnmpConfig, TUpsModel, IUpsStatus } from './types.js';
|
||||||
import { UpsOidSets } from './oid-sets.js';
|
import { UpsOidSets } from './oid-sets.js';
|
||||||
import { SnmpPacketCreator } from './packet-creator.js';
|
import { SnmpPacketCreator } from './packet-creator.js';
|
||||||
import { SnmpPacketParser } from './packet-parser.js';
|
import { SnmpPacketParser } from './packet-parser.js';
|
||||||
|
|
||||||
const execAsync = promisify(exec);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for SNMP communication with UPS devices
|
* Class for SNMP communication with UPS devices
|
||||||
* Main entry point for SNMP functionality
|
* Main entry point for SNMP functionality
|
||||||
@ -507,26 +503,5 @@ export class NupstSnmp {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// initiateShutdown method has been moved to the NupstDaemon class
|
||||||
* Initiate system shutdown
|
|
||||||
* @param reason Reason for shutdown
|
|
||||||
*/
|
|
||||||
public async initiateShutdown(reason: string): Promise<void> {
|
|
||||||
console.log(`Initiating system shutdown due to: ${reason}`);
|
|
||||||
try {
|
|
||||||
// Execute shutdown command with 5 minute delay to allow for VM graceful shutdown
|
|
||||||
const { stdout } = await execAsync('shutdown -h +5 "UPS battery critical, shutting down in 5 minutes"');
|
|
||||||
console.log('Shutdown initiated:', stdout);
|
|
||||||
console.log('Allowing 5 minutes for VMs to shut down safely');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to initiate shutdown:', error);
|
|
||||||
// Try a different method if first one fails
|
|
||||||
try {
|
|
||||||
console.log('Trying alternative shutdown method...');
|
|
||||||
await execAsync('poweroff --force');
|
|
||||||
} catch (innerError) {
|
|
||||||
console.error('All shutdown methods failed:', innerError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user