chore: add current provisioning state before migration

This commit is contained in:
Jesús Pérez 2025-09-22 23:11:41 +01:00
parent a9703b4748
commit 50745b0f22
660 changed files with 88126 additions and 0 deletions

View file

@ -0,0 +1,362 @@
#!/usr/bin/env nu
# Info: UpCloud
# api.nu
export def upcloud_api_auth [
]: nothing -> string {
let upcloud_auth = if (($env | get -o UPCLOUD_AUTH | default "") | is-empty) {
let upcloud_username = ($env | get -o UPCLOUD_USERNAME | default "")
let upcloud_password = ($env | get -o UPCLOUD_PASSWORD | default "")
$"($upcloud_username):($upcloud_password)" | encode base64
} else {
($env | get -o UPCLOUD_AUTH | default "")
}
if $upcloud_auth == ":" or ($upcloud_auth | is-empty) {
_print $"🛑 Not found (_ansi purple)UpCloud(_ansi reset) (_ansi red)credentials(_ansi reset)"
return ""
}
$upcloud_auth
}
export def upcloud_api_url [
url_path: string
]: nothing -> any {
let upcloud_api_url = ($env | get -o UPCLOUD_API_URL | default "")
if ($upcloud_api_url | is-empty) {
_print $"🛑 Not found (_ansi purple)UpCloud(_ansi reset) (_ansi red)API URL(_ansi reset) not found"
return ""
}
$"($upcloud_api_url)/($url_path)"
}
export def upcloud_api_request [
method: string
url_path: string
data?: any
]: nothing -> any {
let $upcloud_auth = (upcloud_api_auth)
let upcloud_api_url = (upcloud_api_url $url_path)
if ($upcloud_auth | is-empty) or ($upcloud_api_url | is-empty) { return "" }
# http options $"($upcloud_api_url)/($url_path)" --allow-errors --headers [Origin "https://api.upcloud.com" Access-Control-Request-Headers "Content-Type, X-Custom-Header" Access-Control-Request-Method GET, "Authorization" $" Basic ($upcloud_auth)"]
let result = match $method {
"post" => {
if ($data | describe | str starts-with "record") {
http post --content-type application/json --allow-errors --headers ["Authorization" $" Basic ($upcloud_auth)"] $upcloud_api_url $data
} else {
http post --allow-errors --headers ["Authorization" $" Basic ($upcloud_auth)"] $upcloud_api_url $data
}
},
"put" => {
http put --allow-errors --headers ["Authorization" $" Basic ($upcloud_auth)"] $upcloud_api_url $data
}
"delete" => {
http delete --allow-errors --headers ["Authorization" $" Basic ($upcloud_auth)"] $upcloud_api_url
}
_ => {
http get --allow-errors --headers ["Authorization" $" Basic ($upcloud_auth)"] $upcloud_api_url
}
}
if ($result | describe) == "string" {
if ($result | is-empty) { return "OK" }
_print $"🛑 Error (_ansi purple)UpCloud(_ansi reset) (_ansi red)($upcloud_api_url)(_ansi reset):\n ($result)"
return ""
}
let status = ($result | get -o status | default "")
let error = ($result | get -o error | default "")
if ($status | is-not-empty) or ($error | is-not-empty) {
_print $"🛑 Error (_ansi purple)UpCloud(_ansi reset) (_ansi red)($upcloud_api_url)(_ansi reset)\n ($status) ($error))"
return ""
}
$result
}
export def upcloud_api_new_server [
server: record
]: nothing -> record {
{
hostname: "dev-wrkr",
zone: "es-mad1",
title: "dev-wrkr Debian server",
labels: {
label: [
{
"key": "test",
"value": ""
}
]
},
plan: "DEV-1xCPU-1GB",
#plan: "DEV-1xCPU-4GB",
metadata: "yes",
simple_backup: "0400,dailies",
timezone: "UTC",
storage_devices: {
storage_device: [
{
action: "clone",
labels: [
{
"key": "foo",
"value": "bar"
}
],
storage: "01000000-0000-4000-8000-000020070100" # Debian GNU/Linux 12 (Bookworm)
encrypted: "no",
title: "dev-wrkr Debian from a template",
#size: 50,
size: 20,
tier: "standard"
#tier: "maxiops"
}
]
},
networking: {
interfaces: {
interface: [
{
ip_addresses: {
ip_address: [
{
family: "IPv4"
}
]
},
type: "public"
},
{
ip_addresses: {
ip_address: [
{
family: "IPv4"
}
]
},
type: "utility"
},
{
ip_addresses: {
ip_address: [
{
family: "IPv6"
}
]
},
type: "public"
},
{
type: "private",
network: "03b1115c-522b-4608-ae08-9a4d32a2d16d"
source_ip_filtering: "yes"
ip_addresses: {
ip_address: [
{
family: "IPv4",
address: "10.11.2.11",
dhcp_provided: "no"
},
]
}
}
]
}
},
login_user: {
ssh_keys: {
ssh_key: [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM5GLeuDFUdLl7p72xt4nCOmCrdwP5QG1F16kIAQQlMT cdci"
]
}
}
}
}
export def upcloud_api_list_servers [
format?: string
]: nothing -> list {
let result = (upcloud_api_request "get" "server" )
if ($result | is-empty) {
return []
}
match $format {
"main" => {
mut servers_list = []
for it in ($result | get -o servers | flatten) {
let srv = ($it | get -o server )
$servers_list = ($servers_list | append {
state: ($srv| get -o state | default ""),
hostname: ($srv| get -o hostname | default ""),
uuid: ($srv| get -o uuid | default ""),
title: ($srv| get -o title | default ""),
plan: ($srv| get -o plan | default ""),
zone: ($srv| get -o zone | default ""),
memory_amount: ($srv| get -o memory_amount | default ""),
core_number: ($srv| get -o core_number | default ""),
simple_backup: ($srv| get -o simple_backup | default ""),
server_group: ($srv| get -o server_group | default ""),
})
}
$servers_list
},
_ => ($result | get -o servers | flatten)
}
}
export def upcloud_api_server_info [
hostname: string
]: nothing -> any {
let servers_list = (upcloud_api_list_servers | where {|it| $it.server.hostname == $hostname })
($servers_list | get -o 0 | get -o server | default "")
}
export def upcloud_api_server_uuid [
hostname: string
uuid: string
]: nothing -> string {
if ($uuid | is-empty) {
if ($hostname | is-empty) { return "" }
(upcloud_api_server_info $hostname | get -o uuid | default "")
} else { $uuid }
}
export def upcloud_api_server_ip [
server_info: record
type: string = "public"
family: string = "IPv4"
]: nothing -> any {
($server_info | get -o server | get -o networking | get -o interfaces | get -o interface
| flatten | where {|item| $item.type == $type} | get -o ip_address
| flatten | where {|it| $it.family == $family} | get -o address | get -o 0 | default ""
)
}
export def upcloud_api_server_uuid_ip [
uuid: string
type: string = "public"
family: string = "IPv4"
]: nothing -> any {
let result = (upcloud_api_request "get" $"server/($uuid)" )
if ($result | is-empty) { return "" }
(upcloud_api_server_ip $result $type $family)
}
export def upcloud_api_server_new_state [
state: string
uuid: string
wait: int = 60
]: nothing -> any {
(upcloud_api_request
"post"
$"server/($uuid)/($state)"
{ stop_server: { stop_type: "soft", timeout: $wait } }
)
}
export def upcloud_api_server_state [
hostname: string
uuid: string
]: nothing -> any {
if ($uuid | is-not-empty) {
(upcloud_api_request "get" $"server/($uuid)" | get -o state | default "" )
} else if ($hostname | is-not-empty) {
(upcloud_api_server_info $hostname | get -o state | default "")
} else {
""
}
}
export def upcloud_api_server_delete [
hostname: string
uuid: string
# storages Controls what to do with storages related to the deleted server. 0, 1, true, false 0
storage: bool = true
# backups If storages are to be deleted, controls what to do with backups related to the storages. keep, keep_latest, delete keep
backups: string = "delete"
]: nothing -> any {
let server_uuid = (upcloud_api_server_uuid $hostname $uuid)
if ($server_uuid | is-empty) {
_print $"🛑 Error (_ansi purple)UpCloud(_ansi reset) DELETE (_ansi red)($hostname) ($uuid)(_ansi reset)"
return
}
(upcloud_api_request "delete" $"server/($uuid)?storages=($storage)&backups=($backups)")
}
export def upcloud_api_get_info [
hostname: string
type: string = "public"
family: string = "IPv4"
]: nothing -> string {
let server = (upcloud_api_server_info $hostname)
if ($server | is-empty) { return "" }
# _print ($server | table -e)
let uuid = ($server | get -o uuid | default "")
if ($uuid | is-empty) { return "" }
(upcloud_api_server_uuid_ip $uuid "public" "IPv4")
}
export def upcloud_api_test [
]: nothing -> string {
let hostname = "dev-wrkr"
# let result = (upcloud_api_request "get" "account")
# if ($result | is-not-empty) and ($result | get -o account | get -o credits | default "" | is-not-empty) {
# _print $"Account '($result | get -o account | get -o username | default "")' credit: ($result | get -o account | get -o credits)"
# }
let server_info = (upcloud_api_server_info $hostname)
if ($server_info | is-not-empty) {
_print $"🛑 Error (_ansi purple)UpCloud(_ansi reset) create (_ansi red)($hostname)(_ansi reset)"
_print $"Server (_ansi green)($hostname)(_ansi reset) ($server_info | get -o uuid | default "") => ($server_info | get -o state | default "")"
} else {
_print $"Server (_ansi green)($hostname)(_ansi reset) creation ..."
let server_data = (upcloud_api_new_server {})
let result = (upcloud_api_request "post" "server" { server: $server_data} )
if ($result | is-not-empty) {
let pub_ip = (upcloud_api_server_ip $result "public" "IPv4")
if ($pub_ip | is-not-empty) {
_print $"ssh -i $HOME/.ssh/id_cdci -l root ($pub_ip)"
}
}
}
#let pub_ip = (upcloud_get_info $hostname "public" "IPv4")
_print $"Server (_ansi green)($hostname)(_ansi reset) state: (upcloud_api_server_state $hostname "")"
let servers_list = (upcloud_api_list_servers "main")
_print ($servers_list | table -i false -e)
let server = (upcloud_api_server_info $hostname)
if ($server | is-empty) { exit }
# _print ($server | table -e)
let uuid = ($server | get -o uuid | default "")
if ($uuid | is-empty) { exit }
let pub_ip = (upcloud_api_server_uuid_ip $uuid "public" "IPv4")
if ($pub_ip | is-not-empty) {
_print $"ssh -i $HOME/.ssh/id_cdci -l root ($pub_ip)"
}
let server_state = (upcloud_api_server_state $hostname "")
if $server_state == "maintenance" or $server_state == "error" {
_print $"🛑 Server (_ansi green)($hostname)(_ansi reset) in (_ansi red)($server_state)(_ansi reset) !!! "
exit 1
}
if $server_state == "started" {
let wait = 20
let max_wait = 240
mut wait_time = 0
_print $"Server (_ansi green)($hostname)(_ansi reset) state: (_ansi yellow)($server_state)(_ansi reset)"
_print $"Server (_ansi green)($hostname | default "")(_ansi reset) ($uuid) to (_ansi yellow)stop(_ansi reset) state ... try every ($wait)sec until ($max_wait)sec"
_print -n $"(_ansi blue_bold) 🌥 (_ansi reset)"
(upcloud_api_server_new_state "stop" $uuid 30)
while true {
if (upcloud_api_server_state $hostname "") == "stopped" { break }
$wait_time = ($wait_time + $wait)
if ($wait_time > $max_wait) {
_print $"🛑 Server (_ansi green)($hostname)(_ansi reset) state (_ansi red)stop(_ansi reset) not found in ($max_wait)secs !!! "
exit 1
}
print -n $"(_ansi blue_bold) 🌥 (_ansi reset) [($wait_time)]"
sleep ($"($wait)sec"| into duration)
}
_print ""
}
let result = (upcloud_api_server_delete "" $uuid)
if $result == "OK" {
_print $"Server (_ansi green)($hostname)(_ansi reset) DELETED "
_print (upcloud_api_server_info $hostname)
}
}

