mirror of
https://github.com/cozystack/cozystack.git
synced 2026-10-26 21:17:32 +09:00
The durable-record ConfigMap write sat under set -euo pipefail right before the version stamp, so a permanent failure (e.g. the record exceeding etcd's object size limit at a very large skip count) would abort the migration and deadlock the fleet upgrade with no path out -- even though every skipped pool was already pinned prune-proof earlier in the sweep, so the workers are safe regardless of whether the record lands. The record is a convenience artifact, not a safety mechanism, so swallow its failure with a warning instead of failing closed. Covered by a bats case that fails the publish and asserts the run still stamps. Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
124 lines
5.6 KiB
Bash
Executable File
124 lines
5.6 KiB
Bash
Executable File
#!/bin/sh
|
|
# Fake kubectl for the migration-56 unit test (hack/migration-56-adopt-values.bats).
|
|
# Mocks only the cluster boundary. Env:
|
|
# FAKE_HR_LIST path to the `get helmrelease -o json` list fixture
|
|
# FAKE_CHILD_HR path to write the child HelmRelease that `apply -f -` receives
|
|
# FAKE_CMDLOG path to append a call log (APPLY-HR / STAMP / annotate / label)
|
|
# FAKE_GET_FAIL substring: any `get` whose args match it fails with a
|
|
# transient server error (message overridable via
|
|
# FAKE_GET_FAIL_MSG, e.g. a conversion-webhook failure whose
|
|
# text happens to contain "not found"), so the migration's
|
|
# absence-vs-failure classification is exercised
|
|
# FAKE_WARN_STDERR when set, every successful get prints a deprecation
|
|
# warning to stderr first, the way real kubectl does -- data
|
|
# captured with 2>&1 would be contaminated by it
|
|
# Absence honors --ignore-not-found the way real kubectl does: with the flag a
|
|
# missing object is SUCCESS with empty output; without it, "Error from server
|
|
# (NotFound)" on stderr and exit 1.
|
|
log() { [ -n "${FAKE_CMDLOG:-}" ] && echo "$*" >> "$FAKE_CMDLOG"; return 0; }
|
|
notfound() { echo "Error from server (NotFound): $1 not found" >&2; exit 1; }
|
|
absent() {
|
|
case "$args" in
|
|
*--ignore-not-found*) exit 0 ;;
|
|
esac
|
|
notfound "$1"
|
|
}
|
|
verb=${1:-}
|
|
shift 2>/dev/null || true
|
|
args="$*"
|
|
case "$verb" in
|
|
get)
|
|
if [ -n "${FAKE_GET_FAIL:-}" ]; then
|
|
case "$args" in
|
|
*"${FAKE_GET_FAIL}"*)
|
|
echo "${FAKE_GET_FAIL_MSG:-Error from server: etcdserver: request timed out}" >&2; exit 1 ;;
|
|
esac
|
|
fi
|
|
if [ -n "${FAKE_WARN_STDERR:-}" ]; then
|
|
echo "Warning: cluster.x-k8s.io/v1beta1 MachineDeployment is deprecated" >&2
|
|
fi
|
|
case "$args" in
|
|
*helmrelease*--all-namespaces*)
|
|
cat "$FAKE_HR_LIST"; exit 0 ;;
|
|
*helmrelease*kubernetes-nodes-*)
|
|
notfound "helmreleases.helm.toolkit.fluxcd.io" ;; # child HR absent -> create path
|
|
esac
|
|
# tokenize: $1=resource, $2=object-name (or a flag for list queries)
|
|
# shellcheck disable=SC2086
|
|
set -- $args
|
|
res=$1; name=$2
|
|
# Real kubectl rejects a name containing '/' client-side, before any API
|
|
# call, deterministically -- reproduce that so the migration provably never
|
|
# issues a read for a composed name that cannot exist.
|
|
case "$name" in
|
|
*/*)
|
|
echo "error: there is no need to specify a resource type as a separate argument when passing arguments in resource/name form" >&2
|
|
exit 1 ;;
|
|
esac
|
|
case "$res" in
|
|
kubevirtmachinetemplate*)
|
|
case "$name" in
|
|
-*|"") # KMT range/list query
|
|
[ -n "${FAKE_KMT_NAMES:-}" ] && printf '%s\n' "$FAKE_KMT_NAMES"
|
|
exit 0 ;;
|
|
esac ;;
|
|
esac
|
|
# Named-object get. When FAKE_OBJS is set (adoption-path tests), look the
|
|
# object up there: a matching line "<res> <name> <release-name>" means present.
|
|
# Without FAKE_OBJS every named get is "absent" (value-mapping tests rely on
|
|
# adopt_one short-circuiting on absent).
|
|
if [ -n "${FAKE_OBJS:-}" ] && [ -f "$FAKE_OBJS" ]; then
|
|
line=$(grep -E "^${res}[[:space:]]+${name}([[:space:]]|$)" "$FAKE_OBJS" || true)
|
|
[ -z "$line" ] && absent "${res} \"${name}\"" # absent
|
|
rel=$(printf '%s\n' "$line" | awk '{print $3}')
|
|
case "$args" in
|
|
*jsonpath*release-name*) printf '%s' "$rel"; exit 0 ;;
|
|
*" -o json"*)
|
|
printf '{"metadata":{"annotations":{"meta.helm.sh/release-name":"%s"}}}' "$rel"; exit 0 ;;
|
|
*" -o name"*) printf '%s/%s\n' "$res" "$name"; exit 0 ;;
|
|
*) exit 0 ;; # existence check
|
|
esac
|
|
fi
|
|
absent "${res} \"${name}\"" ;; # default: absent
|
|
apply)
|
|
payload=$(cat)
|
|
if printf '%s' "$payload" | grep -q 'HelmRelease'; then
|
|
# Reject an RFC-1123-invalid metadata.name the way the real apiserver would,
|
|
# so the migration's name-validity guard is exercised: without it the script
|
|
# would reach this apply and exit non-zero, deadlocking the upgrade.
|
|
hrname=$(printf '%s' "$payload" | jq -r '.metadata.name // ""' 2>/dev/null)
|
|
if ! printf '%s' "$hrname" | grep -qE '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'; then
|
|
echo "The HelmRelease \"$hrname\" is invalid: metadata.name: Invalid value: \"$hrname\": a lowercase RFC 1123 label is required" >&2
|
|
exit 1
|
|
fi
|
|
printf '%s' "$payload" > "$FAKE_CHILD_HR"; log "APPLY-HR"
|
|
elif printf '%s' "$payload" | grep -q 'ConfigMap'; then
|
|
if printf '%s' "$payload" | grep -q 'cozystack-migration-56-unadopted'; then
|
|
# FAKE_UNADOPTED_CM_FAIL exercises the best-effort path: a permanent
|
|
# failure publishing the record must NOT abort the migration.
|
|
if [ -n "${FAKE_UNADOPTED_CM_FAIL:-}" ]; then
|
|
echo "Error from server: ConfigMap \"cozystack-migration-56-unadopted\" is invalid: exceeds object size limit" >&2
|
|
exit 1
|
|
fi
|
|
log "APPLY-UNADOPTED-CM"
|
|
else
|
|
log "STAMP"
|
|
fi
|
|
else
|
|
log "APPLY-OTHER"
|
|
fi
|
|
exit 0 ;;
|
|
annotate) log "annotate $args"; exit 0 ;;
|
|
label) log "label $args"; exit 0 ;;
|
|
create)
|
|
# Only `create configmap cozystack-migration-56-unadopted --from-file ...
|
|
# --dry-run=client -o yaml` is used; emit a minimal ConfigMap manifest so the
|
|
# piped `apply --filename -` receives it and logs APPLY-UNADOPTED-CM.
|
|
case "$args" in
|
|
*configmap*cozystack-migration-56-unadopted*)
|
|
printf 'apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cozystack-migration-56-unadopted\n' ;;
|
|
esac
|
|
exit 0 ;;
|
|
*) exit 0 ;;
|
|
esac
|