#!/usr/bin/env bash set -euo pipefail KUBECONFIG_PATH="${KUBECONFIG:-${LAB_KUBECONFIG_PATH:-/home/jv/.kube/config}}" CONTROL_PLANE_NODE="${LAB_CONTROL_PLANE_NODE:-debian}" TAINT_KEY="${LAB_CONTROL_PLANE_TAINT_KEY:-node-role.kubernetes.io/control-plane}" TAINT_EFFECT="${LAB_CONTROL_PLANE_TAINT_EFFECT:-NoSchedule}" usage() { cat </dev/null 2>&1; then echo "kubectl is required." >&2 exit 1 fi if [ ! -s "$KUBECONFIG_PATH" ]; then echo "kubeconfig is missing: $KUBECONFIG_PATH" >&2 exit 1 fi if ! kubectl --kubeconfig "$KUBECONFIG_PATH" get node "$CONTROL_PLANE_NODE" >/dev/null 2>&1; then echo "control-plane node not found: ${CONTROL_PLANE_NODE}" >&2 echo "Set LAB_CONTROL_PLANE_NODE if the node has a different name." >&2 exit 1 fi } show_taints() { kubectl --kubeconfig "$KUBECONFIG_PATH" get node "$CONTROL_PLANE_NODE" \ -o jsonpath='{range .spec.taints[*]}{.key}{"="}{.value}{":"}{.effect}{"\n"}{end}' | sed '/^$/d' || true } show_non_system_pods() { kubectl --kubeconfig "$KUBECONFIG_PATH" get pods -A \ --field-selector "spec.nodeName=${CONTROL_PLANE_NODE}" \ -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase' --no-headers | awk '$1 !~ /^(kube-system|calico-system|tigera-operator)$/ { print }' } case "${1:-status}" in status) require_kubectl echo "Node: ${CONTROL_PLANE_NODE}" echo echo "Taints:" if ! show_taints | sed 's/^/ /'; then true fi echo echo "Non-system pods currently on control plane:" if ! show_non_system_pods | sed 's/^/ /'; then true fi ;; taint) require_kubectl kubectl --kubeconfig "$KUBECONFIG_PATH" taint node "$CONTROL_PLANE_NODE" "${TAINT_KEY}:${TAINT_EFFECT}" --overwrite echo echo "Current taints:" show_taints | sed 's/^/ /' ;; untaint) require_kubectl kubectl --kubeconfig "$KUBECONFIG_PATH" taint node "$CONTROL_PLANE_NODE" "${TAINT_KEY}:${TAINT_EFFECT}-" || true echo echo "Current taints:" show_taints | sed 's/^/ /' ;; pods) require_kubectl show_non_system_pods ;; -h|--help|help) usage ;; *) usage >&2 exit 1 ;; esac