provisioning-catalog/components/lian_build/cluster/templates/install.sh.tmpl

161 lines
6.8 KiB
Cheetah
Raw Permalink Normal View History

#!/usr/bin/env nu
# GENERATED — component=lian_build bundle={{BUNDLE_ID}} op=build
# Target: {{IMAGE}}
let lian_build_root = "{{LIAN_BUILD_ROOT}}"
let bundle_dir = $env.FILE_PWD
let ctx = (mktemp -d | str trim)
let secrets_base = "{{SECRETS_BASE}}"
let target = (do {
cd $lian_build_root
cargo metadata --no-deps --format-version 1 | from json | get target_directory
})
let bin = $"($target)/release/lian-build"
# ── pre-flight ───────────────────────────────────────────────────────────────
print $"[pre-flight] bundle={{BUNDLE_ID}} (date now | format date '%Y-%m-%dT%H:%M:%S%z')"
let directives_export = (do {
^nickel export --format json --import-path $lian_build_root $"($bundle_dir)/build_directives.ncl"
} | complete)
if $directives_export.exit_code != 0 {
print "[pre-flight] WARNING: could not parse build_directives.ncl — skipping pre-flight checks"
print $directives_export.stderr
} else {
let d = ($directives_export.stdout | from json)
let adapter = ($d | get -o adapter | default {})
let kind = ($adapter | get -o kind | default "hcloud")
let images = ($d | get -o artifacts | default []
| each { |a| $a | get -o image | default "?" }
| str join ", ")
print $"[pre-flight] image → ($images)"
# ── 1. adapter identity + VPN check ─────────────────────────────────────
if $kind == "k8s_local" {
let ns = ($adapter | get -o k8s_namespace | default "build-system")
let dep = ($adapter | get -o k8s_deployment | default "buildkitd")
let port = ($adapter | get -o k8s_port | default 1234)
print $"[pre-flight] buildkit → k8s_local ns=($ns) deployment=($dep) port=($port)"
print "[pre-flight] k8s_local requires VPN — probing cluster..."
let probe = (do { ^kubectl get namespace $ns --request-timeout=5s } | complete)
if $probe.exit_code != 0 {
print ""
print "[pre-flight] ABORT: k8s cluster unreachable"
print $" target: namespace=($ns)"
print $" error: ($probe.stderr | lines | first | default 'no output')"
print ""
print " Likely cause: VPN is down or no route to cluster"
print " Check: wg show (interface up? rx/tx traffic?)"
print $" Check: kubectl get ns ($ns) (cluster reachable?)"
rm -rf $ctx
exit 1
}
print $"[pre-flight] cluster ✓ — buildkitd reachable at ($ns)/($dep):($port)"
} else if $kind == "hcloud" {
let loc = ($adapter | get -o location | default "fsn1")
print $"[pre-flight] buildkit → hcloud ephemeral location=($loc)"
print "[pre-flight] runner: a Hetzner VM will be spawned, used, and destroyed"
} else {
print $"[pre-flight] buildkit → ($kind)"
}
# ── 2. registry credential check ────────────────────────────────────────
let reg_cred_path = (
$d
| get -o registry
| default {}
| get -o push_credential
| default {}
| get -o path
| default ""
)
if ($reg_cred_path | is-empty) {
print "[pre-flight] registry cred: no path defined — will rely on runner built-in auth"
} else {
let sops_file = $"($secrets_base)/($reg_cred_path)"
if not ($sops_file | path exists) {
print ""
print "[pre-flight] ABORT: registry credential file not found"
print $" expected: ($sops_file)"
print $" check: LIAN_BUILD_WORKSPACE_ROOT / LIAN_BUILD_SECRETS_BASE"
print ""
print " The push will fail 401 — no point building without credentials"
rm -rf $ctx
exit 1
}
let sops_check = (do { ^sops --decrypt $sops_file } | complete)
if $sops_check.exit_code != 0 {
print ""
print "[pre-flight] ABORT: registry credential decrypt failed"
print $" file: ($sops_file)"
print $" error: ($sops_check.stderr | lines | first | default 'unknown')"
print ""
print " Hint: set SOPS_AGE_KEY_FILE to your age private key"
print " The push will fail 401 — fix credentials before building"
rm -rf $ctx
exit 1
}
print $"[pre-flight] registry cred ✓ ($reg_cred_path)"
}
}
print ""
print $"[build] bundle={{BUNDLE_ID}} image={{IMAGE}} started=(date now | format date '%Y-%m-%dT%H:%M:%S%z')"
# ── context assembly ─────────────────────────────────────────────────────────
if "{{CTX_TYPE}}" == "leptos" {
just --justfile $"($lian_build_root)/justfile" _ctx-leptos "{{CONTEXT_SRC}}" $ctx
} else if "{{CTX_TYPE}}" == "siblings" {
for dir in ("{{CONTEXT_SRC_DIRS}}" | split row " " | where { |d| not ($d | is-empty) }) {
let name = ($dir | path basename)
^rsync -a --exclude=target/ --exclude=node_modules/ --exclude=.git/ $"($dir)/" $"($ctx)/($name)/"
}
} else {
^rsync -a --exclude=target/ --exclude=node_modules/ --exclude=.git/ "{{CONTEXT_SRC}}/" $"($ctx)/"
}
let build_args = [
"build"
"--directives" $"($bundle_dir)/build_directives.ncl"
"--context" $ctx
"--ssh-key" "{{SSH_KEY}}"
"--language" "rust"
"--secrets-base" $secrets_base
"--runner-image" "{{RUNNER_IMAGE_REF}}"
]
let keep_runner = ("LIAN_BUILD_KEEP_RUNNER" in $env)
let extra_args = if $keep_runner { ["--keep-runner"] } else { [] }
# ── build ────────────────────────────────────────────────────────────────────
# Wrap lian-build in a timeout to prevent hanging on runner cleanup.
# Override: LIAN_BUILD_TIMEOUT_SECONDS=<n>
let timeout_secs = ($env.LIAN_BUILD_TIMEOUT_SECONDS? | default "600")
let timeout_candidates = (
["/opt/homebrew/bin/timeout" "/usr/bin/timeout" "/usr/local/bin/timeout"]
| where { |p| $p | path exists }
)
let timeout_bin = if ($timeout_candidates | is-not-empty) { $timeout_candidates | first } else { "" }
let run_args = [$bin ...$build_args ...$extra_args]
with-env { LIAN_BUILD_NICKEL_IMPORT_PATH: $lian_build_root } {
if ($timeout_bin | is-not-empty) {
run-external $timeout_bin $timeout_secs ...$run_args
} else {
run-external ...$run_args
}
}
rm -rf $ctx
print $"[build] OK finished=(date now | format date '%Y-%m-%dT%H:%M:%S%z')"