Files
SODEW/sodew-bash-main/libs/commands/k3s.sh
T
2026-08-18 09:40:08 +02:00

424 lines
13 KiB
Bash

k3sLabel="[K3S]"
# Interactively lists pods and stores the selected pod name in the given variable.
# $1 (varname): name of the variable to store the selected pod name.
function cmdK3sPodSelect() {
local -n __pod="$1"
printRow
local podList error total
run podList error k3sPodListStatus || { printDanger "k3sPodListStatus: $error"; return 1; }
[[ -n "$podList" ]] || { printRow printDanger "Pods not found"; return 1; }
total=$(grep -c . <<< "$podList")
local i=0 name ready phase reason num
while IFS='|' read -r name ready phase reason; do
[[ -z "$name" ]] && continue
((i++))
num=$(printf "%${#total}d" "$i")
if [[ "$ready" == "1" ]]; then
printDotText "$num: $fontBlue$name$fontReset" "$fontGreen$phase$fontReset"
else
printDotText "$num: $fontBlue$name$fontReset" "$fontGray$reason $fontYellow$phase$fontReset"
fi
done <<< "$podList"
printRow
local input item selected
read -r -p "Specify the pod number: " input
printRow
[[ -z "$input" ]] && input=0
[[ "$input" =~ ^[0-9]+$ ]] || { printDanger "Invalid pod number"; return 1; }
item=$((10#$input))
selected=$(awk 'NF {n++} n == item {print; exit}' item="$item" <<< "$podList")
[[ -n "$selected" ]] || { printDanger "Unknown pod number"; return 1; }
__pod="${selected%%|*}"
}
# Interactively opens a shell or CLI inside a selected pod.
# [$1] (cli): pass "cli" to open the native CLI (mariadb/redis-cli) instead of a shell.
function cmdShell() {
printTitle " Shell $@"
local cli="$1"
local pod
cmdK3sPodSelect pod || return 1
local resource resourceEx
resource=$(printf '%s' "$pod" | sed -E 's/-([0-9a-f]{8,}-[a-z0-9]+|[a-z0-9]{5}|[0-9]+)$//')
resourceEx=$(printf '%s' "$pod" | sed -E 's/-([-a-z0-9]+)$//')
local container=(-c "$resource")
local cmd=(bash)
local cmdLog=(bash)
case "$resourceEx" in
"$redisKube"|"$metricKube"|debug)
cmd=(sh)
cmdLog=(sh)
;;
esac
if [[ "$cli" == "cli" ]]; then
case "$resource" in
"$mariadbMasterKube"|"$mariadbSlaveKube")
cmd=(mariadb -uroot -p"$mariadbRootPass")
cmdLog=(mariadb -uroot -p"********")
;;
"$redisKube")
if [[ -z "$redisRootPass" ]]; then
cmd=(redis-cli)
cmdLog=(redis-cli)
else
cmd=(redis-cli --no-auth-warning -a "$redisRootPass")
cmdLog=(redis-cli --no-auth-warning -a"********")
fi
;;
"$redisSentinelKube")
if [[ -z "$redisRootPass" ]]; then
cmd=(redis-cli -p 26379)
cmdLog=(redis-cli -p 26379)
else
cmd=(redis-cli --no-auth-warning -p 26379 -a "$redisRootPass")
cmdLog=(redis-cli --no-auth-warning -p 26379 -a"********")
fi
;;
esac
fi
printText "$fontBlue$k3sCmd kubectl -n $k3sNamespace exec -it pod/$pod ${container[*]} -- ${cmdLog[*]}$fontReset"
printRow
k3sRun exec -it "pod/$pod" "${container[@]}" -- "${cmd[@]}"
}
# Interactively selects a pod and streams its logs.
# [$@] (...): extra arguments passed to kubectl logs (e.g. -f, --tail=100).
function cmdLog() {
printTitle " Log $@"
local pod
cmdK3sPodSelect pod || return 1
local resource
resource=$(printf '%s' "$pod" | sed -E 's/-([0-9a-f]{8,}-[a-z0-9]+|[a-z0-9]{5}|[0-9]+)$//')
local container=(-c "$resource")
printText "$fontBlue$k3sCmd kubectl -n $k3sNamespace logs pod/$pod ${container[*]} $*$fontReset"
printRow
k3sRun logs "pod/$pod" "${container[@]}" "$@"
}
# Interactively selects a pod and describes it; also supports describing a node.
# [$1] (target): pod (default) or node.
function cmdDescribe() {
local target="${1:-pod}"
shift || true
printTitle " Describe $@"
case "$target" in
pod)
local pod
cmdK3sPodSelect pod || return 1
printText "$fontBlue$k3sCmd kubectl -n $k3sNamespace describe pod/$pod $*$fontReset"
printRow
k3sRun describe "pod/$pod" "$@"
k3sRun describe "pod/$pod" "$@"
;;
node)
k3sRun describe node "$@"
;;
*)
printRow
printWarning "Unsupported or empty command: $target"
cmdHelpDescribe
;;
esac
}
# Interactively selects and deletes a pod.
function cmdDelete() {
printTitle " Delete $@ $fontRed[DANGER]$fontReset"
local pod
cmdK3sPodSelect pod || return 1
printText "$fontBlue$k3sCmd kubectl -n $k3sNamespace delete pod/$pod $*$fontReset"
printRow
k3sRun delete "pod/$pod" "$@"
}
# Lists k3s resources; interactively prompts for type if not provided.
# [$1] (resource): resource type abbreviation (pod, deploy, svc, etc.).
function cmdK3sResourceList() {
local resource="$1"
if [[ ! "$resource" =~ ^(all|pod|event|pv|pvc|deploy|ds|rs|sts|svc|ing|ip|secret|cm|job|cj|ep|no|ns|cs|netpol)$ ]]; then
local resList="
all|Get all resources
pod|Pod
event|Event
pv|PersistentVolume
pvc|PersistentVolumeClaim
deploy|Deployment
ds|DaemonSet
rs|ReplicaSet
sts|StatefulSet
svc|Service
ing|Ingress
ip|IPAddress
secret|Secret
cm|ConfigMap
job|Job
cj|CronJob
ep|Endpoint
no|Node
ns|Namespace
cs|ComponentStatuses
netpol|NetworkPolicies"
printRow
local i=0 line code info num
total=$(grep -c . <<< "$resList")
while IFS= read -r line; do
[[ -n "$line" ]] || continue
((i++))
num=$(printf "%${#total}d" "$i")
code="${line%%|*}"
info="${line#*|}"
printDotFix 20 "$num: $fontBlue$code$fontReset" "$info"
done <<< "$resList"
printRow
local input item selected
read -r -p "Specify the type number [0]: " input
printRow
[[ -z "$input" ]] && input=0
[[ "$input" =~ ^[0-9]+$ ]] || { printDanger "Invalid type number"; return 1; }
item=$((10#$input))
selected=$(awk 'NF {n++} n == item {print; exit}' item="$item" <<< "$resList")
[[ -n "$selected" ]] || { printDanger "Unknown type number"; return 1; }
resource="${selected%%|*}"
fi
run output error k3sRun get "$resource" || { printDanger "$error"; return 1; }
printf '%s\n' "$output"
}
# Installs k3s on the server.
function cmdK3sInstall() {
printInfo "$k3sLabel Install..."
curl -sfL https://get.k3s.io | sh - || return 1
systemctl enable --now k3s
}
# Uninstalls k3s from the server.
function cmdK3sUninstall() {
/usr/local/bin/k3s-uninstall.sh
}
# Adds a namespace to Kubernetes if it does not already exist.
# $1 (namespace): namespace name.
function cmdK3sNamespaceAdd() {
local output error
run output error "$k3sCmd" kubectl get ns -o jsonpath="{range .items[*]}{.metadata.name}{'\n'}{end}" || { printDanger "$k3sLabel $error"; return 1; }
if ! grep -qF -- "$k3sNamespace" <<< "$output"; then
run output error "$k3sCmd" kubectl create ns "$k3sNamespace" || { printDanger "$k3sLabel $error"; return 1; }
fi
}
# Deletes all resources in the current namespace.
function cmdK3sResourceClean() {
printWarning "$k3sLabel Namespace: $k3sNamespace | Wiping..."
k3sRun delete all --all --ignore-not-found --wait=false --timeout=30s --request-timeout=60s || true
k3sRun delete cm,secret,ingress,networkpolicy,svc,pvc,job,cronjob --all --ignore-not-found --wait=false --timeout=30s --request-timeout=60s || true
mapfile -t pvs < <(
"$k3sCmd" kubectl get pv -o jsonpath='{range .items[?(@.spec.claimRef.namespace=="'"$k3sNamespace"'")]}{.metadata.name}{"\n"}{end}' 2>/dev/null
)
local pv
for pv in "${pvs[@]}"; do
[[ -n "$pv" ]] || continue
"$k3sCmd" kubectl patch pv "$pv" --type=merge -p '{"metadata":{"finalizers":[]}}' || true
"$k3sCmd" kubectl delete pv "$pv" --wait=false --timeout=15s || true
done
printSuccess "$k3sLabel Namespace: $k3sNamespace | Wiped"
}
# Waits until all pods not in the baseline snapshot are ready.
# Uses k3sPodListStatus as the single source of truth (accounts for the pod's Ready
# condition, not just its phase), printing each not-ready pod's phase/reason while waiting.
# $1 (varname): name of the baseline array variable (from k3sPodsSnapshot).
# [$2] (attempts): attempts (default 60).
# [$3] (interval): poll interval in seconds (default 4).
function cmdK3sWaitNewPodsReady() {
local -n baseline="$1"
local attempts="${2:-60}"
local interval="${3:-4}"
(( attempts < 1 )) && attempts=1
local i notReady newSeen _statusList _error
for ((i=1; i<=attempts; i++)); do
run _statusList _error k3sPodListStatus || return 1
printSection "Checking readiness of pods ($i/$attempts)"
notReady=0
newSeen=0
local name ready phase reason
while IFS='|' read -r name ready phase reason; do
[[ -z "$name" ]] && continue
arrayContains "$name" "${baseline[@]}" && continue
newSeen=1
if [[ "$ready" == "1" ]]; then
printDotText "$name" "$fontGreen$phase$fontReset"
else
printDotText "$name" "$fontGray$reason $fontYellow$phase$fontReset"
((notReady++))
fi
done < <(awk 'NF' <<< "$_statusList")
if [[ $newSeen -eq 0 || $notReady -eq 0 ]]; then
printDotText "${fontBlue}Result$fontReset" "${fontGreen}ready$fontReset"
return 0
fi
if [[ $i -lt $attempts ]]; then
# printDotText "${fontBlue}Result$fontReset" "${fontYellow}waiting ${interval}s$fontReset"
sleep "$interval"
else
printDotText "${fontBlue}Result$fontReset" "${fontRed}waiting time's up$fontReset"
return 1
fi
done
}
# Validates, applies a YAML file, then waits for new pods to become ready.
# $1 (file): path to the YAML configuration file.
function cmdK3sYamlApplyEx() {
local file="$1" output error
printSection "Applying YAML file"
printDotText "file" "$file"
run output error k3sYamlCheck "$file" || {
printDotText "applying" "$labelFail"
printDanger "Error checking YAML: ${error:-$output}"
return 1
}
printDotText "checking" "$labelDone"
k3sPodsSnapshot podList || {
printDotText "applying" "$labelFail"
printDanger "Failed get list of pods"
return 1
}
runError error k3sYamlApply "$file" || {
printDotText "applying" "$labelFail"
printDanger "Error applied YAML: ${error:-$output}"
return 1
}
printDotText "applying" "$labelDone"
cmdK3sWaitNewPodsReady podList || return 1
}
# Displays pods, services, ingress, and kube-system services info.
function cmdK3sInfo() {
local output error line
printSection "k3s"
if ! run output error k3sRun version; then
printDanger "$error";
else
while IFS= read -r line; do
printDotText "${line%% Version:*}" "${line##*: }"
done < <(awk 'NF' <<< "$output")
fi
if ! run output error "$k3sCmd" kubectl get nodes --no-headers; then
printDanger "$error"
else
local name status roles age version
while IFS='|' read -r name status roles age version; do
printSection "$name"
if [[ "$status" == "Ready" ]]; then
printDotText "Status" "$fontGreen$status$fontReset"
else
printDotText "Status" "$fontRed$status$fontReset"
fi
printDotText "Roles" "$roles"
printDotText "Age" "$age"
printDotText "Version" "$version"
done < <(awk 'NF{print $1 "|" $2 "|" $3 "|" $4 "|" $5}' <<< "$output")
fi
}
# Displays pods, services, ingress, kube-system services, and non-running pod bugs.
function cmdK3sNodesStatus() {
printSection "Pods"
if run output error k3sRun get pods -o wide; then
printText "$output"
else
printDanger "$error"
fi
printSection "Services"
if run output error k3sRun get svc -o wide; then
printText "$output"
else
printDanger "$error"
fi
printSection "Ingress"
if run output error k3sRun get ing; then
printText "$output"
else
printDanger "$error"
fi
printSection "Services (kube-system)"
if run output error "$k3sCmd" kubectl -n kube-system get svc; then
printText "$output"
else
printDanger "$error"
fi
printSection "Bugs..."
local output error
if run output error kubectl get pods -A \
--field-selector=status.phase!=Running,status.phase!=Pending \
-o custom-columns='NS:.metadata.namespace,POD:.metadata.name,PHASE:.status.phase,REASON:.status.reason,NODE:.spec.nodeName'; then
printText "$output"
else
printDanger "$error"
fi
printText "
PHASE | REASON
------------------
Failed | !=0 Process crashed
Failed | Error Process ended with an error
Failed | OOMKilled Ran out of memory
Failed | Evicted Kubelet evicted the pod (disk/memory pressure)
Completed/Succeeded - Not error if Job/migration/init task"
}
# Displays resource usage (CPU/memory) for all pods in the namespace.
function cmdK3sTopPod() {
local output error
run output error k3sRun top pod || { printDanger "$error"; return 1; }
printRow
printText "$output"
}