use lib_provisioning * use ../lib_provisioning/user/config.nu [get-active-workspace get-workspace-path] # Removed broken imports - these modules don't exist # use create.nu * # use servers/delete.nu * # use handlers.nu * #use ../lib_provisioning/utils ssh_cmd # Main CLI handler for infra commands export def "main list" [ --infra (-i): string = "" # Infrastructure (ignored for list, kept for compatibility) --notitles # Suppress title output ] { # Get active workspace name let active_workspace = (get-active-workspace) if ($active_workspace | is-empty) { _print "šŸ›‘ No active workspace" _print " Run: provisioning workspace list" _print " Then: provisioning workspace activate " return } # Get workspace path from the active workspace let ws_path = (get-workspace-path $active_workspace) if ($ws_path | is-empty) { _print $"šŸ›‘ Cannot find workspace path for '$active_workspace'" return } let infra_dir = ($ws_path | path join "infra") let current_infra = (config-get "infra.current" "") # List all infrastructures in the workspace infra directory if ($infra_dir | path exists) { # List directory contents, filter for directories that: # 1. Do not start with underscore (not hidden/system) # 2. Are directories # 3. Contain a settings.k file (marks it as a real infra) let infras = (ls -s $infra_dir | where {|it| ((($it.name | str starts-with "_") == false) and ($it.type == "dir") and (($infra_dir | path join $it.name "settings.k") | path exists)) } | each {|it| $it.name} | sort) if ($infras | length) > 0 { _print $"(_ansi cyan_bold)Infrastructures in workspace:(_ansi reset)\n" for infra_name in $infras { let is_current = if ($infra_name == $current_infra) { $"(_ansi green_bold)ā—(_ansi reset) " } else { " " } _print $"($is_current)(_ansi blue)($infra_name)(_ansi reset)" } } else { _print "No infrastructures found in workspace '$active_workspace'" } } else { _print $"šŸ›‘ Infra directory not found: ($infra_dir)" } } # Validate and display detailed infrastructure configuration export def "main validate" [ infra_name?: string # Infrastructure name (optional, uses current or detects from args) --infra (-i): string = "" # Infrastructure name (alternate flag format) --check (-c) # Check mode (accepted but not used for validate) --onsel: string = "" # On selection (accepted but not used for validate) --yes (-y) # Auto-confirm (accepted but not used for validate) --notitles # Suppress title output ] { # Get active workspace name let active_workspace = (get-active-workspace) if ($active_workspace | is-empty) { _print "šŸ›‘ No active workspace" _print " Run: provisioning workspace list" _print " Then: provisioning workspace activate " return } # Get workspace path from the active workspace let ws_path = (get-workspace-path $active_workspace) if ($ws_path | is-empty) { _print $"šŸ›‘ Cannot find workspace path for '$active_workspace'" return } let infra_dir = ($ws_path | path join "infra") # Determine which infrastructure to validate let target_infra = if ($infra_name | is-not-empty) { $infra_name } else if ($infra | is-not-empty) { $infra } else { # Try to detect from config (config-get "infra.current" "") } if ($target_infra | is-empty) { _print "āŒ No infrastructure specified" _print "" _print "Usage: provisioning infra validate []" _print "" _print "Available infrastructures:" # List available infras if ($infra_dir | path exists) { let infras = (ls -s $infra_dir | where {|it| ((($it.name | str starts-with "_") == false) and ($it.type == "dir") and (($infra_dir | path join $it.name "settings.k") | path exists)) } | each {|it| $it.name} | sort) for infra in $infras { _print $" • (_ansi blue)($infra)(_ansi reset)" } } return } let target_path = ($infra_dir | path join $target_infra) if not ($target_path | path exists) { _print $"āŒ Infrastructure not found: (_ansi red)($target_infra)(_ansi reset)" return } # Load infrastructure configuration files let settings_file = ($target_path | path join "settings.k") let servers_file = ($target_path | path join "defs" "servers.k") if not ($settings_file | path exists) { _print $"āŒ Settings file not found: ($settings_file)" return } # Display infrastructure header _print "" _print $"(ansi cyan_bold)════════════════════════════════════════════════════════════════════════════(ansi reset)" _print $"(ansi cyan_bold) ($target_infra | str upcase) INFRASTRUCTURE CONFIGURATION (ansi reset)" _print $"(ansi cyan_bold)════════════════════════════════════════════════════════════════════════════(ansi reset)" _print "" # Parse and display servers if the file exists if ($servers_file | path exists) { let servers_content = (open -r $servers_file) # Extract servers from the _servers array # Split by "upcloud_prov.Server_upcloud {" to find server blocks let server_blocks = ($servers_content | split row "upcloud_prov.Server_upcloud {" | skip 1) if ($server_blocks | length) > 0 { _print $"(ansi green_bold)Servers:(ansi reset)" _print "" for srv_idx in (0..($server_blocks | length)) { if $srv_idx >= ($server_blocks | length) { break } let block = ($server_blocks | get $srv_idx) let server_count = ($srv_idx + 1) # Extract hostname - look for: hostname = "..." let hostname = if ($block | str contains "hostname =") { let lines = ($block | split row "\n" | where { |l| (($l | str contains "hostname =") and not ($l | str starts-with "#")) }) if ($lines | length) > 0 { let line = ($lines | first) let match = ($line | split row "\"" | get 1? | default "") $match } else { "N/A" } } else { "N/A" } # Check if server is disabled - look for: not_use = True let is_disabled = ($block | str contains "not_use = True") let status = if $is_disabled { $"(ansi yellow)DISABLED(ansi reset)" } else { $"(ansi green)ACTIVE(ansi reset)" } # Extract plan - look for: plan = "..." (not commented, prefer last one) let plan = if ($block | str contains "plan =") { let lines = ($block | split row "\n" | where { |l| (($l | str contains "plan =") and ($l | str contains "\"") and not ($l | str starts-with "#")) }) if ($lines | length) > 0 { let line = ($lines | last) ($line | split row "\"" | get 1? | default "") } else { "N/A" } } else { "N/A" } # Extract total storage - look for: total = ... let storage = if ($block | str contains "total =") { let lines = ($block | split row "\n" | where { |l| (($l | str contains "total =") and not ($l | str starts-with "#")) }) if ($lines | length) > 0 { let line = ($lines | first) let value = ($line | str trim | split row "=" | get 1? | str trim) ($value | str replace "," "" | str trim) } else { "N/A" } } else { "N/A" } # Extract IP - look for: network_private_ip = "..." let ip = if ($block | str contains "network_private_ip =") { let lines = ($block | split row "\n" | where { |l| (($l | str contains "network_private_ip =") and not ($l | str starts-with "#")) }) if ($lines | length) > 0 { let line = ($lines | first) ($line | split row "\"" | get 1? | default "") } else { "N/A" } } else { "N/A" } # Extract taskservs - look for all lines with {name = "..."} within taskservs array let taskservs_list = if ($block | str contains "taskservs = [") { let taskservs_section = ($block | split row "taskservs = [" | get 1? | split row "]" | first | default "") let lines = ($taskservs_section | split row "\n" | where { |l| (($l | str contains "name =") and not ($l | str starts-with "#")) }) let taskservs = ($lines | each { |l| let parts = ($l | split row "name =") let value_part = if ($parts | length) > 1 { ($parts | get 1) } else { "" } let name = ($value_part | split row "\"" | get 1? | default "") if ($name | is-not-empty) { $name } else { null } } | where { |n| ($n != null) }) $taskservs } else { [] } _print $" ($server_count). (ansi cyan_bold)($hostname)(ansi reset) - ($status)" _print $" Plan: (ansi blue)($plan)(ansi reset)" _print $" Storage: (ansi blue)($storage)GB(ansi reset)" _print $" IP: (ansi blue)($ip)(ansi reset)" if ($taskservs_list | length) > 0 { _print $" Taskservs: (ansi yellow)($taskservs_list | length)(ansi reset) installed" for svc in $taskservs_list { _print $" • ($svc)" } } _print "" } } } # Display summary _print $"(ansi cyan_bold)Summary:(ansi reset)" _print $" Workspace: (ansi green)($active_workspace)(ansi reset)" _print $" Infrastructure: (ansi green)($target_infra)(ansi reset)" _print $" Path: (ansi yellow)($target_path)(ansi reset)" _print "" _print $"(ansi green)āœ“ Infrastructure configuration validated(ansi reset)" _print "" } export def on_create_infras [ infras_list: list # infras list check: bool # Only check mode no servers will be created wait: bool # Wait for creation outfile?: string # Out file for creation hostname?: string # Server hostname in settings serverpos?: int # Server position in settings ] { let create_infra = {|infra| if not ($env.PROVISIONING_INFRA_PATH | path join $infra.item | path exists) { print $"\nšŸ›‘ Path not found for (_ansi red)($infra.item)(_ansi reset) in (_ansi cyan)($env.PROVISIONING_KLOUD_PATH)(_ansi reset)" } else { let settings = (find_get_settings --infra $infra.item) on_infra $infra $settings $check $wait $outfile $hostname $serverpos } } if $check { $infras_list | enumerate | each { |infra| do $create_infra $infra } } else { $infras_list | enumerate | par-each { |infra| do $create_infra $infra } } } export def on_infra [ infra: record settings: record check: bool wait: bool outfile?: string # Out file for creation hostname?: string # Server hostname in settings serverpos?: int # Server position in settings ] { print "TODO on_infra" print $infra } export def on_taskserv_infras [ infras_list: list # infras list check: bool # Only check mode no servers will be created name?: string server?: string --iptype: string = "public" # Ip type to connect ] { let run_create = { |infra| let curr_settings = (find_get_settings --infra $infra) $env.WK_CNPROV = $curr_settings.wk_path let match_task = if $name == null or $name == "" { "" } else { $name } let match_server = if $server == null or $server == "" { "" } else { $server} on_taskservs $curr_settings $match_task $match_server $iptype $check } $infras_list | enumerate | par-each { |infra| let task = { do $run_create $infra.item } let result = desktop_run_notify $"($env.PROVISIONING_NAME) ($infra.item) taskservs create" "-> " $task --timeout 11sec } } export def on_delete_infras [ infras_list: list # infras list keep_storage: bool # keepstorage wait: bool # Wait for creation name?: string # Server hostname in settings serverpos?: int # Server position in settings ] { let run_delete = { |infra, keepstorage| let curr_settings = (find_get_settings --infra $infra) on_delete_servers $curr_settings $keepstorage $wait $name $serverpos } $infras_list | enumerate | par-each { |infra| let task = { do $run_delete $infra.item $keep_storage } let result = desktop_run_notify $"($env.PROVISIONING_NAME) ($infra.item) servers delete" "-> " $task --timeout 11sec } } export def on_generate_infras [ infras_list: list # infras list check: bool # Only check mode wait: bool # Wait for creation outfile?: string # Out file for generation name?: string # Server hostname in settings serverpos?: int # Server position in settings ] { print "TODO on_generate_infras" # let curr_settings = (find_get_settings --infra $infra) } export def infras_walk_by [ infras_list: list match_hostname: string check: bool # Only check mode no servers will be created return_no_exists: bool ] { mut infra_servers = {} mut total_month = 0 mut total_hour = 0 mut total_day = 0 mut table_items = [] let sum_color = { fg: '#0000ff' bg: '#dadada' attr: b } let total_color = { fg: '#ffff00' bg: '#0000ff' attr: b } print $"(_ansi purple_reverse) Cost ($infras_list | str join ' ')(_ansi reset) " for infra in $infras_list { if not ($env.PROVISIONING_INFRA_PATH | path join $infra | path exists) { print $"\nšŸ›‘ Path not found for (_ansi red)($infra)(_ansi reset) in (_ansi cyan)($env.PROVISIONING_KLOUD_PATH)(_ansi reset)" continue } let settings = (find_get_settings --infra $infra) mut c_infra_servers = {} mut c_total_month = 0 mut c_total_hour = 0 mut c_total_day = 0 for server in $settings.data.servers { if $match_hostname != null and $match_hostname != "" and $server.hostname != $match_hostname { continue } # Check if provider key exists in infra_servers if not (($infra_servers | columns) | any { |col| $col == $server.provider }) { $infra_servers = ($infra_servers | merge { $server.provider: (mw_load_infra_servers_info $settings $server false)} ) } let item_raw = (mw_get_infra_item $server $settings $infra_servers false) let item = { item: $item_raw, target: "server" } if $env.PROVISIONING_DEBUG_CHECK { print ($item | table -e)} let price_month = (mw_get_infra_price $server $item "month" false | default 0) let price_hour = (mw_get_infra_price $server $item "hour" false | default 0) let price_day = ($price_hour * 24) $total_month += $price_month $total_hour += $price_hour $total_day += ($price_day) $c_total_month += $price_month $c_total_hour += $price_hour $c_total_day += ($price_day) let already_created = (mw_server_exists $server false) let host_color = if $already_created { "green_bold" } else { "red" } $table_items = ($table_items | append { host: $"(_ansi $host_color)($server.hostname)(_ansi reset) (_ansi blue_bold)($server.plan)(_ansi reset)", prov: $"(_ansi default_bold) ($server.provider) (_ansi reset)", hour: $"(_ansi default_bold) ($price_hour)€ (_ansi reset)", day: $"(_ansi default_bold) ($price_day | math round -p 4)€ (_ansi reset)", month: $"(_ansi default_bold) ($price_month)€ (_ansi reset)" }) if not $check { if not ($already_created) { if $return_no_exists { return { status: false, error: $"($server.hostname) not created" } #} else { #print $"(_ansi red_bold)($server.hostname)(_ansi reset) not created" } } } } rm -rf $settings.wk_path $table_items = ($table_items | append { host: $"(_ansi --escape $sum_color) ($settings.infra) (_ansi reset)", prov: $"(_ansi default_bold) (_ansi reset)", hour: $"(_ansi --escape $sum_color) ($c_total_hour | math round -p 4)€ (_ansi reset)", day: $"(_ansi --escape $sum_color) ($c_total_day | math round -p 4)€ (_ansi reset)", month:$"(_ansi --escape $sum_color) ($c_total_month)€ (_ansi reset)" }) } $table_items = ($table_items | append { host: "", prov: "", month: "", day: "", hour: ""}) $table_items = ($table_items | append { host: $"(_ansi --escape $total_color) TOTAL (_ansi reset)", prov: $"(_ansi default_bold) (_ansi reset)", hour: $"(_ansi --escape $total_color) ($total_hour | math round -p 4)€ (_ansi reset)", day: $"(_ansi --escape $total_color) ($total_day | math round -p 4)€ (_ansi reset)", month:$"(_ansi --escape $total_color) ($total_month)€ (_ansi reset)" }) _print ($table_items | table -i false) }