424 lines
13 KiB
Bash
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"
|
|
}
|