cka-sim/etcd-tools.sh

75 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Install etcdctl/etcdutl on the control-plane node (the real exam has them on the node, and
# Q02 (snapshot) / Q102 (restore) need them there). They cannot be copied out of the running
# etcd pod: registry.k8s.io/etcd is distroless, so there is no cat, sh or tar inside it.
# Re-run this after ./setup.sh if the install was skipped or the network was down.
# ./etcd-tools.sh [TRACK] install them on the control-plane node of TRACK's cluster (default: the
# track ./exam defaults to; CKA_CP=<node> names the node directly)
# ./etcd-tools.sh --emit print the node-side script; ./exam pipes it through CKA_NODE_ACCESS,
# so ssh/vagrant clusters get the same install when a task is seeded
# Version-agnostic: it takes whatever etcd the node runs (3.6.x on v1.35, 3.7.x on v1.37).
set -euo pipefail
cd "$(dirname "$0")"
# Runs on the node, as root, POSIX sh only. Three sources, best first:
# 1. the etcd image already in the node's containerd - offline, exactly the server version
# 2. the matching upstream release tarball - needs network, exactly the server version
# 3. the distro's etcd-client package - needs network, etcdctl only, version skew
NODE_SCRIPT=$(cat <<'EOS'
set -u
PATH="/usr/local/bin:$PATH"; export PATH
BIN=/usr/local/bin
have() { command -v etcdctl >/dev/null 2>&1 && command -v etcdutl >/dev/null 2>&1; }
have && { echo "already installed: $(etcdctl version | head -1)"; exit 0; }
img=$(ctr -n k8s.io images ls -q 2>/dev/null | grep -m1 -E '(^|/)etcd:[0-9]' || true)
ver=$(echo "$img" | sed 's/.*etcd://; s/-[0-9]*$//')
if [ -n "$img" ]; then
mnt=$(mktemp -d)
if ctr -n k8s.io images mount --rw "$img" "$mnt" >/dev/null 2>&1; then
cp "$mnt/usr/local/bin/etcdctl" "$mnt/usr/local/bin/etcdutl" "$BIN/" 2>/dev/null || true
ctr -n k8s.io images unmount --rm "$mnt" >/dev/null 2>&1 || true
fi
rmdir "$mnt" 2>/dev/null || true
chmod +x "$BIN/etcdctl" "$BIN/etcdutl" 2>/dev/null || true
have && { echo "installed $ver from $img"; exit 0; }
fi
if [ -n "$ver" ] && command -v curl >/dev/null 2>&1; then
arch=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
d="etcd-v$ver-linux-$arch"
curl -sfL --max-time 180 "https://github.com/etcd-io/etcd/releases/download/v$ver/$d.tar.gz" \
| tar -xzf - -C "$BIN" --strip-components=1 "$d/etcdctl" "$d/etcdutl" 2>/dev/null || true
chmod +x "$BIN/etcdctl" "$BIN/etcdutl" 2>/dev/null || true
have && { echo "installed $ver from the upstream release"; exit 0; }
fi
if command -v apt-get >/dev/null 2>&1; then
DEBIAN_FRONTEND=noninteractive apt-get update -qq >/dev/null 2>&1 || true
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq etcd-client >/dev/null 2>&1 || true
command -v etcdctl >/dev/null 2>&1 && {
echo "installed $(etcdctl version | head -1 | awk '{print $3}') from apt: no etcdutl (use"
echo "'etcdctl snapshot restore') and it may not match the ${ver:-running} server"
exit 0
}
fi
echo "ERROR: could not install etcdctl/etcdutl. Tried the etcd image in containerd"
echo "(${img:-none found}), the upstream release and apt-get (needs outbound network)."
exit 1
EOS
)
if [ "${1:-}" = --emit ]; then
printf '%s\n' "$NODE_SCRIPT"
exit 0
fi
RT="${CONTAINER_RUNTIME:-$(cat .state/runtime 2>/dev/null || echo podman)}"
[ "$RT" = podman ] && export KIND_EXPERIMENTAL_PROVIDER=podman
CP="${CKA_CP:-$(./exam ${1:+--track "$1"} cluster-env | sed -n 's/^CLUSTER=//p')-control-plane}"
printf '%s: ' "$CP"
printf '%s\n' "$NODE_SCRIPT" | "$RT" exec -i "$CP" sh -s