Files
2026-08-18 09:40:08 +02:00

117 lines
4.5 KiB
Bash

# Waits for the k3s API to become ready by polling /readyz.
# Retries up to $k3sReadyRetries times with $k3sReadySleep seconds between attempts.
function k3sReady() {
local tries=${k3sReadyRetries:-10}
local delay=${k3sReadySleep:-2}
local i
for ((i=1; i<=tries; i++)); do
"$k3sCmd" kubectl get --raw=/readyz >/dev/null 2>&1 && return 0
sleep "$delay"
done
appError "k3s API not ready after $tries tries"
return 1
}
# Validates a YAML file against the Kubernetes API (dry-run).
# $1 (file): path to the YAML file.
function k3sYamlCheck() {
local file="$1"
[[ -n "$file" ]] || { appError "File not specified"; return 1; }
[[ -f "$file" ]] || { appError "File not found: $file"; return 1; }
k3sReady
runFail "$k3sCmd" kubectl apply --dry-run=client -f "$file"
}
# Applies a YAML configuration to Kubernetes.
# $1 (file): path to the YAML configuration file.
function k3sYamlApply() {
local file="$1" output error
[[ -n "$file" ]] || { appError "File not specified"; return 1; }
run output error "$k3sCmd" kubectl apply -f "$file" --validate=false --request-timeout=60s || {
appError "Error applying YAML: ${error:-$output}"
return 1
}
}
# Runs kubectl in $k3sNamespace after ensuring k3s is ready.
function k3sRun() {
k3sReady || return 1
"$k3sCmd" kubectl -n "$k3sNamespace" "$@"
}
# Lists pod names sorted alphabetically, optionally filtered by app label.
# [$1] (app): app label value to filter by (optional).
function k3sPodList() {
local args=()
[[ -n "${1-}" ]] && args+=(-l "app=$1")
k3sRun get pods "${args[@]}" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' --sort-by='{.metadata.name}'
}
# Lists pods with detailed status: name|status|phase|reason.
# status is 1 when the pod is fully ready (phase Running/Succeeded), 0 otherwise.
# phase/reason describe the state for humans — a fine pod (status=1) can still show
# different phase/reason combinations, so gate logic must use status, not phase.
# reason is a comma-separated, deduplicated list of not-True condition types (excluding
# the generic PodReadyToStartContainers/Initialized/ContainersReady/Ready chain, which
# is always false together during startup and adds nothing beyond phase) plus each
# not-ready container's (including init containers) waiting/terminated reason
# (CrashLoopBackOff, ImagePullBackOff, OOMKilled, PodInitializing, ...).
# [$1] (app): app label value to filter by (optional).
function k3sPodListStatus() {
local args=()
[[ -n "${1-}" ]] && args+=(-l "app=$1")
k3sRun get pods "${args[@]}" -o json --sort-by='{.metadata.name}' | jq -r '
def dedupe: reduce .[] as $x ([]; if any(.[]; . == $x) then . else . + [$x] end);
.items[] |
(.metadata.name) as $name |
(.status.phase // "Unknown") as $phaseRaw |
(.status.conditions // []) as $conditions |
([$conditions[] | select(.type == "Ready")][0]) as $ready |
([$conditions[] | select(.type == "DisruptionTarget")][0]) as $disruption |
((.status.initContainerStatuses // []) + (.status.containerStatuses // [])) as $containers |
(["PodReadyToStartContainers", "Initialized", "ContainersReady", "Ready"]) as $noisyConditionTypes |
(
if $phaseRaw == "Running" and ($disruption.status // "") == "True" then "Terminating"
elif $phaseRaw == "Running" and ($ready.status // "False") != "True" then "NotReady"
else $phaseRaw
end
) as $phase |
(if $phase == "Running" or $phase == "Succeeded" then 1 else 0 end) as $status |
(
[$conditions[] |
(if .type == "DisruptionTarget" then (select(.status == "True")) else (select(.status != "True")) end) |
select(.type as $t | $noisyConditionTypes | index($t) | not) |
.type
]
) as $badConditionTypes |
(
[$containers[] | select(.ready == false) |
(.state.waiting.reason // .state.terminated.reason) | select(. != null)
]
) as $containerReasons |
((if $status == 1 then [] else ($badConditionTypes + $containerReasons | dedupe) end) | join(",")) as $reason |
"\($name)|\($status)|\($phase)|\($reason)"
'
}
# Captures the current list of pod names into an array variable.
# $1 (varname): name of the array variable to populate.
function k3sPodsSnapshot() {
local -n __out="$1"
mapfile -t __out < <(
k3sRun get pods --no-headers 2>/dev/null | awk '{print $1}'
)
}