406 lines
15 KiB
Plaintext
Raw Normal View History

2025-10-07 10:32:04 +01:00
# Infrastructure Command Handlers
# Handles: server, taskserv, cluster, infra commands
use ../flags.nu *
use ../../lib_provisioning *
use ../../lib_provisioning/plugins/auth.nu *
2025-10-07 10:32:04 +01:00
# Pre-load server module to preserve plugin context (tera, auth, kms, etc.)
# This is needed so template rendering and other plugin operations work
# in the same Nushell process
use ../../servers/create.nu *
2025-10-07 10:32:04 +01:00
# Helper to run module commands
# Modules are pre-loaded above to preserve plugin context
2025-10-07 10:32:04 +01:00
def run_module [
args: string
module: string
subcommand?: string # Optional explicit subcommand (for create operations)
2025-10-07 10:32:04 +01:00
--exec
] {
# Convert args string to list by splitting on spaces
let args_list = if ($args | is-not-empty) {
$args | split row " " | where {|x| ($x | str trim | is-not-empty) }
2025-10-07 10:32:04 +01:00
} else {
[]
}
# Call the appropriate module's main function
# Server module is pre-loaded above, so plugins (tera, auth, kms, etc.) are in scope
match $module {
"server" => {
# For server: call the "main create" function directly from the already-loaded servers/create.nu
# This preserves the tera plugin context in the same process
# If subcommand is explicitly provided (from handle_server), use it
# Otherwise, extract from args
let actual_subcommand = if ($subcommand | is-not-empty) {
$subcommand
} else {
let op_list = ($args | split row " " | where { |x| ($x | is-not-empty) })
if ($op_list | length) > 0 { $op_list | first } else { "help" }
}
# For now, only handle "create" directly. For others, use -mod
match $actual_subcommand {
"create" | "c" => {
# The servers/create.nu is pre-loaded at the top of this file
# Call "main create" function directly with the arguments
# This preserves the tera plugin context in the same process
let use_debug = if ($env.PROVISIONING_DEBUG? | default false) { "-x" } else { "" }
let cmd_args = [-mod, "server", "create", ...$args_list]
exec $"($env.PROVISIONING_NAME)" $use_debug ...$cmd_args
}
_ => {
# For other operations (delete, list, ssh, etc.), use -mod
let use_debug = if ($env.PROVISIONING_DEBUG? | default false) { "-x" } else { "" }
let cmd_args = [-mod, "server", ...$args_list]
exec $"($env.PROVISIONING_NAME)" $use_debug ...$cmd_args
}
}
}
"taskserv" | "task" => {
# Taskserv uses exec mode
let use_debug = if ($env.PROVISIONING_DEBUG? | default false) { "-x" } else { "" }
let cmd_args = [-mod, $module, ...$args_list, --notitles]
exec $"($env.PROVISIONING_NAME)" $use_debug ...$cmd_args
}
"cluster" => {
# Cluster uses exec mode
let use_debug = if ($env.PROVISIONING_DEBUG? | default false) { "-x" } else { "" }
let cmd_args = [-mod, $module, ...$args_list, --notitles]
exec $"($env.PROVISIONING_NAME)" $use_debug ...$cmd_args
}
"infra" => {
# Infra uses exec mode since it's a legacy module
let use_debug = if ($env.PROVISIONING_DEBUG? | default false) { "-x" } else { "" }
let cmd_args = [-mod, $module, ...$args_list, --notitles]
exec $"($env.PROVISIONING_NAME)" $use_debug ...$cmd_args
}
_ => {
print $"❌ Unknown module: ($module)"
exit 1
}
2025-10-07 10:32:04 +01:00
}
}
# Main infrastructure command dispatcher
export def handle_infrastructure_command [
command: string
ops: string
flags: record
] {
set_debug_env $flags
match $command {
"create" | "c" => {
# Handle: provisioning create server/taskserv/cluster <name> ...
let create_ops_list = if ($ops | is-not-empty) {
$ops | split row " " | where {|x| ($x | is-not-empty) }
} else { [] }
let resource_type = if (($create_ops_list | length) > 0) {
$create_ops_list | first
} else { "" }
let resource_name_and_args = if (($create_ops_list | length) > 1) {
$create_ops_list | skip 1 | str join " "
} else { "" }
match $resource_type {
"server" | "s" => { handle_server $"create $resource_name_and_args" $flags }
"taskserv" | "task" | "t" => { handle_taskserv $"create $resource_name_and_args" $flags }
"cluster" | "cl" => { handle_cluster $"create $resource_name_and_args" $flags }
_ => {
if ($resource_type | is-empty) {
print "❌ Resource type required for create command"
} else {
print $"❌ Unknown resource type for create: ($resource_type)"
}
print ""
print "Usage: provisioning create <resource> <name>"
print ""
print "Resources:"
print " server (s) - Create a server"
print " taskserv (t) - Create a task service"
print " cluster (cl) - Create a cluster"
exit 1
}
}
}
"delete" | "d" => {
# Handle: provisioning delete server/taskserv/cluster <name> ...
let delete_ops_list = if ($ops | is-not-empty) {
$ops | split row " " | where {|x| ($x | is-not-empty) }
} else { [] }
let resource_type = if (($delete_ops_list | length) > 0) {
$delete_ops_list | first
} else { "" }
let resource_name_and_args = if (($delete_ops_list | length) > 1) {
$delete_ops_list | skip 1 | str join " "
} else { "" }
match $resource_type {
"server" | "s" => { handle_server $"delete $resource_name_and_args" $flags }
"taskserv" | "task" | "t" => { handle_taskserv $"delete $resource_name_and_args" $flags }
"cluster" | "cl" => { handle_cluster $"delete $resource_name_and_args" $flags }
_ => {
print $"❌ Unknown resource type for delete: ($resource_type)"
exit 1
}
}
}
2025-10-07 10:32:04 +01:00
"server" => { handle_server $ops $flags }
"taskserv" | "task" => { handle_taskserv $ops $flags }
"cluster" => { handle_cluster $ops $flags }
"vm" => {
# Import VM domain handler
use vm_domain.nu handle_vm_command
# Parse VM subcommand
let vm_ops_list = if ($ops | is-not-empty) {
$ops | split row " " | where {|x| ($x | is-not-empty) }
} else { [] }
let vm_command = if (($vm_ops_list | length) > 0) {
$vm_ops_list | first
} else { "vm" }
let vm_remaining_ops = if (($vm_ops_list | length) > 1) {
$vm_ops_list | skip 1 | str join " "
} else { "" }
handle_vm_command $vm_command $vm_remaining_ops $flags
}
2025-10-07 10:32:04 +01:00
"infra" | "infras" => { handle_infra $ops $flags }
_ => {
print $"❌ Unknown infrastructure command: ($command)"
print ""
print "Available infrastructure commands:"
print " server - Server management (create, delete, list, ssh, price)"
print " taskserv - Task service management (create, delete, list, generate)"
print " cluster - Cluster operations (create, delete, list)"
print " vm - Virtual machine management (create, list, start, stop, delete)"
2025-10-07 10:32:04 +01:00
print " infra - Infrastructure management (list, validate, generate)"
print ""
print "Use 'provisioning help infrastructure' for more details"
exit 1
}
}
}
# Server command handler
def handle_server [ops: string, flags: record] {
# Show help if no subcommand provided
if ($ops | is-empty) {
print "Server Management"
print "================="
print ""
print "Usage: provisioning server <command> [options]"
print ""
print "Commands:"
print " create <name> Create a new server"
print " delete <name> Delete a server"
print " list List all servers"
print " ssh <name> SSH into server"
print " price Show server pricing"
print ""
print "Examples:"
print " provisioning server create web-01"
print " provisioning server list"
print " provisioning server ssh web-01"
print ""
return
}
# Authentication check for server operations (metadata-driven)
let operation_parts = ($ops | split row " " | where {|x| ($x | is-not-empty)})
let action = if ($operation_parts | is-empty) { "" } else { $operation_parts | first }
# Determine operation type
let operation_type = match $action {
"create" | "c" => "create"
"delete" | "d" | "remove" => "delete"
"modify" | "update" => "modify"
_ => "read"
}
# Check authentication using metadata-driven approach
if not (is-check-mode $flags) and $operation_type != "read" {
let operation_name = $"server ($action)"
check-operation-auth $operation_name $operation_type $flags
}
# Extract the remaining arguments after the action verb (create/delete/list/etc)
let action_and_args = if ($operation_parts | length) > 1 {
$operation_parts | skip 1 | str join " "
} else {
""
}
let args = build_module_args $flags $action_and_args
# Pass the action as explicit subcommand so run_module knows which operation is being performed
# For create operations, this preserves plugin context by calling "main create" directly
run_module $args "server" $action --exec
2025-10-07 10:32:04 +01:00
}
# Task service command handler
def handle_taskserv [ops: string, flags: record] {
# Show help if no subcommand provided
if ($ops | is-empty) {
print "Task Service Management"
print "======================"
print ""
print "Usage: provisioning taskserv <command> [options]"
print ""
print "Commands:"
print " create <service> Create a task service"
print " delete <service> Delete a task service"
print " list List all task services"
print " generate <service> Generate task service config"
print ""
print "Service Mesh Options:"
print " istio - Full-featured service mesh with built-in ingress gateway"
print " linkerd - Lightweight service mesh (requires external ingress)"
print " cilium - CNI with service mesh capabilities"
print ""
print "Ingress Controller Options:"
print " nginx-ingress - Most popular, battle-tested ingress controller"
print " traefik - Modern cloud-native ingress with middleware"
print " contour - Envoy-based ingress with simple configuration"
print " haproxy-ingress - High-performance HAProxy-based ingress"
print ""
print "Examples:"
print " provisioning taskserv create kubernetes"
print " provisioning taskserv create istio"
print " provisioning taskserv create linkerd"
print " provisioning taskserv create nginx-ingress"
print " provisioning taskserv create traefik"
print " provisioning taskserv list"
print ""
print "Recommended Combinations:"
print " 1. Linkerd + Nginx Ingress - Lightweight mesh + proven ingress"
print " 2. Istio (standalone) - Full-featured with built-in gateway"
print " 3. Linkerd + Traefik - Lightweight mesh + modern ingress"
print " 4. No mesh + Nginx Ingress - Simple deployments"
print ""
return
}
# Authentication check for taskserv operations (metadata-driven)
let operation_parts = ($ops | split row " ")
let action = if ($operation_parts | is-empty) { "" } else { $operation_parts | first }
# Determine operation type
let operation_type = match $action {
"create" | "c" => "create"
"delete" | "d" | "remove" => "delete"
"modify" | "update" => "modify"
_ => "read"
}
# Check authentication using metadata-driven approach
if not (is-check-mode $flags) and $operation_type != "read" {
let operation_name = $"taskserv ($action)"
check-operation-auth $operation_name $operation_type $flags
}
2025-10-07 10:32:04 +01:00
let args = build_module_args $flags $ops
run_module $args "taskserv" --exec
}
# Cluster command handler
def handle_cluster [ops: string, flags: record] {
# Show help if no subcommand provided
if ($ops | is-empty) {
print "Cluster Management"
print "=================="
print ""
print "Usage: provisioning cluster <command> [options]"
print ""
print "Commands:"
print " create <name> Create a new cluster"
print " delete <name> Delete a cluster"
print " list List all clusters"
print ""
print "Examples:"
print " provisioning cluster create k8s-prod"
print " provisioning cluster list"
print ""
return
}
# Authentication check for cluster operations (metadata-driven)
let operation_parts = ($ops | split row " ")
let action = if ($operation_parts | is-empty) { "" } else { $operation_parts | first }
# Determine operation type
let operation_type = match $action {
"create" | "c" => "create"
"delete" | "d" | "remove" | "destroy" => "delete"
"modify" | "update" => "modify"
_ => "read"
}
# Check authentication using metadata-driven approach
if not (is-check-mode $flags) and $operation_type != "read" {
let operation_name = $"cluster ($action)"
check-operation-auth $operation_name $operation_type $flags
}
2025-10-07 10:32:04 +01:00
let args = build_module_args $flags $ops
run_module $args "cluster" --exec
}
# Infrastructure command handler
def handle_infra [ops: string, flags: record] {
# Handle infra-specific argument building
let infra_arg = if ($flags.infra | is-not-empty) {
$"-i ($flags.infra)"
} else if ($flags.infras | is-not-empty) {
$"--infras ($flags.infras)"
} else {
$"-i (get_infra | path basename)"
}
let use_yes = if $flags.auto_confirm { "--yes" } else { "" }
let use_check = if $flags.check_mode { "--check" } else { "" }
let use_onsel = if ($flags.onsel | is-not-empty) {
$"--onsel ($flags.onsel)"
} else { "" }
let args = $"($ops) ($infra_arg) ($use_check) ($use_onsel) ($use_yes)" | str trim
run_module $args "infra"
}
# Price/cost command handler
export def handle_price_command [ops: string, flags: record] {
let use_check = if $flags.check_mode { "--check " } else { "" }
let str_infra = if ($flags.infra | is-not-empty) {
$"--infra ($flags.infra) "
} else { "" }
let str_out = if ($flags.outfile | is-not-empty) {
$"--outfile ($flags.outfile) "
} else { "" }
run_module $"($ops) ($str_infra) ($use_check) ($str_out)" "server" "price" --exec
}
# Create-server-task combined command handler
export def handle_create_server_task [ops: string, flags: record] {
# Create servers first
let server_args = build_module_args $flags $ops
run_module $server_args "server" "create"
# Check if server creation succeeded
if $env.LAST_EXIT_CODE != 0 {
_print $"🛑 Errors found in (_ansi yellow_bold)create-server(_ansi reset)"
exit 1
}
# Create taskservs
let taskserv_args = build_module_args $flags $"- ($ops)"
run_module $taskserv_args "taskserv" "create"
}