View file

@ -0,0 +1,93 @@
#!/usr/bin/env nu
# Info: UpCloud
use std
export def upcloud_start_cache_info [
settings: record
server: record
] {
$""
}
export def upcloud_create_cache [
settings: record
server: record
error_exit: bool
] {
if $settings == null {
print $"❗ No settings found "
return
}
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-not-empty) or ($data | get -o main) != "?" {
if $env.PROVISIONING_DEBUG {
print $"UpCloud main data already exists in ($provider_path | path basename)"
}
}
let result = (^upctl "server" "show" $server.hostname -o "json" err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" })| complete)
let info_server = if $result.exit_code == 0 {
($result.stdout | from json)
} else { {} }
let all_servers = if ($data.servers? == null) {
{}
} else if ($info_server | is-empty) {
$data.servers
} else {
$data.servers | default {} | append $info_server
}
let new_data = ( $data | merge { servers: $all_servers})
save_provider_env $new_data $settings $provider_path
if $env.PROVISIONING_DEBUG { print $"Cache for ($server.provider) on ($server.hostname) saved in: ($provider_path | path basename)" }
}
export def upcloud_read_cache [
settings: record
server: record
error_exit: bool
] {
if $settings == null {
print $"❗ No settings found "
return
}
}
export def upcloud_clean_cache [
settings: record
server: record
error_exit: bool
] {
if $settings == null {
print $"❗ No settings found "
return
}
let provider_path = (get_provider_data_path $settings $server)
let data = (load_provider_env $settings $server $provider_path)
if ($data.servers? == null) { return {} }
if ($data.servers | where {|it| ($it.hostname? | default "") == $server.hostname} | length) == 0 {
if $env.PROVISIONING_DEBUG {
print $"❗server ($server.hostname) already deleted from ($provider_path | path basename)"
}
return
}
let all_servers = ( $data.servers? | default [] | where {|it| ($it.hostname? | is-not-empty) and ($it.hostname? | default "") != $server.hostname})
if $env.PROVISIONING_DEBUG { print $"Cache for ($server.provider) delete ($server.hostname) in: ($provider_path | path basename)" }
let new_data = if ($all_servers | length) == 0 {
( $data | merge { servers: []})
} else {
( $data | merge { servers: $all_servers})
}
save_provider_env $new_data $settings $provider_path
}
export def upcloud_ip_from_cache [
settings: record
server: record
error_exit: bool
] {
let data = ($settings.providers | find $server.provider | get -o settings | get -o servers | flatten
| find $server.hostname | select -o ip_addresses)
mut pub_ip = ""
for it in $data {
$pub_ip = ($it | get -o ip_addresses | find "public" | get -o address | get -o 0)
}
$pub_ip
}

