1330 lines
54 KiB
Plaintext
1330 lines
54 KiB
Plaintext
|
|
#!/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
|
|||
|
|
})
|
|||
|
|
""
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
}
|