fix: Only log 'Migration complete' when inline allowed_nodes actually migrated. Related to Discussion #946

The sensor proxy self-heal script runs every 5 minutes and calls migrate-to-file.
Previously it would print 'Migration complete' every time, even when already in
file mode with nothing to migrate.

Now migrateInlineToFile returns a boolean indicating if migration actually
occurred, and the CLI only prints the message when work was done.
This commit is contained in:
rcourtman 2025-12-29 14:15:57 +00:00
parent 4ce1d551e4
commit 277aca3e4e
3 changed files with 402 additions and 4 deletions

View file

@ -140,12 +140,16 @@ Safe to run multiple times (idempotent).
allowedNodesPath = filepath.Join(filepath.Dir(cfgPath), "allowed_nodes.yaml")
}
if err := migrateInlineToFile(cfgPath, allowedNodesPath); err != nil {
migrated, err := migrateInlineToFile(cfgPath, allowedNodesPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Migration failed: %v\n", err)
return err
}
fmt.Println("Migration complete: inline allowed_nodes moved to file")
if migrated {
fmt.Println("Migration complete: inline allowed_nodes moved to file")
}
// Silent success when nothing to migrate (idempotent)
return nil
},
}
@ -539,13 +543,16 @@ func extractNodesFromYAML(data []byte) []string {
}
// migrateInlineToFile atomically migrates inline allowed_nodes from config.yaml to allowed_nodes.yaml
func migrateInlineToFile(configPath, allowedNodesPath string) error {
// Returns (true, nil) if migration was performed, (false, nil) if nothing to migrate, or (false, err) on error.
func migrateInlineToFile(configPath, allowedNodesPath string) (bool, error) {
configLockPath := configPath + ".lock"
allowedNodesLockPath := allowedNodesPath + ".lock"
var migrated bool
// Lock both files in consistent order to prevent deadlocks
// Always lock config.yaml before allowed_nodes.yaml
return withLockedFile(configLockPath, func(configLock *os.File) error {
err := withLockedFile(configLockPath, func(configLock *os.File) error {
return withLockedFile(allowedNodesLockPath, func(allowedNodesLock *os.File) error {
// Read current config
configData, err := os.ReadFile(configPath)
@ -562,6 +569,15 @@ func migrateInlineToFile(configPath, allowedNodesPath string) error {
return fmt.Errorf("failed to parse config: %w", err)
}
// Check if inline allowed_nodes exists - this determines if migration is needed
_, hasInlineNodes := config["allowed_nodes"]
_, hasFileRef := config["allowed_nodes_file"]
// If already using file mode and no inline nodes, nothing to migrate
if !hasInlineNodes && hasFileRef {
return nil
}
// Extract inline nodes (if any)
var inlineNodes []string
if allowedNodes, ok := config["allowed_nodes"]; ok {
@ -574,6 +590,9 @@ func migrateInlineToFile(configPath, allowedNodesPath string) error {
}
}
// Mark that migration is being performed
migrated = hasInlineNodes
// Remove inline allowed_nodes block from config
delete(config, "allowed_nodes")
@ -616,4 +635,5 @@ func migrateInlineToFile(configPath, allowedNodesPath string) error {
return atomicWriteFile(allowedNodesPath, finalData, 0644)
})
})
return migrated, err
}