prvng_core/nulib/backu_provisioning

1330 lines
54 KiB
Plaintext
Raw Permalink Normal View History

2025-10-07 10:32:04 +01:00
#!/usr/bin/env nu
# Info: Script to run Provisioning
# Author: JesusPerezLorenzo
# Release: 1.0.4
# Date: 6-2-2024
#use std # assert
use std log
# Detect project root and set up module paths early
# This ensures NU_LIB_DIRS is properly configured before loading modules
export-env {
# Project root detection: look for kcl.mod or provisioning structure
let potential_roots = [
$env.PWD
($env.PWD | path dirname)
($env.PWD | path dirname | path dirname)
]
let matching_roots = ($potential_roots
| where ($it | path join "kcl.mod" | path exists)
or ($it | path join "core" "nulib" | path exists))
let project_root = if ($matching_roots | length) > 0 {
$matching_roots | first
} else {
$env.PWD
}
# Update PWD in NU_LIB_DIRS to use detected project root
if ($env.NU_LIB_DIRS? | default [] | any {|path| $path == $env.PWD}) {
$env.NU_LIB_DIRS = ($env.NU_LIB_DIRS | each {|path|
if $path == $env.PWD { $project_root } else { $path }
})
}
# Add project-local env if it exists - will be loaded after main env.nu
}
use lib_provisioning *
use env.nu *
#Load all main defs
use main_provisioning *
#module srv { use instances.nu * }
use servers/ssh.nu *
use servers/utils.nu *
use taskservs/utils.nu find_taskserv
def run_module [
args: string
module: string
option?: string
--exec
] {
let use_debug = if $env.PROVISIONING_DEBUG { "-x" } else { "" }
# print $"($env.PROVISIONING_NAME) ($use_debug) -mod ($module) ($option | default "") ($args) --notitles "
if $exec {
exec $"($env.PROVISIONING_NAME)" $use_debug -mod $module ($option | default "") $args --notitles
} else {
^$"($env.PROVISIONING_NAME)" $use_debug -mod $module ($option | default "") $args --notitles
}
}
# Help on provisioning commands
export def "main help" [
category?: string # Optional category: infrastructure, orchestration, development, workspace, concepts
--notitles # not titles
--out: string # Print Output format: json, yaml, text (default)
] {
if $notitles == null or not $notitles { show_titles }
if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
print (provisioning_options $category)
if not $env.PROVISIONING_DEBUG { end_run "" }
}
def main [
...args: string # Other options, use help to get info
--infra (-i): string # Cloud directory
--settings (-s): string # Settings path
--serverpos (-p): int # Server position in settings
--outfile (-o): string # Output file
--template(-t): string # Template path or name in PROVISION_KLOUDS_PATH
--check (-c) # Only check mode no servers will be created
--yes (-y) # confirm task
--wait (-w) # Wait servers to be created
--keepstorage # keep storage
--select: string # Select with task as option
--onsel: string # On selection: e (edit) | v (view) | l (list) | t (tree)
--infras: string # Infra list names separated by commas
--new (-n): string # New infrastructure name
--debug (-x) # Use Debug mode
--xm # Debug with PROVISIONING_METADATA
--xc # Debug for task and services locally PROVISIONING_DEBUG_CHECK
--xr # Debug for remote servers PROVISIONING_DEBUG_REMOTE
--xld # Log level with DEBUG PROVISIONING_LOG_LEVEL=debug
--nc # Not clean working settings
--metadata # Error with metadata (-xm)
--notitles # not tittles
--environment: string # Environment override (dev/test/prod)
-v # Show version
--version (-V) # Show version with title
--info (-I) # Show Info with title
--about (-a) # Show About
--helpinfo (-h) # For more details use options "help" (no dashes)
--out: string # Print Output format: json, yaml, text (default)
--view # Print with highlight
--inputfile: string # Input format: json, yaml, text (default)
--include_notuse # Include servers not use
]: nothing -> nothing {
if ($out | is-not-empty) {
$env.PROVISIONING_OUT = $out
$env.PROVISIONING_NO_TERMINAL = true
}
provisioning_init $helpinfo "" $args
if $version or $v { ^$env.PROVISIONING_NAME -v ; exit }
if $info { ^$env.PROVISIONING_NAME -i ; exit }
if $about {
#use defs/about.nu [ about_info ]
_print (get_about_info)
exit
}
if $debug { $env.PROVISIONING_DEBUG = true }
if $metadata { $env.PROVISIONING_METADATA = true }
if ($environment | is-not-empty) { $env.PROVISIONING_ENV = $environment }
let task = if ($args | length) > 0 { ($args| get 0) } else { if ($new | is-not-empty) { "new" } else { "" } }
let ops = if ($args | length) > 0 {
($args| skip 1)
} else {
( $"($env.PROVISIONING_ARGS? | default "") " | str replace $"($task) " ""
| str trim | split row " ")
}
let str_ops = ($ops | str join " ")
match $task {
# "upcloud" => {
# #use upcloud/servers.nu upcloud
# if $infra == null {
# upcloud $args
# } else {
# upcloud --infra $infra $args
# }
# },
# "aws" => {
# #use aws/servers.nu aws
# if $infra == null {
# aws $args
# } else {
# aws --infra $infra $args
# }
# },
# "local" => {
# #use local/servers.nu local
# if $infra == null {
# local $args
# } else {
# local --infra $infra $args
# }
# },
"h" => {
^($env.PROVISIONING_NAME) help ($env.PROVISIONING_ARGS | str replace $task '') "--notitles"
},
"cache" => {
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let str_outfile = if $outfile != null { $"--outfile ($outfile) "} else { "" }
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_infra) ($str_out) ($str_outfile)" "server" "cache"
},
"providers" => {
#use defs/lists.nu *
_print $"(_ansi green)PROVIDERS(_ansi reset) list: \n"
_print (providers_list "selection" | to json) "json" "result" "table"
},
"ssh" => {
#use servers/ssh.nu *
#use utils/settings.nu *
let curr_settings = (find_get_settings --infra $infra --settings $settings $include_notuse)
rm -rf $curr_settings.wk_path
server_ssh $curr_settings "" "pub" false
}
"sed" | "sops" => {
if ($ops | length) == -2 {
(throw-error $"🛑 No file found" $"for (_ansi yellow_bold)sops(_ansi reset) edit")
exit -1
}
let pos = if $task == "sed" { 0 } else { 1 }
let target_file = ($ops | get -o $pos | default "")
let target_full_path = if ($target_file | path exists) == false {
let infra_path = (get_infra $infra)
if ($infra_path | path join $target_file | path exists) {
($infra_path | path join $target_file)
} else {
(throw-error $"🛑 No file (_ansi green_italic)($target_file)(_ansi reset) found" $"for (_ansi yellow_bold)sops(_ansi reset) edit")
exit -1
}
} else { $target_file }
if $env.PROVISIONING_SOPS? == null {
let curr_settings = (find_get_settings --infra $infra --settings $settings $include_notuse)
rm -rf $curr_settings.wk_path
$env.CURRENT_INFRA_PATH = ($curr_settings.infra_path | path join $curr_settings.infra)
use sops_env.nu
}
#use sops on_sops
if $task == "sed" {
on_sops "sed" $target_full_path
} else {
on_sops $task $target_full_path ($ops | skip 1)
}
},
"e" | "env" => {
# Check if this is the new environment management system
let subcmd = ($ops | get -o 0 | default "")
if $subcmd in ["list" "current" "switch" "validate" "compare" "show" "init" "detect" "set" "paths" "create" "delete" "export" "status"] {
# Use new environment management system
use lib_provisioning/cmd/environment.nu *
match $subcmd {
"list" => { env list }
"current" => { env current }
"switch" => {
let target_env = ($ops | get -o 1 | default "")
if ($target_env | is-empty) {
print "Usage: env switch <environment>"
exit 1
}
env switch $target_env
}
"validate" => {
let target_env = ($ops | get -o 1 | default "")
env validate $target_env
}
"compare" => {
let env1 = ($ops | get -o 1 | default "")
let env2 = ($ops | get -o 2 | default "")
if ($env1 | is-empty) or ($env2 | is-empty) {
print "Usage: env compare <env1> <env2>"
exit 1
}
env compare $env1 $env2
}
"show" => {
let target_env = ($ops | get -o 1 | default "")
env show $target_env
}
"init" => {
let target_env = ($ops | get -o 1 | default "")
if ($target_env | is-empty) {
print "Usage: env init <environment>"
exit 1
}
env init $target_env
}
"detect" => { env detect }
"set" => {
let target_env = ($ops | get -o 1 | default "")
if ($target_env | is-empty) {
print "Usage: env set <environment>"
exit 1
}
env set $target_env
}
"paths" => {
let target_env = ($ops | get -o 1 | default "")
env paths $target_env
}
"create" => {
let target_env = ($ops | get -o 1 | default "")
if ($target_env | is-empty) {
print "Usage: env create <environment>"
exit 1
}
env create $target_env
}
"delete" => {
let target_env = ($ops | get -o 1 | default "")
if ($target_env | is-empty) {
print "Usage: env delete <environment>"
exit 1
}
env delete $target_env
}
"export" => {
let target_env = ($ops | get -o 1 | default "")
env export $target_env
}
"status" => {
let target_env = ($ops | get -o 1 | default "")
env status $target_env
}
_ => {
print "Environment Management Commands:"
print " env list - List available environments"
print " env current - Show current environment"
print " env switch <env> - Switch to environment"
print " env validate [env] - Validate environment"
print " env compare <e1> <e2> - Compare environments"
print " env show [env] - Show environment config"
print " env init <env> - Initialize environment"
print " env detect - Detect current environment"
print " env set <env> - Set environment variable"
print " env paths [env] - Show environment paths"
print " env create <env> - Create new environment"
print " env delete <env> - Delete environment"
print " env export [env] - Export environment config"
print " env status [env] - Show environment status"
}
}
} else {
# Fall back to legacy environment display
match $out {
"json" => { _print (show_env | to json) "json" "result" "table" },
"yaml" => { _print (show_env | to yaml) "yaml" "result" "table" },
"toml" => { _print (show_env | to toml) "toml" "result" "table" },
_ => { print (show_env | table -e) } ,
}
}
},
"allenv" => {
let all_env = {
env: (show_env),
providers: (on_list "providers" "-" ""),
taskservs: (on_list "taskservs" "-" ""),
clusters: (on_list "clusters" "-" ""),
infras: (on_list "infras" "-" ""),
itemdefs: {
providers: (find_provgendefs),
taskserv: (
open ($env.PROVISIONING_TASKSERVS_PATH | path join $env.PROVISIONING_GENERATE_DIRPATH | path join $env.PROVISIONING_GENERATE_DEFSFILE)
)
}
}
if ($view) {
match $out {
"json" => ($all_env | to json | highlight),
"yaml" => ($all_env | to yaml | highlight),
"toml" => ($all_env | to toml | highlight),
_ => ($all_env | to json | highlight),
}
} else {
match $out {
"json" => { _print ($all_env | to json) "json" "result" "table" },
"yaml" => { _print ($all_env | to yaml) "yaml" "result" "table" },
"toml" => { _print ($all_env | to toml) "toml" "result" "table" },
_ => { print ($all_env | to json) } ,
}
}
},
"show" => {
match ($ops | get -o 0 | default "") {
"h" |"help" => {
print (provisioning_show_options)
exit
},
}
let curr_settings = (find_get_settings --infra $infra --settings $settings $include_notuse)
if ($curr_settings | is-empty) {
if ($out | is-empty) {
_print $"🛑 Errors found in infra (_ansi yellow_bold)($infra)(_ansi reset) notuse ($include_notuse)"
print ($curr_settings | describe)
print $settings
}
exit
}
let show_info = (get_show_info $ops $curr_settings ($out | default ""))
if ($view) {
match $out {
"json" => { print ($show_info | to json | highlight json) },
"yaml" => { print ($show_info | to yaml | highlight yaml) },
"toml" => { print ($show_info | to toml | highlight toml) },
_ => { print ($show_info | to json | highlight) },
}
} else {
match $out {
"json" => { _print ($show_info | to json) "json" "result" "table" },
"yaml" => { _print ($show_info | to yaml) "yaml" "result" "table" },
"toml" => { _print ($show_info | to toml) "toml" "result" "table" },
_ => { print ($show_info | to json) } ,
}
}
},
"c" | "create" => {
let use_debug = if $debug or $env.PROVISIONING_DEBUG { "-x"} else { "" }
let use_check = if $check { "--check "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let str_out = if $outfile != null { $"--outfile ($outfile) "} else { "" }
exec $"($env.PROVISIONING_NAME)" $use_debug "create" $str_ops $use_check $str_infra $str_out --notitles
},
"d" | "delete" => {
let use_debug = if $debug { "-x"} else { "" }
let use_check = if $check { "--check "} else { "" }
let use_yes = if $yes { "--yes "} else { "" }
let use_keepstorage = if $keepstorage { "--keepstorage "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
exec $"($env.PROVISIONING_NAME)" "delete" $str_ops $use_check $use_yes $use_keepstorage $str_infra --notitles
},
"u" | "update" => {
let use_debug = if $debug { "-x"} else { "" }
let use_check = if $check { "--check "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
exec $"($env.PROVISIONING_NAME)" "update" $str_ops $use_check $str_infra --notitles
},
"cst" | "create-server-task" | "csts" | "create-servers-tasks" => {
run_module $str_ops "server" "create"
if $env.LAST_EXIT_CODE != 0 {
_print $"🛑 Errors found in (_ansi yellow_bold)create-server(_ansi reset)"
exit 1
}
run_module $"- ($str_ops)" "taskserv" "create"
},
"s" | "server" => {
let use_check = if $check { "--check "} else { "" }
let use_yes = if $yes { "--yes" } else { "" }
let use_wait = if $wait { "--wait" } else { "" }
let use_keepstorage = if $keepstorage { "--keepstorage "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let str_outfile = if $outfile != null { $"--outfile ($outfile) "} else { "" }
let str_out = if $out != null { $"--out ($out) "} else { "" }
let arg_include_notuse = if $include_notuse { $"--include_notuse "} else { "" }
run_module $"($str_ops) ($str_infra) ($use_check) ($str_out) ($str_outfile) ($use_yes) ($use_wait) ($use_keepstorage) ($arg_include_notuse)" "server" --exec
},
"price" | "prices" | "cost" | "costs" => {
let use_check = if $check { "--check "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let str_out = if $outfile != null { $"--outfile ($outfile) "} else { "" }
run_module $"($str_ops) ($str_infra) ($use_check) ($str_out)" "server" "price" --exec
},
"t" | "task" | "taskserv" => {
let use_check = if $check { "--check "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
run_module $"($str_ops) ($str_infra) ($use_check)" "taskserv" --exec
},
"cl" | "cluster" => {
let use_check = if $check { "--check "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
run_module $"($str_ops) ($str_infra) ($use_check)" "cluster" --exec
},
"g" | "gen" | "generate" => {
match ($ops | get -o 0 | default "") {
"h" |"help" => {
print (provisioning_generate_options)
exit
},
}
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let use_debug = if $debug { "-x"} else { "" }
let use_check = if $check { "--check "} else { "" }
let str_out = if $outfile != null { $"--outfile ($outfile) "} else { "" }
let str_input = if $inputfile != null { $"--inputfile ($inputfile) "} else { "" }
let str_template = if ($template != null) { $"--template ($template)" } else { "" }
let str_select = if ($select != null) { $"--select ($select)" } else { "" }
if ($str_ops | is-empty) {
exec $"($env.PROVISIONING_NAME)" $use_debug "generate" $str_ops $use_check $str_infra $str_out --notitles
} else {
let target = ($ops | get -o 0)
let gen_ops = ($ops | skip 1 | str join " ") + $" ($str_infra) ($str_template) ($str_out) ($use_check) ($use_debug) ($str_select) ($str_input)"
match $target {
"s" | "server" => { run_module $"- ($gen_ops)" "server" "generate" --exec },
"t" | "task" | "taskserv" => { run_module $"- ($gen_ops)" "taskserv" "generate" --exec },
"i" | "infra" | "infras" => { run_module $"- ($gen_ops)" "infra" "generate" --exec },
"cl" | "cluster" => { run_module $"- ($gen_ops)" "cluster" "generate" --exec },
"h" | "help" => {
_print $"\n(provisioning_generate_options)"
exit
},
"new" => {
exec $"($env.PROVISIONING_NAME)" $use_debug "generate" "new" $gen_ops $str_template $use_check $str_infra $str_out --notitles
},
"_" => {
invalid_task "" $target --end
exit
}
}
}
print $"($str_ops) ($str_infra)"
#generate
},
"ctx" | "context" => {
^$"($env.PROVISIONING_NAME)" "context" $str_ops --notitles
run_module $str_ops "" --exec
},
"setup" | "st" | "config" => {
run_module $str_ops "setup" --exec
},
"init" => {
# Initialize user configuration
match ($ops | get -o 0 | default "") {
"config" => {
# Initialize user config with template selection
use lib_provisioning/config/loader.nu init-user-config
let template_type = ($ops | get -o 1 | default "user")
let force_flag = ($ops | any {|op| $op == "--force" or $op == "-f"})
print "🚀 Initializing user configuration"
print "=================================="
print ""
init-user-config --template $template_type --force $force_flag
}
"help" | "h" => {
print "📋 Init Command Help"
print "===================="
print ""
print "Initialize user configuration from templates:"
print ""
print "Commands:"
print " init config [template] [--force] Initialize user config"
print ""
print "Templates:"
print " user General user configuration (default)"
print " dev Development environment optimized"
print " prod Production environment optimized"
print " test Testing environment optimized"
print ""
print "Options:"
print " --force, -f Overwrite existing configuration"
print ""
print "Examples:"
print " provisioning init config"
print " provisioning init config dev"
print " provisioning init config prod --force"
}
_ => {
print "❌ Unknown init command. Use 'provisioning init help' for available options."
}
}
},
"tpl" | "tmpl" | "template" => {
# Workspace template management (infrastructure patterns)
let use_check = if $check { "--check "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_infra) ($use_check) ($str_out)" "template" --exec
}
"ws" | "workspace" => {
# Workspace management
let use_check = if $check { "--check "} else { "" }
let use_yes = if $yes { "--yes" } else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_infra) ($use_check) ($use_yes) ($str_out)" "workspace" --exec
}
"mod" | "module" => {
let use_check = if $check { "--check "} else { "" }
let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_infra) ($use_check) ($str_out)" "module" --exec
}
"lyr" | "layer" => {
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_out)" "layer" --exec
}
"version" => {
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_out)" "version" --exec
}
"pack" => {
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_out)" "pack" --exec
}
"wf" | "flow" | "workflow" => {
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($str_out)" "workflow" --exec
}
"bat" | "batch" => {
let use_check = if $check { "--check "} else { "" }
let use_wait = if $wait { "--wait" } else { "" }
let str_out = if $out != null { $"--out ($out) "} else { "" }
run_module $"($str_ops) ($use_check) ($use_wait) ($str_out)" "batch" --exec
}
"orch" | "orchestrator" => {
run_module $"($str_ops)" "orchestrator" --exec
}
"control-center" => {
run_module $"($str_ops)" "control-center" --exec
}
"mcp-server" => {
run_module $"($str_ops)" "mcp-server" --exec
}
"config-template" => {
# Configuration template management (config.*.toml templates)
match ($ops | get -o 0 | default "") {
"list" => {
print "📋 Available Configuration Templates"
print "==================================="
print ""
let project_root = $env.PWD
let templates = [
{ name: "user", file: "config.user.toml.example", description: "General user configuration with comprehensive documentation" }
{ name: "dev", file: "config.dev.toml.example", description: "Development environment with enhanced debugging" }
{ name: "prod", file: "config.prod.toml.example", description: "Production environment with security and performance focus" }
{ name: "test", file: "config.test.toml.example", description: "Testing environment with mock providers and CI/CD integration" }
]
for template in $templates {
let template_path = ($project_root | path join $template.file)
let status = if ($template_path | path exists) { "✅" } else { "❌" }
print $"($status) ($template.name) - ($template.description)"
if ($template_path | path exists) {
print $" 📁 ($template_path)"
} else {
print $" ❌ Template file not found: ($template_path)"
}
print ""
}
print "💡 Usage: provisioning init config [template_name]"
}
"show" => {
# Show template content
let template_name = ($ops | get -o 1 | default "")
if ($template_name | is-empty) {
print "❌ Please specify a template name. Use 'provisioning config-template list' to see available templates."
return
}
let template_file = match $template_name {
"user" => "config.user.toml.example"
"dev" => "config.dev.toml.example"
"prod" => "config.prod.toml.example"
"test" => "config.test.toml.example"
_ => {
print $"❌ Unknown template: ($template_name). Valid options: user, dev, prod, test"
return
}
}
let project_root = $env.PWD
let template_path = ($project_root | path join $template_file)
if not ($template_path | path exists) {
print $"❌ Template file not found: ($template_path)"
return
}
print $"📄 Template: ($template_name)"
print $"📁 Path: ($template_path)"
print "=" * 80
print ""
# Show template content using configured file viewer
let file_viewer = ($env.PROVISIONING_FILE_VIEWER? | default "less")
^$file_viewer $template_path
}
"validate" => {
# Validate all templates
print "🔍 Validating Configuration Templates"
print "====================================="
print ""
let project_root = $env.PWD
let templates = ["config.user.toml.example", "config.dev.toml.example", "config.prod.toml.example", "config.test.toml.example"]
mut all_valid = true
for template in $templates {
let template_path = ($project_root | path join $template)
print $"🔍 Validating ($template)..."
if not ($template_path | path exists) {
print $" ❌ File not found: ($template_path)"
$all_valid = false
continue
}
# Basic TOML syntax validation and section checking
print " ✅ TOML syntax assumed valid (template file)"
let config_data = (open $template_path)
# Check if config_data is a record (properly parsed TOML)
if (($config_data | describe) == "record") {
let required_sections = ["core", "paths", "debug", "output"]
for section in $required_sections {
if ($config_data | get -o $section | is-not-empty) {
print $" ✅ Required section present: ($section)"
} else {
print $" ⚠️ Section missing or empty: ($section)"
}
}
} else {
print " ⚠️ Template contains only comments/documentation (no active config sections)"
}
print ""
}
if $all_valid {
print "✅ All templates validated successfully!"
} else {
print "❌ Some templates have validation issues"
}
}
"help" | "h" => {
print "📋 Configuration Template Command Help"
print "======================================"
print ""
print "Manage configuration file templates (config.*.toml):"
print ""
print "Commands:"
print " config-template list List available config templates"
print " config-template show <name> Show template content"
print " config-template validate Validate all templates"
print ""
print "Examples:"
print " provisioning config-template list"
print " provisioning config-template show dev"
print " provisioning config-template validate"
}
_ => {
print "❌ Unknown config-template command. Use 'provisioning config-template help' for available options."
}
}
},
"i" | "infra" | "infras" => {
if ($str_ops | str contains "help") or $str_ops == "h" {
run_module "help" "infra"
exit -2
}
let infra_ops = if ($infra | is-not-empty) { $"-i ($infra)"
} else if $infras != null {
$"--infras ($infras)"
} else {
$"-i (get_infra | path basename)"
}
let use_yes = if $yes { "--yes"} else { "" }
let use_check = if $check { "--check"} else { "" }
let use_onsel = if $onsel != null { $"--onsel ($onsel)"} else { "" }
run_module $"($str_ops) ($infra_ops) ($use_check) ($use_onsel) ($use_yes)" "infra"
},
"deploy-rm" | "deploy-del" | "dp-rm" | "d-r" | "destroy" => {
let curr_settings = (find_get_settings --infra $infra --settings $settings)
deploy_remove $curr_settings ($str_ops | split row "-" | get -o 0 | default "")
rm -rf $curr_settings.wk_path
if $task == "destroy" {
let with_yes = if $yes { "--yes" } else { "" }
exec $"($env.PROVISIONING_NAME)" "delete" server --notitles $with_yes
}
},
"deploy-sel" | "deploy-list" | "dp-sel" | "d-s" => {
let curr_settings = (find_get_settings --infra $infra --settings $settings)
deploy_list $curr_settings ($str_ops | split row "-" | get -o 0 | default "") ($onsel | default "")
rm -rf $curr_settings.wk_path
},
"deploy-sel-tree" | "deploy-list-tree" | "dp-sel-t" | "d-st" => {
let curr_settings = (find_get_settings --infra $infra --settings $settings)
(deploy_list $curr_settings $str_ops "tree")
rm -rf $curr_settings.wk_path
},
"nu" => {
let run_ops = if ($str_ops | str trim | str starts-with "-") {
""
} else {
($ops | get -o 0)
}
if ($infra | is-not-empty) and ($env.PROVISIONING_INFRA_PATH | path join $infra |path exists) {
cd ($env.PROVISIONING_INFRA_PATH | path join $infra)
}
if ($env.PROVISIONING_OUT | is-empty) {
if ($run_ops | is-empty) {
print (
$"\nTo exit (_ansi purple_bold)NuShell(_ansi reset) session, with (_ansi default_dimmed)lib_provisioning(_ansi reset) loaded, " +
$"use (_ansi green_bold)exit(_ansi reset) or (_ansi green_bold)[CTRL-D](_ansi reset)"
)
^nu -i -e $"use lib_provisioning * ; use env.nu * ; show_titles;"
#^nu -e $"use lib_provisioning * ; show_titles; $env.PROMPT_INDICATOR = {|| 'provisioning> ' } ; $env.PROMPT_COMMAND = {|| create_left_prompt } "
} else {
^nu -c $"($run_ops)"
}
}
},
"list" | "l" | "ls" => {
#use defs/lists.nu on_list
let target_list = if ($args | length) > -1 { ($args| get -o 1 | default "") } else { "" }
let list_ops = ($ops | str join " " | str replace $"($target_list) " "" | str trim)
on_list $target_list ($onsel | default "") $list_ops
},
"qr" => {
#use utils/qr.nu *
make_qr
},
"nuinfo" => {
print $"\n (_ansi yellow)Nu shell info(_ansi reset)"
print (version)
},
"plugin" | "plugins" => {
print $"\n (_ansi yellow)Nu shell Plugins(_ansi reset)"
^nu -c "plugin list"
},
"new" => {
let str_new = ($new | default "")
print $"\n (_ansi yellow)New Infra ($str_new)(_ansi reset)"
},
"ai" => {
# AI command module
let str_infra = if $infra != null { $"--infra ($infra) " } else { "" }
let str_settings = if $settings != null { $"--settings ($settings) " } else { "" }
let str_out = if $out != null { $"--out ($out) " } else { "" }
run_module $"($str_ops) ($str_infra) ($str_settings) ($str_out)" "ai" --exec
},
"validate" | "val" => {
# Infrastructure validation module
let sub_command = ($ops | get -o 0 | default "")
match $sub_command {
"help" | "h" => {
use main_provisioning/ops.nu *
print (provisioning_validate_options)
}
"config" => {
# Configuration validation
print "🔍 Configuration Validation"
print "=========================="
print ""
# Load configuration using the config loader
use lib_provisioning/config/loader.nu *
let config_result = (load-provisioning-config --debug $debug --validate false)
# Run detailed validation
let strict_mode = (($ops | get -o 1 | default "") == "strict")
let validation_result = (validate-config $config_result --detailed true --strict $strict_mode)
print $"📊 Validation Summary:"
print $" • Structure valid: ($validation_result.summary.structure_valid)"
print $" • Paths valid: ($validation_result.summary.paths_valid)"
print $" • Types valid: ($validation_result.summary.types_valid)"
print $" • Semantic rules valid: ($validation_result.summary.semantic_valid)"
print $" • File references valid: ($validation_result.summary.files_valid)"
print ""
if ($validation_result.errors | length) > 0 {
print "❌ Errors found:"
for error in $validation_result.errors {
print $" • [($error.severity | str upcase)] ($error.message)"
}
print ""
}
if ($validation_result.warnings | length) > 0 {
print "⚠️ Warnings found:"
for warning in $validation_result.warnings {
print $" • [($warning.severity | str upcase)] ($warning.message)"
}
print ""
}
if $validation_result.valid {
print "✅ Configuration validation passed!"
print ""
print " All configuration checks completed successfully."
print " Configuration is ready for use."
exit 0
} else {
print "❌ Configuration validation failed!"
print ""
print " Please fix the errors above before proceeding."
exit 1
}
}
"interpolation" | "interp" => {
# Enhanced interpolation validation and testing
use lib_provisioning/config/loader.nu *
let interp_command = ($ops | get -o 1 | default "test")
match $interp_command {
"test" => {
# Test interpolation with sample data
let sample_type = ($ops | get -o 2 | default "basic")
test-interpolation --sample $sample_type
}
"validate" => {
# Validate interpolation patterns in current config
print "🔍 Interpolation Pattern Validation"
print "==================================="
print ""
let config_result = (load-provisioning-config --debug $debug --validate false)
let validation_result = (validate-interpolation $config_result --detailed true)
if $validation_result.valid {
print "✅ Interpolation validation passed!"
print $" • ($validation_result.summary.interpolation_patterns_detected) patterns processed"
} else {
print "❌ Interpolation validation failed!"
for error in $validation_result.errors {
print $" • [ERROR] ($error.message)"
}
}
if ($validation_result.warnings | length) > 0 {
print ""
print "⚠️ Warnings:"
for warning in $validation_result.warnings {
print $" • [WARNING] ($warning.message)"
}
}
print ""
print $"📊 Summary: ($validation_result.summary.total_errors) errors, ($validation_result.summary.total_warnings) warnings"
}
"testsuite" | "suite" => {
# Run comprehensive interpolation test suite
print "🧪 Running Comprehensive Interpolation Test Suite"
print "================================================="
print ""
let output_file = ($ops | get -o 2 | default "interpolation_test_results.json")
let suite_results = (create-interpolation-test-suite --output-file $output_file)
print ""
print "🎯 Test Suite Results:"
print $" Success rate: ($suite_results.success_rate)%"
print $" Total tests: ($suite_results.total)"
print $" Passed: ($suite_results.passed)"
print $" Failed: ($suite_results.failed)"
if $suite_results.failed > 0 {
exit 1
}
}
"show" => {
# Show interpolation patterns and results
let mode = ($ops | get -o 2 | default "interpolated")
print "📋 Configuration Interpolation View"
print "===================================="
print ""
let config_result = (load-provisioning-config --debug $debug --validate false)
match $mode {
"raw" => {
print "🔍 Raw configuration (before interpolation):"
print ""
# Load config without interpolation
let raw_config = (load-provisioning-config --debug $debug --validate false)
print ($raw_config | to json)
}
"interpolated" => {
print "✨ Interpolated configuration:"
print ""
print ($config_result | to json)
}
"patterns" => {
print "🔍 Detected interpolation patterns:"
print ""
# Convert to JSON and find all patterns
let json_str = ($config_result | to json)
# Simple pattern detection
if ($json_str | str contains "{{") {
print " Found interpolation patterns in configuration"
# This is a simplified implementation
let pattern_count = (count-interpolation-patterns $json_str)
print $" Total patterns: ($pattern_count)"
} else {
print " No interpolation patterns found"
}
}
_ => {
print "❌ Unknown show mode. Valid options: raw, interpolated, patterns"
}
}
}
"help" | "h" => {
print "📋 Interpolation Command Help"
print "=============================="
print ""
print "Enhanced interpolation features for advanced configuration templating:"
print ""
print "Commands:"
print " validate interpolation test [sample] Test interpolation with sample data"
print " validate interpolation validate Validate interpolation patterns"
print " validate interpolation show [mode] Show interpolation results"
print " validate interpolation testsuite [file] Run comprehensive test suite"
print ""
print "Sample Types:"
print " basic Basic interpolation patterns ({{paths.base}}, {{env.HOME}})"
print " advanced Advanced patterns (git info, providers, conditionals)"
print " all All interpolation features"
print ""
print "Show Modes:"
print " raw Show configuration before interpolation"
print " interpolated Show configuration after interpolation (default)"
print " patterns Show detected interpolation patterns"
print ""
print "Supported Interpolation Patterns:"
print " {{paths.base}} Base path interpolation"
print " {{env.HOME}}, {{env.USER}} Environment variables"
print " {{now.date}}, {{now.timestamp}} Date/time values"
print " {{git.branch}}, {{git.commit}} Git repository information"
print " {{sops.key_file}} SOPS configuration"
print " {{providers.aws.region}} Cross-section references"
print " {{path.join(paths.base, \"dir\")}} Function calls"
print " {{env.HOME || \"/tmp\"}} Conditional expressions"
print ""
print "Examples:"
print " provisioning validate interpolation test basic"
print " provisioning validate interpolation validate"
print " provisioning validate interpolation show raw"
print " provisioning validate interpolation testsuite"
}
_ => {
print "❌ Unknown interpolation command. Use 'provisioning validate interpolation help' for options."
}
}
}
"test" => {
# Run the test script directly
nu test_validation.nu
}
"quick" => {
let target_path = if $infra != null { $infra } else {
let next_arg = ($ops | get -o 1 | default ".")
if ($next_arg | path exists) { $next_arg } else { "." }
}
print "🚀 Quick Infrastructure Validation"
print "=================================="
print ""
print $"📁 Target: ($target_path | path expand)"
print ""
print "🔄 Running quick validation (errors and critical issues only)..."
print ""
let result = (nu test_validation.nu | complete)
if $result.exit_code == 0 {
print "✅ Quick validation passed!"
print ""
print " No critical errors or blocking issues found."
print $" Infrastructure ($target_path) is ready for deployment."
} else {
print "❌ Quick validation found issues"
print ""
print " Please review and fix critical/error-level issues before deployment."
}
print ""
}
"rules" => {
# Show rules list
print "📋 Available Validation Rules"
print "============================"
print ""
print "🔧 👁️ VAL001: 🚨 YAML Syntax Validation (critical)"
print " Category: syntax | Severity: critical | Auto-fix: false"
print ""
print "🔧 👁️ VAL002: 🚨 KCL Compilation Check (critical)"
print " Category: compilation | Severity: critical | Auto-fix: false"
print ""
print "🔧 ✅ VAL003: ❌ Unquoted Variable References (error)"
print " Category: syntax | Severity: error | Auto-fix: true"
print ""
print "🔧 👁️ VAL004: ❌ Required Fields Validation (error)"
print " Category: schema | Severity: error | Auto-fix: false"
print ""
print "🔧 ✅ VAL005: ⚠️ Resource Naming Conventions (warning)"
print " Category: best_practices | Severity: warning | Auto-fix: true"
print ""
print "🔧 👁️ VAL006: ❌ Basic Security Checks (error)"
print " Category: security | Severity: error | Auto-fix: false"
print ""
print "🔧 👁️ VAL007: ⚠️ Version Compatibility Check (warning)"
print " Category: compatibility | Severity: warning | Auto-fix: false"
print ""
print "🔧 👁️ VAL008: ❌ Network Configuration Validation (error)"
print " Category: networking | Severity: error | Auto-fix: false"
print ""
print "Legend:"
print "✅ = Auto-fixable | 👁️ = Manual fix required"
print "🚨 = Critical | ❌ = Error | ⚠️ = Warning | = Info"
}
_ => {
# Execute actual validation
let target_path = if $infra != null {
$infra
} else if ($sub_command | path exists) {
$sub_command
} else {
# Use current directory if it contains infrastructure files
# Check for common infrastructure indicators: settings.k, kcl.mod, or .k files
let current_dir = "."
let has_settings = ($current_dir | path join "settings.k" | path exists)
let has_kcl_mod = ($current_dir | path join "kcl.mod" | path exists)
let has_k_files = ((glob "*.k") | length) > 0
if $has_settings or $has_kcl_mod or $has_k_files {
$current_dir
} else {
# If no infrastructure files in current dir, show help
use main_provisioning/ops.nu *
print (provisioning_validate_options)
return
}
}
print "🔍 Infrastructure Validation & Review Tool"
print "=========================================="
print ""
print $"📁 Validating: ($target_path | path expand)"
print ""
# Check if target path exists
if not ($target_path | path exists) {
print $"🛑 Infrastructure path not found: ($target_path)"
print ""
print "Use 'provisioning validate help' for usage information"
exit 1
}
# Run the validation using our working test system
print "🔄 Running infrastructure validation..."
print ""
# Run basic validation directly without external script dependency
# Count and validate infrastructure files recursively
let k_files = (glob "**/*.k")
let yaml_files = (glob "**/*.yaml" | append (glob "**/*.yml"))
let toml_files = (glob "**/*.toml")
let total_files = ($k_files | length) + ($yaml_files | length) + ($toml_files | length)
print $"📊 Found ($total_files) infrastructure files:"
print $" • KCL files: ($k_files | length)"
print $" • YAML files: ($yaml_files | length)"
print $" • TOML files: ($toml_files | length)"
print ""
# Simple validation checks
mut issues = []
# Check for settings.k file
if ("settings.k" | path exists) {
print "✅ settings.k file found"
} else {
print "⚠️ No settings.k file found"
$issues = ($issues | append "Missing settings.k file")
}
# Basic KCL syntax check for each .k file
for file in $k_files {
print $"🔍 Checking KCL file: ($file)"
# Check if file is SOPS encrypted
let content = (open $file --raw)
let is_sops_file = ($content | str contains "\"sops\":") or ($content | str contains "ENC[AES256_GCM")
if $is_sops_file {
# Handle SOPS encrypted file
print $" 🔐 ($file) - SOPS encrypted file detected"
# Set up SOPS environment using the config-driven approach
$env.PROVISIONING_USE_SOPS = ($env.PROVISIONING_USE_SOPS? | default "age")
$env.PROVISIONING_SOPS = ($env.PROVISIONING_SOPS? | default "")
use lib_provisioning/sops/lib.nu get_def_age
let kage_path = (get_def_age $env.PROVISIONING_KLOUD_PATH)
if ($kage_path | is-not-empty) and ($kage_path | path exists) {
$env.SOPS_AGE_KEY_FILE = $kage_path
}
# Check if SOPS can decrypt it
let sops_check = (^sops -d $file | complete)
if $sops_check.exit_code == 0 {
# Try to validate the decrypted content
let kcl_check = (^sops -d $file | ^kcl - | complete)
if $kcl_check.exit_code == 0 {
print $" ✅ ($file) - SOPS encrypted KCL syntax OK"
} else {
print $" ❌ ($file) - SOPS encrypted KCL syntax error"
$issues = ($issues | append $"KCL syntax error in SOPS file ($file)")
}
} else {
print $" ⚠️ ($file) - SOPS decryption failed - check keys/config"
print $" Skipping validation (SOPS error: ($sops_check.stderr | str trim))"
# Don't add to issues - this might be expected if keys aren't available
}
} else {
# Regular KCL file validation
let check_result = (^kcl $file | complete)
if $check_result.exit_code == 0 {
print $" ✅ ($file) - KCL syntax OK"
} else {
print $" ❌ ($file) - KCL syntax error"
$issues = ($issues | append $"KCL syntax error in ($file)")
}
}
}
# Basic YAML syntax check
for file in $yaml_files {
print $"🔍 Checking YAML file: ($file)"
let yaml_result = (^yq eval . $file | complete)
if $yaml_result.exit_code == 0 {
print $" ✅ ($file) - YAML syntax OK"
} else {
print $" ❌ ($file) - YAML syntax error"
$issues = ($issues | append $"YAML syntax error in ($file)")
}
}
let result = {
exit_code: (if ($issues | length) > 0 { 1 } else { 0 })
issues: $issues
}
print ""
if $result.exit_code == 0 {
print "✅ Validation completed successfully!"
print ""
print "📊 Summary:"
print " • No critical issues found"
print " • All infrastructure files are valid"
print " • Infrastructure is ready for deployment"
print ""
print $"📁 Files processed in: ($target_path | path expand)"
print ""
print "💡 For detailed validation options, use:"
print " provisioning validate help"
} else {
print "❌ Validation found issues"
print ""
print "🔍 Issues found:"
for issue in $result.issues {
print $" • ($issue)"
}
print ""
print "💡 Please fix these issues before deployment"
print " Use 'provisioning validate help' for more options"
}
}
}
},
_ => {
invalid_task "" $task --end
exit
},
}
if not $env.PROVISIONING_DEBUG { end_run "" }
#print $"($env.PWD)\n($env.FILE_PWD)\n($env.PROCESS_PATH)\n"
}
export def get_show_info [
ops: list
curr_settings: record
out: string
]: nothing -> record {
match ($ops | get -o 0 | default "") {
"set" |"setting" | "settings" => $curr_settings,
"def" | "defs" |"defsetting" | "defsettings" => {
let src = ($curr_settings | get -o src | default "");
let src_path = ($curr_settings | get -o src_path | default "");
let def_settings = if ($src_path | path join $src | path exists) {
open -r ($src_path | path join $src)
} else { "" }
let main_path = ($env.PROVISIONING | path join "kcl" | path join "settings.k")
let src_main_settings = if ($main_path | path exists) {
open -r $main_path
} else { "" }
{
def: $src,
def_path: $src_path,
infra: ($curr_settings | get -o infra | default ""),
infra_path: ($curr_settings | get -o infra_path | default ""),
def_settings: $def_settings,
main_path: $main_path,
main_settings: $src_main_settings,
}
},
"server" |"servers" | "s" => {
let servers = ($curr_settings | get -o data | get -o servers | default {})
let item = ($ops | get -o 1 | default "")
if ($item | is-empty) {
$servers
} else {
let server = (find_server $item $servers ($out | default ""))
let def_target = ($ops | get -o 2 | default "")
match $def_target {
"t" | "task" | "taskserv" => {
let task = ($ops | get -o 3 | default "")
(find_taskserv $curr_settings $server $task ($out | default ""))
},
_ => $server,
}
}
},
"serverdefs" |"serversdefs" | "sd" => {
(find_serversdefs $curr_settings)
},
"provgendefs" |"provgendef" | "pgd" => {
(find_provgendefs)
},
"taskservs" |"taskservs" | "ts" => {
#(list_taskservs $curr_settings)
let list_taskservs = (taskservs_list)
if ($list_taskservs | length) == 0 {
_print $"🛑 no items found for (_ansi cyan)taskservs list(_ansi reset)"
return
}
$list_taskservs
},
"taskservsgendefs" |"taskservsgendef" | "tsd" => {
let defs_path = ($env.PROVISIONING_TASKSERVS_PATH | path join $env.PROVISIONING_GENERATE_DIRPATH | path join $env.PROVISIONING_GENERATE_DEFSFILE)
if ($defs_path | path exists) {
open $defs_path
}
},
"cost" | "costs" | "c" | "price" | "prices" | "p" => {
(servers_walk_by_costs $curr_settings "" false false "stdout")
},
"alldata" => ($curr_settings | get -o data | default {}
| merge { costs: (servers_walk_by_costs $curr_settings "" false false "stdout") }
),
"data" | _ => {
if ($out | is-not-empty) {
($curr_settings | get -o data | default {})
} else {
print ($" (_ansi cyan_bold)($curr_settings | get -o data | get -o main_name | default '')"
+ $"(_ansi reset): (_ansi yellow_bold)($curr_settings | get -o data | get -o main_title | default '') (_ansi reset)"
)
print ($curr_settings | get -o data | default {} | merge { servers: ''})
($curr_settings | get -o data | default {} | get -o servers | each {|item|
print $"\n server: (_ansi cyan_bold)($item.hostname | default '') (_ansi reset)"
print $item
})
""
}
},
}
}