prvng_core/nulib/provisioning template

440 lines
13 KiB
Plaintext
Raw Normal View History

2025-10-07 10:32:04 +01:00
#!/usr/bin/env nu
# Info: Script to run Provisioning Template Management
# Author: JesusPerezLorenzo
# Release: 1.0.0
# Date: 29-09-2025
use std log
use lib_provisioning *
use env.nu *
# - > Help on Template
export def "main help" [
--src: string = ""
--notitles # not titles
--out: string # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
if $notitles == null or not $notitles { show_titles }
^$"($env.PROVISIONING_NAME)" -mod template --help
if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
print (provisioning_options $src)
if not $env.PROVISIONING_DEBUG { end_run "" }
}
# > Template Management
def main [
...args: string # Other options, use help to get info
-v # Show version
-i # Show Info
--version (-V) # Show version with title
--info (-I) # Show Info with title
--about (-a) # Show About
--infra: string # Infrastructure name
--provider: string = "" # Provider name
--type: string = "" # Template type: taskservs, providers, servers, clusters
--layer: string = "workspace" # Layer: core, workspace, infra
--dry-run # Show what would be done without doing it
--backup # Create backup before operations
--force (-f) # Force operation
--check (-c) # Only check mode, no actual changes
--yes (-y) # Confirm task
--debug (-x) # Use Debug mode
--xm # Debug with PROVISIONING_METADATA
--xld # Log level with DEBUG PROVISIONING_LOG_LEVEL=debug
--metadata # Error with metadata (-xm)
--notitles # Do not show banner titles
--helpinfo (-h) # For more details use options "help" (no dashes)
--out: string # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
if ($out | is-not-empty) {
$env.PROVISIONING_OUT = $out
$env.PROVISIONING_NO_TERMINAL = true
}
provisioning_init $helpinfo "template" $args
if $version or $v { ^$env.PROVISIONING_NAME -v ; exit }
if $info or $i { ^$env.PROVISIONING_NAME -i ; exit }
if $about {
_print (get_about_info)
exit
}
if $debug { $env.PROVISIONING_DEBUG = true }
if $metadata { $env.PROVISIONING_METADATA = true }
let task = if ($args | length) > 0 { ($args | get 0) } else { "" }
let ops = $"($env.PROVISIONING_ARGS? | default "") " | str replace $" ($task) " "" | str trim
let template_name = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
($ops | split row " " | get 0)
} else {
""
}
let target_infra = if ($ops | split row " " | length) > 1 {
($ops | split row " " | get 1)
} else {
$infra
}
$env.PROVISIONING_MODULE = "template"
match $task {
"h" | "help" => {
# Redirect to main categorized help system
exec $"($env.PROVISIONING_NAME)" help workspace --notitles
},
"list" | "ls" => {
template_list --type $type --out $out
},
"types" => {
template_types --out $out
},
"show" => {
if ($template_name | is-empty) {
print "❌ Template name required"
print "Usage: provisioning template show <name>"
exit 1
}
template_show $template_name --type $type --out $out
},
"apply" => {
if ($template_name | is-empty) or ($target_infra | is-empty) {
print "❌ Template name and target infrastructure required"
print "Usage: provisioning template apply <template_name> <infra_name> --provider <provider>"
exit 1
}
if $dry_run {
template_apply $template_name $target_infra --provider $provider --dry-run
} else {
template_apply $template_name $target_infra --provider $provider
}
},
"extract" => {
if ($target_infra | is-empty) {
print "❌ Infrastructure name required"
print "Usage: provisioning template extract <infra_name>"
exit 1
}
if $dry_run {
template_extract $target_infra --type $type --dry-run
} else {
template_extract $target_infra --type $type
}
},
"convert" => {
if ($target_infra | is-empty) {
print "❌ Infrastructure name required"
print "Usage: provisioning template convert <infra_name>"
exit 1
}
if $backup and $dry_run {
template_convert $target_infra --backup --dry-run
} else if $backup {
template_convert $target_infra --backup
} else if $dry_run {
template_convert $target_infra --dry-run
} else {
template_convert $target_infra
}
},
"validate" => {
if ($target_infra | is-empty) {
print "❌ Infrastructure name required"
print "Usage: provisioning template validate <infra_name>"
exit 1
}
template_validate $target_infra
},
"layer" => {
template_layer_info --infra $target_infra --out $out
},
_ => {
print $"❌ Unknown task: ($task)"
print "Use 'provisioning template help' for available commands"
exit 1
}
}
}
# List available templates
def template_list [
--type: string
--out: string
]: nothing -> nothing {
let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
let templates_path = ($provisioning_root | path join "workspace" "templates")
if not ($templates_path | path exists) {
print "❌ Templates directory not found"
exit 1
}
let template_types = if ($type | is-not-empty) {
[$type]
} else {
["taskservs", "providers", "servers", "clusters"]
}
let all_templates = ($template_types | each {|ttype|
let type_path = ($templates_path | path join $ttype)
if ($type_path | path exists) {
let items = (ls $type_path | where type == dir | select name)
$items | each {|item| {
type: $ttype
name: ($item.name | path basename)
path: $item.name
}}
} else {
[]
}
} | flatten)
if ($out | is-not-empty) {
if $out == "json" {
print ($all_templates | to json)
} else if $out == "yaml" {
print ($all_templates | to yaml)
} else {
print ($all_templates | table)
}
} else {
print "📋 Available Templates:"
for template in $all_templates {
print $" [($template.type)] ($template.name)"
}
}
}
# List template types
def template_types [--out: string]: nothing -> nothing {
let types = [
{type: "taskservs", description: "Task service configurations (kubernetes, containerd, etc.)"}
{type: "providers", description: "Cloud provider templates (upcloud, aws, local)"}
{type: "servers", description: "Server configuration patterns"}
{type: "clusters", description: "Complete cluster templates"}
]
if ($out | is-not-empty) {
if $out == "json" {
print ($types | to json)
} else if $out == "yaml" {
print ($types | to yaml)
} else {
print ($types | table)
}
} else {
print "📁 Template Types:"
for t in $types {
print $" ($t.type): ($t.description)"
}
}
}
# Show template details
def template_show [
name: string
--type: string
--out: string
]: nothing -> nothing {
let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
let templates_path = ($provisioning_root | path join "workspace" "templates")
let template_types = if ($type | is-not-empty) {
[$type]
} else {
["taskservs", "providers", "servers", "clusters"]
}
let found = ($template_types | each {|ttype|
let template_path = ($templates_path | path join $ttype $name)
if ($template_path | path exists) {
let files = (ls $template_path | select name type size)
{
type: $ttype
name: $name
path: $template_path
files: $files
}
} else {
null
}
} | where {|x| $x != null} | first)
if ($found | is-empty) {
print $"❌ Template not found: ($name)"
exit 1
}
if ($out | is-not-empty) {
_print $found
} else {
print $"📦 Template: ($found.name)"
print $" Type: ($found.type)"
print $" Path: ($found.path)"
print " Files:"
for file in $found.files {
print $" - ($file.name | path basename) [($file.type)] ($file.size)"
}
}
}
# Apply template to infrastructure
def template_apply [
template_name: string
target_infra: string
--provider: string
--dry-run
]: nothing -> nothing {
let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
let templates_path = ($provisioning_root | path join "workspace" "templates")
# Find template
let template_types = ["taskservs", "providers", "servers", "clusters"]
let template_path = ($template_types | each {|ttype|
let path = ($templates_path | path join $ttype $template_name)
if ($path | path exists) {
{type: $ttype, path: $path}
} else {
null
}
} | where {|x| $x != null} | first)
if ($template_path | is-empty) {
print $"❌ Template not found: ($template_name)"
exit 1
}
let config = get-config
let workspace_root = $config.paths.base? | default $env.PWD
let target_path = ($workspace_root | path join "infra" $target_infra)
if not ($target_path | path exists) {
print $"❌ Infrastructure not found: ($target_infra)"
exit 1
}
if $dry_run {
print $"🔍 DRY RUN: Would apply template ($template_name) to ($target_infra)"
print $" Template type: ($template_path.type)"
print $" Template path: ($template_path.path)"
print $" Target path: ($target_path)"
print $" Provider: ($provider)"
} else {
print $"🔧 Applying template ($template_name) to ($target_infra)"
let target_subdir = match $template_path.type {
"taskservs" => "task-servs"
"providers" => "defs"
"servers" => "defs"
"clusters" => "clusters"
_ => $template_path.type
}
let dest_dir = ($target_path | path join $target_subdir)
mkdir $dest_dir
# Copy template files
cp -r ($template_path.path | path join "*") $dest_dir
print $"✅ Template applied: ($template_name) -> ($target_infra)"
print $"📁 Files copied to: ($dest_dir)"
}
}
# Extract patterns from infrastructure
def template_extract [
infra_name: string
--type: string
--dry-run
]: nothing -> nothing {
let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
let migrate_script = ($provisioning_root | path join "workspace" "tools" "migrate-infra.nu")
if not ($migrate_script | path exists) {
print $"❌ Migration script not found: ($migrate_script)"
exit 1
}
let type_flag = if ($type | is-not-empty) { ["--type" $type] } else { [] }
let dry_run_flag = if $dry_run { ["--dry-run"] } else { [] }
^nu $migrate_script extract $infra_name ...$type_flag ...$dry_run_flag
}
# Convert infrastructure to use templates
def template_convert [
infra_name: string
--backup
--dry-run
]: nothing -> nothing {
let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
let migrate_script = ($provisioning_root | path join "workspace" "tools" "migrate-infra.nu")
if not ($migrate_script | path exists) {
print $"❌ Migration script not found: ($migrate_script)"
exit 1
}
let backup_flag = if not $backup { ["--no-backup"] } else { [] }
let dry_run_flag = if $dry_run { ["--dry-run"] } else { [] }
^nu $migrate_script convert $infra_name ...$backup_flag ...$dry_run_flag
}
# Validate template usage in infrastructure
def template_validate [infra_name: string]: nothing -> nothing {
let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
let migrate_script = ($provisioning_root | path join "workspace" "tools" "migrate-infra.nu")
if not ($migrate_script | path exists) {
print $"❌ Migration script not found: ($migrate_script)"
exit 1
}
^nu $migrate_script validate $infra_name
}
# Show layer information
def template_layer_info [
--infra: string
--out: string
]: nothing -> nothing {
let layers = [
{
name: "core"
priority: 100
path: "provisioning/extensions/"
description: "Base provisioning system extensions"
}
{
name: "workspace"
priority: 200
path: "provisioning/workspace/templates/"
description: "Shared templates and reusable configurations"
}
{
name: "infrastructure"
priority: 300
path: $"workspace/infra/($infra | default '{name}')/"
description: "Infrastructure-specific configurations and overrides"
}
]
if ($out | is-not-empty) {
if $out == "json" {
print ($layers | to json)
} else if $out == "yaml" {
print ($layers | to yaml)
} else {
print ($layers | table)
}
} else {
print "🏗️ Layer Resolution Order:"
print " (Higher priority overrides lower priority)"
print ""
for layer in ($layers | reverse) {
print $" ($layer.priority) - ($layer.name | str upcase)"
print $" Path: ($layer.path)"
print $" ($layer.description)"
print ""
}
}
}