75 lines
3.5 KiB
Bash
Executable File
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
|