provisioning/core/nulib/lib_provisioning/config/migration.nu
Jesús Pérez 0a837aed54 feat: add config module and agent setup for migration
- Add config module from backup (loader, accessor, migration)
- Add agent reference cards for token-efficient migration
- Add migration knowledge base and instructions
- Ready to start systematic config-driven migration
2025-09-22 23:36:59 +01:00

262 lines
10 KiB
Plaintext

# Configuration Migration Tool
# Helps migrate from environment variable based configuration to the new config system
use std log
# Mapping of old environment variables to new config paths
export def get-env-mapping [] {
[
{ env_var: "PROVISIONING", config_path: "paths.base", description: "Base provisioning path" }
{ env_var: "PROVISIONING_KLOUD_PATH", config_path: "paths.kloud", description: "Infrastructure kloud path" }
{ env_var: "PROVISIONING_PROVIDERS_PATH", config_path: "paths.providers", description: "Providers path" }
{ env_var: "PROVISIONING_TASKSERVS_PATH", config_path: "paths.taskservs", description: "Task services path" }
{ env_var: "PROVISIONING_CLUSTERS_PATH", config_path: "paths.clusters", description: "Clusters path" }
{ env_var: "PROVISIONING_RESOURCES", config_path: "paths.resources", description: "Resources path" }
{ env_var: "PROVISIONING_TEMPLATES_PATH", config_path: "paths.templates", description: "Templates path" }
{ env_var: "PROVISIONING_TOOLS_PATH", config_path: "paths.tools", description: "Tools path" }
{ env_var: "PROVISIONING_CORE", config_path: "paths.core", description: "Core path" }
{ env_var: "PROVISIONING_DEBUG", config_path: "debug.enabled", description: "Debug mode" }
{ env_var: "PROVISIONING_METADATA", config_path: "debug.metadata", description: "Metadata debug" }
{ env_var: "PROVISIONING_DEBUG_CHECK", config_path: "debug.check", description: "Debug check mode" }
{ env_var: "PROVISIONING_DEBUG_REMOTE", config_path: "debug.remote", description: "Remote debug mode" }
{ env_var: "PROVISIONING_LOG_LEVEL", config_path: "debug.log_level", description: "Log level" }
{ env_var: "PROVISIONING_NO_TERMINAL", config_path: "debug.no_terminal", description: "No terminal mode" }
{ env_var: "PROVISIONING_FILEVIEWER", config_path: "output.file_viewer", description: "File viewer command" }
{ env_var: "PROVISIONING_WK_FORMAT", config_path: "output.format", description: "Working format" }
{ env_var: "PROVISIONING_USE_SOPS", config_path: "sops.use_sops", description: "SOPS encryption type" }
{ env_var: "PROVISIONING_KAGE", config_path: "sops.key_search_paths.0", description: "Primary SOPS key path" }
{ env_var: "PROVISIONING_SOPS", config_path: "sops.config_path", description: "SOPS config path" }
{ env_var: "PROVISIONING_DFLT_SET", config_path: "paths.files.settings", description: "Default settings file" }
{ env_var: "PROVISIONING_KEYS_PATH", config_path: "paths.files.keys", description: "Keys file path" }
{ env_var: "PROVISIONING_REQ_VERSIONS", config_path: "paths.files.requirements", description: "Requirements file" }
{ env_var: "PROVISIONING_NOTIFY_ICON", config_path: "paths.files.notify_icon", description: "Notification icon" }
{ env_var: "PROVISIONING_RUN_TASKSERVS_PATH", config_path: "taskservs.run_path", description: "Task services run path" }
{ env_var: "PROVISIONING_RUN_CLUSTERS_PATH", config_path: "clusters.run_path", description: "Clusters run path" }
{ env_var: "PROVISIONING_GENERATE_DIRPATH", config_path: "generation.dir_path", description: "Generation directory" }
{ env_var: "PROVISIONING_GENERATE_DEFSFILE", config_path: "generation.defs_file", description: "Generation definitions file" }
]
}
# Analyze current environment variables and suggest migration
export def analyze-current-env [] {
let mapping = (get-env-mapping)
mut analysis = []
for entry in $mapping {
let env_value = ($env | get -o $entry.env_var)
if ($env_value | is-not-empty) {
$analysis = ($analysis | append {
env_var: $entry.env_var
current_value: $env_value
config_path: $entry.config_path
description: $entry.description
action: "migrate"
})
} else {
$analysis = ($analysis | append {
env_var: $entry.env_var
current_value: "not set"
config_path: $entry.config_path
description: $entry.description
action: "default"
})
}
}
$analysis
}
# Generate user configuration based on current environment variables
export def generate-user-config [
--output: string = "" # Output file (default: ~/.config/provisioning/config.toml)
--dry-run = false # Show what would be generated without writing
] {
let analysis = (analyze-current-env)
let active_vars = ($analysis | where action == "migrate")
if ($active_vars | is-empty) {
print "No environment variables found to migrate"
return
}
# Build configuration structure
mut config = {
core: {
name: "provisioning"
}
paths: {}
debug: {}
output: {}
sops: {
key_search_paths: []
}
}
# Convert environment variables to config structure
for var in $active_vars {
$config = (set-config-value $config $var.config_path $var.current_value)
}
# Convert to TOML
let config_toml = ($config | to toml)
let output_path = if ($output | is-empty) {
($env.HOME | path join ".config" | path join "provisioning" | path join "config.toml")
} else {
$output
}
if $dry_run {
print "Generated configuration (dry run):"
print "=====================================\n"
print $config_toml
print $"\nWould be written to: ($output_path)"
} else {
# Ensure directory exists
let config_dir = ($output_path | path dirname)
if not ($config_dir | path exists) {
mkdir $config_dir
print $"Created directory: ($config_dir)"
}
# Write configuration
$config_toml | save $output_path
print $"Generated user configuration: ($output_path)"
print "Review and edit this file as needed"
}
}
# Set a nested configuration value using dot notation
def set-config-value [
config: record
path: string
value: any
] {
let path_parts = ($path | split row ".")
if ($path_parts | length) == 1 {
# Simple top-level assignment
return ($config | upsert ($path_parts | first) $value)
}
# Handle nested paths
let first_part = ($path_parts | first)
let remaining_path = ($path_parts | skip 1 | str join ".")
let existing_section = ($config | get -o $first_part | default {})
let updated_section = (set-config-value $existing_section $remaining_path $value)
$config | upsert $first_part $updated_section
}
# Check for potential issues in the migration
export def check-migration-issues [] {
let analysis = (analyze-current-env)
mut issues = []
# Check for conflicting paths
let base_path = ($env | get -o PROVISIONING)
if ($base_path | is-not-empty) and not ($base_path | path exists) {
$issues = ($issues | append {
type: "missing_path"
item: "PROVISIONING"
value: $base_path
issue: "Base path does not exist"
severity: "error"
})
}
# Check for SOPS configuration
let sops_key = ($env | get -o PROVISIONING_KAGE)
if ($sops_key | is-not-empty) and not ($sops_key | path exists) {
$issues = ($issues | append {
type: "missing_file"
item: "PROVISIONING_KAGE"
value: $sops_key
issue: "SOPS key file does not exist"
severity: "warning"
})
}
# Check for deprecated variables that should be removed
let deprecated_vars = [
"PROVISIONING_ARGS"
"PROVISIONING_MODULE"
"PROVISIONING_NAME"
"PROVISIONING_OUT"
"PROVISIONING_LAST_ERROR"
]
for var in $deprecated_vars {
let value = ($env | get -o $var)
if ($value | is-not-empty) {
$issues = ($issues | append {
type: "deprecated"
item: $var
value: $value
issue: "This variable is deprecated and should be removed"
severity: "info"
})
}
}
$issues
}
# Show migration status and recommendations
export def show-migration-status [] {
print "🔄 Environment Variable Migration Analysis"
print "==========================================\n"
let analysis = (analyze-current-env)
let to_migrate = ($analysis | where action == "migrate")
let using_defaults = ($analysis | where action == "default")
print $"📊 Summary:"
print $" • Variables to migrate: ($to_migrate | length)"
print $" • Using system defaults: ($using_defaults | length)"
print ""
if ($to_migrate | length) > 0 {
print "🔧 Variables that will be migrated:"
$to_migrate | select env_var current_value config_path | table --index false
print ""
}
let issues = (check-migration-issues)
if ($issues | length) > 0 {
print "⚠️ Potential issues found:"
$issues | table --index false
print ""
}
print "💡 Next steps:"
print " 1. Run 'migration generate-user-config --dry-run' to preview"
print " 2. Run 'migration generate-user-config' to create config file"
print " 3. Test the new configuration system"
print " 4. Remove old environment variables from your shell profile"
}
# Create a backup of current environment variables
export def backup-current-env [
output: string = "provisioning-env-backup.nu"
] {
let mapping = (get-env-mapping)
mut backup_content = "# Backup of provisioning environment variables\n"
$backup_content = ($backup_content + "# Generated on " + (date now | format date "%Y-%m-%d %H:%M:%S") + "\n\n")
for entry in $mapping {
let env_value = ($env | get -o $entry.env_var)
if ($env_value | is-not-empty) {
$backup_content = ($backup_content + $"$env.($entry.env_var) = \"($env_value)\"\n")
}
}
$backup_content | save $output
print $"Environment variables backed up to: ($output)"
}