fix(migration): properly transform v3 flat structure to v4 nested snmp config
All checks were successful
CI / Type Check & Lint (push) Successful in 6s
CI / Build Test (Current Platform) (push) Successful in 8s
Release / build-and-release (push) Successful in 48s
CI / Build All Platforms (push) Successful in 51s

The v3→v4 migration was only renaming upsList to upsDevices without
transforming the device structure. V3 had a flat structure with SNMP
fields directly on the device object, while v4 expects a nested 'snmp'
object.

This commit fixes the migration to:
- Move host, port, community, version, etc. into nested snmp object
- Convert version from string to number
- Add default timeout (5000ms)
- Create thresholds object with defaults
- Preserve all SNMPv1, v2c, and v3 authentication fields

Also includes install.sh fix for better non-interactive handling.
This commit is contained in:
2025-10-19 21:32:55 +00:00
parent 88ad16c638
commit fb4d776bdd
4 changed files with 246 additions and 13 deletions

View File

@@ -4,19 +4,38 @@ import { logger } from '../logger.ts';
/**
* Migration from v3 (upsList) to v4 (upsDevices)
*
* Detects v3 format:
* Transforms v3 format with flat SNMP config:
* {
* upsList: [ ... ],
* groups: [ ... ],
* checkInterval: 30000
* upsList: [
* {
* id: "ups-1",
* name: "UPS 1",
* host: "192.168.1.1",
* port: 161,
* community: "public",
* version: "1" // string
* }
* ]
* }
*
* Converts to:
* To v4 format with nested SNMP config:
* {
* version: "4.0",
* upsDevices: [ ... ], // renamed from upsList
* groups: [ ... ],
* checkInterval: 30000
* upsDevices: [
* {
* id: "ups-1",
* name: "UPS 1",
* snmp: {
* host: "192.168.1.1",
* port: 161,
* community: "public",
* version: 1, // number
* timeout: 5000
* },
* thresholds: { battery: 60, runtime: 20 },
* groups: []
* }
* ]
* }
*/
export class MigrationV3ToV4 extends BaseMigration {
@@ -30,16 +49,58 @@ export class MigrationV3ToV4 extends BaseMigration {
}
async migrate(config: any): Promise<any> {
logger.info(`${this.getName()}: Renaming upsList to upsDevices...`);
logger.info(`${this.getName()}: Migrating v3 config to v4 format...`);
logger.dim(` - Renaming upsList → upsDevices`);
logger.dim(` - Restructuring UPS devices (flat → nested snmp config)`);
// Transform each UPS device from v3 flat structure to v4 nested structure
const transformedDevices = config.upsList.map((device: any) => {
// Build SNMP config object
const snmpConfig: any = {
host: device.host,
port: device.port || 161,
version: typeof device.version === 'string' ? parseInt(device.version, 10) : device.version,
timeout: device.timeout || 5000,
};
// Add SNMPv1/v2c fields
if (device.community) {
snmpConfig.community = device.community;
}
// Add SNMPv3 fields
if (device.securityLevel) snmpConfig.securityLevel = device.securityLevel;
if (device.username) snmpConfig.username = device.username;
if (device.authProtocol) snmpConfig.authProtocol = device.authProtocol;
if (device.authKey) snmpConfig.authKey = device.authKey;
if (device.privProtocol) snmpConfig.privProtocol = device.privProtocol;
if (device.privKey) snmpConfig.privKey = device.privKey;
// Add UPS model if present
if (device.upsModel) snmpConfig.upsModel = device.upsModel;
if (device.customOIDs) snmpConfig.customOIDs = device.customOIDs;
// Return v4 format with nested structure
return {
id: device.id,
name: device.name,
snmp: snmpConfig,
thresholds: device.thresholds || {
battery: 60,
runtime: 20,
},
groups: device.groups || [],
};
});
const migrated = {
version: this.toVersion,
upsDevices: config.upsList, // Rename upsList → upsDevices
upsDevices: transformedDevices,
groups: config.groups || [],
checkInterval: config.checkInterval || 30000,
};
logger.success(`${this.getName()}: Migration complete`);
logger.success(`${this.getName()}: Migration complete (${transformedDevices.length} devices transformed)`);
return migrated;
}
}