#!/usr/bin/env nu # Info: Script to run Provisioning # Author: JesusPerezLorenzo # Release: 1.0.4 # Date: 30-4-2024 use std log #use lib_provisioning * use ../env.nu * use ../lib_provisioning/config/accessor.nu * use ../lib_provisioning/utils/interface.nu * use ../lib_provisioning/utils/init.nu * use ../lib_provisioning/utils/error.nu * use ../lib_provisioning/utils/version_manager.nu * use ../lib_provisioning/utils/version_formatter.nu * use ../lib_provisioning/utils/version_loader.nu * use ../lib_provisioning/utils/version_registry.nu * use ../lib_provisioning/utils/version_taskserv.nu * # Tools management export def "main tools" [ task?: string # tools tasks for tools command ...args # tools options --update (-u) # Update tools --debug (-x) # Use Debug mode --xm # Debug with PROVISIONING_METADATA --xc # Debuc 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 --metadata # Error with metadata (-xm) --notitles # not tittles --helpinfo (-h) # For more details use options "help" (no dashes) --out: string # Print Output format: json, yaml, text (default) --dry-run (-n) # Dry run mode for update operations --force (-f) # Force updates even if fixed --yes (-y) # Auto-confirm prompts (skip interactive prompts) ]: nothing -> nothing { if ($out | is-not-empty) { $env.PROVISIONING_OUT = $out $env.PROVISIONING_NO_TERMINAL = true } if (use_titles) { show_titles } if $helpinfo { _print (provisioning_tools_options) # if not $env.PROVISIONING_DEBUG { end_run "" } exit } let tools_task = if $task == null { "" } else { $task } let tools_args = if ($args | length) == 0 { ["all"] } else { $args } let provisioning_path = ($env.PROVISIONING? | default (get-base-path)) let core_cli = ($provisioning_path | path join "core" | path join "cli") match $tools_task { "install" => { let update_tools = if $update { "--update" } else { "" } _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools_install (_ansi green_bold)($tools_args | str join ' ') ($update_tools)(_ansi reset) " ^$"($core_cli)/tools-install" ...$tools_args $update_tools }, "show" | "s" | "info" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " let target = ($args | get 0? | default "") let match = ($args | get 1? | default "") match $target { "a" | "all" => { (show_tools_info $target) (show_provs_info $match) }, "p" | "prov" | "provider" | "providers" => (show_provs_info $match), _ => (show_tools_info $target), } }, "" | "check" | "c" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools check (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " # Get all results first let all_results = (check-versions --fetch-latest=false) let all_configs = (discover-configurations) # Filter based on arguments let filtered_results = if ($args | length) == 0 { # No args - show all $all_results } else if ($args | length) == 1 { let arg = ($args | get 0) # Handle special cases for providers if $arg == "providers" { # Show all provider components $all_results | where type == "provider" } else { # Check if it's a type or component ID let by_type = ($all_results | where type == $arg) let by_id = ($all_results | where id == $arg) if ($by_type | length) > 0 { $by_type } else { $by_id } } } else { # Multiple args - "provider upcloud" format let type_filter = ($args | get 0) let category_filter = ($args | get 1) if $type_filter == "provider" { # Filter by provider category let configs_by_category = ($all_configs | where type == "provider" and category == $category_filter) let ids_by_category = ($configs_by_category | get id) $all_results | where id in $ids_by_category } else { # Fallback to ID filtering let id_filter = $category_filter $all_results | where type == $type_filter and id == $id_filter } } _print ($filtered_results | select id type configured status | table) }, "versions" | "v" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools versions (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " # Get all results first let all_results = (check-versions --fetch-latest=false) let all_configs = (discover-configurations) # Filter based on arguments (same logic as check command) let filtered_results = if ($args | length) == 0 { # No args - show all $all_results } else if ($args | length) == 1 { let arg = ($args | get 0) # Handle special cases for providers if $arg == "providers" { # Show all provider components $all_results | where type == "provider" } else { # Check if it's a type or component ID let by_type = ($all_results | where type == $arg) let by_id = ($all_results | where id == $arg) if ($by_type | length) > 0 { $by_type } else { $by_id } } } else { # Multiple args - "provider upcloud" format let type_filter = ($args | get 0) let category_filter = ($args | get 1) if $type_filter == "provider" { # Filter by provider category let configs_by_category = ($all_configs | where type == "provider" and category == $category_filter) let ids_by_category = ($configs_by_category | get id) $all_results | where id in $ids_by_category } else { # Fallback to ID filtering let id_filter = $category_filter $all_results | where type == $type_filter and id == $id_filter } } _print ($filtered_results | select id type configured status | table) _print "\nNote: Run 'tools check-updates' to fetch latest versions from remote sources" return }, "check-updates" | "cu" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools check-updates (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " let types = if ($args | length) > 0 { $args } else { [] } check-available-updates --types=$types return }, "apply-updates" | "au" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools apply-updates (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " let types = if ($args | length) > 0 { $args } else { [] } apply-config-updates --types=$types --dry-run=$dry_run --force=$force --auto-yes=$yes return }, "pin" => { let component = ($args | get 0? | default null) if ($component | is-empty) { _print "❌ Please specify a component ID" return } _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools pin (_ansi green_bold)($component)(_ansi reset) " set-fixed $component true return }, "unpin" => { let component = ($args | get 0? | default null) if ($component | is-empty) { _print "❌ Please specify a component ID" return } _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools unpin (_ansi green_bold)($component)(_ansi reset) " set-fixed $component false return }, "taskserv-versions" | "tv" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) taskserv versions (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " let format = ($args | get 0? | default "table") let taskservs_path = if ($args | length) > 1 { ($args | get 1) } else { "" } show-version-status --taskservs-path=$taskservs_path --format=$format return }, "taskserv-check" | "tc" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) taskserv check (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " let taskservs_path = if ($args | length) > 0 { ($args | get 0) } else { "" } let configs = (discover-taskserv-configurations --base-path=$taskservs_path) _print ($configs | select id version kcl_file | table) return }, "taskserv-update" | "tu" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) taskserv update (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " let components = if ($args | length) > 0 { $args } else { [] } update-registry-versions --components=$components --dry-run=$dry_run return }, "taskserv-sync" | "ts" => { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) taskserv sync (_ansi green_bold)($tools_args | str join ' ')(_ansi reset) " let taskservs_path = if ($args | length) > 0 { ($args | get 0) } else { "" } let component = if ($args | length) > 1 { ($args | get 1) } else { "" } taskserv-sync-versions --taskservs-path=$taskservs_path --component=$component --dry-run=$dry_run return }, "help" | "helpinfo" | "h" => { _print (provisioning_tools_options) }, _ => { on_tools_task $core_cli $tools_task let text = $"expected to be one of [install, show, info, check, versions, check-updates, update-versions, pin, unpin], got ($tools_task)" (throw-error "πŸ›‘ invalid_option" $text #--span (metadata $pkg_dir | get span) ) }, } if not $env.PROVISIONING_DEBUG { end_run "" } } export def show_tools_info [ match: string ]: nothing -> nothing { let tools_data = (open (get-provisioning-req-versions)) if ($match | is-empty) { _print ($tools_data | table -e) } else { let data_to_show = if ($match in ($tools_data | columns)) { $tools_data | get $match } else { null } _print ($data_to_show | table -e) } } export def show_provs_info [ match: string ]: nothing -> nothing { if not ((get-providers-path)| path exists) { _print $"❗Error providers path (_ansi red)((get-providers-path))(_ansi reset) not found" return } ^ls (get-providers-path) | each {|prv| if ($match | is-empty) or $match == ($prv | str trim) { let prv_path = ((get-providers-path) | path join ($prv | str trim) | path join "provisioning.yaml") if ($prv_path | path exists) { _print $"(_ansi magenta_bold)($prv | str trim | str upcase)(_ansi reset)" _print (open $prv_path | table -e) } } } } export def on_tools_task [ core_bin: string tools_task: string ]: nothing -> nothing { if not ((get-provisioning-req-versions) | path exists) { _print $"❗Error tools path (_ansi red)((get-provisioning-req-versions))(_ansi reset) not found" return } let tools_data = (open (get-provisioning-req-versions)) let tool_name = if ($tools_task in ($tools_data | columns)) { $tools_data | get $tools_task } else { null } if ($tool_name | is-not-empty) { _print $"(_ansi blue_bold)((get-provisioning-name))(_ansi reset) tools check (_ansi green_bold)($tools_task)(_ansi reset) " ^$"($core_bin)/tools-install" check $tools_task # if not $env.PROVISIONING_DEBUG { end_run "" } exit } } # Tools help output - displayed by "provisioning tools help" def provisioning_tools_options []: nothing -> string { ( $"(_ansi yellow_bold)╔══════════════════════════════════════════════════╗(_ansi reset)\n" + $"(_ansi yellow_bold)β•‘(_ansi reset) πŸ”§ TOOLS & DEPENDENCIES (_ansi yellow_bold)β•‘(_ansi reset)\n" + $"(_ansi yellow_bold)β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•(_ansi reset)\n\n" + $"(_ansi green_bold)[Installation](_ansi reset) Tool Setup\n" + $" (_ansi blue)tools install(_ansi reset) - Install all tools\n" + $" (_ansi blue)tools install (_ansi reset) - Install specific tool [aws|hcloud|upctl]\n" + $" (_ansi blue)tools install --update(_ansi reset) - Force reinstall all tools\n\n" + $"(_ansi green_bold)[Version Management](_ansi reset) Tool Versions\n" + $" (_ansi blue)tools check(_ansi reset) - Check all tool versions\n" + $" (_ansi blue)tools versions(_ansi reset) - Show configured versions\n" + $" (_ansi blue)tools check-updates(_ansi reset) - Check for available updates\n" + $" (_ansi blue)tools apply-updates(_ansi reset) - Apply configuration updates [--dry-run]\n\n" + $"(_ansi green_bold)[Tool Information](_ansi reset) Tool Details\n" + $" (_ansi blue)tools show(_ansi reset) - Display tool information\n" + $" (_ansi blue)tools show all(_ansi reset) - Show all tools and providers\n" + $" (_ansi blue)tools show (_ansi reset) - Tool-specific information\n" + $" (_ansi blue)tools show provider(_ansi reset) - Show provider information\n\n" + $"(_ansi green_bold)[Pinning & Configuration](_ansi reset) Version Control\n" + $" (_ansi blue)tools pin (_ansi reset) - Pin tool to current version\n" + $" (_ansi blue)tools unpin (_ansi reset) - Unpin tool for auto-update\n\n" + $"(_ansi green_bold)[Provider Tools](_ansi reset) Cloud CLI Tools\n" + $" (_ansi blue)tools check aws(_ansi reset) - Check AWS CLI status\n" + $" (_ansi blue)tools check hcloud(_ansi reset) - Check Hetzner CLI status\n" + $" (_ansi blue)tools check upctl(_ansi reset) - Check UpCloud CLI status\n\n" + $"(_ansi green_bold)EXAMPLES(_ansi reset)\n\n" + $" # Check all tool versions\n" + $" provisioning tools check\n\n" + $" # Check specific provider tool\n" + $" provisioning tools check hcloud\n" + $" provisioning tools versions\n\n" + $" # Check for updates and apply\n" + $" provisioning tools check-updates\n" + $" provisioning tools apply-updates --dry-run\n" + $" provisioning tools apply-updates\n\n" + $" # Install or update tools\n" + $" provisioning tools install\n" + $" provisioning tools install --update\n" + $" provisioning tools install hcloud\n\n" + $" # Pin/unpin specific tools\n" + $" provisioning tools pin upctl\n" + $" provisioning tools unpin upctl\n\n" + $"(_ansi green_bold)SUPPORTED TOOLS(_ansi reset)\n\n" + $" β€’ (_ansi cyan)aws(_ansi reset) - AWS CLI v2\n" + $" β€’ (_ansi cyan)hcloud(_ansi reset) - Hetzner Cloud CLI\n" + $" β€’ (_ansi cyan)upctl(_ansi reset) - UpCloud CLI\n" + $" β€’ (_ansi cyan)kcl(_ansi reset) - KCL configuration language\n" + $" β€’ (_ansi cyan)nu(_ansi reset) - Nushell scripting engine\n\n" + $"(_ansi green_bold)VERSION INFORMATION(_ansi reset)\n\n" + $" Each tool can have:\n" + $" - Configured version: Target version in config\n" + $" - Installed version: Currently installed on system\n" + $" - Latest version: Available upstream\n" + $" - Status: not_installed, installed, update_available, or ahead\n\n" + $"(_ansi green_bold)TOOL STATUS MEANINGS(_ansi reset)\n\n" + $" not_installed - Tool not found on system, needs installation\n" + $" installed - Tool is installed and version matches config\n" + $" update_available - Newer version available, can be updated\n" + $" ahead - Installed version is newer than configured\n" + $" behind - Installed version is older than configured\n\n" + $"(_ansi default_dimmed)πŸ’‘ Use provisioning tools install to set up all required tools\n" + $" Most tools are optional but recommended for specific cloud providers\n" + $" Pinning ensures version stability for production deployments(_ansi reset)\n" ) }