provisioning-core/nulib/domain/config/cache/commands.nu

536 lines
17 KiB
Text
Raw Normal View History

# Cache Management CLI Commands
# Provides user-facing commands for cache operations and configuration
# Follows Nushell 0.109.0+ guidelines
# Selective imports (ADR-025 Phase 3 Layer 2).
# cache/metadata star-import was dead — dropped.
use domain/cache/core.nu [cache-clear-type get-cache-stats]
# Avoid importing all modules - use only what's needed
# use ./config_manager.nu *
# use ./nickel.nu *
# use ./sops.nu *
# use ./final.nu *
# ============================================================================
# Data Operations: Clear, List, Warm, Validate
# ============================================================================
# Clear all or specific type of cache
export def cache-clear [
--type: string = "all" # "all", "nickel", "sops", "final", "provider", "platform"
--force = false # Skip confirmation
] {
if (not $force) and ($type == "all") {
let response = (input "Clear ALL cache? This cannot be undone. (yes/no): ")
if $response != "yes" {
print "Cancelled."
return
}
}
match $type {
"all" => {
print "Clearing all caches..."
do {
cache-clear-type "nickel"
cache-clear-type "sops"
cache-clear-type "final"
cache-clear-type "provider"
cache-clear-type "platform"
} | complete | ignore
print "✅ All caches cleared"
},
"nickel" => {
print "Clearing Nickel compilation cache..."
clear-nickel-cache
print "✅ Nickel cache cleared"
},
"sops" => {
print "Clearing SOPS decryption cache..."
clear-sops-cache
print "✅ SOPS cache cleared"
},
"final" => {
print "Clearing final configuration cache..."
clear-final-cache
print "✅ Final config cache cleared"
},
_ => {
print $"❌ Unknown cache type: ($type)"
}
}
}
# List cache entries
export def cache-list [
--type: string = "*" # "nickel", "sops", "final", etc or "*" for all
--format: string = "table" # "table", "json", "yaml"
] {
let stats = (get-cache-stats)
if ($stats.total_entries | is-empty) or ($stats.total_entries == 0) {
print "📭 Cache is empty"
return
}
let home = ($env.HOME? | default "~" | path expand)
let base = ($home | path join ".provisioning" "cache" "config")
mut entries = []
let type_dir = match $type {
"all" => $base,
"nickel" => ($base | path join "nickel"),
"sops" => ($base | path join "sops"),
"final" => ($base | path join "workspaces"),
_ => ($base | path join $type)
}
if not ($type_dir | path exists) {
print $"No cache directory for type: ($type)"
return
}
for meta_file in (glob $"($type_dir)/**/*.meta") {
let cache_file = ($meta_file | str substring 0..-6)
let meta = (do { open $meta_file } | complete | get stdout)
if $meta.exit_code == 0 {
let size_result = (do {
if ($cache_file | path exists) {
$cache_file | stat | get size
} else {
0
}
} | complete)
if $size_result.exit_code == 0 {
let size_kb = ($size_result.stdout / 1024)
let cache_type = ($meta_file | path dirname | path basename)
$entries = ($entries | append {
type: $cache_type,
key: ($cache_file | path basename),
size_kb: ($size_kb | math round -p 2),
created: ($meta.stdout.created_at? | default "unknown"),
expires: ($meta.stdout.expires_at? | default "unknown")
})
}
}
}
if ($entries | length) == 0 {
print "📭 No cache entries found"
return
}
match $format {
"json" => {
$entries | to json --indent 2 | print
},
"yaml" => {
$entries | to yaml | print
},
_ => {
print $"📦 Cache Entries (($entries | length)) total):\n"
$entries | table
}
}
}
# Warm cache (pre-populate)
export def cache-warm [
--workspace: string = ""
--environment: string = "*"
] {
print "🔥 Warming cache..."
if ($workspace | is-empty) {
# Try to get active workspace
use ../../user/config.nu get-active-workspace
let active = (get-active-workspace)
if ($active | is-empty) {
print "❌ No active workspace. Use: provisioning workspace activate <name>"
return
}
print $"Warming cache for workspace: ($active.name)"
do {
warm-nickel-cache $active.path
} | complete | ignore
} else {
print $"Warming cache for workspace: ($workspace)"
}
print "✅ Cache warming complete"
}
# Validate cache integrity
export def cache-validate [] {
print "🔍 Validating cache integrity..."
let home = ($env.HOME? | default "~" | path expand)
let base = ($home | path join ".provisioning" "cache" "config")
if not ($base | path exists) {
return {
valid: true,
total_files: 0,
errors: [],
warnings: []
}
}
mut errors = []
mut warnings = []
mut total_files = 0
# Check SOPS permissions
let sops_stats = (get-sops-cache-stats)
if ($sops_stats.permission_errors | default 0) > 0 {
$errors = ($errors | append $"SOPS cache: ($sops_stats.permission_errors) files with invalid permissions")
}
# Check all metadata files
for meta_file in (glob $"($base)/**/*.meta") {
$total_files += 1
let cache_file = ($meta_file | str substring 0..-6)
let meta_result = (do { open $meta_file } | complete)
if $meta_result.exit_code != 0 {
$errors = ($errors | append $"Cannot read metadata: ($meta_file)")
continue
}
let meta = $meta_result.stdout
# Check expiration
let now = (date now | format date "%Y-%m-%dT%H:%M:%SZ")
if $now > $meta.expires_at {
$warnings = ($warnings | append $"Expired cache: ($cache_file)")
}
}
let result = {
valid: ($errors | length) == 0,
total_files: $total_files,
errors: $errors,
warnings: $warnings
}
if $result.valid {
print "✅ Cache validation passed"
} else {
print "❌ Cache validation failed"
for error in $errors {
print $" ❌ ($error)"
}
}
if ($warnings | length) > 0 {
for warning in $warnings {
print $" ⚠️ ($warning)"
}
}
$result
}
# ============================================================================
# Configuration Commands: Show, Get, Set, Reset
# ============================================================================
# Show cache configuration (enhanced with paths and all settings)
export def cache-config-show [
--format: string = "table"
] {
let config = (get-cache-config)
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print "📋 Cache Configuration"
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print ""
print "▸ Core Settings:"
print $" Enabled: ($config.enabled)"
print $" Max Size: ($config.max_cache_size / 1048576 | math round -p 0) MB"
print ""
print "▸ Cache Location:"
print $" Base Path: ($config.paths.base)"
print ""
print "▸ Time-To-Live (TTL) Settings:"
print $" Final Config: ($config.ttl.final_config)s (5 minutes)"
print $" Nickel Compilation: ($config.ttl.nickel_compilation)s (30 minutes)"
print $" SOPS Decryption: ($config.ttl.sops_decryption)s (15 minutes)"
print $" Provider Config: ($config.ttl.provider_config)s (10 minutes)"
print $" Platform Config: ($config.ttl.platform_config)s (10 minutes)"
print ""
print "▸ Security Settings:"
print $" SOPS File Permissions: ($config.security.sops_file_permissions)"
print $" SOPS Dir Permissions: ($config.security.sops_dir_permissions)"
print ""
print "▸ Validation Settings:"
print $" Strict mtime Checking: ($config.validation.strict_mtime)"
print ""
print "▸ Metadata:"
print $" Last Modified: ($config.metadata.last_modified)"
print $" Modified By: ($config.metadata.modified_by)"
print $" Config Version: ($config.metadata.version)"
print ""
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}
# Get specific cache configuration setting
export def cache-config-get [
setting_path: string # "enabled", "ttl.final_config", etc.
] {
let value = (cache-config-get $setting_path)
if ($value | is-empty) {
print $"Setting not found: ($setting_path)"
return
}
print $"($setting_path): ($value)"
$value
}
# Set cache configuration
export def cache-config-set [
setting_path: string
value: any
] {
print $"Setting ($setting_path) = ($value)"
cache-config-set $setting_path $value
print "✅ Configuration updated"
}
# Reset cache configuration
export def cache-config-reset [
setting_path?: string = ""
] {
if ($setting_path | is-empty) {
let confirm = (input "Reset ALL cache configuration to defaults? (yes/no): ")
if $confirm != "yes" {
print "Cancelled."
return
}
cache-config-reset
print "✅ All configuration reset to defaults"
} else {
print $"Resetting ($setting_path) to default..."
cache-config-reset $setting_path
print "✅ Setting reset to default"
}
}
# Validate cache configuration
export def cache-config-validate [] {
print "Validating cache configuration..."
let result = (cache-config-validate)
if $result.valid {
print "✅ Configuration is valid"
} else {
print "❌ Configuration has errors:"
for error in $result.errors {
print $" ❌ ($error)"
}
}
if ($result.warnings | length) > 0 {
print "⚠️ Warnings:"
for warning in $result.warnings {
print $" ⚠️ ($warning)"
}
}
$result
}
# ============================================================================
# Monitoring: Status, Stats
# ============================================================================
# Show comprehensive cache status (configuration + statistics)
export def cache-status [] {
let status = (get-cache-status)
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print "📊 Cache Configuration"
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
let config = $status.configuration
print $" Enabled: ($config.enabled)"
print $" Max Size: ($status.max_size_mb) MB"
print $" Current Usage: ($status.current_usage_percent)%"
print ""
print " TTL Settings:"
print $" Final Config: ($config.ttl.final_config)s (5 min)"
print $" Nickel Compilation: ($config.ttl.nickel_compilation)s (30 min)"
print $" SOPS Decryption: ($config.ttl.sops_decryption)s (15 min)"
print $" Provider Config: ($config.ttl.provider_config)s (10 min)"
print $" Platform Config: ($config.ttl.platform_config)s (10 min)"
print ""
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print "📈 Cache Statistics"
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
let stats = $status.statistics
print $" Total Entries: ($stats.total_entries)"
print $" Total Size: ($stats.total_size_mb | math round -p 2) MB"
print ""
print " By Type:"
let nickel_stats = (get-nickel-cache-stats)
print $" Nickel: ($nickel_stats.total_entries) entries, ($nickel_stats.total_size_mb | math round -p 2) MB"
let sops_stats = (get-sops-cache-stats)
print $" SOPS: ($sops_stats.total_entries) entries, ($sops_stats.total_size_mb | math round -p 2) MB"
let final_stats = (get-final-cache-stats)
print $" Final Config: ($final_stats.total_entries) entries, ($final_stats.total_size_mb | math round -p 2) MB"
print ""
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}
# Show cache statistics only
export def cache-stats [
--format: string = "table"
] {
let stats = (get-cache-stats)
print $"📊 Cache Statistics\n"
print $" Total Entries: ($stats.total_entries)"
print $" Total Size: ($stats.total_size_mb | math round -p 2) MB"
print ""
let nickel_stats = (get-nickel-cache-stats)
let sops_stats = (get-sops-cache-stats)
let final_stats = (get-final-cache-stats)
let summary = [
{ type: "Nickel Compilation", entries: $nickel_stats.total_entries, size_mb: ($nickel_stats.total_size_mb | math round -p 2) },
{ type: "SOPS Decryption", entries: $sops_stats.total_entries, size_mb: ($sops_stats.total_size_mb | math round -p 2) },
{ type: "Final Config", entries: $final_stats.total_entries, size_mb: ($final_stats.total_size_mb | math round -p 2) }
]
match $format {
"json" => {
$summary | to json --indent 2 | print
},
"yaml" => {
$summary | to yaml | print
},
_ => {
print "By Type:"
$summary | table
}
}
}
# ============================================================================
# Helper: Dispatch cache commands
# ============================================================================
# Main cache command dispatcher
export def main [
...args: string
] {
if ($args | is-empty) {
cache-status
return
}
let command = ($args | get 0)
let rest = (if ($args | length) > 1 { $args | skip 1 } else { [] })
match $command {
"clear" => {
let cache_type = ($rest | get 0 | default "all")
cache-clear --type $cache_type
},
"list" => {
cache-list
},
"warm" => {
cache-warm
},
"validate" => {
cache-validate | ignore
},
"config" => {
let subcommand = ($rest | get 0 | default "show")
match $subcommand {
"show" => { cache-config-show },
"get" => {
let path = ($rest | get 1 | default "")
if ($path | is-empty) {
print "Usage: cache config get <setting>"
} else {
cache-config-get $path | ignore
}
},
"set" => {
let path = ($rest | get 1 | default "")
let value = ($rest | get 2 | default "")
if ($path | is-empty) or ($value | is-empty) {
print "Usage: cache config set <setting> <value>"
} else {
cache-config-set $path $value
}
},
"reset" => {
let path = ($rest | get 1 | default "")
cache-config-reset $path
},
"validate" => {
cache-config-validate | ignore
},
_ => {
print $"Unknown config subcommand: ($subcommand)"
}
}
},
"status" => {
cache-status
},
"stats" => {
cache-stats
},
"help" => {
print "Cache Management Commands:
cache clear [--type <type>] Clear cache (all, nickel, sops, final)
cache list List cache entries
cache warm Pre-populate cache
cache validate Validate cache integrity
cache config show Show configuration
cache config get <path> Get specific setting
cache config set <path> <value> Set configuration
cache config reset [path] Reset to defaults
cache config validate Validate configuration
cache status Show full status (config + stats)
cache stats Show statistics only
cache help Show this help"
},
_ => {
print $"Unknown cache command: ($command)"
print "Use 'cache help' for available commands"
}
}
}