#!/usr/bin/env python3 """sanitize_k8s_manifest.py — strip source-cluster-specific fields from a captured `kubectl get ... -o yaml` dump so it can be applied fresh onto a different (DR/standby) cluster. backup-k8s-apps.sh's manifests.yaml/pvc.yaml/secret.yaml are raw `kubectl get -o yaml` output: server-assigned fields like resourceVersion/uid are always present, and PVCs additionally carry spec.volumeName + a Bound status pointing at a specific PersistentVolume that only exists on the ORIGINAL cluster. Applying any of that verbatim onto a fresh cluster either fails outright (a stale resourceVersion trips optimistic-concurrency checks — the exact bug fixed in restore-k8s-apps.sh's Secret handling) or silently tries to bind a PVC to a PV that was never created there. Usage: sanitize_k8s_manifest.py """ import sys import yaml DROP_METADATA_KEYS = ( 'resourceVersion', 'uid', 'creationTimestamp', 'selfLink', 'generation', 'finalizers', 'managedFields', 'annotations', ) def sanitize_item(item): meta = item.get('metadata') or {} for key in DROP_METADATA_KEYS: meta.pop(key, None) item.pop('status', None) if item.get('kind') == 'PersistentVolumeClaim': spec = item.get('spec') or {} spec.pop('volumeName', None) return item def main(): if len(sys.argv) != 3: print(f"usage: {sys.argv[0]} ", file=sys.stderr) sys.exit(1) with open(sys.argv[1]) as f: doc = yaml.safe_load(f) if doc is None: items = [] elif doc.get('kind') == 'List': items = [sanitize_item(i) for i in doc.get('items', [])] else: items = [sanitize_item(doc)] with open(sys.argv[2], 'w') as f: yaml.safe_dump_all(items, f, default_flow_style=False) if __name__ == '__main__': main()