Skip to main content

Uninstall

Before uninstalling Testudo, decide whether you are deleting only the control plane, the CRDs, or backup data. These choices determine whether history and recovery data remain available.

Uninstall Modes

ModeDeletesKeepsUse Case
Control plane onlyoperator/server/web Deployments, Services, and Helm resourcesCRDs, object storage data, remote Velero resourcesTemporary shutdown or control-plane migration
Control plane with backups retainedHelm resources and some platform configObject storage backup dataStop the system but keep recovery data
Full cleanupHelm resources, CRDs, Secrets, backup dataNothingLab environment teardown

Full cleanup is not recommended in production by default.

Pre-checks

kubectl -n disaster-system get disasteroperation
kubectl -n disaster-system get appbackups,apprestores
kubectl -n disaster-system get disasterdrills.testudo.softcdata.com

Confirm:

  • No long-running operations are running.
  • CRDs that must be retained are exported.
  • Object storage bucket retention is decided.
  • Remote Velero resources are decided.
  • Console/API users are notified.

Uninstall Helm Release Only

helm uninstall testudo -n disaster-system

Check remaining resources:

kubectl -n disaster-system get all
kubectl get crd | grep testudo.softcdata.com

Whether CRDs are deleted depends on how the Chart packages CRDs. Use helm get manifest before uninstalling.

Delete Testudo CRDs During Uninstall

Helm does not delete CRDs installed from the chart crds/ directory by default. Normal install, upgrade, or control-plane-only uninstall does not require uninstallCleanup.enabled; enable it only when you explicitly want uninstall to delete Testudo CRDs and their CR instances. In that case, first upgrade the current release to a chart that contains the cleanup hook and enable uninstallCleanup.enabled:

helm repo update

helm upgrade testudo testudo/testudo-chart \
-n disaster-system \
--reuse-values \
--set uninstallCleanup.enabled=true

If you use an offline package or a private chart repository, replace testudo/testudo-chart with the same chart reference used for installation or upgrade. Do not uninstall an old release first and expect the new chart cleanup logic to run; Helm only runs hooks already stored in the current release.

Then uninstall:

helm uninstall testudo -n disaster-system --wait --timeout 10m

The cleanup hook runs the testudo-crd-cleanup Job before uninstall. It:

  1. Deletes the Testudo validating webhook so CR updates during cleanup are not blocked by the old webhook.
  2. Removes finalizers from Testudo CR instances.
  3. Deletes Testudo CRDs.

Deleting CRDs deletes all matching Testudo CR instance data. Before enabling this in production, confirm that those CRs are no longer needed or have been exported. uninstallCleanup.deleteVeleroCrds defaults to false; do not delete Velero CRDs while another Velero installation or backup data still depends on them.

If uninstall is stuck on the cleanup Job, inspect events and logs first:

kubectl -n disaster-system get job,pod | grep testudo-crd-cleanup
kubectl -n disaster-system describe job testudo-crd-cleanup
kubectl -n disaster-system logs job/testudo-crd-cleanup --all-containers

Common causes are an unpullable cleanup image or an image that does not contain /bin/sh and kubectl. The current chart default uses docker.io/dtzar/helm-kubectl:3.17.3 as the cleanup image. In offline environments, mirror this image to a registry the cluster can pull from and override these values:

uninstallCleanup:
enabled: true
kubectlImage:
repository: <registry.example.com>/dtzar/helm-kubectl
tag: "3.17.3"

If your cluster has many leftover CRDs or CR instances, or if the apiserver is slow, increase uninstallCleanup.timeoutSeconds further. This value controls both the per-CRD wait time and the Job deadline, so helm uninstall --wait --timeout must leave extra room as well.

If CRDs and historical CR instances are retained, the next installation may report errors similar to:

admission webhook "vdisasterinstance.kb.io" denied the request:
ModifierRuleRejected: load disasterConfig <name> failed:
DisasterConfig.testudo.softcdata.com "<name>" not found

This is usually not a failure of the new install itself. It means an old CR such as DisasterInstance remains with a finalizer and references a DisasterConfig that has already been deleted. When the operator tries to remove the finalizer, the update triggers webhook validation; the webhook cannot load the referenced object and rejects the update.

Retain Data

To retain recovery capability, keep:

  • Object storage bucket and backup objects.
  • Velero Backup/Restore metadata.
  • Exported StorageRepository, Cluster, and DisasterInstance CRDs.
  • values files and image version records.

Dangerous Operations

These operations can cause irreversible data loss and require production approval:

kubectl delete crd <name>.testudo.softcdata.com
kubectl delete namespace disaster-system
mc rm --recursive --force <bucket/path>

Do not delete the object storage bucket without confirming backup retention policy.

Post-uninstall Verification

  • Console entry no longer responds.
  • Server API no longer responds.
  • Business cluster workloads are not automatically deleted by control-plane uninstall.
  • Object storage data is retained or deleted as intended.
  • If CRDs are retained, reinstalling should allow the control plane to read existing state again.

If CRD cleanup was enabled, also confirm that Testudo CRDs are gone:

kubectl get crd | grep testudo.softcdata.com || true
kubectl -n disaster-system get job,pod | grep testudo-crd-cleanup || true