provisioning-catalog/components/lian_build/nulib/runners.nu

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 }
}
}