feat(02-01): add config backup env vars, NATS event, device SSH fields, migration, metrics

- Config: CONFIG_BACKUP_INTERVAL (21600s), CONFIG_BACKUP_MAX_CONCURRENT (10), CONFIG_BACKUP_COMMAND_TIMEOUT (60s)
- NATS: ConfigSnapshotEvent type, PublishConfigSnapshot method, config.snapshot.> stream subject
- Device: SSHPort/SSHHostKeyFingerprint fields, UpdateSSHHostKey method, updated queries/scans
- Migration 028: ssh_port, ssh_host_key_fingerprint, timestamp columns with poller_user grants
- Metrics: ConfigBackupTotal (counter), ConfigBackupDuration (histogram), ConfigBackupActive (gauge)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-12 20:48:12 -05:00
parent f1abb75cab
commit 4ae39d2cb3
5 changed files with 162 additions and 4 deletions

View File

@@ -90,6 +90,15 @@ type Config struct {
// SSHMaxPerDevice is the maximum number of concurrent SSH relay sessions per device.
SSHMaxPerDevice int
// ConfigBackupIntervalSeconds is how often config backups are collected per device (default 6h = 21600s).
ConfigBackupIntervalSeconds int
// ConfigBackupMaxConcurrent is the max number of concurrent config backup jobs.
ConfigBackupMaxConcurrent int
// ConfigBackupCommandTimeoutSeconds is the per-command timeout for SSH config export.
ConfigBackupCommandTimeoutSeconds int
}
// knownInsecureEncryptionKey is the base64-encoded dev default encryption key.
@@ -118,8 +127,11 @@ func Load() (*Config, error) {
SSHRelayPort: getEnv("SSH_RELAY_PORT", "8080"),
SSHIdleTimeout: getEnvInt("SSH_IDLE_TIMEOUT", 900),
SSHMaxSessions: getEnvInt("SSH_MAX_SESSIONS", 200),
SSHMaxPerUser: getEnvInt("SSH_MAX_PER_USER", 10),
SSHMaxPerDevice: getEnvInt("SSH_MAX_PER_DEVICE", 20),
SSHMaxPerUser: getEnvInt("SSH_MAX_PER_USER", 10),
SSHMaxPerDevice: getEnvInt("SSH_MAX_PER_DEVICE", 20),
ConfigBackupIntervalSeconds: getEnvInt("CONFIG_BACKUP_INTERVAL", 21600),
ConfigBackupMaxConcurrent: getEnvInt("CONFIG_BACKUP_MAX_CONCURRENT", 10),
ConfigBackupCommandTimeoutSeconds: getEnvInt("CONFIG_BACKUP_COMMAND_TIMEOUT", 60),
}
if cfg.DatabaseURL == "" {