mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-03 02:27:01 +09:00
feat(platform): make unprotect strips no-delete label for teardown
Address review feedback from @lexfrei on packages/core/platform/templates/ deletion-protection.yaml: with this PR every protected object — CRDs, ClusterIssuers, cozy-system and tenant-root Namespaces, cozystack-version ConfigMap, cozystack-packages Repository, tenant-root HelmRelease, LinstorCluster, plus the VAP and Binding themselves — carries the no-delete label. `helm uninstall cozy-platform` issues DELETE on each, and DELETE is denied for every one of them, so the chart effectively cannot be uninstalled without manual `kubectl label` against each object. Disaster recovery and dev-cluster reset both regress as a result. Add packages/core/platform/hack/unprotect.sh: enumerates the guarded set locally (per-kind, not via a single all-resources sweep — some kinds may not exist on every install, e.g. linstorcluster on a non-LINSTOR cluster, and kubectl errors on unknown kinds). For cluster-scoped kinds, lists objects with the label and labels them off one at a time. For namespaced kinds, lists (namespace, name) pairs via jsonpath and labels each in the right namespace. Idempotent: a label that is already absent is a no-op. Wire `make unprotect` in packages/core/platform/Makefile so the operator runs it before `helm uninstall`. The Makefile target carries a comment noting this is teardown / disaster-recovery only — after it runs, the cluster has no guardrail until the next `helm upgrade` re-stamps the label. Verified with a stub kubectl in PATH that the script issues the right get/label calls for both cluster-scoped (e.g. `kubectl label customresourcedefinition/packages.cozystack.io platform.cozystack.io/ no-delete-`) and namespaced kinds (e.g. `kubectl label --namespace tenant-root helmrelease tenant-root platform.cozystack.io/no-delete-`). The template-header reference at templates/deletion-protection.yaml that forward-links to `make unprotect` was added in the preceding L3 commit; the recipe it points at now exists. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
This commit is contained in:
2 files changed
+78
No files matched your search
@@ -20,6 +20,14 @@ diff:
|
||||
test:
|
||||
helm unittest .
|
||||
|
||||
# Strip the platform.cozystack.io/no-delete label from every guarded object so
|
||||
# `helm uninstall cozy-platform` (and ad-hoc deletes of protected resources)
|
||||
# is no longer denied by the deletion-protection VAP. After this runs, the
|
||||
# cluster has no guardrail until the next `helm upgrade` re-stamps the label.
|
||||
# Intended for teardown / disaster-recovery, not routine use.
|
||||
unprotect:
|
||||
hack/unprotect.sh
|
||||
|
||||
image: image-migrations
|
||||
|
||||
image-migrations:
|
||||
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/bin/sh
|
||||
# Strip the platform.cozystack.io/no-delete=true label from every object that
|
||||
# carries it, so `helm uninstall cozy-platform` (and ad-hoc `kubectl delete`
|
||||
# on a protected resource) is no longer denied by the deletion-protection
|
||||
# ValidatingAdmissionPolicy.
|
||||
#
|
||||
# Intended for chart teardown and disaster-recovery — NOT a routine operation.
|
||||
# After this runs, the cluster has no guardrail until the next `helm upgrade`
|
||||
# re-stamps the label.
|
||||
#
|
||||
# Idempotent: a label that is already absent is a no-op.
|
||||
#
|
||||
# The set of guarded kinds is enumerated locally rather than discovered
|
||||
# dynamically because some of the kinds may not exist in every cluster
|
||||
# (e.g. linstorcluster on a non-LINSTOR install) and kubectl returns an
|
||||
# error for unknown resource types. The per-kind get is best-effort.
|
||||
|
||||
set -eu
|
||||
|
||||
LABEL="platform.cozystack.io/no-delete"
|
||||
|
||||
# Cluster-scoped guarded kinds. CRDs and Namespaces sit here, plus the
|
||||
# VAP/Binding pair (which is also self-labeled) and LinstorCluster.
|
||||
CLUSTER_KINDS="
|
||||
customresourcedefinition
|
||||
clusterissuer
|
||||
namespace
|
||||
validatingadmissionpolicy
|
||||
validatingadmissionpolicybinding
|
||||
linstorcluster
|
||||
"
|
||||
|
||||
# Namespaced guarded kinds. ConfigMap, Repository/OCIRepository, HelmRelease.
|
||||
# Use --all-namespaces with -o jsonpath so we get back (ns, name) pairs and
|
||||
# can pass each to a per-object `kubectl label`.
|
||||
NS_KINDS="
|
||||
configmap
|
||||
ocirepository
|
||||
helmrelease
|
||||
"
|
||||
|
||||
echo "Removing $LABEL label from all guarded objects..."
|
||||
|
||||
for kind in $CLUSTER_KINDS; do
|
||||
names=$(kubectl get "$kind" --selector="$LABEL=true" --output=name 2>/dev/null || true)
|
||||
if [ -n "$names" ]; then
|
||||
# One kubectl per resource — `kubectl label` takes the label op as the
|
||||
# last argument, so xargs's trailing-args model would put it in the
|
||||
# wrong position. The protected set is small (<20 objects) so the
|
||||
# extra round-trips are negligible.
|
||||
printf '%s\n' "$names" | while read -r ref; do
|
||||
[ -z "$ref" ] && continue
|
||||
kubectl label "$ref" "$LABEL-"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
for kind in $NS_KINDS; do
|
||||
pairs=$(kubectl get "$kind" --all-namespaces --selector="$LABEL=true" \
|
||||
--output=jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' \
|
||||
2>/dev/null || true)
|
||||
if [ -n "$pairs" ]; then
|
||||
printf '%s\n' "$pairs" | while read -r ns name; do
|
||||
[ -z "$name" ] && continue
|
||||
kubectl label --namespace "$ns" "$kind" "$name" "$LABEL-"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Done. helm uninstall is now unblocked."
|
||||
Reference in new issue
Block a user