132 lines
4.5 KiB
Text
132 lines
4.5 KiB
Text
#!/usr/bin/env nu
|
|
# lian_build catalog CLI — ephemeral build runner management via hcloud.
|
|
# Entry: prvng runners <list|status|kill|gc> [name]
|
|
|
|
export-env {
|
|
let lib_dirs_raw = ($env.NU_LIB_DIRS? | default "")
|
|
let current_lib_dirs = if ($lib_dirs_raw | describe) == "string" {
|
|
if ($lib_dirs_raw | is-empty) { [] } else { ($lib_dirs_raw | split row ":") }
|
|
} else { $lib_dirs_raw }
|
|
let dynamic = ($env.PROVISIONING? | default "" | path join "core" "nulib")
|
|
$env.NU_LIB_DIRS = ([
|
|
"/opt/provisioning/core/nulib"
|
|
"/usr/local/provisioning/core/nulib"
|
|
] | append $current_lib_dirs
|
|
| append (if ($dynamic | is-not-empty) { [$dynamic] } else { [] }))
|
|
}
|
|
|
|
use cli/flags.nu [parse_common_flags]
|
|
|
|
def hcloud-servers []: nothing -> list<record> {
|
|
let r = (do { ^hcloud server list --output json } | complete)
|
|
if $r.exit_code != 0 {
|
|
error make { msg: $"hcloud server list failed: ($r.stderr | str trim)" }
|
|
}
|
|
$r.stdout | from json
|
|
}
|
|
|
|
def format-server [s: record]: nothing -> record {
|
|
let priv = ($s.private_net | get 0? | default {} | get ip? | default "—")
|
|
{
|
|
name: $s.name
|
|
status: $s.status
|
|
public_ip: $s.public_net.ipv4.ip
|
|
private_ip: $priv
|
|
type: $s.server_type.name
|
|
location: $s.datacenter.location.name
|
|
age: $s.created
|
|
}
|
|
}
|
|
|
|
def runners-list []: nothing -> nothing {
|
|
let servers = (hcloud-servers)
|
|
let runners = ($servers | where { |s| ($s.name | str starts-with "runner-") or ($s.name | str starts-with "buildkit-runner-") })
|
|
if ($runners | is-empty) {
|
|
print "no active runners"
|
|
return
|
|
}
|
|
$runners | each { |s| format-server $s } | table
|
|
}
|
|
|
|
def runners-status [name: string]: nothing -> nothing {
|
|
if ($name | is-empty) {
|
|
error make { msg: "runners status requires a server name" }
|
|
}
|
|
let r = (do { ^hcloud server describe $name --output json } | complete)
|
|
if $r.exit_code != 0 {
|
|
error make { msg: $"hcloud server describe failed: ($r.stderr | str trim)" }
|
|
}
|
|
$r.stdout | from json | table
|
|
}
|
|
|
|
def runners-kill [name: string, confirmed: bool]: nothing -> nothing {
|
|
if ($name | is-empty) {
|
|
error make { msg: "runners kill requires a server name" }
|
|
}
|
|
if not $confirmed {
|
|
let answer = (input $"Delete runner '($name)'? [y/N]: " | str downcase | str trim)
|
|
if $answer != "y" { print "aborted"; return }
|
|
}
|
|
let r = (do { ^hcloud server delete $name } | complete)
|
|
if $r.exit_code != 0 {
|
|
error make { msg: $"hcloud server delete failed: ($r.stderr | str trim)" }
|
|
}
|
|
print $"deleted ($name)"
|
|
}
|
|
|
|
def runners-gc [confirmed: bool]: nothing -> nothing {
|
|
let servers = (hcloud-servers)
|
|
let orphans = ($servers
|
|
| where { |s|
|
|
(($s.name | str starts-with "runner-") or ($s.name | str starts-with "buildkit-runner-"))
|
|
and $s.status != "running"
|
|
})
|
|
if ($orphans | is-empty) {
|
|
print "no stopped/errored runners to collect"
|
|
return
|
|
}
|
|
print $"Found ($orphans | length) orphaned runner(s):"
|
|
$orphans | each { |s| format-server $s } | table
|
|
if not $confirmed {
|
|
let answer = (input "Delete all? [y/N]: " | str downcase | str trim)
|
|
if $answer != "y" { print "aborted"; return }
|
|
}
|
|
$orphans | each { |s|
|
|
let r = (do { ^hcloud server delete $s.name } | complete)
|
|
if $r.exit_code == 0 {
|
|
print $"deleted ($s.name)"
|
|
} else {
|
|
print $"error deleting ($s.name): ($r.stderr | str trim)"
|
|
}
|
|
}
|
|
}
|
|
|
|
def runners-help []: nothing -> nothing {
|
|
print "Usage: prvng runners <command> [name]"
|
|
print ""
|
|
print "Commands:"
|
|
print " list List all active build runners"
|
|
print " status <name> Show runner details"
|
|
print " kill <name> Delete a runner"
|
|
print " gc Delete all stopped/errored runners"
|
|
}
|
|
|
|
def main [
|
|
command: string = ""
|
|
...rest: string
|
|
--yes (-y)
|
|
--debug (-x)
|
|
--notitles
|
|
]: nothing -> nothing {
|
|
if $debug { $env.PROVISIONING_DEBUG = true }
|
|
let name = ($rest | get 0? | default "")
|
|
let flags = (parse_common_flags { yes: $yes, debug: $debug, notitles: $notitles })
|
|
let confirmed = ($flags.auto_confirm? | default false)
|
|
match $command {
|
|
"list" | "l" | "" => { runners-list }
|
|
"status" | "s" => { runners-status $name }
|
|
"kill" | "k" | "d" => { runners-kill $name $confirmed }
|
|
"gc" => { runners-gc $confirmed }
|
|
_ => { runners-help }
|
|
}
|
|
}
|