# Provider middleware now available through lib_provisioning use lib_provisioning * use ssh.nu * use ../lib_provisioning/utils/ssh.nu ssh_cmd use ../lib_provisioning/utils/settings.nu get_file_format use ../lib_provisioning/secrets/lib.nu encrypt_secret export def on_server [ settings: record # Settings record 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 ]: nothing -> list { # _check_settings let match_hostname = if $hostname != null { $hostname } else if $serverpos != null { let total = $settings.data.servers | length let pos = if $serverpos == 0 { _print $"Use number form 1 to ($total)" $serverpos } else if $serverpos <= $total { $serverpos - 1 } else { (throw-error $"πŸ›‘ server pos" $"($serverpos) from ($total) servers" "on_create" --span (metadata $serverpos).span) exit 1 } ($settings.data.servers | get $pos).hostname } if $check { $settings.data.servers | enumerate | each { |it| if $match_hostname == null or $it.item.hostname == $match_hostname { on_create_server $it.item $it.index true $outfile } } } else { $settings.data.servers | enumerate | par-each { |it| if $match_hostname == null or $it.item.hostname == $match_hostname { on_create_server $it.item $it.index false $outfile } } } } export def wait_for_server [ server_pos: int server: record settings: record ip: string ]: nothing -> bool { if $ip == "" { return false } mut num = 0 let liveness_port = (if $server.liveness_port? != null { $server.liveness_port } else { 22 } | into int) let val_timeout = if $server.running_timeout? != null { $server.running_timeout } else { 0 } let wait = if $server.running_wait? != null { $server.running_wait } else { 10 } let wait_duration = ($"($wait)sec"| into duration) _print ( $"wait for server (_ansi blue_bold)($server.hostname)(_ansi reset) state " + $"(_ansi yellow_bold)started(_ansi reset) (_ansi default_dimmed)until ($val_timeout)secs check every ($wait)sec(_ansi reset)" ) while true { let status = (mw_server_is_running $server false) #let res = (run-external --redirect-combine "nc" "-zv" "-w" 1 $ip $liveness_port | complete) #if $res.exit_code == 0 { if $status and (port_scan $ip $server.liveness_port 1) and (ssh_cmd $settings $server false "ls" $ip) { _print $"done in ($num)secs " break } else if $val_timeout > 0 and $num > $val_timeout { _print ($"\nπŸ›‘ (_ansi red)Timeout(_ansi reset) ($val_timeout) (_ansi blue)($server.hostname)(_ansi reset)" + $"(_ansi blue_bold)($ip)(_ansi reset) at ($liveness_port) (_ansi red_bold)failed(_ansi reset) " ) #print $"\n($res.stdout)" return false } else { $num = $num + $wait #print -n $"($nupm) " print -n $"(_ansi blue_bold) πŸŒ₯ (_ansi reset)" sleep $wait_duration } } _print ( $"(_ansi blue)($server.hostname)(_ansi reset) at (_ansi blue_bold)($ip)(_ansi reset) " + $"port ($liveness_port) (_ansi green_bold)ready(_ansi reset) " ) true } export def on_server_template [ server_template: string server: record index: int check: bool only_make: bool wait: bool settings: record outfile?: string ]: nothing -> bool { if $server.provider == local { return true } if not ( $server_template | path exists ) { _print $"($server_template) not found for ($server.hostname) [($index)]" return false } let suffix = if ($server_template | str contains "storage") { "storage" } else { "server" } #use utils/templates.nu run_from_template #mut create_result = false let duration = timeit { let wk_file = $"($settings.wk_path)/($server.hostname)_($suffix)_cmd" let wk_vars = $"($settings.wk_path)/($server.hostname)_($suffix)_vars.($env.PROVISIONING_WK_FORMAT)" let run_file = $"($settings.wk_path)/on_($server.hostname)_($suffix)_run.sh" rm --force $wk_file $wk_vars $run_file let data_settings = if $suffix == "storage" { ($settings.data | merge { wk_file: $wk_file, now: $env.NOW, server_pos: $index, storage_pos: 0, provisioning_vers: ($env.PROVISIONING_VERS? | str replace "null" ""), wait: $wait, server: $server }) } else { ($settings.data | merge { wk_file: $wk_file, now: $env.NOW, serverpos: $index, provisioning_vers: ($env.PROVISIONING_VERS? | str replace "null" ""), wait: $wait, provider: ($settings.providers | where {|it| $it.provider == $server.provider} | get -o 0 | get -o settings | default {}), server: $server }) } if $env.PROVISIONING_WK_FORMAT == "json" { $data_settings | to json | save --force $wk_vars } else { $data_settings | to yaml | save --force $wk_vars } let res = if $only_make and $check { (run_from_template $server_template $wk_vars $run_file $outfile --only_make --check_mode) } else if $only_make { (run_from_template $server_template $wk_vars $run_file $outfile --only_make) } else if $check { (run_from_template $server_template $wk_vars $run_file $outfile --check_mode) } else { (run_from_template $server_template $wk_vars $run_file $outfile) } if $res { if $env.PROVISIONING_DEBUG == false { rm --force $wk_file $wk_vars $run_file } _print $"(_ansi green_bold)($server.hostname)(_ansi reset) (_ansi green)successfully(_ansi reset)" } else { _print $"(_ansi red)Failed(_ansi reset) (_ansi green_bold)($server.hostname)(_ansi reset)" } } let text_duration = if not $check { $"in (_ansi blue_bold)($duration)(_ansi reset)" } else { "" } _print $"Done run template (_ansi blue_italic)($server_template | path basename | str replace ".j2" "" )(_ansi reset) for (_ansi green_bold)($server.hostname)(_ansi reset) ($text_duration)" true # $create_result } export def servers_selector [ settings: record ip_type: string is_for_task: bool ]: nothing -> string { if ($env | get -o PROVISIONING_OUT | default "" | is-not-empty) or $env.PROVISIONING_NO_TERMINAL { return ""} mut servers_pick_lists = [] if not $env.PROVISIONING_DEBUG_CHECK { #use ssh.nu * for server in $settings.data.servers { let ip = (mw_get_ip $settings $server $ip_type false | default "") if $ip == "" { _print $"πŸ›‘ No IP ($ip_type) found for (_ansi green_bold)($server.hostname)(_ansi reset) " continue } let ssh_id = (server_ssh_id $server) let ssh_addr = (server_ssh_addr $settings $server) $servers_pick_lists = ($servers_pick_lists | append { name: $server.hostname, id: $ssh_id, addr: $ssh_addr }) } } let msg_sel = if $is_for_task { "Select one server" } else { "To connect to a server select one" } if ($servers_pick_lists | length) == 0 { return "" } let selection = if ($servers_pick_lists | length) > 1 { _print $"(_ansi default_dimmed)($msg_sel) \(use arrows and press [enter] or [esc] to cancel\):(_ansi reset)" ($servers_pick_lists | each {|it| _print $"($it.name) -> ($it.addr)"}) let pos_select = ($servers_pick_lists | each {|it| $"($it.name) -> ($it.addr)"} |input list --index) if $pos_select == null { return null } let selection = ($servers_pick_lists | get -o $pos_select) if not $is_for_task { _print $"\nFor (_ansi green_bold)($selection.name)(_ansi reset) server use:" } $selection } else { let selection = ($servers_pick_lists | get -o 0) if not $is_for_task { _print $"\n(_ansi default_dimmed)To connect to server (_ansi reset)(_ansi green_bold)($selection.name)(_ansi reset) use:" } $selection } if not $is_for_task { let id = ($selection | get -o id | default "") if ($id | is-not-empty) { show_clip_to $"ssh -i($id) ($selection.addr)" true } } $selection } def add_item_price [ server: record already_created: bool resource: string item: string price: record host_color: string ]: nothing -> record { let str_price_monthly = if $price.month < 10 { $" ($price.month)" } else { $"($price.month)" } let price_monthly = if ($str_price_monthly | str contains ".") { $str_price_monthly } else { $"($str_price_monthly).0"} if ($env.PROVISIONING_OUT | is-empty) { { host: $"(_ansi $host_color)($server.hostname)(_ansi reset)", item: $"(_ansi default_bold)($item)(_ansi reset)", resource: $"(_ansi blue_bold)($resource)(_ansi reset)", prov: $"(_ansi default_bold)($server.provider)(_ansi reset)", zone: $"(_ansi default_bold)($server.zone)(_ansi reset)", unit: ($price.unit_info | default "") hour: $"(_ansi default_bold) ($price.hour | fill -a left -c '0' -w 7 | str replace '.' ',') € (_ansi reset)", day: $"(_ansi default_bold) ($price.day | math round -p 4 | fill -a left -c '0' -w 7 | str replace '.' ',') € (_ansi reset)", month: $"(_ansi default_bold) ($price_monthly | fill -a left -c '0' -w 7 | str replace '.' ',' | str replace ',0000' '') € (_ansi reset)", created: $already_created, } } else { { host: $server.hostname, item: $item, resource: $resource, prov: $server.provider, zone: $server.zone, unit: ($price.unit_info | default ""), hour: $"($price.hour | fill -a left -c '0' -w 7 | str replace '.' ',') €", day: $"($price.day | math round -p 4 | fill -a left -c '0' -w 7 | str replace '.' ',') €", month: $"($price_monthly | fill -a left -c '0' -w 7 | str replace '.' ',' | str replace ',0000' '') €", created: $already_created, } } } export def servers_walk_by_costs [ settings: record # Settings record match_hostname: string check: bool # Only check mode no servers will be created return_no_exists: bool outfile?: string ]: nothing -> nothing { if $outfile != null { $env.PROVISIONING_NO_TERMINAL = true } if $outfile == null { _print $"\n (_ansi cyan)($settings.data | get -o main_title | default "")(_ansi reset) prices ($outfile)" } mut infra_servers = {} mut total_month = 0 mut total_hour = 0 mut total_day = 0 mut table_items = [] let total_color = { fg: '#ffff00' bg: '#0000ff' attr: b } for server in $settings.data.servers { if $match_hostname != null and $match_hostname != "" and $server.hostname != $match_hostname { continue } if ($infra_servers | is-empty) or ($infra_servers | get -o $server.provider | if ($in | describe | str starts-with "record") { [$in] } else { $in } | default [] | where {|it| $it.zone? != null and $it.zone == $server.zone and $it.plan? == null and $it.plan == $server.plan} | length) == 0 { $infra_servers = ($infra_servers | merge { $server.provider: (mw_load_infra_servers_info $settings $server false)} ) } if ($infra_servers | get -o $server.provider | if ($in | describe | str starts-with "record") { [$in] } else { $in } | default [] | where {|it| $it.zone? != null and $it.zone == $server.zone and $it.store? != null and ($it.store | is-not-empty) } | length) == 0 { let store_data = (mw_load_infra_storages_info $settings $server false) if ($store_data |is-not-empty ) { $infra_servers = ($infra_servers | merge { $server.provider: (mw_load_infra_storages_info $settings $server false)} ) } } if ($infra_servers | is-empty) or ($infra_servers | get -o $server.provider | is-empty) { continue } let item = { item: (mw_get_infra_item $server $settings $infra_servers false), target: "server" } if ($item | get -o item | is-empty) { continue } #if $env.PROVISIONING_DEBUG_CHECK { _print ($item | table -e)} let already_created = (mw_server_exists $server false) let host_color = if $already_created { "green_bold" } else { "red" } let price_hour = (mw_get_infra_price $server $item "hour" false) let price = { hour: $price_hour, month: ((mw_get_infra_price $server $item "month" false) | math round -p 4) day : (($price_hour * 24) | math round -p 4) unit_info: (mw_get_infra_price $server $item "unit" false) } let str_server_plan = if ($server.reqplan? != null ) { $"($server.reqplan.cores | default 1)xCPU-(($server.reqplan.memory | default 1024) / 1024)GB ($server.plan)" } else { $server.plan } if ($price.hour > 0 or $price.month > 0) { $total_month += $price.month $total_hour += $price.hour $total_day += ($price.day) $table_items = ($table_items | append (add_item_price $server $already_created $str_server_plan "server" $price $host_color)) } for it in ($server | get -o storages | default [] | enumerate) { let storage = $it.item let storage_item = { item: (mw_get_infra_storage $server $settings $infra_servers false), target: "storage", src: $it } if ($storage_item | get -o item | is-empty) { continue } #if $env.PROVISIONING_DEBUG_CHECK { _print ($storage_item | table -e)} let storage_size = if ($storage | get -o parts | length) > 0 { ($storage | get -o parts | each {|part| $part | get -o size | default 0} | math sum) } else { ($storage | get -o size | default 0) } if $storage_size > 0 { let storage_targets = if ($storage | get -o parts | length) > 0 { ($storage | get -o parts | each {|part| $part | get -o mount_path | default ""} | str join " - ") } else { ($storage | get -o mount_path | default "") } let store_price_month = ((mw_get_infra_price $server $storage_item "month" false) * $storage_size | math round -p 4 ) let store_price_day = ((mw_get_infra_price $server $storage_item "day" false) * $storage_size | math round -p 4 ) let store_price_hour = ((mw_get_infra_price $server $storage_item "hour" false) * $storage_size | math round -p 4 ) let store_price = { month : $store_price_month, day : $store_price_day, hour : $store_price_hour unit_info: (mw_get_infra_price $server $storage_item "unit" false) } if ($store_price.hour > 0 or $store_price.month > 0) { $total_month += $store_price.month $total_hour += $store_price.hour $total_day += ($store_price.day) $table_items = ($table_items | append (add_item_price $server $already_created $"($storage_size) Gb ($storage_targets)" "store" $store_price $host_color)) } } } if not $check { let already_created = (mw_server_exists $server false) if not ($already_created) { if $return_no_exists { return { status: false, error: $"($server.hostname) not created" } # _print $"(_ansi red_bold)($server.hostname)(_ansi reset) not created" } } } #{ status: true, error: "" } } if ($env.PROVISIONING_OUT | is-empty) { $table_items = ($table_items | append { host: "", item: "", resource: "", prov: "", zone: "", unit: "", month: "", day: "", hour: "", created: ""}) } let str_total_month = if ($"($total_month)" | str contains ".") { ($total_month | math round -p 4 | fill -a left -c '0' -w 7 | str replace ',0000' '') } else { ($"($total_month).0" | fill -a left -c '0' -w 7 | str replace ',0000' '') } if ($env.PROVISIONING_OUT | is-empty) { $table_items = ($table_items | append { host: $"(_ansi --escape $total_color) TOTAL (_ansi reset)", item: $"(_ansi default_bold) (_ansi reset)", resource: $"(_ansi default_bold) (_ansi reset)", prov: $"(_ansi default_bold) (_ansi reset)", zone: $"(_ansi default_bold) (_ansi reset)", unit: $"(_ansi default_bold) (_ansi reset)", hour: $"(_ansi --escape $total_color) ($total_hour | math round -p 4 | fill -a left -c '0' -w 7 | str replace '.' ',') € (_ansi reset)", day: $"(_ansi --escape $total_color) ($total_day | math round -p 4 | fill -a left -c '0' -w 7 | str replace '.' ',') € (_ansi reset)", month:$"(_ansi --escape $total_color) ($str_total_month | str replace '.' ',' | str replace ',0000' '') € (_ansi reset)" created: $"(_ansi default_bold) (_ansi reset)", }) } else { $table_items = ($table_items | append { host: "TOTAL", item: "", resource: "", prov: "", zone: "", unit: "", hour: $"(_ansi --escape $total_color)($total_hour | math round -p 4 | fill -a left -c '0' -w 7 | str replace '.' ',') €(_ansi reset)", day: $"(_ansi --escape $total_color)($total_day | math round -p 4 | fill -a left -c '0' -w 7 | str replace '.' ',') €(_ansi reset)", month:$"(_ansi --escape $total_color)($str_total_month | str replace '.' ',' | str replace ',0000' '') €(_ansi reset)" created: false, }) } if $outfile != null { if ($outfile == "stdout") { return $table_items } else if ($outfile | str ends-with ".json") { $table_items | to json | save --force $outfile } else if ($outfile | str ends-with ".yaml") { $table_items | to yaml | save --force $outfile } else if ($outfile | str ends-with ".csv") { $table_items | to csv | save --force $outfile } else if ($outfile | str ends-with ".table") { $table_items | table -e | save --force $outfile } else { $table_items | to text | save --force $outfile } $env.PROVISIONING_NO_TERMINAL = false _print $"Prices saved in (_ansi cyan_bold)($outfile)(_ansi reset) " } else { $env.PROVISIONING_NO_TERMINAL = false match $env.PROVISIONING_OUT { "json" => { _print ($table_items | to json) "json" "result" "table" }, "yaml" => { _print ($table_items | to yaml) "yaml" "result" "table" }, _ => { _print ($table_items | table -i false) }, } } } export def wait_for_servers [ settings: record check: bool ip_type: string = "public" ]: nothing -> bool { mut server_pos = 0 mut has_errors = false for srvr in $settings.data.servers { $server_pos += 1 let ip = if $env.PROVISIONING_DEBUG_CHECK or $check { "127.0.0.1" } else { let curr_ip = (mw_get_ip $settings $srvr $ip_type false | default "") if $curr_ip == "" { _print $"πŸ›‘ No IP ($ip_type) found for (_ansi green_bold)($srvr.hostname)(_ansi reset) ($server_pos) " $has_errors = true continue } #use utils.nu wait_for_server if not (wait_for_server $server_pos $srvr $settings $curr_ip) { _print $"πŸ›‘ server ($srvr.hostname) ($curr_ip) (_ansi red_bold)not in running state(_ansi reset)" $has_errors = true continue } } _print $"on (_ansi green_bold)($srvr.hostname)(_ansi reset) ($ip)" } $has_errors } export def provider_data_cache [ settings: record --outfile (-o): string # Output file ]: nothing -> nothing { mut cache_already_loaded = [] for server in ($settings.data.servers? | default []) { _print $"server (_ansi green)($server.hostname)(_ansi reset) on (_ansi blue)($server.provider)(_ansi reset)" if ($cache_already_loaded | where {|it| $it == $server.provider} |length) > 0 { continue } else { $cache_already_loaded = ($cache_already_loaded | append $server.provider)} let provider_path = (get_provider_data_path $settings $server) #use ../lib_provisioning/utils/settings.nu load_provider_env let data = (load_provider_env $settings $server $provider_path) if ($data | is-empty) { _print $"❗server ($server.hostname) no data in cache path found ($provider_path | path basename)" exit } let outfile_path = if ($outfile | is-not-empty) { ($outfile | path dirname | path join $"($server.provider)_($outfile | path basename)") } else { "" } if ($outfile_path | is-not-empty ) { let out_extension = (get_file_format $outfile_path) if $out_extension == "json" { ($data | to json | save --force $outfile_path) } else { ($data | to yaml | save --force $outfile_path) } if ($outfile_path | path exists) { _print $"βœ… (_ansi green_bold)($server.provider)(_ansi reset) (_ansi cyan_bold)cache settings(_ansi reset) saved in (_ansi yellow_bold)($outfile_path)(_ansi reset)" _print $"To create a (_ansi purple)kcl(_ansi reset) for (_ansi cyan)defs(_ansi reset) file use:" let k_file_path = $"($outfile_path | str replace $'.($out_extension)' '').k" ^kcl import ($outfile_path) -o ($k_file_path) --force ^sed -i '1,4d;s/^{/_data = {/' $k_file_path '{ main = _data.main, priv = _data.priv }' | tee {save -a $k_file_path} | ignore let res = ( ^kcl $k_file_path | complete) if $res.exit_code == 0 { $res.stdout | save $"($k_file_path).yaml" --force ^kcl import $"($k_file_path).yaml" -o ($k_file_path) --force ^sed -i '1,4d;s/^{/_data = {/' $k_file_path let content = (open $k_file_path --raw) let comment = $"# ($server.provider)" + " environment settings, if not set will be autogenerated in 'provider_path' (data/" + $server.provider + "_cache.yaml)" let from_scratch = (mw_start_cache_info $settings $server) ($"# Info: KCL Settings created by ($env.PROVISIONING_NAME)\n# Date: (date now | format date '%Y-%m-%d %H:%M:%S')\n\n" + $"($comment)\n($from_scratch)" + $"# Use a command like: '($env.PROVISIONING_NAME) server cache -o /tmp/data.yaml' to genereate '/tmp/($server.provider)_data.k' for 'defs' settings\n" + $"# then you can move genereated '/tmp/($server.provider)_data.k' to '/defs/($server.provider)_data.k' \n\n" + $"import ($server.provider)_prov\n" + ($content | str replace '_data = {' $"($server.provider)_prov.Provision_($server.provider) {") | save $k_file_path --force ) let result = (encrypt_secret $k_file_path --quiet) if ($result | is-not-empty) { ($result | save --force $k_file_path) } _print $"(_ansi purple)kcl(_ansi reset) for (_ansi cyan)defs(_ansi reset) file has been created at (_ansi green)($k_file_path)(_ansi reset)" } #show_clip_to $"kcl import ($outfile_path) -o ($k_file_path) --force ; sed -i '1,4d;s/^{/_data = {/' ($k_file_path) ; echo '{ main = _data.main, priv = _data.priv }' >> ($k_file_path)" true } } else { let cmd = ($env| get -o PROVISIONING_FILEVIEWER | default (if (^bash -c "type -P bat" | is-not-empty) { "bat" } else { "cat" })) if $cmd != "bat" { _print $"(_ansi magenta_bold)----------------------------------------------------------------------------------------------------------------(_ansi reset)"} if $env.PROVISIONING_WK_FORMAT == "json" { ($data | to json | run-external $cmd -) } else { ($data | to yaml | run-external $cmd -) } if $cmd != "bat" { _print $"(_ansi magenta_bold)----------------------------------------------------------------------------------------------------------------(_ansi reset)"} } } } export def find_server [ item: string servers: list, out: string, ]: nothing -> record { if ($item | parse --regex '^[0-9]' | length) > 0 { let pos = ($item | into int) if ($pos >= ($servers | length)) { if ($out | is-empty) { _print $"No server index ($pos) found "} {} } else { ($servers | get -o ($item | into int) | default {}) } } else { ($servers | where {|s| ( $s | get -o hostname | default "") == $item} | get -o 0 | default {}) } } export def find_serversdefs [ settings: record ]: nothing -> record { let src_path = ($settings | get -o src_path | default "") mut defs = [] for it in ($settings | get -o data | get -o servers_paths | default []) { let name = ($it| str replace "/" "_") let it_path = if ($it | str ends-with ".k") { $it } else { $"($it).k" } let path_def = ($src_path | path join $it_path ) let defs_srvs = if ($path_def | path exists ) { (open -r $path_def) } else { "" } $defs = ($defs | append { name: $name, path_def: $it_path, def: $defs_srvs, defaults: "" } ) } let defaults_path = ($env.PROVISIONING | path join "kcl" | path join "defaults.k") let defaults = if ($defaults_path | path exists) { (open -r $defaults_path | default "") } else { "" } let path_main = ($env.PROVISIONING | path join "kcl" | path join "server.k") let main = if ($path_main | path exists) { (open -r $path_main | default "") } else { "" } let prov_defs = if ($env.PROVISIONING_PROVIDERS_PATH? == null) { { defs_providers: [], providers: [], } } else { let providers_list = (ls -s $env.PROVISIONING_PROVIDERS_PATH | where {|it| ( ($it.name | str starts-with "_") == false and ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path type) == "dir" and ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path join "templates" | path exists) ) }) let defs_providers = ($providers_list | each {|it| let it_path = ($src_path| path join "defs") let defaults = if ($it_path | path join $"($it.name)_defaults.k" | path exists) { (open -r ($it_path | path join $"($it.name)_defaults.k")) } else { "" } let def = if ($it_path | path join "servers.k" | path exists) { (open -r ($it_path | path join "servers.k")) } else { "" } { name: $it.name, path_def: $it_path, def: $def, defaults: $defaults } } | default []) let providers = ($providers_list | each {|it| let it_path = ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path join "kcl") let defaults = if ($it_path | path join $"defaults_($it.name).k" | path exists) { (open -r ($it_path | path join $"defaults_($it.name).k")) } else { "" } let def = if ($it_path | path join $"server_($it.name).k" | path exists) { (open -r ($it_path | path join $"server_($it.name).k")) } else { "" } { name: $it.name, path_def: $it_path, def: $def, defaults: $defaults } } | default []) { defs_providers: $defs_providers, providers: $providers, } } { defaults: $defaults, path_main: $path_main, main: $main, providers: $prov_defs.providers, defs_providers: $prov_defs.defs_providers, defs: $defs } } export def find_provgendefs [ ]: nothing -> record { let prov_defs = if ($env.PROVISIONING_PROVIDERS_PATH? == null) { { defs_providers: [], } } else { let providers_list = (ls -s $env.PROVISIONING_PROVIDERS_PATH | where {|it| ( ($it.name | str starts-with "_") == false and ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path type) == "dir" and ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path join "templates" | path exists) ) }) mut provdefs = [] for it in $providers_list { let it_defs_path = ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path join $env.PROVISIONING_GENERATE_DIRPATH | path join $env.PROVISIONING_GENERATE_DEFSFILE) if ($it_defs_path | path exists) { $provdefs = ($provdefs | append { name: $it.name, defs: (open $it_defs_path) }) } } $provdefs } $prov_defs }