refactor(cli): single-route CLI entry — delete legacy Nu runner (ADR-025 Phase 4 B)
This commit is contained in:
parent
e8f86d0997
commit
271f41aa53
6 changed files with 374 additions and 587 deletions
|
|
@ -51,7 +51,7 @@ fi
|
||||||
export PROVISIONING_RESOURCES=${PROVISIONING_RESOURCES:-"$PROVISIONING/resources"}
|
export PROVISIONING_RESOURCES=${PROVISIONING_RESOURCES:-"$PROVISIONING/resources"}
|
||||||
PROVIISONING_WKPATH=${PROVIISONING_WKPATH:-/tmp/tmp.}
|
PROVIISONING_WKPATH=${PROVIISONING_WKPATH:-/tmp/tmp.}
|
||||||
|
|
||||||
RUNNER="provisioning"
|
RUNNER="provisioning-cli.nu"
|
||||||
PROVISIONING_MODULE=""
|
PROVISIONING_MODULE=""
|
||||||
PROVISIONING_MODULE_TASK=""
|
PROVISIONING_MODULE_TASK=""
|
||||||
|
|
||||||
|
|
@ -68,8 +68,8 @@ _show_help() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Fallback: Call Nushell for help (will use daemon if available)
|
# Fallback: Call Nushell for help via single CLI entry
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/$RUNNER" help $category
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cli.nu" help $category
|
||||||
}
|
}
|
||||||
|
|
||||||
# Workflow help function (defined early for early help detection)
|
# Workflow help function (defined early for early help detection)
|
||||||
|
|
@ -995,11 +995,9 @@ _validate_command() {
|
||||||
# - Daemon fallback: Automatic, user sees no difference
|
# - Daemon fallback: Automatic, user sees no difference
|
||||||
|
|
||||||
if [ -n "$PROVISIONING_MODULE" ]; then
|
if [ -n "$PROVISIONING_MODULE" ]; then
|
||||||
if [[ -x $PROVISIONING/core/nulib/$RUNNER\ $PROVISIONING_MODULE ]]; then
|
# -mod <module> mode: provisioning-cli.nu reads PROVISIONING_MODULE from env
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/$RUNNER $PROVISIONING_MODULE" $CMD_ARGS
|
# and dispatches to the module's main function directly.
|
||||||
else
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cli.nu" $CMD_ARGS </dev/null
|
||||||
echo "Error \"$PROVISIONING/core/nulib/$RUNNER $PROVISIONING_MODULE\" not found"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
# Only redirect stdin for non-interactive commands (nu command needs interactive stdin)
|
# Only redirect stdin for non-interactive commands (nu command needs interactive stdin)
|
||||||
if [ "${1:-}" = "nu" ]; then
|
if [ "${1:-}" = "nu" ]; then
|
||||||
|
|
@ -1058,15 +1056,14 @@ else
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/main_provisioning/workspace.nu" $CMD_ARGS </dev/null
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/main_provisioning/workspace.nu" $CMD_ARGS </dev/null
|
||||||
;;
|
;;
|
||||||
env | allenv | list | ls | l | provider | providers | validate | plugin | plugins | nuinfo)
|
env | allenv | list | ls | l | provider | providers | validate | plugin | plugins | nuinfo)
|
||||||
# Safe commands - can use /dev/null
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cli.nu" $CMD_ARGS </dev/null
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/$RUNNER" $CMD_ARGS </dev/null
|
|
||||||
;;
|
;;
|
||||||
platform | plat | p)
|
platform | plat | p)
|
||||||
# logs needs interactive stdin for typedialog — use full entry.
|
# logs needs interactive stdin for typedialog — keep stdin open.
|
||||||
# All other platform subcommands use the thin entry (~50ms vs ~9s).
|
# All other platform subcommands use the thin entry (~50ms vs ~3s).
|
||||||
case "${2:-}" in
|
case "${2:-}" in
|
||||||
logs | log)
|
logs | log)
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/$RUNNER" $CMD_ARGS
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cli.nu" $CMD_ARGS
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-platform.nu" $CMD_ARGS </dev/null
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-platform.nu" $CMD_ARGS </dev/null
|
||||||
|
|
@ -1095,7 +1092,7 @@ else
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-workflow.nu" $CMD_ARGS </dev/null
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-workflow.nu" $CMD_ARGS </dev/null
|
||||||
;;
|
;;
|
||||||
alias)
|
alias)
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/$RUNNER" $CMD_ARGS </dev/null
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cli.nu" $CMD_ARGS </dev/null
|
||||||
;;
|
;;
|
||||||
create | new)
|
create | new)
|
||||||
# "prvng create server ..." → "prvng server create ..."
|
# "prvng create server ..." → "prvng server create ..."
|
||||||
|
|
@ -1113,7 +1110,7 @@ else
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cluster.nu" cluster create "$@" </dev/null
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cluster.nu" cluster create "$@" </dev/null
|
||||||
exit $? ;;
|
exit $? ;;
|
||||||
*)
|
*)
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/$RUNNER" create "$_resource" "$@"
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cli.nu" create "$_resource" "$@"
|
||||||
exit $? ;;
|
exit $? ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
|
@ -1158,9 +1155,9 @@ else
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/main_provisioning/fip.nu" "${@:2}"
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/main_provisioning/fip.nu" "${@:2}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
# All other commands (create, delete, server, taskserv, etc.) - keep stdin open
|
# All other commands — provisioning-cli.nu is the single fallback entry.
|
||||||
# NOTE: PROVISIONING_MODULE is automatically inherited by Nushell from bash environment
|
# stdin kept open for interactive commands (delete, update, etc.).
|
||||||
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/$RUNNER" $CMD_ARGS
|
$NU "${NU_ARGS[@]}" "$PROVISIONING/core/nulib/provisioning-cli.nu" $CMD_ARGS
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
|
|
||||||
export use plugins_defs.nu *
|
|
||||||
export use utils *
|
|
||||||
#export use cmd *
|
|
||||||
export use defs *
|
|
||||||
export use sops *
|
|
||||||
export use kms *
|
|
||||||
export use secrets *
|
|
||||||
export use ai *
|
|
||||||
export use context.nu *
|
|
||||||
export use setup *
|
|
||||||
#export use deploy.nu *
|
|
||||||
export use extensions *
|
|
||||||
# providers.nu deleted (ADR-025 blocker 3) — callers import directly from
|
|
||||||
# extensions/providers/prov_lib/middleware.nu
|
|
||||||
export use workspace *
|
|
||||||
export use config *
|
|
||||||
export use diagnostics *
|
|
||||||
#export use tera_daemon *
|
|
||||||
#export use fluent_daemon *
|
|
||||||
|
|
@ -7,11 +7,15 @@
|
||||||
|
|
||||||
# Command module imports are lazy — loaded inside wrapper functions at dispatch time.
|
# Command module imports are lazy — loaded inside wrapper functions at dispatch time.
|
||||||
# Only load lib_provisioning helpers required for routing logic in dispatch_command itself.
|
# Only load lib_provisioning helpers required for routing logic in dispatch_command itself.
|
||||||
|
#
|
||||||
|
# ADR-025 Phase 4: narrowed from stars to selective imports. The two prior
|
||||||
|
# imports `commands/traits.nu *` (20 exports) and `utils/command-registry.nu *`
|
||||||
|
# (3 exports) were fully DEAD here — zero symbol uses — and have been removed.
|
||||||
|
# `enforcement.nu` and `metadata_handler.nu` are narrowed to the single symbol
|
||||||
|
# each that dispatcher actually calls (`check-and-enforce`, `validate-and-prepare`).
|
||||||
use ../lib_provisioning/utils/undefined.nu [invalid_task]
|
use ../lib_provisioning/utils/undefined.nu [invalid_task]
|
||||||
use ../lib_provisioning/workspace/enforcement.nu *
|
use ../lib_provisioning/workspace/enforcement.nu [check-and-enforce]
|
||||||
use ../lib_provisioning/commands/traits.nu *
|
use ./metadata_handler.nu [validate-and-prepare]
|
||||||
use ./metadata_handler.nu *
|
|
||||||
use ../lib_provisioning/utils/command-registry.nu *
|
|
||||||
use ../lib_provisioning/utils/nickel_processor.nu [ncl-eval-soft, default-ncl-paths]
|
use ../lib_provisioning/utils/nickel_processor.nu [ncl-eval-soft, default-ncl-paths]
|
||||||
|
|
||||||
# Helper to run module commands
|
# Helper to run module commands
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
export use ops.nu *
|
|
||||||
|
|
||||||
export use query.nu *
|
|
||||||
|
|
||||||
# create.nu, delete.nu, status.nu, update.nu are handled by dispatcher
|
|
||||||
# Do not export them to avoid "main create", "main delete" etc conflicting with dispatch routing
|
|
||||||
# export use create.nu *
|
|
||||||
# export use delete.nu *
|
|
||||||
# export use status.nu *
|
|
||||||
# export use update.nu *
|
|
||||||
export use generate.nu *
|
|
||||||
|
|
||||||
# Modular command system (refactored)
|
|
||||||
export use flags.nu *
|
|
||||||
export use dispatcher.nu *
|
|
||||||
export use commands/guides.nu *
|
|
||||||
|
|
||||||
export use tools.nu *
|
|
||||||
export use sops.nu *
|
|
||||||
export use secrets.nu *
|
|
||||||
export use ai.nu *
|
|
||||||
export use contexts.nu *
|
|
||||||
export use extensions.nu *
|
|
||||||
export use taskserv.nu *
|
|
||||||
|
|
||||||
# Strategic commands
|
|
||||||
export use module.nu *
|
|
||||||
export use layer.nu *
|
|
||||||
export use version.nu *
|
|
||||||
# Commented out - causes infinite loop, use handle_pack in commands/development.nu instead
|
|
||||||
# export use pack.nu *
|
|
||||||
export use workflow.nu *
|
|
||||||
export use ontoref-queries.nu *
|
|
||||||
export use dag.nu *
|
|
||||||
export use components.nu *
|
|
||||||
export use batch.nu *
|
|
||||||
export use bootstrap.nu *
|
|
||||||
export use cluster-deploy.nu *
|
|
||||||
export use orchestrator.nu *
|
|
||||||
export use workspace.nu *
|
|
||||||
export use template.nu *
|
|
||||||
|
|
||||||
# Platform services
|
|
||||||
export use control-center.nu *
|
|
||||||
export use mcp-server.nu *
|
|
||||||
#export use main.nu *
|
|
||||||
|
|
||||||
# export use server.nu *
|
|
||||||
#export use task.nu *
|
|
||||||
|
|
||||||
#export use server/server_delete.nu *
|
|
||||||
|
|
||||||
#export module instances.nu
|
|
||||||
|
|
@ -1,492 +0,0 @@
|
||||||
#!/usr/bin/env nu
|
|
||||||
# Info: Script to run Provisioning
|
|
||||||
# Author: Jesus Perez Lorenzo
|
|
||||||
# Release: 2.0.4
|
|
||||||
# Date: 6-2-2024
|
|
||||||
|
|
||||||
# CRITICAL: Must be in export-env block so it runs DURING PARSING,
|
|
||||||
# not after. This sets up NU_LIB_DIRS before modules are loaded.
|
|
||||||
export-env {
|
|
||||||
# Initialize NU_LIB_DIRS, handling both string (from bash) and list (from Nushell)
|
|
||||||
let lib_dirs_raw = ($env.NU_LIB_DIRS? | default "")
|
|
||||||
let current_lib_dirs = if ($lib_dirs_raw | type) == "string" {
|
|
||||||
if ($lib_dirs_raw | is-empty) {
|
|
||||||
[]
|
|
||||||
} else {
|
|
||||||
($lib_dirs_raw | split row ":")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$lib_dirs_raw
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure known provisioning paths are in NU_LIB_DIRS
|
|
||||||
let default_paths = [
|
|
||||||
"/opt/provisioning/core/nulib"
|
|
||||||
"/usr/local/provisioning/core/nulib"
|
|
||||||
]
|
|
||||||
|
|
||||||
# Combine paths: use default paths first, then add any from current
|
|
||||||
$env.NU_LIB_DIRS = ($default_paths | append $current_lib_dirs)
|
|
||||||
|
|
||||||
# Auto-load tera plugin BEFORE loading any modules
|
|
||||||
# This ensures tera-render is available throughout the script
|
|
||||||
if ( (version).installed_plugins | str contains "tera" ) {
|
|
||||||
(plugin use tera)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use std log
|
|
||||||
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
|
|
||||||
# Bootstrap will be loaded on-demand only when needed for real operations
|
|
||||||
# use lib_provisioning/platform/bootstrap.nu *
|
|
||||||
|
|
||||||
# Helper: Reorder arguments to put flags before positional args
|
|
||||||
# This allows: provisioning workspace update --yes
|
|
||||||
# Instead of requiring: provisioning --yes workspace update
|
|
||||||
# NOTE: Nushell's parameter parsing handles interleaved flags well, so we just return args as-is
|
|
||||||
# This avoids breaking flag:value pairs
|
|
||||||
def reorder_args [args: list]: nothing -> list {
|
|
||||||
$args
|
|
||||||
}
|
|
||||||
|
|
||||||
# Help on provisioning commands
|
|
||||||
export def "main help" [
|
|
||||||
...args: 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 }
|
|
||||||
# Use only the first argument, ignore any extras (e.g., "orch status" -> "orch")
|
|
||||||
let category = if ($args | length) > 0 { ($args | get 0) } else { "" }
|
|
||||||
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
|
|
||||||
--upload (-u) # Upload scripts to server for inspection without executing (use with --check)
|
|
||||||
--yes (-y) # confirm task
|
|
||||||
--wait # 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)
|
|
||||||
--dep-option: string # Workspace dependency option: workspace-home, home-package, git-package, publish-repo
|
|
||||||
--dep-url: string # Dependency URL for git-package or publish-repo
|
|
||||||
--dry-run # Show what would be done without doing it (pack command)
|
|
||||||
--force (-f) # Skip confirmation prompts (pack/delete commands)
|
|
||||||
--all # Process all items (pack clean command)
|
|
||||||
--keep-latest: int # Keep N latest versions (pack clean command)
|
|
||||||
--workspace (-w): string # Workspace name (for bootstrap, cluster deploy, etc.)
|
|
||||||
--activate # Activate workspace as default (workspace commands)
|
|
||||||
--interactive # Interactive workspace creation wizard
|
|
||||||
--org: string # Organization name (for detect/complete commands)
|
|
||||||
--apply # Apply changes (for complete command)
|
|
||||||
--verbose # Verbose output (for detect/complete/workflow commands)
|
|
||||||
--pretty # Pretty-print JSON/YAML output (for detect/complete commands)
|
|
||||||
-v # Show version
|
|
||||||
--version (-V) # Show version with title
|
|
||||||
--info # Show Info with title
|
|
||||||
--about # 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
|
|
||||||
--services: string # Platform services set: core, all, custom (for platform start)
|
|
||||||
]: nothing -> nothing {
|
|
||||||
# Reorder arguments: move flags to the beginning
|
|
||||||
# This allows: provisioning workspace update --yes
|
|
||||||
let reordered_args = (reorder_args $args)
|
|
||||||
|
|
||||||
# Extract flags from reordered args (for flags that came after positional args)
|
|
||||||
let has_yes_in_args = ($reordered_args | any {|x| $x == "--yes" or $x == "-y"})
|
|
||||||
let has_check_in_args = ($reordered_args | any {|x| $x == "--check" or $x == "-c"})
|
|
||||||
let has_upload_in_args = ($reordered_args | any {|x| $x == "--upload" or $x == "-u"})
|
|
||||||
let has_force_in_args = ($reordered_args | any {|x| $x == "--force" or $x == "-f"})
|
|
||||||
let has_verbose_in_args = ($reordered_args | any {|x| $x == "--verbose" or $x == "-v"})
|
|
||||||
let has_wait_in_args = ($reordered_args | any {|x| $x == "--wait"})
|
|
||||||
|
|
||||||
# Combine with already-parsed flags (take OR - if either parsed or in args, then true)
|
|
||||||
let final_yes = ($yes or $has_yes_in_args)
|
|
||||||
let final_check = ($check or $has_check_in_args)
|
|
||||||
let final_upload = ($upload or $has_upload_in_args)
|
|
||||||
let final_force = ($force or $has_force_in_args)
|
|
||||||
let final_verbose = ($verbose or $has_verbose_in_args)
|
|
||||||
let final_wait = ($wait or $has_wait_in_args)
|
|
||||||
|
|
||||||
# Initialize provisioning system
|
|
||||||
provisioning_init $helpinfo "" $reordered_args
|
|
||||||
|
|
||||||
# Parse all flags into normalized structure
|
|
||||||
let parsed_flags = (parse_common_flags {
|
|
||||||
version: $version, v: $v, info: $info, about: $about,
|
|
||||||
debug: $debug, metadata: $metadata, xc: $xc, xr: $xr, xld: $xld,
|
|
||||||
check: $final_check, upload: $final_upload, yes: $final_yes, wait: $final_wait, keepstorage: $keepstorage,
|
|
||||||
nc: $nc, include_notuse: $include_notuse,
|
|
||||||
out: $out, notitles: $notitles, view: $view,
|
|
||||||
infra: $infra, infras: $infras, settings: $settings, outfile: $outfile,
|
|
||||||
template: $template, select: $select, onsel: $onsel, serverpos: $serverpos,
|
|
||||||
new: $new, environment: $environment,
|
|
||||||
dep_option: $dep_option, dep_url: $dep_url,
|
|
||||||
dry_run: $dry_run, force: $final_force, all: $all, keep_latest: $keep_latest,
|
|
||||||
activate: $activate, interactive: $interactive,
|
|
||||||
org: $org, apply: $apply, verbose: $final_verbose, pretty: $pretty,
|
|
||||||
services: $services, workspace: $workspace
|
|
||||||
})
|
|
||||||
|
|
||||||
# Handle version, info, about flags
|
|
||||||
if $parsed_flags.show_version { ^$env.PROVISIONING_NAME -v ; exit }
|
|
||||||
if $parsed_flags.show_info { ^$env.PROVISIONING_NAME -i ; exit }
|
|
||||||
if $parsed_flags.show_about { _print (get_about_info) ; exit }
|
|
||||||
|
|
||||||
# Bootstrap platform services (only if running actual commands, not help/info)
|
|
||||||
# Skip bootstrap for help-like, guide, setup, discovery/info, and utility commands
|
|
||||||
# Updated for Phase 1: Fast-Path Expansion - Include read-only workspace commands
|
|
||||||
let is_help_command = (
|
|
||||||
($reordered_args | length) == 0 or
|
|
||||||
($reordered_args | get 0) in [
|
|
||||||
# Help and guides
|
|
||||||
"help", "-h", "--help",
|
|
||||||
"sc", "shortcuts", "quickstart", "quick",
|
|
||||||
"from-scratch", "scratch",
|
|
||||||
"customize", "custom",
|
|
||||||
"guide", "guides", "howto",
|
|
||||||
# Setup
|
|
||||||
"setup", "st",
|
|
||||||
# Workspace commands (read-only, fast-path)
|
|
||||||
"workspace", "ws",
|
|
||||||
# Discovery and module commands
|
|
||||||
"mod", "module", "discover", "disc",
|
|
||||||
"dt", "dp", "dc",
|
|
||||||
"discover-taskservs", "disc-t",
|
|
||||||
"discover-providers", "disc-p",
|
|
||||||
"discover-clusters", "disc-c",
|
|
||||||
# Development info
|
|
||||||
"lyr", "layer", "version", "pack",
|
|
||||||
# Utilities and info
|
|
||||||
"nuinfo", "env", "allenv",
|
|
||||||
"validate", "val", "show", "config-template",
|
|
||||||
"cache",
|
|
||||||
"list", "l", "ls",
|
|
||||||
"plugin", "plugins",
|
|
||||||
"qr", "ssh", "sops",
|
|
||||||
"providers",
|
|
||||||
# Diagnostics commands (workspace-agnostic)
|
|
||||||
"status", "health", "diagnostics", "next", "phase"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if this is a command that doesn't need platform bootstrap
|
|
||||||
# VM commands and infrastructure commands can work without bootstrap
|
|
||||||
# Also skip bootstrap if --check flag is present (validation mode, no execution needed)
|
|
||||||
let skip_bootstrap = (
|
|
||||||
(($reordered_args | length) > 0 and
|
|
||||||
($reordered_args | get 0) in [
|
|
||||||
# Interactive Nushell session (no bootstrap needed)
|
|
||||||
"nu",
|
|
||||||
# Platform commands (don't need bootstrap)
|
|
||||||
"platform", "plat", "p",
|
|
||||||
# VM commands (info/list only, no bootstrap needed)
|
|
||||||
"vm", "vmi", "vmh", "vml",
|
|
||||||
# Infrastructure commands can work offline
|
|
||||||
"server", "s",
|
|
||||||
"taskserv", "task", "t",
|
|
||||||
"cluster", "cl",
|
|
||||||
"bootstrap",
|
|
||||||
# Create command (with various targets)
|
|
||||||
"create", "c",
|
|
||||||
# Delete command
|
|
||||||
"delete", "d",
|
|
||||||
# Update command
|
|
||||||
"update", "u",
|
|
||||||
# Build commands (image management, doesn't need orchestrator)
|
|
||||||
"build", "b", "bi", "build-image"
|
|
||||||
]) or
|
|
||||||
# Skip bootstrap if in check mode (validation/dry-run, no execution needed)
|
|
||||||
$final_check
|
|
||||||
)
|
|
||||||
|
|
||||||
if (not $is_help_command) and (not $skip_bootstrap) {
|
|
||||||
# Load bootstrap module dynamically when needed
|
|
||||||
use lib_provisioning/platform/bootstrap.nu *
|
|
||||||
let bootstrap_result = (bootstrap-platform --auto-start --timeout=60 --verbose=($final_verbose))
|
|
||||||
if not $bootstrap_result.all_healthy {
|
|
||||||
_print ""
|
|
||||||
_print $"(_ansi red)❌ Platform services not healthy(_ansi reset)"
|
|
||||||
_print ""
|
|
||||||
_print "Failed services:"
|
|
||||||
for service in ($bootstrap_result.services | where {|s| $s.status != "healthy"}) {
|
|
||||||
_print $" - ($service.name): ($service.action)"
|
|
||||||
}
|
|
||||||
_print ""
|
|
||||||
_print "To start services manually:"
|
|
||||||
_print " cd provisioning/platform && docker-compose up -d"
|
|
||||||
_print ""
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# DEBUG
|
|
||||||
if ($env.PROVISIONING_DEBUG? | default false) {
|
|
||||||
print $"DEBUG provisioning: reordered_args = ($reordered_args)" >&2
|
|
||||||
print $"DEBUG provisioning: parsed_flags.infra = (($parsed_flags | get -o infra | default 'MISSING'))" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
# Handle help command BEFORE dispatcher to avoid infinite loop
|
|
||||||
# The dispatcher used to call "exec provisioning help" which created infinite recursion
|
|
||||||
if (($reordered_args | length) > 0) and (($reordered_args | get 0) in ["help", "h"]) {
|
|
||||||
if ($env.PROVISIONING_DEBUG? | default false) {
|
|
||||||
print $"DEBUG: Help command detected, args=($reordered_args)" >&2
|
|
||||||
}
|
|
||||||
let category = if ($reordered_args | length) > 1 { ($reordered_args | get 1) } else { "" }
|
|
||||||
print (provisioning_options $category)
|
|
||||||
if not ($env.PROVISIONING_DEBUG? | default false) { end_run "" }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
# For info/discovery/utility commands, dispatch directly without going through workspace enforcement
|
|
||||||
# These commands don't need workspace context
|
|
||||||
if (($reordered_args | length) > 0) and (($reordered_args | get 0) in [
|
|
||||||
# Guide commands
|
|
||||||
"guide", "guides", "sc", "howto", "shortcuts", "quickstart", "quick",
|
|
||||||
"from-scratch", "scratch", "customize", "custom",
|
|
||||||
# Discovery/info commands
|
|
||||||
"mod", "module", "discover", "disc",
|
|
||||||
"dt", "dp", "dc",
|
|
||||||
"discover-taskservs", "disc-t",
|
|
||||||
"discover-providers", "disc-p",
|
|
||||||
"discover-clusters", "disc-c",
|
|
||||||
"lyr", "layer", "version",
|
|
||||||
"nuinfo", "env", "allenv",
|
|
||||||
"validate", "val", "show", "cache",
|
|
||||||
# Utility commands (these are informational)
|
|
||||||
"plugin", "plugins",
|
|
||||||
"qr", "nuinfo",
|
|
||||||
# Diagnostics commands (workspace-agnostic)
|
|
||||||
"status", "health", "diagnostics", "next", "phase"
|
|
||||||
]) {
|
|
||||||
dispatch_command $reordered_args $parsed_flags
|
|
||||||
if not $env.PROVISIONING_DEBUG { end_run "" }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if we're in module mode (invoked with -mod flag from bash wrapper)
|
|
||||||
# If so, bypass dispatcher and call the module directly
|
|
||||||
if ($env.PROVISIONING_MODULE? | default "" | is-not-empty) {
|
|
||||||
let module = $env.PROVISIONING_MODULE
|
|
||||||
# At this point, $reordered_args contains [create, ...] or whatever the user provided after -mod
|
|
||||||
# We need to invoke the module's main function
|
|
||||||
|
|
||||||
match $module {
|
|
||||||
"server" => {
|
|
||||||
use servers/create.nu *
|
|
||||||
# Ensure tera plugin is loaded for template rendering
|
|
||||||
let tera_available = ((plugin list | where name == "tera" | length) > 0)
|
|
||||||
if $tera_available {
|
|
||||||
if ($env.PROVISIONING_DEBUG? | default false) {
|
|
||||||
_print "DEBUG: Loading tera plugin (-mod server)..." >&2
|
|
||||||
}
|
|
||||||
(plugin use tera)
|
|
||||||
if ($env.PROVISIONING_DEBUG? | default false) {
|
|
||||||
_print "DEBUG: Tera plugin loaded for -mod server" >&2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# Call server create module main function
|
|
||||||
# $reordered_args now has ["create"] or ["delete"] or ["list"] etc.
|
|
||||||
main ...$reordered_args --check=$final_check --wait=$final_wait --infra=($infra | default "") --settings=($settings | default "") --outfile=($outfile | default "") --debug=$debug --xm=$xm --xc=$xc --xr=$xr --xld=$xld --metadata=$metadata --notitles=$notitles --out=($out | default "")
|
|
||||||
}
|
|
||||||
"taskserv" | "task" => {
|
|
||||||
use taskservs/create.nu *
|
|
||||||
main ...$reordered_args --check=$final_check --upload=$final_upload --wait=$final_wait --debug=$debug
|
|
||||||
}
|
|
||||||
"cluster" => {
|
|
||||||
use clusters/create.nu *
|
|
||||||
main ...$reordered_args --check=$final_check --debug=$debug
|
|
||||||
}
|
|
||||||
"images" => {
|
|
||||||
use images/create.nu *
|
|
||||||
use images/list.nu *
|
|
||||||
use images/update.nu *
|
|
||||||
use images/delete.nu *
|
|
||||||
use images/state.nu *
|
|
||||||
use images/watch.nu *
|
|
||||||
# $reordered_args now has ["create", "cp", "--infra", "..."] or similar
|
|
||||||
let subcommand = if ($reordered_args | length) > 0 { $reordered_args | get 0 } else { "help" }
|
|
||||||
match $subcommand {
|
|
||||||
"create" | "c" => {
|
|
||||||
let role = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "" }
|
|
||||||
let infra_arg = if ($infra | is-not-empty) { $infra } else { "" }
|
|
||||||
image-create $role --infra=$infra_arg --check=$final_check
|
|
||||||
}
|
|
||||||
"list" | "l" => {
|
|
||||||
let provider = if ($infra | is-not-empty) { $infra } else { "" }
|
|
||||||
image-list --provider=$provider
|
|
||||||
}
|
|
||||||
"update" | "u" => {
|
|
||||||
let role = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "" }
|
|
||||||
let infra_arg = if ($infra | is-not-empty) { $infra } else { "" }
|
|
||||||
image-update $role --infra=$infra_arg --check=$final_check
|
|
||||||
}
|
|
||||||
"delete" | "d" => {
|
|
||||||
let role = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "" }
|
|
||||||
image-delete $role --yes=$final_yes
|
|
||||||
}
|
|
||||||
"state" | "s" => {
|
|
||||||
image-state-list --provider=$infra
|
|
||||||
}
|
|
||||||
"watch" | "w" => {
|
|
||||||
let interval = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "30" }
|
|
||||||
image-watch --interval=($interval | into int)
|
|
||||||
}
|
|
||||||
"help" | "h" | _ => {
|
|
||||||
print "Image Management Commands"
|
|
||||||
print "======================="
|
|
||||||
print ""
|
|
||||||
print "Usage: provisioning build image <command> [options]"
|
|
||||||
print ""
|
|
||||||
print "Commands:"
|
|
||||||
print " create <role> - Build snapshot for role"
|
|
||||||
print " list - Show all role states"
|
|
||||||
print " update <role> - Rebuild stale snapshot"
|
|
||||||
print " delete <role> - Remove snapshot + state"
|
|
||||||
print " state - List all state files"
|
|
||||||
print " watch - Monitor role freshness"
|
|
||||||
print ""
|
|
||||||
print "Options:"
|
|
||||||
print " --infra <path> - Infrastructure directory"
|
|
||||||
print " --check - Validate without executing"
|
|
||||||
print " --yes - Skip confirmation"
|
|
||||||
print ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
print $"Unknown module: ($module)"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# Normal command dispatch through dispatcher
|
|
||||||
dispatch_command $reordered_args $parsed_flags
|
|
||||||
}
|
|
||||||
|
|
||||||
# End run if not in debug mode
|
|
||||||
if not ($env.PROVISIONING_DEBUG? | default false) { end_run "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
})
|
|
||||||
""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
351
nulib/provisioning-cli.nu
Normal file
351
nulib/provisioning-cli.nu
Normal file
|
|
@ -0,0 +1,351 @@
|
||||||
|
#!/usr/bin/env nu
|
||||||
|
# Single CLI entry — replaces legacy nulib/provisioning runner (ADR-025 Phase 4).
|
||||||
|
#
|
||||||
|
# Single-route architecture: every command goes through dispatch_command, which
|
||||||
|
# lazy-loads per-domain handlers on demand. The star-imports that dominated
|
||||||
|
# cold-start in the legacy runner are gone; only the dispatcher surface + a
|
||||||
|
# handful of init helpers are parsed on startup.
|
||||||
|
#
|
||||||
|
# Daemon and cache become orthogonal concerns applied INSIDE handlers (or their
|
||||||
|
# lazy dependencies), not separate routes.
|
||||||
|
|
||||||
|
export-env {
|
||||||
|
let lib_dirs_raw = ($env.NU_LIB_DIRS? | default "")
|
||||||
|
let current_lib_dirs = if ($lib_dirs_raw | type) == "string" {
|
||||||
|
if ($lib_dirs_raw | is-empty) {
|
||||||
|
[]
|
||||||
|
} else {
|
||||||
|
($lib_dirs_raw | split row ":")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$lib_dirs_raw
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_paths = [
|
||||||
|
"/opt/provisioning/core/nulib"
|
||||||
|
"/usr/local/provisioning/core/nulib"
|
||||||
|
]
|
||||||
|
|
||||||
|
$env.NU_LIB_DIRS = ($default_paths | append $current_lib_dirs)
|
||||||
|
|
||||||
|
if ( (version).installed_plugins | str contains "tera" ) {
|
||||||
|
(plugin use tera)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ADR-025 Phase 4 perf insight: Nushell selective imports (`use x [sym]`) still
|
||||||
|
# parse the entire source module. To actually defer parse cost we must move
|
||||||
|
# `use` statements INSIDE function bodies — they're then evaluated only when
|
||||||
|
# the function is called, not at file-parse time. Parsing this file itself
|
||||||
|
# only sees two `def` headers and one `export-env` block.
|
||||||
|
|
||||||
|
# Pass-through: Nushell parameter parsing handles interleaved flags, so we
|
||||||
|
# just return args as-is. Preserved as a seam for future normalization.
|
||||||
|
def reorder_args [args: list]: nothing -> list { $args }
|
||||||
|
|
||||||
|
export def "main help" [
|
||||||
|
...args: string
|
||||||
|
--notitles
|
||||||
|
--out: string
|
||||||
|
] {
|
||||||
|
use lib_provisioning/utils/init.nu [show_titles]
|
||||||
|
use lib_provisioning/utils/interface.nu [end_run]
|
||||||
|
use main_provisioning/ops.nu [provisioning_options]
|
||||||
|
|
||||||
|
if $notitles == null or not $notitles { show_titles }
|
||||||
|
if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
|
||||||
|
let category = if ($args | length) > 0 { ($args | get 0) } else { "" }
|
||||||
|
print (provisioning_options $category)
|
||||||
|
if not $env.PROVISIONING_DEBUG { end_run "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
def main [
|
||||||
|
...args: string
|
||||||
|
--infra (-i): string
|
||||||
|
--settings (-s): string
|
||||||
|
--serverpos (-p): int
|
||||||
|
--outfile (-o): string
|
||||||
|
--template(-t): string
|
||||||
|
--check (-c)
|
||||||
|
--upload (-u)
|
||||||
|
--yes (-y)
|
||||||
|
--wait
|
||||||
|
--keepstorage
|
||||||
|
--select: string
|
||||||
|
--onsel: string
|
||||||
|
--infras: string
|
||||||
|
--new (-n): string
|
||||||
|
--debug (-x)
|
||||||
|
--xm
|
||||||
|
--xc
|
||||||
|
--xr
|
||||||
|
--xld
|
||||||
|
--nc
|
||||||
|
--metadata
|
||||||
|
--notitles
|
||||||
|
--environment: string
|
||||||
|
--dep-option: string
|
||||||
|
--dep-url: string
|
||||||
|
--dry-run
|
||||||
|
--force (-f)
|
||||||
|
--all
|
||||||
|
--keep-latest: int
|
||||||
|
--workspace (-w): string
|
||||||
|
--activate
|
||||||
|
--interactive
|
||||||
|
--org: string
|
||||||
|
--apply
|
||||||
|
--verbose
|
||||||
|
--pretty
|
||||||
|
-v
|
||||||
|
--version (-V)
|
||||||
|
--info
|
||||||
|
--about
|
||||||
|
--helpinfo (-h)
|
||||||
|
--out: string
|
||||||
|
--view
|
||||||
|
--inputfile: string
|
||||||
|
--include_notuse
|
||||||
|
--services: string
|
||||||
|
]: nothing -> nothing {
|
||||||
|
# Function-local imports: parsed only when main() is called, not at
|
||||||
|
# file-parse time. Keeps cold-start for help-like shortcuts minimal.
|
||||||
|
use lib_provisioning/utils/interface.nu [_ansi _print end_run]
|
||||||
|
use lib_provisioning/utils/init.nu [provisioning_init]
|
||||||
|
use lib_provisioning/defs/about.nu [about_info]
|
||||||
|
use main_provisioning/flags.nu [parse_common_flags]
|
||||||
|
use main_provisioning/ops.nu [provisioning_options]
|
||||||
|
use main_provisioning/dispatcher.nu [dispatch_command]
|
||||||
|
|
||||||
|
let reordered_args = (reorder_args $args)
|
||||||
|
|
||||||
|
let has_yes_in_args = ($reordered_args | any {|x| $x == "--yes" or $x == "-y"})
|
||||||
|
let has_check_in_args = ($reordered_args | any {|x| $x == "--check" or $x == "-c"})
|
||||||
|
let has_upload_in_args = ($reordered_args | any {|x| $x == "--upload" or $x == "-u"})
|
||||||
|
let has_force_in_args = ($reordered_args | any {|x| $x == "--force" or $x == "-f"})
|
||||||
|
let has_verbose_in_args = ($reordered_args | any {|x| $x == "--verbose" or $x == "-v"})
|
||||||
|
let has_wait_in_args = ($reordered_args | any {|x| $x == "--wait"})
|
||||||
|
|
||||||
|
let final_yes = ($yes or $has_yes_in_args)
|
||||||
|
let final_check = ($check or $has_check_in_args)
|
||||||
|
let final_upload = ($upload or $has_upload_in_args)
|
||||||
|
let final_force = ($force or $has_force_in_args)
|
||||||
|
let final_verbose = ($verbose or $has_verbose_in_args)
|
||||||
|
let final_wait = ($wait or $has_wait_in_args)
|
||||||
|
|
||||||
|
provisioning_init $helpinfo "" $reordered_args
|
||||||
|
|
||||||
|
let parsed_flags = (parse_common_flags {
|
||||||
|
version: $version, v: $v, info: $info, about: $about,
|
||||||
|
debug: $debug, metadata: $metadata, xc: $xc, xr: $xr, xld: $xld,
|
||||||
|
check: $final_check, upload: $final_upload, yes: $final_yes, wait: $final_wait, keepstorage: $keepstorage,
|
||||||
|
nc: $nc, include_notuse: $include_notuse,
|
||||||
|
out: $out, notitles: $notitles, view: $view,
|
||||||
|
infra: $infra, infras: $infras, settings: $settings, outfile: $outfile,
|
||||||
|
template: $template, select: $select, onsel: $onsel, serverpos: $serverpos,
|
||||||
|
new: $new, environment: $environment,
|
||||||
|
dep_option: $dep_option, dep_url: $dep_url,
|
||||||
|
dry_run: $dry_run, force: $final_force, all: $all, keep_latest: $keep_latest,
|
||||||
|
activate: $activate, interactive: $interactive,
|
||||||
|
org: $org, apply: $apply, verbose: $final_verbose, pretty: $pretty,
|
||||||
|
services: $services, workspace: $workspace
|
||||||
|
})
|
||||||
|
|
||||||
|
if $parsed_flags.show_version { ^$env.PROVISIONING_NAME -v ; exit }
|
||||||
|
if $parsed_flags.show_info { ^$env.PROVISIONING_NAME -i ; exit }
|
||||||
|
if $parsed_flags.show_about { _print (about_info) ; exit }
|
||||||
|
|
||||||
|
let is_help_command = (
|
||||||
|
($reordered_args | length) == 0 or
|
||||||
|
($reordered_args | get 0) in [
|
||||||
|
"help", "-h", "--help",
|
||||||
|
"sc", "shortcuts", "quickstart", "quick",
|
||||||
|
"from-scratch", "scratch",
|
||||||
|
"customize", "custom",
|
||||||
|
"guide", "guides", "howto",
|
||||||
|
"setup", "st",
|
||||||
|
"workspace", "ws",
|
||||||
|
"mod", "module", "discover", "disc",
|
||||||
|
"dt", "dp", "dc",
|
||||||
|
"discover-taskservs", "disc-t",
|
||||||
|
"discover-providers", "disc-p",
|
||||||
|
"discover-clusters", "disc-c",
|
||||||
|
"lyr", "layer", "version", "pack",
|
||||||
|
"nuinfo", "env", "allenv",
|
||||||
|
"validate", "val", "show", "config-template",
|
||||||
|
"cache",
|
||||||
|
"list", "l", "ls",
|
||||||
|
"plugin", "plugins",
|
||||||
|
"qr", "ssh", "sops",
|
||||||
|
"providers",
|
||||||
|
"status", "health", "diagnostics", "next", "phase"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
let skip_bootstrap = (
|
||||||
|
(($reordered_args | length) > 0 and
|
||||||
|
($reordered_args | get 0) in [
|
||||||
|
"nu",
|
||||||
|
"platform", "plat", "p",
|
||||||
|
"vm", "vmi", "vmh", "vml",
|
||||||
|
"server", "s",
|
||||||
|
"taskserv", "task", "t",
|
||||||
|
"cluster", "cl",
|
||||||
|
"bootstrap",
|
||||||
|
"create", "c",
|
||||||
|
"delete", "d",
|
||||||
|
"update", "u",
|
||||||
|
"build", "b", "bi", "build-image"
|
||||||
|
]) or
|
||||||
|
$final_check
|
||||||
|
)
|
||||||
|
|
||||||
|
if (not $is_help_command) and (not $skip_bootstrap) {
|
||||||
|
use lib_provisioning/platform/bootstrap.nu *
|
||||||
|
let bootstrap_result = (bootstrap-platform --auto-start --timeout=60 --verbose=($final_verbose))
|
||||||
|
if not $bootstrap_result.all_healthy {
|
||||||
|
_print ""
|
||||||
|
_print $"(_ansi red)❌ Platform services not healthy(_ansi reset)"
|
||||||
|
_print ""
|
||||||
|
_print "Failed services:"
|
||||||
|
for service in ($bootstrap_result.services | where {|s| $s.status != "healthy"}) {
|
||||||
|
_print $" - ($service.name): ($service.action)"
|
||||||
|
}
|
||||||
|
_print ""
|
||||||
|
_print "To start services manually:"
|
||||||
|
_print " cd provisioning/platform && docker-compose up -d"
|
||||||
|
_print ""
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env.PROVISIONING_DEBUG? | default false) {
|
||||||
|
print $"DEBUG provisioning-cli: reordered_args = ($reordered_args)" >&2
|
||||||
|
print $"DEBUG provisioning-cli: parsed_flags.infra = (($parsed_flags | get -o infra | default 'MISSING'))" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Help: short-circuit before dispatcher to avoid recursive exec loops.
|
||||||
|
if (($reordered_args | length) > 0) and (($reordered_args | get 0) in ["help" "h"]) {
|
||||||
|
let category = if ($reordered_args | length) > 1 { ($reordered_args | get 1) } else { "" }
|
||||||
|
print (provisioning_options $category)
|
||||||
|
if not ($env.PROVISIONING_DEBUG? | default false) { end_run "" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Info/discovery/utility commands bypass workspace enforcement.
|
||||||
|
if (($reordered_args | length) > 0) and (($reordered_args | get 0) in [
|
||||||
|
"guide", "guides", "sc", "howto", "shortcuts", "quickstart", "quick",
|
||||||
|
"from-scratch", "scratch", "customize", "custom",
|
||||||
|
"mod", "module", "discover", "disc",
|
||||||
|
"dt", "dp", "dc",
|
||||||
|
"discover-taskservs", "disc-t",
|
||||||
|
"discover-providers", "disc-p",
|
||||||
|
"discover-clusters", "disc-c",
|
||||||
|
"lyr", "layer", "version",
|
||||||
|
"nuinfo", "env", "allenv",
|
||||||
|
"validate", "val", "show", "cache",
|
||||||
|
"plugin", "plugins",
|
||||||
|
"qr", "nuinfo",
|
||||||
|
"status", "health", "diagnostics", "next", "phase"
|
||||||
|
]) {
|
||||||
|
dispatch_command $reordered_args $parsed_flags
|
||||||
|
if not $env.PROVISIONING_DEBUG { end_run "" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# -mod <module> mode: bash wrapper extracts `-mod <name>` into
|
||||||
|
# PROVISIONING_MODULE and forwards remaining args. We invoke that module's
|
||||||
|
# `main` directly, bypassing the dispatcher.
|
||||||
|
if ($env.PROVISIONING_MODULE? | default "" | is-not-empty) {
|
||||||
|
let module = $env.PROVISIONING_MODULE
|
||||||
|
|
||||||
|
match $module {
|
||||||
|
"server" => {
|
||||||
|
use servers/create.nu *
|
||||||
|
let tera_available = ((plugin list | where name == "tera" | length) > 0)
|
||||||
|
if $tera_available {
|
||||||
|
if ($env.PROVISIONING_DEBUG? | default false) {
|
||||||
|
_print "DEBUG: Loading tera plugin (-mod server)..." >&2
|
||||||
|
}
|
||||||
|
(plugin use tera)
|
||||||
|
if ($env.PROVISIONING_DEBUG? | default false) {
|
||||||
|
_print "DEBUG: Tera plugin loaded for -mod server" >&2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
main ...$reordered_args --check=$final_check --wait=$final_wait --infra=($infra | default "") --settings=($settings | default "") --outfile=($outfile | default "") --debug=$debug --xm=$xm --xc=$xc --xr=$xr --xld=$xld --metadata=$metadata --notitles=$notitles --out=($out | default "")
|
||||||
|
}
|
||||||
|
"taskserv" | "task" => {
|
||||||
|
use taskservs/create.nu *
|
||||||
|
main ...$reordered_args --check=$final_check --upload=$final_upload --wait=$final_wait --debug=$debug
|
||||||
|
}
|
||||||
|
"cluster" => {
|
||||||
|
use clusters/create.nu *
|
||||||
|
main ...$reordered_args --check=$final_check --debug=$debug
|
||||||
|
}
|
||||||
|
"images" => {
|
||||||
|
use images/create.nu *
|
||||||
|
use images/list.nu *
|
||||||
|
use images/update.nu *
|
||||||
|
use images/delete.nu *
|
||||||
|
use images/state.nu *
|
||||||
|
use images/watch.nu *
|
||||||
|
let subcommand = if ($reordered_args | length) > 0 { $reordered_args | get 0 } else { "help" }
|
||||||
|
match $subcommand {
|
||||||
|
"create" | "c" => {
|
||||||
|
let role = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "" }
|
||||||
|
let infra_arg = if ($infra | is-not-empty) { $infra } else { "" }
|
||||||
|
image-create $role --infra=$infra_arg --check=$final_check
|
||||||
|
}
|
||||||
|
"list" | "l" => {
|
||||||
|
let provider = if ($infra | is-not-empty) { $infra } else { "" }
|
||||||
|
image-list --provider=$provider
|
||||||
|
}
|
||||||
|
"update" | "u" => {
|
||||||
|
let role = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "" }
|
||||||
|
let infra_arg = if ($infra | is-not-empty) { $infra } else { "" }
|
||||||
|
image-update $role --infra=$infra_arg --check=$final_check
|
||||||
|
}
|
||||||
|
"delete" | "d" => {
|
||||||
|
let role = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "" }
|
||||||
|
image-delete $role --yes=$final_yes
|
||||||
|
}
|
||||||
|
"state" | "s" => {
|
||||||
|
image-state-list --provider=$infra
|
||||||
|
}
|
||||||
|
"watch" | "w" => {
|
||||||
|
let interval = if ($reordered_args | length) > 1 { $reordered_args | get 1 } else { "30" }
|
||||||
|
image-watch --interval=($interval | into int)
|
||||||
|
}
|
||||||
|
"help" | "h" | _ => {
|
||||||
|
print "Image Management Commands"
|
||||||
|
print "======================="
|
||||||
|
print ""
|
||||||
|
print "Usage: provisioning build image <command> [options]"
|
||||||
|
print ""
|
||||||
|
print "Commands:"
|
||||||
|
print " create <role> - Build snapshot for role"
|
||||||
|
print " list - Show all role states"
|
||||||
|
print " update <role> - Rebuild stale snapshot"
|
||||||
|
print " delete <role> - Remove snapshot + state"
|
||||||
|
print " state - List all state files"
|
||||||
|
print " watch - Monitor role freshness"
|
||||||
|
print ""
|
||||||
|
print "Options:"
|
||||||
|
print " --infra <path> - Infrastructure directory"
|
||||||
|
print " --check - Validate without executing"
|
||||||
|
print " --yes - Skip confirmation"
|
||||||
|
print ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
print $"Unknown module: ($module)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispatch_command $reordered_args $parsed_flags
|
||||||
|
}
|
||||||
|
|
||||||
|
if not ($env.PROVISIONING_DEBUG? | default false) { end_run "" }
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue