Major type safety improvements throughout the codebase: - Updated DEFAULT_CONFIG version to 4.2 - Replaced 'any' with proper types in systemd.ts: * displaySingleUpsStatus now uses IUpsConfig and NupstSnmp types * Fixed legacy config handling to use proper IUpsConfig format * Removed inline 'any' type annotations - Replaced 'any' with proper types in daemon.ts: * emergencyUps now properly typed as { ups: IUpsConfig, status: ISnmpUpsStatus } * Exported IUpsStatus interface for reuse * Added ISnmpUpsStatus import to disambiguate from daemon's IUpsStatus - Replaced 'any' with Record<string, unknown> in migration system: * Updated BaseMigration abstract class signatures * Updated MigrationRunner.run() signature * Updated migration-v4.0-to-v4.1.ts to use proper types * Migrations use Record<string, unknown> because they deal with unknown config schemas that are being upgraded Benefits: - TypeScript now catches type errors at compile time - Would have caught the ups.thresholds bug earlier - Better IDE autocomplete and type checking - More maintainable and self-documenting code
128 lines
3.9 KiB
TypeScript
128 lines
3.9 KiB
TypeScript
import { BaseMigration } from './base-migration.ts';
|
|
import { logger } from '../logger.ts';
|
|
|
|
/**
|
|
* Migration from v4.0 to v4.1
|
|
*
|
|
* Major changes:
|
|
* 1. Moves thresholds from UPS level to action level
|
|
* 2. Creates default shutdown action for UPS devices that had thresholds
|
|
* 3. Adds empty actions array to UPS devices without actions
|
|
* 4. Adds empty actions array to groups
|
|
*
|
|
* Transforms v4.0 format (with UPS-level thresholds):
|
|
* {
|
|
* version: "4.0",
|
|
* upsDevices: [
|
|
* {
|
|
* id: "ups-1",
|
|
* name: "UPS 1",
|
|
* snmp: {...},
|
|
* thresholds: { battery: 60, runtime: 20 }, // UPS-level
|
|
* groups: []
|
|
* }
|
|
* ]
|
|
* }
|
|
*
|
|
* To v4.1 format (with action-level thresholds):
|
|
* {
|
|
* version: "4.1",
|
|
* upsDevices: [
|
|
* {
|
|
* id: "ups-1",
|
|
* name: "UPS 1",
|
|
* snmp: {...},
|
|
* groups: [],
|
|
* actions: [ // Thresholds moved here
|
|
* {
|
|
* type: "shutdown",
|
|
* thresholds: { battery: 60, runtime: 20 },
|
|
* triggerMode: "onlyThresholds",
|
|
* shutdownDelay: 5
|
|
* }
|
|
* ]
|
|
* }
|
|
* ]
|
|
* }
|
|
*/
|
|
export class MigrationV4_0ToV4_1 extends BaseMigration {
|
|
readonly fromVersion = '4.0';
|
|
readonly toVersion = '4.1';
|
|
|
|
async shouldRun(config: Record<string, unknown>): Promise<boolean> {
|
|
// Run if config is version 4.0
|
|
if (config.version === '4.0') {
|
|
return true;
|
|
}
|
|
|
|
// Also run if config has upsDevices with thresholds at UPS level (v4.0 format)
|
|
if (Array.isArray(config.upsDevices) && config.upsDevices.length > 0) {
|
|
const firstDevice = config.upsDevices[0] as Record<string, unknown>;
|
|
// v4.0 has thresholds at UPS level, v4.1 has them in actions
|
|
return firstDevice.thresholds !== undefined;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
async migrate(config: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
logger.info(`${this.getName()}: Migrating v4.0 config to v4.1 format...`);
|
|
logger.dim(` - Moving thresholds from UPS level to action level`);
|
|
logger.dim(` - Creating default shutdown actions from existing thresholds`);
|
|
|
|
// Migrate UPS devices
|
|
const devices = (config.upsDevices as Array<Record<string, unknown>>) || [];
|
|
const migratedDevices = devices.map((device) => {
|
|
const migrated: Record<string, unknown> = {
|
|
id: device.id,
|
|
name: device.name,
|
|
snmp: device.snmp,
|
|
groups: device.groups || [],
|
|
};
|
|
|
|
// If device has thresholds at UPS level, convert to shutdown action
|
|
const deviceThresholds = device.thresholds as { battery: number; runtime: number } | undefined;
|
|
if (deviceThresholds) {
|
|
migrated.actions = [
|
|
{
|
|
type: 'shutdown',
|
|
thresholds: {
|
|
battery: deviceThresholds.battery,
|
|
runtime: deviceThresholds.runtime,
|
|
},
|
|
triggerMode: 'onlyThresholds', // Preserve old behavior (only on threshold violation)
|
|
shutdownDelay: 5, // Default delay
|
|
},
|
|
];
|
|
logger.dim(
|
|
` → ${device.name}: Created shutdown action (battery: ${deviceThresholds.battery}%, runtime: ${deviceThresholds.runtime}min)`,
|
|
);
|
|
} else {
|
|
// No thresholds, just add empty actions array
|
|
migrated.actions = device.actions || [];
|
|
}
|
|
|
|
return migrated;
|
|
});
|
|
|
|
// Add actions to groups
|
|
const groups = (config.groups as Array<Record<string, unknown>>) || [];
|
|
const migratedGroups = groups.map((group) => ({
|
|
...group,
|
|
actions: group.actions || [],
|
|
}));
|
|
|
|
const result = {
|
|
version: this.toVersion,
|
|
upsDevices: migratedDevices,
|
|
groups: migratedGroups,
|
|
checkInterval: config.checkInterval || 30000,
|
|
};
|
|
|
|
logger.success(
|
|
`${this.getName()}: Migration complete (${migratedDevices.length} devices, ${migratedGroups.length} groups updated)`,
|
|
);
|
|
return result;
|
|
}
|
|
}
|