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

359 lines
9.7 KiB
Text
Raw Normal View History

# Dynamic Cache Configuration Manager
# Manages cache settings at runtime via persistent JSON config
# Follows Nushell 0.109.0+ guidelines
# Helper: Get runtime config file path
def get-runtime-config-path [] {
let home = ($env.HOME? | default "~" | path expand)
$home | path join ".provisioning" "cache" "config" "settings.json"
}
# Helper: Get system defaults path
def get-defaults-config-path [] {
let provisioning = ($env.PROVISIONING? | default "/usr/local/provisioning")
$provisioning | path join "config" "config.defaults.toml"
}
# Helper: Load runtime config file
def load-runtime-config [] {
let config_path = (get-runtime-config-path)
if ($config_path | path exists) {
let load_result = (do {
open $config_path
} | complete)
if $load_result.exit_code == 0 {
return $load_result.stdout
}
}
# Return empty record if not exists
{}
}
# Helper: Save runtime config file
def save-runtime-config [
config: record
] {
let config_path = (get-runtime-config-path)
let config_dir = ($config_path | path dirname)
# Ensure directory exists
if not ($config_dir | path exists) {
mkdir $config_dir
}
# Save with pretty formatting
do {
$config | to json --indent 2 | save --force $config_path
} | complete | ignore
}
# ============================================================================
# PUBLIC API: Configuration Management
# ============================================================================
# Get complete cache configuration (merged: runtime overrides + defaults)
export def get-cache-config [] {
let defaults = {
enabled: true,
max_cache_size: 104857600, # 100 MB
ttl: {
final_config: 300, # 5 minutes
nickel_compilation: 1800, # 30 minutes
sops_decryption: 900, # 15 minutes
provider_config: 600, # 10 minutes
platform_config: 600 # 10 minutes
},
paths: {
base: (($env.HOME? | default "~" | path expand) | path join ".provisioning" "cache" "config")
},
security: {
sops_file_permissions: "0600",
sops_dir_permissions: "0700"
},
validation: {
strict_mtime: true
},
metadata: {
last_modified: (date now | format date "%Y-%m-%dT%H:%M:%SZ"),
modified_by: "system",
version: "1.0"
}
}
# Load runtime overrides
let runtime = (load-runtime-config)
# Merge: runtime overrides take precedence
$defaults | merge $runtime
}
# Get specific cache setting (dot notation: "ttl.final_config")
export def cache-config-get [
setting_path: string # "enabled", "ttl.final_config", etc.
] {
let config = (get-cache-config)
let result = (do {
eval $"$config | get ($setting_path)"
} | complete)
if $result.exit_code == 0 {
$result.stdout
} else {
null
}
}
# Set cache configuration (persists to runtime config)
export def cache-config-set [
setting_path: string
value: any
] {
let runtime = (load-runtime-config)
# Build nested structure from dot notation
mut updated = $runtime
# Simple update for direct keys
if not ($setting_path | str contains ".") {
$updated = ($updated | insert $setting_path $value)
} else {
# For nested paths, we need to handle carefully
# Convert "ttl.final_config" -> insert into ttl section
let parts = ($setting_path | split row ".")
if ($parts | length) == 2 {
let section = ($parts | get 0)
let key = ($parts | get 1)
let section_obj = if ($runtime | has -c $section) {
$runtime | get $section
} else {
{}
}
let updated_section = ($section_obj | insert $key $value)
$updated = ($updated | insert $section $updated_section)
}
}
# Add metadata
$updated = ($updated | insert "metadata" {
last_modified: (date now | format date "%Y-%m-%dT%H:%M:%SZ"),
modified_by: "user",
version: "1.0"
})
save-runtime-config $updated
}
# Reset cache configuration (delete runtime overrides)
export def cache-config-reset [
setting_path?: string = "" # Optional: reset specific setting
] {
if ($setting_path | is-empty) {
# Delete entire runtime config file
let config_path = (get-runtime-config-path)
if ($config_path | path exists) {
do {
rm -f $config_path
} | complete | ignore
}
} else {
# Remove specific setting
let runtime = (load-runtime-config)
mut updated = $runtime
# Handle nested paths
if not ($setting_path | str contains ".") {
if ($updated | has -c $setting_path) {
$updated = ($updated | del $setting_path)
}
} else {
let parts = ($setting_path | split row ".")
if ($parts | length) == 2 {
let section = ($parts | get 0)
let key = ($parts | get 1)
if ($updated | has -c $section) {
let section_obj = ($updated | get $section)
let updated_section = (if ($section_obj | has -c $key) {
$section_obj | del $key
} else {
$section_obj
})
$updated = ($updated | insert $section $updated_section)
}
}
}
save-runtime-config $updated
}
}
# Show cache configuration in formatted output
export def cache-config-show [
--format: string = "yaml" # "yaml", "json", "table"
] {
let config = (get-cache-config)
match $format {
"json" => {
$config | to json --indent 2 | print
},
"table" => {
$config | print
},
_ => {
$config | to yaml | print
}
}
}
# Validate cache configuration
export def cache-config-validate [] {
let config = (get-cache-config)
mut errors = []
mut warnings = []
# Validate enabled field
if not ($config | has -c "enabled") {
$errors = ($errors | append "Missing 'enabled' field")
}
# Validate TTL values (should be positive integers)
if ($config | has -c "ttl") {
for ttl_key in [
"final_config"
"nickel_compilation"
"sops_decryption"
"provider_config"
"platform_config"
] {
let ttl_value = ($config.ttl | get --optional $ttl_key | default 0)
if ($ttl_value <= 0) {
$warnings = ($warnings | append $"TTL ($ttl_key) is not positive: ($ttl_value)")
}
}
}
# Validate max cache size (should be reasonable)
if ($config | has -c "max_cache_size") {
let max_size = $config.max_cache_size
if ($max_size < 1048576) { # Less than 1 MB
$warnings = ($warnings | append $"max_cache_size is very small: ($max_size) bytes")
}
if ($max_size > 10737418240) { # More than 10 GB
$warnings = ($warnings | append $"max_cache_size is very large: ($max_size) bytes")
}
}
{
valid: (($errors | length) == 0),
errors: $errors,
warnings: $warnings
}
}
# Get cache statistics along with configuration
export def get-cache-status [] {
use ../../cache/core.nu get-cache-stats
let config = (get-cache-config)
let stats = (get-cache-stats)
{
configuration: $config,
statistics: $stats,
enabled: $config.enabled,
max_size_mb: ($config.max_cache_size / 1048576),
current_usage_percent: (
if ($stats.total_size_mb | is-not-empty) {
($stats.total_size_mb / ($config.max_cache_size / 1048576) * 100) | math round -p 1
} else {
0
}
)
}
}
# Export configuration to portable format
export def cache-config-export [
--format: string = "json"
] {
let config = (get-cache-config)
match $format {
"json" => {
$config | to json --indent 2
},
"yaml" => {
$config | to yaml
},
"toml" => {
# Basic TOML conversion (limited)
$"[cache]
enabled = ($config.enabled)
max_cache_size = ($config.max_cache_size)
"
},
_ => {
$config | to json --indent 2
}
}
}
# Import configuration from JSON string
export def cache-config-import [
json_string: string
] {
let result = (do {
$json_string | from json
} | complete)
if $result.exit_code == 0 {
save-runtime-config $result.stdout
} else {
error make { msg: "Failed to parse configuration JSON" }
}
}
# Get configuration defaults (system-wide)
export def get-cache-defaults [] {
{
enabled: true,
max_cache_size: 104857600, # 100 MB
ttl: {
final_config: 300,
nickel_compilation: 1800,
sops_decryption: 900,
provider_config: 600,
platform_config: 600
},
paths: {
base: (($env.HOME? | default "~" | path expand) | path join ".provisioning" "cache" "config")
},
security: {
sops_file_permissions: "0600",
sops_dir_permissions: "0700"
},
validation: {
strict_mtime: true
}
}
}
# Restore default configuration
export def cache-config-restore-defaults [] {
let config_path = (get-runtime-config-path)
if ($config_path | path exists) {
do {
rm -f $config_path
} | complete | ignore
}
}