View file

@ -0,0 +1,6 @@
export-env {
$env.UPCLOUD_API_URL = ($env | get -o UPCLOUD_API_URL | default "https://api.upcloud.com/1.3")
$env.UPCLOUD_AUTH = ($env | get -o UPCLOUD_AUTH | default "")
$env.UPCLOUD_INTERFACE = ($env | get -o UPCLOUD_INTERFACE | default "CLI") # API or CLI
#$env.UPCLOUD_INTERFACE = ($env | get -o UPCLOUD_INTERFACE | default "API") # API or CLI
}

View file

@ -0,0 +1,13 @@
upcloud_api_auth
upcloud_api_url
upcloud_api_request
upcloud_api_new_server
upcloud_api_list_servers
upcloud_api_server_info
upcloud_api_server_uuid
upcloud_api_server_ip
upcloud_api_server_uuid_ip
upcloud_api_server_new_state
upcloud_api_server_state
upcloud_api_server_delete
upcloud_api_get_info

View file

@ -0,0 +1,6 @@
use env.nu
export use servers.nu *
export use cache.nu *
export use usage.nu *
export use utils.nu *
export use prices.nu *

View file

@ -0,0 +1,304 @@
export def upcloud_sel_data_table [
data: any
id: string
] {
($data | where {|it| $it.id == $id } | get -o table | get -o 0)
}
export def upcloud_get_plan_prefix [
id: string
] {
match $id {
"general-purpose" | "general" => "",
"developer-plans" | "dev" => "DEV-",
"high-cpu-plans" | "high-cpu" | "cpu" => "HICPU-",
"high-memory-plans" | "high-memory" | "memory" | "ram" => "HIMEM-",
_ => "",
}
}
export def upcloud_get_id_from_plan [
plan: string
] {
if ($plan | str starts-with "HICPU-") {
"high-cpu-plans"
} else if ($plan | str starts-with "HIMEM-") {
"high-memory-plans"
} else if ($plan | str starts-with "DEV-") {
"developer-plans"
} else {
"general-purpose"
}
}
export def upcloud_sel_table_item [
data: list
key: string
condition: string
value: string
] {
($data | where {|it|
let item_data = match $key {
"memory" | "ram" => ($it | get $key | get 0 | str replace "GB" "" | str trim),
_ => ($it | get $key | get 0 ),
}
(match $condition {
"lt" | "<" => (($item_data | into int ) < ($value | str replace "GB" "" | into int)),
"lte" | "<=" => (($item_data | into int ) <= ($value | str replace "GB" "" | into int)),
_ => false
})
}| flatten)
}
export def upcloud_get_price [
all_data: record
key: string
price_col: string = "global_price"
] {
let data = ($all_data | get -o item)
let str_price_col = if ($price_col | is-empty) { "global_price" } else { $price_col }
match ($all_data | get -o target) {
"server" => {
let table_key = if $key == "unit" { "hour" } else { $key }
let value = ($data | get -o $str_price_col | flatten | get -o $table_key | default "" | str replace -a "€" "" )
if $key == "unit" {
$"($value | get -o 0) Hrs"
} else if ($value | is-not-empty) {
($value | get -o 0 | into float)
} else {
0
}
},
"storage" => {
# Index 0 should be part of the server PLAN
let it = ($all_data | get -o src )
if ($it | is-empty) or ($it | get -o item | is-empty) { return 0 }
if ($it.index) == 0 { return 0 }
let storage = $it.item
let storage_type = match ($storage | get -o voltype) {
"maxiops" => "MaxIOPS",
"hdd" => "HDD",
"custom" => "Custom image",
}
let month = ($data | find $storage_type | select $str_price_col | flatten | into record | get -o month | default "" | str replace -a "€" "" | into float)
let hour = ($data | find $storage_type | select $str_price_col | flatten | into record | get -o hour | default "" | str replace -a "€" "" | into float)
match $key {
"unit" =>
$"($data | find $storage_type | select $str_price_col | flatten | into record | get -o month | default "" | str replace -a "€" "") GB-Mo",
"month" =>
($data | find $storage_type | select $str_price_col | flatten | into record | get -o month | default "" | str replace -a "€" "" | into float),
"day" =>
(($data | find $storage_type | select $str_price_col | flatten | into record | get -o hour | default "" | str replace -a "€" "" | into float) * 24),
"hour" =>
($data | find $storage_type | select $str_price_col | flatten | into record | get -o hour | default "" | str replace -a "€" "" | into float),
_ => 0,
}
},
"networking" => {
0
},
"backups" => {
0
},
_ => {
0
}
}
}
export def upcloud_get_item_for_storage [
server: record
settings: record
cloud_data: record
] {
let data = ($cloud_data | get -o $server.provider| get -o "block_storage")
if ($data | is-empty) { return {} }
($data | get -o table | get -o 0)
}
export def upcloud_get_item_for_server [
server: record
settings: record
cloud_data: record
] {
let data = ($cloud_data | get -o $server.provider | get -o "servers")
if ($data | is-empty) { return {} }
let plan = ($server | get -o plan | default "")
let key_id = (upcloud_get_id_from_plan $plan)
let cloud_table_data = (upcloud_sel_data_table $data $key_id)
if ($cloud_table_data | is-empty) { return {} }
($cloud_table_data | where {|it|
($it | get -o plan ) == $plan
} | get -o 0)
}
export def upcloud_clean_table [
id: string
data: string
target: string
] {
let table = ( $data | split row "<tr>" | where {|it| $it | str starts-with "<" } |
each {|it| $it | str replace -a -r "<(\/td|sup|\/sup|small|\/small|b|\/b|br|\/tr|tbody|\/tbody|\/thead|\/th)>" "" }
)
let table_cols = if ($table | get 0 | str contains "<th>") {
($table | get 0 | split row "<th>")
} else {
($table | get 0 | split row "<td>")
}
let cols = ($table_cols | where {|it| $it != "" } | str replace " *" " " |
str trim | str downcase | str replace " " "_" | str replace 'price*' 'price')
let plan_prefix = (upcloud_get_plan_prefix $id)
let res = ( $table | drop nth 0 | each {|line| $line | split column "<td>" -c ...$cols } |
each {|it|
#if $target == "networking" => { print $it }
match $target {
"block-storage" => {
$it |
update storage_type $"($it | get -o 'storage_type' | get -o 0 )" |
update global_price ($it| get -o global_price | get -o 0 | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0) |
update helsinki_price ($it| get -o helsinki_price | get -o 0 | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0)
},
"object-storage" => {
$it |
update price ($it| get -o price | get -o 0 | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0) |
},
"cloud-servers" | "servers" => {
let helsinki_price = ($it| get -o helsinki_price | get -o 0 | default "")
if ($helsinki_price | is-not-empty) {
$it | insert plan $"($plan_prefix)($it | get -o 'cpu_cores' | get -o 0 )xCPU-($it | get -o 'memory' | get -o 0 | str replace ' ' '')" |
update global_price ($it| get -o global_price | get -o 0 | default "" | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0) |
update helsinki_price ($it| get -o helsinki_price | get -o 0 | default "" | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0)
} else {
$it | insert plan $"($plan_prefix)($it | get -o 'cpu_cores' | get -o 0 )xCPU-($it | get -o 'memory' | get -o 0 | str replace ' ' '')" |
update global_price ($it| get -o global_price | get -o 0 | default "" | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0) |
}
},
"simple-backups" => {
$it | update global_price ($it| get -o global_price | get -o 0 | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0) |
update helsinki_price ($it| get -o helsinki_price | get -o 0 | parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h" | get -o 0)
},
"networking" => {
$it | update price ($it| get -o price | get -o 0 | str replace "Price" "---" | str replace " " " " |
parse --regex "(?<month>.*?)/mo (?<hour>.*?)/h|(?<price>.*)" | get -o 0)
},
_ => { $it },
}
})
($res | flatten)
}
export def upcloud_get_provider_path [
settings: record
server: record
] {
let data_path = if ($settings.data.prov_data_dirpath | str starts-with "." ) {
($settings.src_path | path join $settings.data.prov_data_dirpath)
} else { $settings.data.prov_data_dirpath }
if not ($data_path | path exists) { mkdir $data_path }
($data_path | path join $"($server.provider)_prices.($env.PROVISIONING_WK_FORMAT)")
}
export def upcloud_load_infra_storages_info [
settings: record
server: record
error_exit: bool
] {
let data = (upcloud_load_infra_servers_info $settings $server $error_exit)
let res = ($data | get -o "block-storage")
print ($res | table -e)
$res
}
export def upcloud_load_infra_servers_info [
settings: record
server: record
error_exit: bool
]: nothing -> record {
let provider_prices_path = (upcloud_get_provider_path $settings $server)
let data = if ($provider_prices_path | path exists) {
open $provider_prices_path
} else {
let url = "https://upcloud.com/pricing"
let pricing_html_path = ($env.PROVISIONING_PROVIDERS_PATH | path join "upcloud" | path join "pricing.html")
{ servers: (upcloud_load_infra $url $pricing_html_path "cloud-servers"),
block_storage: (upcloud_load_infra $url $pricing_html_path "block-storage"),
object_storage: (upcloud_load_infra $url $pricing_html_path "object-storage"),
backups: (upcloud_load_infra $url $pricing_html_path "simple-backups"),
networking: (upcloud_load_infra $url $pricing_html_path "networking"),
}
}
if ($provider_prices_path | path exists) { return $data }
if $env.PROVISIONING_WK_FORMAT == "json" {
$data | to json | save -f $provider_prices_path
} else {
$data | to yaml | save -f $provider_prices_path
}
if $env.PROVISIONING_DEBUG { print $"Price for ($server.provider) in: ($provider_prices_path | path basename)" }
$data
}
export def upcloud_load_infra [
url: string
html_path: string
target: string = "servers"
]: nothing -> list {
let id_target = match $target {
"object" | "object-storage" | "os" => "object-storage",
"block" | "block-storage" | "bs" => "block-storage",
"server" | "servers" | "s" => "cloud-servers",
"backup" | "simple-backups" | "s" => "simple-backups",
"network" | "networking" | "s" => "networking",
_ => "cloud-servers",
}
# cookie error if use curl o http get
let html_content = if ($html_path | path exists) {
open -r $html_path
} else {
#let res = (http get $url -r )
let res = (^curl -s $url | complete)
if ($res.exit_code != 0) {
print $"🛑 Error (_ansi red)($url)(_ansi reset):\n ($res.exit_code) ($res.stderr)"
return ""
} else { $res.stdout }
}
($html_content | split row "<section "| find $'id="($id_target)"' | split row role="tabpanel" | find "<table" | each {|it|
let id = ($it | parse --regex 'id="(?<id>.*?)"' | get id | get -o 0 | str replace -r "-tab$" "")
let title = ($it | parse --regex '<h3>(?<title>.*?)<\/h3>' | get title | get -o 0)
let info = ($it | parse --regex '<\/h3><p>(?<info>.*?)<\/p>' | get info | get -o 0)
let table = ($it | parse --regex '<table\s*(?<table>.*?)<\/table>' | get table | get -o 0)
{ id: $id, table: (upcloud_clean_table $id $table $id_target), title: $title, info: $info }
})
# mut $group_data = {}
# for item in $data {
# print $item
# let group = ($item | get -o id)
# let table = ($item | get -o table)
# print $group
# print ($table | flatten | table -e)
# if ($group | is-empty) { continue }
# # if ($group_data | get -o $group | is-empty) {
# # $group_data = ($group_data | merge { $group: [($item | reject id)]})
# # } else {
# # $group_data = ($group_data | merge { $group: ($group_data | get -o $group | append ($item | reject id))})
# # }
# }
# exit
# $group_data
# each { |it| $it | parse --regex 'id="(?<id>.*?)"(?<other>.*)<h3>(?<title>.*)<\/h3><p>(?<info>.*)</p>(?.*)<table\s*(?<table>.*)<\/table>' }
# where {|it| $it | str starts-with "<" } |
#print ($cloud_servers | each {|it| select id table} | flatten | each {|it|
#let res = ($cloud_servers | each {|it| select id table} | flatten | each {|it|
# let id = ($it.id | str replace -r "-tab$" "")
# { id: $id, table: (upcloud_clean_table $id $it.table) }
# }
#)
}
export def upcloud_test_infra_servers [
] {
let data_infra_servers = (upcloud_load_infra_servers "https://upcloud.com/pricing")
let key_id = ($data_infra_servers | get id | input list "Select server group ")
let cloud_data = (upcloud_sel_data_table $data_infra_servers $key_id)
let mem_limit = (["4 GB" "8 GB" "16 GB" "32 GB" "64 GB" "96 GB" "128 GB" "256 GB" "512 GB" ] | input list "Select MEMORY limit ")
let items = (upcloud_sel_table_item $cloud_data "memory" "lte" $mem_limit)
print ($items | table -e)
#let line = ($cloud_servers | get 0 | get table | get 1 )
print $"From ($key_id) with ($mem_limit)\n"
print $"memory | cores | month | hour | plan "
print "============================================="
for line in $items {
print ($"($line | get memory) \t| ($line | get cpu_cores) \t| (upcloud_get_price $line 'month')" +
$" \t| (upcloud_get_price $line 'hour') | ($line | get plan) "
)
}
}

View file

@ -0,0 +1,829 @@
#!/usr/bin/env nu
# Info: UpCloud
# servers.nu
use std
use api.nu *
export def upcloud_interface [
]: nothing -> string {
($env | get -o UPCLOUD_INTERFACE | default "CLI") # API or CLI
}
export def upcloud_use_api [
]: nothing -> bool {
(upcloud_interface) == "API"
}
export def upcloud_query_servers [
find: string
cols: string
]: nothing -> list {
if upcloud_use_api {
upcloud_api_list_servers
} else {
let res = (^upctl server list -o json err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code == 0 {
$res.stdout | from json | get servers
} else {
if $env.PROVISIONING_DEBUG {
(throw-error "🛑 upctl server list " $"($res.exit_code) ($res.stdout)" "upcloud query server" --span (metadata $res).span)
} else {
print $"🛑 Error upctl server list: ($res.exit_code) ($res.stdout | ^grep 'error')"
}
}
}
}
export def upcloud_server_info [
server: record
check: bool
]: nothing -> record {
let hostname = $server.hostname
if (upcloud_use_api) {
upcloud_api_server_info $hostname
} else {
let res = (^upctl server show $hostname -o json err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code == 0 {
$res.stdout | from json
} else if $check {
{}
} else {
if $env.PROVISIONING_DEBUG {
(throw-error "🛑 upctl server show" $"($res.exit_code) ($res.stdout)" $"upcloud server info ($hostname)" --span (metadata $res).span)
} else {
print $"🛑 upctl server show ($hostname):($res.stdout | ^grep 'error')"
}
}
}
}
export def upcloud_on_prov_server [
server?: record
] {
#let info = if ( $env.CURRENT_FILE? | into string ) != "" { (^grep "^# Info:" $env.CURRENT_FILE ) | str replace "# Info: " "" } else { "" }
#$"From (_ansi purple_bold)UpCloud(_ansi reset)"
}
# infrastructure and services
export def upcloud [
args: list<string> # Args for create command
--server(-s): record
--serverpos (-p): int # Server position in settings
--check (-c) # Only check mode no servers will be created
--wait (-w) # Wait servers to be created
--infra (-i): string # Infra path
--settings (-s): string # Settings path
--outfile (-o): string # Output file
--debug (-x) # Use Debug mode
]: nothing -> any {
if $debug { $env.PROVISIONING_DEBUG = true }
let target = ($args | get -o 0 | default "")
let task = ($args | get -o 1 | default "")
let cmd_args = if ($args | length) > 1 { ($args | drop nth ..1) } else { [] }
match ($task) {
"help" | "h" => {
print "TODO upcloud help"
if not $env.PROVISIONING_DEBUG { end_run "" }
exit
},
_ => {
if ($args | find "help" | length) > 0 {
match $task {
"server" => {
print "SERVER "
upcloud_server ($args | drop nth ..0)
},
"inventory" => {
upcloud_server ($args | drop nth ..0)
},
"ssh" => {
upcloud_server ($args | drop nth ..0)
},
"delete" => {
upcloud_server ($args | drop nth ..0)
# ($args | drop nth ..1) --server $server
},
_ => {
option_undefined "upcloud" ""
print "TODO upcloud help"
}
}
if not $env.PROVISIONING_DEBUG { end_run "" }
exit
}
}
}
#use utils/settings.nu [ load_settings ]
let curr_settings = if $infra != null {
if $settings != null {
(load_settings --infra $infra --settings $settings)
} else {
(load_settings --infra $infra)
}
} else {
if $settings != null {
(load_settings --settings $settings)
} else {
(load_settings)
}
}
match ($task) {
"get_ip" => {
upcloud_get_ip $curr_settings $server ($cmd_args | get -o 0 | default "")
},
"server" => {
print (
upcloud_server $cmd_args --server $server --settings $curr_settings --error_exit
)
},
"inventory" => {
},
"ssh" => {
},
"delete" => {
# ($args | drop nth ..1) --server $server
},
_ => {
option_undefined "upcloud" ""
if not $env.PROVISIONING_DEBUG { end_run "" }
exit
}
}
}
export def upcloud_get_ip [
settings: record
server: record
ip_type?: string = "public"
family?: string = "IPv4"
]: nothing -> string {
match $ip_type {
"private" | "prv" | "priv" => {
$"($server.network_private_ip)"
},
_ => {
if (upcloud_use_api) {
let server = (upcloud_api_server_info $server.hostname)
if ($server | is-empty) { return "" }
let uuid = ($server | get -o uuid | default "")
if ($uuid | is-empty) { return "" }
(upcloud_api_server_uuid_ip $uuid $ip_type $family)
} else {
let result = (^upctl "server" "show" $server.hostname "-o" "json" | complete)
if $result.exit_code == 0 {
let data = ($result.stdout | from json)
#let id = ($data.id? | default "")
let ip_addresses = ($data.networking?.interfaces? | where {|it| ($it.type | str contains "public") }).ip_addresses?
$"(($ip_addresses | get -o 0).address? | get -o 0 | default '')"
} else { "" }
}
}
}
}
# To create infrastructure and services
export def upcloud_server [
args: list<string> # Args for create command
--server: record
--error_exit
--status
--serverpos (-p): int # Server position in settings
--check (-c) # Only check mode no servers will be created
--wait (-w) # Wait servers to be created
--infra (-i): string # Infra path
--settings (-s): record # Settings path
--outfile (-o): string # Output file
--debug (-x) # Use Debug mode
]: nothing -> nothing {
let task = ($args | get -o 0)
let target = if ($args | length) > 1 { ($args | get -o 1) } else { "" }
let cmd_args = if ($args | length) > 1 { ($args | drop nth ..1) } else { [] }
match ($task) {
"help" | "h" | "" => {
print "TODO upcloud server help"
if not $env.PROVISIONING_DEBUG { end_run "" }
exit
},
_ => {
if $target == "" or ($args | find "help" | length) > 0 {
match $task {
"server" => {
upcloud_server $cmd_args
},
"status" => {
print $server
print $error_exit
}
"inventory" => {
print "TODO upcloud server inventory help"
},
"ssh" => {
print "TODO upcloud server ssh help"
},
"delete" => {
# ($args | drop nth ..1) --server $server
#upcloud_delete_server $cmd_args true
},
_ => {
option_undefined "upcloud" "server"
print "TODO upcloud server help"
}
}
if not $env.PROVISIONING_DEBUG { end_run "" }
exit
}
}
}
let server_target = if $server != null {
$server
} else if $settings != null {
($settings.data.servers | where {|it| $it.hostname == $target } | get -o 0)
} else {
null
}
if $server_target == null {
if $error_exit {
let text = $"($args | str join ' ')"
(throw-error "🛑 upcloud server" $text "" --span (metadata $server_target).span)
}
return ""
}
if $status or $task == "status" {
print "upcloud server status "
return true
}
match $task {
"get_ip" => {
upcloud_get_ip $settings $server_target ($cmd_args | get -o 0 | default "")
},
"stop" => {
print "TODO upcloud server stop"
},
"start" => {
print "TODO upcloud server start"
},
"restart" => {
print "TODO upcloud server restart"
},
_ => {
option_undefined "upcloud" "server"
if not $env.PROVISIONING_DEBUG { end_run "" }
exit
}
}
}
export def upcloud_create_private_network [
settings: record
server: record
check: bool
] {
if $server == null {
print $"❗ No server found in settings "
return ""
}
# new_upctl network list -o json |
# let net_id = ($data.networks | get -o 0 ).uuid)
let zone = ( $server.zone? | default "")
if $zone == "" {
print $"($server.hostname) No zone found to CREATE network_privat_id"
return ""
}
let network_private_name = ($server.network_private_name? | default "")
if $network_private_name == "" {
print $"($server.hostname) No network_private_name found to CREATE network_privat_id"
return ""
}
let priv_cidr_block = ($server.priv_cidr_block | default "")
if $network_private_name == "" {
print $"($server.hostname) No priv_cidr_block found to CREATE network_privat_id"
return ""
}
let private_net_id = if (upcloud_use_api) {
# TODO make it via API
""
} else {
# EXAMPLE_BASH private_net_id=$(upctl network list -o yaml | $YQ '.networks[] | select(.ip_networks.ip_network[].address == "'"$priv_cidr_block"'") | .uuid' 2>/dev/null | sed 's,",,g')
let result = (^upctl network list -o json | complete)
if $result.exit_code == 0 {
let data = ($result.stdout | from json | get -o networks | find $priv_cidr_block | get -o 0 | get -o uuid | default "" | str trim)
} else {
""
}
}
if $check and ($private_net_id | is-empty) {
print $"❗private_network will be register in a real creation request not in check state"
return ""
} else {
let result = (^upctl network create --name ($network_private_name) --zone $zone --ip-network $"address=($priv_cidr_block),dhcp=true" -o json | complete)
let new_net_id = if $result.exit_code == 0 {
($result.stdout | from json | find $priv_cidr_block | get -o uuid | default "")
} else { "" }
if ($new_net_id | is-empty) {
(throw-error $"🛑 no private network '($network_private_name)' created"
$"for server ($server.hostname) ip ($server.network_private_ip)\n($result.stdout)"
$"upcloud_create_private_network" --span (metadata $new_net_id).span)
exit
}
# Save changes ...
#use utils/settings.nu [ save_servers_settings save_settings_file ]
let match_text = " network_private_id = "
let default_provider_path = ($settings.data | get -o servers_paths | get -o 0 | default "" | path dirname | path join $"($server.provider)_defaults.k")
let old_text = 'network_private_id = "CREATE"'
let new_text = $'network_private_id = "($new_net_id)"'
save_settings_file $settings $default_provider_path $old_text $new_text
return $new_net_id
}
return ""
}
export def upcloud_check_server_requirements [
settings: record
server: record
check: bool
] {
if $server.provider == "upcloud" {
if (^upctl account show "-o" "json" err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete).exit_code != 0 and $check {
(throw-error $"🛑 no account found"
$"for server ($server.hostname)"
"upcloud_check_server_requirements" --span (metadata $server.provider).span)
exit
}
let private_net_id = if ($server.network_private_id? | default "") == "CREATE" {
print $"❗($server.network_private_id?) found for (_ansi yellow)network_private_id(_ansi reset) will be created for ($server.priv_cidr_block | default '')"
(upcloud_create_private_network $settings $server $check)
} else {
($server.network_private_id? | default "" )
}
if ($private_net_id | is-empty) and $check {
return true
}
let result = (^upctl network show $private_net_id -o json | complete)
let privavet_net_id = if (not $check) and $result.exit_code != 0 {
let net_id = (upcloud_create_private_network $settings $server $check)
let res = (^upctl "network" "show" $private_net_id "-o" "json" | complete)
if $res.exit_code != 0 {
print $"❗Error: no ($private_net_id) found "
" "
} else {
let data = ($result.stdout | from json )
($data.networks | get -o 0 | get -o uuid)
}
} else if $result.exit_code == 0 {
let data = ($result.stdout | from json)
($data.uuid)
} else {
""
}
let server_private_ip = ($server.network_private_ip? | default "")
if $private_net_id == "" and $server_private_ip != "" {
(throw-error $"🛑 no private network ($private_net_id) found"
$"for server ($server.hostname) ip ($server_private_ip)"
"upcloud_check_requirements" --span (metadata $server_private_ip).span)
exit
}
}
true
}
export def upcloud_make_settings [
settings: record
server: record
] {
let out_settings_path = $"($settings.infra_fullpath)/($server.provider)_settings.yaml"
let data = if ($out_settings_path | path exists ) {
(open $out_settings_path | from yaml)
} else {
null
}
let task = if $data != null { "update" } else { "create" }
let uuid = (^upctl server show $server.hostname "-o" "json" | from json).uuid? | default ""
if $uuid == "" {
return false
}
let ip_pub = (upcloud_get_ip $settings $server "public")
let ip_priv = (upcloud_get_ip $settings $server "private")
let server_settings = {
name: $server.hostname,
id: $uuid,
private_net: {
id: $server.network_private_id
name: $server.network_private_name
},
zone: $server.zone,
datetime: $env.NOW,
ip_addresses: {
pub: $ip_pub, priv: $ip_priv
}
}
let new_data = if $data != null and $data.servers? != null {
( $data.servers | each { |srv|
where {|it| $it.name != $server.hostname }
}) | append $server_settings
} else {
{
servers: [ $server_settings ]
}
}
$new_data | to yaml | save --force $out_settings_path
print $"✅ upcloud settings ($task) -> ($out_settings_path)"
true
}
export def upcloud_delete_settings [
settings: record
server: record
] {
}
export def upcloud_post_create_server [
settings: record
server: record
check: bool
] {
mut req_storage = ""
for storage in ($server | get -o storages | enumerate) {
let res = (upcloud_storage_fix_size $settings $server $storage.index)
if ($req_storage | is-empty) and ($res | is-not-empty) {
$req_storage = $res
}
}
$req_storage
}
export def upcloud_modify_server [
settings: record
server: record
new_values: list
error_exit: bool
] {
mut args = ""
for item in $new_values {
if ($item | get -o plan | is-not-empty) { $args = $args + $" --plan ($item.plan)" }
}
if ($args | is-empty) { return }
print $"Stop (_ansi blue_bold)($server.hostname)(_ansi reset) to modify (_ansi yellow_bold)($args)(_ansi reset)"
if (upcloud_change_server_state $settings $server "stop" "") == false {
print $"❗ Stop ($server.hostname) errors "
if $error_exit {
exit 1
} else {
return "error"
}
}
let res = (^upctl ...($"server modify ($server.hostname) ($args | str trim)" | split row " ") err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code != 0 {
print $"❗ Server ($server.hostname) modify ($args) errors ($res.stdout ) "
}
print $"Start (_ansi blue_bold)($server.hostname)(_ansi reset) with modifications (_ansi green_bold)($args)(_ansi reset) ... "
if (upcloud_change_server_state $settings $server "start" "") == false {
print $"❗ Errors to start ($server.hostname)"
if $error_exit {
exit 1
} else {
return "error"
}
}
}
export def upcloud_wait_storage [
settings: record
server: record
new_state: string
id: string
] {
print $"Checking storage ($id) state for (_ansi blue_bold)($server.hostname)(_ansi reset) state (_ansi yellow_bold)($new_state)(_ansi reset) ..."
let state = (^upctl storage show $id -o json e> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | from json | get -o state)
if ($state | str contains $new_state) { return true }
let val_timeout = if $server.running_timeout? != null { $server.running_timeout } else { 60 }
let wait = if $server.running_wait? != null { $server.running_wait } else { 10 }
let wait_duration = ($"($wait)sec"| into duration)
mut num = 0
while true {
let status = (^upctl storage show $id -o json e> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | from json | get -o state)
if ($status | str contains $new_state) {
return true
} else if $val_timeout > 0 and $num > $val_timeout {
print ($"\n🛑 (_ansi red)Timeout(_ansi reset) ($val_timeout) volume ($id) state for (_ansi blue)($server.hostname)(_ansi reset) " +
$"(_ansi blue_bold)($new_state)(_ansi reset) (_ansi red_bold)failed(_ansi reset) "
)
return false
} else {
$num = $num + $wait
if $env.PROVISIONING_DEBUG {
print ($"(_ansi blue_bold) 🌥 (_ansi reset) storage state for (_ansi yellow)($id)(_ansi reset) " +
$"for (_ansi green)($server.hostname)(_ansi reset)-> ($status | str trim) "
)
} else {
print -n $"(_ansi blue_bold) 🌥 (_ansi reset)"
}
sleep $wait_duration
}
}
false
}
export def upcloud_create_storage [
settings: record
server: record
server_info: record
storage: record
volumes: list
total_size: int
] {
if $total_size <= 0 {
print $"❗Create storage for ($server.hostname) size (_ansi red)($total_size) error(_ansi reset)"
return {}
}
let av_zone = ($storage.item | get -o zone | default ($server | get -o zone))
if ($av_zone | is-empty) {
print ($"❗Create storage for (_ansi green_bold)($server.hostname)(_ansi reset) " +
$"(_ansi cyan_bold)($total_size)(_ansi reset) (_ansi red)Zone error(_ansi reset)"
)
return {}
}
let vol_device = ($storage.item | get -o voldevice)
let op_vol_device = if ($vol_device | is-not-empty) {
$"--address ($vol_device)"
} else {
""
}
let op_encrypted = if ($storage.item | get -o encrypted | default false) {
"--encrypted"
} else {
""
}
let $op_backup = if ($storage.item | get -o backup | is-not-empty) {
( $" --backup-time ($storage.item | get -o backup | get -o time) " +
$" --backup-interval ($storage.item | get -o backup | get -o interval) " +
$" --backup-retention ($storage.item | get -o backup | get -o retention)"
)
} else {
""
}
print ($"Create storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) in " +
$"(_ansi blue_bold)($av_zone)(_ansi reset) with name (_ansi yellow)($storage.item | get -o name)_($server | get -o hostname)(_ansi reset) ... "
)
let res_create = (^upctl storage create --title $"($storage.item | get -o name)_($server.hostname)" --size ($total_size)
--tier ($storage.item | get -o voltype) --zone $av_zone $op_encrypted $op_backup -o json | complete)
if $res_create.exit_code != 0 {
print ($"❗ Create storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) in " +
$"(_ansi blue_bold)($av_zone)(_ansi reset) with ($storage.item | get -o name) (_ansi red)error(_ansi reset) ($res_create.stdout)"
)
return {}
}
let server_id = ($server_info | get -o uuid | default "")
let vol = ($res_create.stdout | from json)
let vol_id = ($vol | get -o uuid)
let new_state = "online"
if not (upcloud_wait_storage $settings $server $new_state $vol_id) {
print ($"❗ Wait ($vol_id) storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) ($storage.item | get -o name) " +
$"in (_ansi blue_bold)($av_zone)(_ansi reset) errors not in (_ansi red)($new_state)(_ansi reset) state"
)
^upctl storage delete $vol_id
print $"❗ Attach ($vol_id) deleted"
return {}
}
let vol_device = ($storage.item | get -o voldevice)
if ($server_id | is-empty) { return $vol }
print ($"Attach storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) in " +
$"(_ansi blue_bold)($av_zone)(_ansi reset) with name (_ansi yellow)($storage.item | get -o name)_($server | get -o hostname)(_ansi reset) ... "
)
let res_attach = if ($vol_device | is-not-empty) {
(^upctl server storage attach $server_id --storage $vol_id --address $vol_device -o "json" | complete)
} else {
(^upctl server storage attach $server_id --storage $vol_id -o "json" | complete)
}
if $res_attach.exit_code != 0 {
print $res_attach.exit_code
print ($"❗Attach ($vol_id) storage for (_ansi green_bold)($server.hostname)(_ansi reset) (_ansi cyan_bold)($total_size)(_ansi reset) " +
$"($storage.item | get -o name) ($vol_device) in (_ansi blue_bold)($av_zone)(_ansi reset) (_ansi red)errors(_ansi reset) " +
$"\n($res_attach.stdout)"
)
^upctl storage delete $vol_id
print $"❗Attach (_ansi red_bold)($vol_id)(_ansi reset) deleted"
return {}
}
let res_vol = (^upctl storage show $vol_id -o json | complete)
if $res_vol.exit_code == 0 {
let info_vol = ($res_vol.stdout | from json)
print $info_vol
if ($info_vol | get -o servers | get -o server | where {|srv| $srv == $server_id } | length) > 0 {
print ($"✅ Atached (_ansi yellow)($vol_id)(_ansi reset) storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) " +
$"($storage.item | get -o name)(if $vol_device != "" { $' ($vol_device)'}) in (_ansi blue_bold)(_ansi blue_bold)($av_zone)(_ansi reset)(_ansi reset)"
)
} else {
print ($"❗ Volume ($vol_id) storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) " +
$"device ($vol_device) in (_ansi blue_bold)(_ansi blue_bold)($av_zone)(_ansi reset)(_ansi reset) (_ansi red)error(_ansi reset) not ($server_id)"
)
}
$info_vol
} else {
print ($"❗ Volume ($vol_id) storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) " +
$"device ($vol_device) in (_ansi blue_bold)(_ansi blue_bold)($av_zone)(_ansi reset)(_ansi reset) (_ansi red)errors(_ansi reset) ($res_vol.stdout)"
)
{}
}
}
export def upcloud_storage_fix_size [
settings: record
server: record
storage_pos: int
] {
let total_size = ($server | get -o storages | get -o $storage_pos | get -o total | default 0)
if $total_size == 0 { return 0 }
let storage = (^upctl server show $server.hostname "-o" "json" | from json | get -o storage_devices | get -o $storage_pos)
if $storage == null {
let server_info = (^upctl server show $server.hostname "-o" "json" | from json)
let volumes = ($server_info | get -o storage_devices | default [])
let storage_data = { item: ($server | get -o storages | get -o $storage_pos), index: $storage_pos }
upcloud_create_storage $settings $server $server_info $storage_data $volumes $total_size
}
let $curr_size = ($storage | get -o storage_size | default 0)
if $curr_size == 0 { return 0 }
#let storage_parts = ($server.storages? | get -o $storage_pos | get -o parts | default [])
#if ($storage_parts | length) == 0 { return 0 }
if $curr_size != $total_size {
print (
$"Stop (_ansi blue_bold)($server.hostname)(_ansi reset) for storage (_ansi yellow_bold)($storage.storage)(_ansi reset)" +
$" from (_ansi purple_bold)($curr_size)(_ansi reset) to (_ansi green_bold)($total_size)(_ansi reset) ... "
)
if (upcloud_change_server_state $settings $server "stop" "") == false {
print $"❗ Stop ($server.hostname) errors "
return "error"
}
if $storage_pos == 0 {
let res = (^upctl storage modify --size $total_size $storage.storage err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code != 0 {
print $"❗ Storage modify errors ($res.stdout ) "
return "error"
}
let new_storage = (^upctl server show $server.hostname "-o" "json" | from json | get -o storage_devices | get -o $storage_pos)
let new_curr_size = $new_storage.storage_size? | default 0
print $"Start (_ansi blue_bold)($server.hostname)(_ansi reset) with new size (_ansi green_bold)($new_curr_size)(_ansi reset) ... "
} else {
let storage_settings = ($server | get -o storages | get -o $storage_pos)
let new_storage = (^upctl storage $server.hostname "-o" "json" | from json | get -o storage_devices | get -o $storage_pos)
let $op_backup = if ($storage_settings | get -o backup | is-not-empty) {
( $" --backup-time ($storage_settings | get -o backup | get -o time) " +
$" --backup-interval ($storage_settings | get -o backup | get -o interval) " +
$" --backup-retention ($storage_settings | get -o backup | get -o retention)"
)
} else {
""
}
let op_encrypted = if ($storage_settings | get -o encrypted | default false) { "--encrypted" } else { "" }
let res_modify = (^upctl storage modify ($new_storage | get -o uuid) --size $total_size $op_encrypted $op_backup| complete)
if $res_modify.exit_code != 0 {
print ($"❗ Modify storage for ($server.hostname) (_ansi cyan_bold)($total_size)(_ansi reset) in " +
$"(_ansi blue_bold)($storage.zone)(_ansi reset) with ($storage.item | get -o name) (_ansi red)error(_ansi reset) ($res_modify.stdout)"
)
return {}
}
}
if (upcloud_change_server_state $settings $server "start" "") == false {
print $"❗ Errors to start ($server.hostname) "
return "error"
}
#return "storage"
}
"storage"
}
export def upcloud_status_server [
hostname: string
] {
let res = (^upctl server show $hostname "-o" "json" err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code != 0 {
print $"❗ status ($hostname) errors "
if $env.PROVISIONING_DEBUG { print $res.stdout }
return ""
}
return ($res.stdout | from json | get -o state | default "")
}
export def upcloud_server_exists [
server: record
error_exit: bool
] {
let res = (^upctl server show $server.hostname "-o" "json" err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code != 0 {
if $error_exit {
print $"❗ server ($server.hostname) exists errors ($res.stdout ) "
exit 1
} else {
return false
}
}
true
}
export def upcloud_server_state [
server: record
new_state: string
error_exit: bool
wait: bool
settings: record
] {
let res = (^upctl server show $server.hostname "-o" "json" err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code != 0 {
if $error_exit {
print $"❗ state ($server.hostname) errors ($res.stdout ) "
exit 1
} else {
return false
}
}
true
}
export def upcloud_server_is_running [
server: record
error_exit: bool
] {
let res = (^upctl server show $server.hostname "-o" "json" err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $res.exit_code != 0 {
print $"❗ is running ($server.hostname) errors ($res.stdout ) "
if $error_exit {
exit 1
} else {
return false
}
}
(($res.stdout | from json).state? | str contains "started" | default false)
}
export def upcloud_change_server_state [
settings: record
server: record
new_state: string
ops: string
] {
let state = (upcloud_status_server $server.hostname)
if $state == "" { return false }
if ($state | str contains $new_state) { return true }
print $"Checking (_ansi blue_bold)($server.hostname)(_ansi reset) state (_ansi yellow_bold)($new_state)(_ansi reset) ..."
let val_timeout = if $server.running_timeout? != null { $server.running_timeout } else { 60 }
let wait = if $server.running_wait? != null { $server.running_wait } else { 10 }
let wait_duration = ($"($wait)sec"| into duration)
let res = if ($ops | str contains "--type" ) {
(^upctl server $new_state --type ($ops | str replace "--type " "") $server.hostname err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
} else if $ops != "" {
(^upctl server $new_state $ops $server.hostname err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" })| complete)
} else {
(^upctl server $new_state $server.hostname err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
}
if $res.exit_code != 0 {
print $"❗Errors ($server.hostname) to ($new_state) ($res.stdout ) "
return false
}
mut num = 0
while true {
let status = (upcloud_status_server $server.hostname)
if ($status | str contains $new_state) {
print " "
return true
} 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)($new_state)(_ansi reset) (_ansi red_bold)failed(_ansi reset) "
return false
} else {
$num = $num + $wait
if $env.PROVISIONING_DEBUG {
print -n $"(_ansi blue_bold) 🌥 (_ansi reset)(_ansi green)($server.hostname)(_ansi reset)->($status) "
} else {
print -n $"(_ansi blue_bold) 🌥 (_ansi reset)"
}
sleep $wait_duration
}
}
false
}
export def upcloud_delete_server_storage [
settings: record
server: record
error_exit: bool
] {
let res = (^upctl storage list --normal -o json | complete)
if $res.exit_code == 0 {
let data = ($res.stdout | from json)
$data.storages? | default [] | each {|storage|
if ($storage.title | str starts-with $server.hostname ) {
if (upcloud_server_exists $server false) {
print $"❗ (_ansi blue_bold)($server.hostname)(_ansi reset) (_ansi red_bold)exists(_ansi reset) can not delete storage (_ansi yellow)($storage.uuid)(_ansi reset)"
} else {
let del_res = (^upctl storage delete $storage.uuid err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete)
if $del_res.exit_code != 0 {
print $"❗ Delete storage (_ansi yellow)($storage.uuid)(_ansi reset) for (_ansi blue_bold)($server.hostname)(_ansi reset) (_ansi red_bold)errors(_ansi reset) ($del_res.stdout ) "
} else {
print $"(_ansi yellow)($storage.uuid)(_ansi reset) for (_ansi blue_bold)($server.hostname)(_ansi reset) (_ansi green_bold)deleted(_ansi reset) ($del_res.stdout ) "
}
}
}
}
}
true
}
export def upcloud_delete_server [
settings: record
server: record
keep_storage: bool
error_exit: bool
] {
if not (upcloud_change_server_state $settings $server "stop" "--type hard") {
if $env.PROVISIONING_DEBUG { print $"❗ Stop (_ansi blue_bold)($server.hostname)(_ansi reset) errors " }
return false
}
let ops = if $keep_storage { "" } else { "--delete-storages" }
let res = (^upctl server delete $server.hostname $ops err> (std null-device) | complete)
if $res.exit_code != 0 {
print $"❗ Delete (_ansi blue_bold)($server.hostname)(_ansi reset) (_ansi red_bold)errors(_ansi reset) ($res.stdout ) "
return false
}
print $"(_ansi blue_bold)($server.hostname)(_ansi reset) (_ansi green_bold)deleted(_ansi reset)"
true
}

View file

@ -0,0 +1,42 @@
#!/usr/bin/env nu
# myscript.nu
export def usage [provider: string, infra: string] {
let info = if ( $env.CURRENT_FILE? | into string ) != "" { (^grep "^# Info:" $env.CURRENT_FILE ) | str replace "# Info: " "" } else { "" }
# $(declare -F _usage_options >/dev/null && _usage_options)
$"
USAGE provisioning ($provider) -k cloud-path file-settings.yaml provider-options
DESCRIPTION
UPCLOUD ($info)
OPTIONS
-s server-hostname
with server-hostname target selection
-p provider-name
use provider name
do not need if 'current directory path basename' is not one of providers available
-new | new [provisioning-name]
create a new provisioning-directory-name by a copy of ($infra)
-k cloud-path-item
use cloud-path-item as base directory for settings
-x
Trace script with 'set -x'
providerslist | providers-list | providers list
Get available providers list
taskslist | tasks-list | tasks list
Get available tasks list
serviceslist | service-list
Get available services list
tools
Run core/on-tools info
-i
About this
-v
Print version
-h, --help
Print this help and exit.
PROV: ($env.WK_CNPROV)
"
# ["hello" $name $title]
}

View file

@ -0,0 +1,24 @@
export def upcloud_check_requirements [
settings: record
fix_error: bool
] {
let has_upctl = (^bash -c "type -P upctl")
if ($has_upctl | path exists) == false and $fix_error {
( ^($env.PROVISIONING_NAME) "tools" "install" "upctl")
}
let has_upctl = (^bash -c "type -P upctl")
if ($has_upctl | path exists) == false {
(throw-error $"🛑 CLI command upclouds not found"
"upcloud_check_requirements" --span (metadata $has_upctl).span)
exit 1
}
let upctl_version = (^upctl version | grep "Version" | cut -f2 -d":" | sed 's/ //g')
let req_version = (open $env.PROVISIONING_REQ_VERSIONS).upctl?.version? | default "")
if ($upctl_version != $req_version ) and $fix_error {
( ^($env.PROVISIONING_NAME) "tools" "update" "upctl")
}
let upctl_version = (^upctl version | grep "Version" | cut -f2 -d":" | sed 's/ //g')
if $upctl_version != $req_version {
print $"warning❗ upctl command as CLI for UpCloud ($upctl_version) with Provisioning is not ($req_version)"
}
}