mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 18:24:32 +00:00
195 lines
5.0 KiB
Bash
195 lines
5.0 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
KNOE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
|
SCRIPT_UNDER_TEST="$KNOE_HOME/tools/k3s-cluster-rename.sh"
|
|
|
|
TMP_DIR=$(mktemp -d)
|
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
export TMP_DIR
|
|
|
|
BIN_DIR="$TMP_DIR/bin"
|
|
mkdir -p "$BIN_DIR"
|
|
|
|
cat <<'K_EOF' >"$BIN_DIR/kubectl"
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
cfg="${KUBECONFIG:?KUBECONFIG is required}"
|
|
|
|
if [[ "$*" == "config view --raw -o json" ]]; then
|
|
cat "$cfg"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$*" == "config get-contexts -o name" ]]; then
|
|
python3 - "$cfg" <<'PY'
|
|
import json
|
|
import sys
|
|
|
|
with open(sys.argv[1], "r", encoding="utf-8") as fh:
|
|
data = json.load(fh)
|
|
|
|
for ctx in data.get("contexts", []):
|
|
name = ctx.get("name") if isinstance(ctx, dict) else None
|
|
if name:
|
|
print(name)
|
|
PY
|
|
exit 0
|
|
fi
|
|
|
|
echo "unsupported kubectl invocation: $*" >&2
|
|
exit 2
|
|
K_EOF
|
|
chmod +x "$BIN_DIR/kubectl"
|
|
|
|
cat <<'X_EOF' >"$BIN_DIR/kubectx"
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
echo "$*" >>"${TMP_DIR}/kubectx_calls.log"
|
|
exit 0
|
|
X_EOF
|
|
chmod +x "$BIN_DIR/kubectx"
|
|
|
|
assert_target_names() {
|
|
local cfg="$1"
|
|
python3 - "$cfg" <<'PY'
|
|
import json
|
|
import sys
|
|
|
|
target = "knoe.dev.knoe.org"
|
|
|
|
with open(sys.argv[1], "r", encoding="utf-8") as fh:
|
|
data = json.load(fh)
|
|
|
|
context_names = [c.get("name") for c in data.get("contexts", []) if isinstance(c, dict)]
|
|
cluster_names = [c.get("name") for c in data.get("clusters", []) if isinstance(c, dict)]
|
|
user_names = [u.get("name") for u in data.get("users", []) if isinstance(u, dict)]
|
|
|
|
assert target in context_names, f"missing target context: {context_names}"
|
|
assert target in cluster_names, f"missing target cluster: {cluster_names}"
|
|
assert target in user_names, f"missing target user: {user_names}"
|
|
assert data.get("current-context") == target, f"unexpected current-context: {data.get('current-context')}"
|
|
|
|
for ctx in data.get("contexts", []):
|
|
if isinstance(ctx, dict) and ctx.get("name") == target:
|
|
body = ctx.get("context") or {}
|
|
assert body.get("cluster") == target, f"target context cluster mismatch: {body}"
|
|
assert body.get("user") == target, f"target context user mismatch: {body}"
|
|
break
|
|
else:
|
|
raise AssertionError("target context body not found")
|
|
PY
|
|
}
|
|
|
|
assert_has_kubectx_call() {
|
|
if ! [[ -f "$TMP_DIR/kubectx_calls.log" ]]; then
|
|
echo "FAILURE: expected kubectx to be called" >&2
|
|
exit 1
|
|
fi
|
|
if ! grep -q '^knoe.dev.knoe.org$' "$TMP_DIR/kubectx_calls.log"; then
|
|
echo "FAILURE: expected kubectx to be called with knoe.dev.knoe.org" >&2
|
|
cat "$TMP_DIR/kubectx_calls.log" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
create_single_context_cfg() {
|
|
local cfg="$1"
|
|
local name="$2"
|
|
cat >"$cfg" <<EOF
|
|
{
|
|
"apiVersion": "v1",
|
|
"kind": "Config",
|
|
"clusters": [
|
|
{
|
|
"name": "${name}",
|
|
"cluster": {
|
|
"server": "https://example:6443",
|
|
"insecure-skip-tls-verify": true
|
|
}
|
|
}
|
|
],
|
|
"users": [
|
|
{
|
|
"name": "${name}",
|
|
"user": {
|
|
"token": "test-token"
|
|
}
|
|
}
|
|
],
|
|
"contexts": [
|
|
{
|
|
"name": "${name}",
|
|
"context": {
|
|
"cluster": "${name}",
|
|
"user": "${name}",
|
|
"namespace": "default"
|
|
}
|
|
}
|
|
],
|
|
"current-context": "${name}"
|
|
}
|
|
EOF
|
|
}
|
|
|
|
export PATH="$BIN_DIR:$PATH"
|
|
|
|
# Core rename + idempotency
|
|
cfg_primary="$TMP_DIR/kubeconfig-primary.json"
|
|
create_single_context_cfg "$cfg_primary" "knoe-k3s"
|
|
|
|
bash "$SCRIPT_UNDER_TEST" --kubeconfig "$cfg_primary" --no-backup
|
|
assert_target_names "$cfg_primary"
|
|
|
|
bash "$SCRIPT_UNDER_TEST" --kubeconfig "$cfg_primary" --no-backup
|
|
assert_target_names "$cfg_primary"
|
|
assert_has_kubectx_call
|
|
|
|
# Repair fallback when old name is absent but only one context exists
|
|
cfg_repair="$TMP_DIR/kubeconfig-repair.json"
|
|
create_single_context_cfg "$cfg_repair" "default"
|
|
|
|
bash "$SCRIPT_UNDER_TEST" --kubeconfig "$cfg_repair" --no-backup
|
|
assert_target_names "$cfg_repair"
|
|
|
|
# Default path behavior: active shell kubeconfig (~/.kube/config when KUBECONFIG unset)
|
|
home_dir="$TMP_DIR/home"
|
|
mkdir -p "$home_dir/.kube"
|
|
cfg_default="$home_dir/.kube/config"
|
|
create_single_context_cfg "$cfg_default" "knoe-k3s"
|
|
|
|
unset KUBECONFIG || true
|
|
HOME="$home_dir" bash "$SCRIPT_UNDER_TEST" --no-backup
|
|
assert_target_names "$cfg_default"
|
|
|
|
# Negative path: ambiguous fallback must fail
|
|
cfg_ambiguous="$TMP_DIR/kubeconfig-ambiguous.json"
|
|
cat >"$cfg_ambiguous" <<'EOF'
|
|
{
|
|
"apiVersion": "v1",
|
|
"kind": "Config",
|
|
"clusters": [
|
|
{"name": "default", "cluster": {"server": "https://default:6443", "insecure-skip-tls-verify": true}},
|
|
{"name": "other", "cluster": {"server": "https://other:6443", "insecure-skip-tls-verify": true}}
|
|
],
|
|
"users": [
|
|
{"name": "default", "user": {"token": "t1"}},
|
|
{"name": "other", "user": {"token": "t2"}}
|
|
],
|
|
"contexts": [
|
|
{"name": "default", "context": {"cluster": "default", "user": "default"}},
|
|
{"name": "other", "context": {"cluster": "other", "user": "other"}}
|
|
],
|
|
"current-context": "default"
|
|
}
|
|
EOF
|
|
|
|
if bash "$SCRIPT_UNDER_TEST" --kubeconfig "$cfg_ambiguous" --no-backup >/dev/null 2>&1; then
|
|
echo "FAILURE: expected ambiguous rename to fail" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "SUCCESS" |