44from src .helpers .kubernetes import Kubernetes
55
66
7- # Get a YAML map of what will be backuped
87def get_backup_map (kubernetes : Kubernetes ):
8+ """
9+ Get a YAML map of what will be backuped
10+ """
911 current_ns = kubernetes .get_namespace ()
1012
1113 print (f"context: { kubernetes .get_context ()} " )
@@ -17,7 +19,6 @@ def get_backup_map(kubernetes: Kubernetes):
1719 print ("error: no PVC found or unauthorized access." )
1820 return 0
1921
20- # Loop to display the backup map
2122 print (f" claims:" )
2223 for pvc in kubernetes .list_pvc ():
2324 print (f" - name: { pvc ['name' ]} " )
@@ -36,101 +37,59 @@ def get_backup_map(kubernetes: Kubernetes):
3637 print (f" mounts: { mounts } " )
3738
3839
39- # Run a backup job
4040def run_backup_job (kubernetes : Kubernetes ):
41- # Display the map before running the job
42- get_backup_map (kubernetes )
43-
44- # for pvc in kubernetes.list_pvc():
45- # pvc_name = pvc['name']
46-
47- # targets = kubernetes.get_pvc(pvc_name)
48- # if not targets:
49- # print(f"info: no active workload config found for {pvc_name}. Skipping.")
50- # continue
51-
52- # target = targets[0]
53- # mounted_path = target['mount_path']
54- # resource = target['resource']
55- # resource_type, resource_name = resource.split('/')
56- # resource_initial_replicas = kubernetes.get_replicas(resource_type, resource_name)
57-
58- # print(f"replicas quantity found for {resource}: {resource_initial_replicas}")
59-
60- # is_running = resource_initial_replicas > 0
61- # if is_running:
62- # kubernetes.scale_replicas(resource_type, resource_name, replicas=0)
63- # if not kubernetes.wait_for_scale_down(resource_type, resource_name):
64- # print(f"error: scale down fail for {resource}. Aborting backup of {pvc_name}")
65- # continue
66- # else:
67- # print(f"info: {resource} is already scaled down. Safe to proceed.")
68-
69- # job_success = kubernetes.create_backup_job(pvc=pvc_name, mounted_path=mounted_path)
70- # if is_running:
71- # kubernetes.scale_replicas(resource_type, resource_name, replicas=resource_initial_replicas)
72- # print(f"restored replicas of {resource} {resource_initial_replicas}")
73-
74- # print('')
75-
76-
7741 """
78- Orchestrateur séquentiel global :
79- Phase 0: Nettoyage + Attente de suppression des vieux Jobs
80- Phase 1: Collecte des infos + Ordre de Scale Down (0)
81- Phase 2: Attente de l'extinction complète de la prod
82- Phase 3: Lancement de tous les nouveaux Jobs en parallèle via K8s
83- Phase 4: Restauration (Scale Up) de la prod à son état initial
42+ Global sequential orchestrator :
43+ Phase 0: Cleanup + wait for deletion of old Jobs
44+ Phase 1: Gather configuration + Trigger Scale Down (0)
45+ Phase 2: Wait for complete production workload termination
46+ Phase 3: Trigger all new backup Jobs concurrently via K8s control plane
47+ Phase 4: Restore (Scale Up) production workloads to original layout states
8448 """
85- # Récupération de la liste des PVCs du namespace
49+ get_backup_map (kubernetes )
50+
8651 pvcs = kubernetes .list_pvc ()
8752 if not pvcs :
8853 print ("error: no PVC found to backup." )
8954 return
9055
9156 print (f"\n ==================================================" )
92- print (f"⚡ Starting Sequential Backup Orchestration for { len (pvcs )} PVCs" )
57+ print (f"Starting Sequential Backup Orchestration for { len (pvcs )} PVCs" )
9358 print (f"==================================================" )
9459
9560 # ==================================================
96- # PHASE 0 : NETTOYAGE GLOBAL DES ANCIENS JOBS
61+ # PHASE 0 : GLOBAL JOB CLEANUP
9762 # ==================================================
98- print ("\n 🧹 PHASE 0: Purging any existing/stale backup jobs..." )
63+ print ("\n PHASE 0: Purging any existing/stale backup jobs..." )
9964 pvc_names = []
10065
10166 for pvc in pvcs :
10267 pvc_name = pvc ['name' ]
10368 pvc_names .append (pvc_name )
104- # Envoie l'ordre de suppression à l'API (non-bloquant)
10569 kubernetes .delete_backup_job (pvc_name = pvc_name )
10670
107- # Validation dynamique de la disparition des anciens Jobs
10871 if not kubernetes .wait_for_jobs_deletion (pvc_names = pvc_names , timeout = 45 ):
109- print (" ⚠️ Warning : Some old jobs might still be terminating. Proceeding anyway..." )
72+ print (" warn : Some old jobs might still be terminating. Proceeding anyway..." )
11073
111- # Structure pour mémoriser l'état initial de chaque workload
11274 backup_workloads = {}
11375
11476 # ==================================================
115- # PHASE 1 : ANALYSE ET ENVOI DU SCALE DOWN (0)
77+ # PHASE 1 : WORKLOAD ASSESSMENT AND SCALE DOWN
11678 # ==================================================
117- print ("\n 🛑 PHASE 1: Capturing states and scaling down workloads..." )
79+ print ("\n PHASE 1: Capturing states and scaling down workloads..." )
11880 for pvc in pvcs :
11981 pvc_name = pvc ['name' ]
12082 targets = kubernetes .get_pvc (pvc_name )
12183 if not targets :
122- print (f" ⚠️ No active workload config found for { pvc_name } . Skipping." )
84+ print (f" warn: No active workload config found for { pvc_name } . Skipping." )
12385 continue
12486
125- # On prend la première configuration trouvée liée au PVC
12687 target = targets [0 ]
127- resource_key = target ['resource' ] # Ex: "StatefulSet/postgresql"
88+ resource_key = target ['resource' ]
12889 resource_type , resource_name = resource_key .split ('/' )
12990 mounted_path = target ['mount_path' ]
13091
131- # Évite de traiter deux fois le même StatefulSet si celui-ci a plusieurs PVCs
13292 if resource_key not in backup_workloads :
133- # On lit et on stocke le nombre de répliques en cours (ex: 1, 2, 3...)
13493 initial_replicas = kubernetes .get_replicas (resource_type , resource_name )
13594
13695 backup_workloads [resource_key ] = {
@@ -141,56 +100,49 @@ def run_backup_job(kubernetes: Kubernetes):
141100 "mounted_path" : mounted_path
142101 }
143102
144- # Si l'application tourne, on demande à K8s de l'éteindre
145103 if initial_replicas > 0 :
146104 kubernetes .scale_replicas (resource_type , resource_name , replicas = 0 )
147105 else :
148- print (f" 🌙 { resource_key } is already stopped (Night mode)." )
106+ print (f" info: { resource_key } is already stopped (Night mode)." )
149107
150108 # ==================================================
151- # PHASE 2 : ATTENTE DE L'EXTINCTION GLOBALE
109+ # PHASE 2 : WAIT FOR COMPLETE EXCLUSIVITY
152110 # ==================================================
153- print ("\n ⏳ PHASE 2: Waiting for all workloads to be fully stopped..." )
111+ print ("\n PHASE 2: Waiting for all workloads to be fully stopped..." )
154112 for resource_key , info in backup_workloads .items ():
155113 if info ["initial_replicas" ] > 0 :
156- # Bloque le script tant que les conteneurs de l'application ne sont pas à 0
157114 kubernetes .wait_for_scale_down (info ["resource_type" ], info ["resource_name" ])
158115
159116 # ==================================================
160- # PHASE 3 : LANCEMENT DE TOUS LES BACKUPS D'UN COUP
117+ # PHASE 3 : TRIGGER CONCURRENT BACKUPS
161118 # ==================================================
162- print ("\n 🚀 PHASE 3: Triggering all Kubernetes backup jobs simultaneously..." )
119+ print ("\n PHASE 3: Triggering all Kubernetes backup jobs simultaneously..." )
163120 for resource_key , info in backup_workloads .items ():
164- # K8s instancie les Jobs en tâche de fond (le traitement disque se fait en parallèle sur le cluster)
165121 kubernetes .create_backup_job (pvc_name = info ["pvc_name" ], mounted_path = info ["mounted_path" ])
166122
167- # Temporisation de sécurité pour laisser le temps aux Pods de backup de démarrer,
168- # d'accrocher le volume et de poser leurs verrous de lecture.
169- print (" 🛌 Allowing a 5s safety buffer for backup containers to initialize..." )
123+ print (" info: Allowing a 5s safety buffer for backup containers to initialize..." )
170124 time .sleep (5 )
171125
172126 # ==================================================
173- # PHASE 4 : RESTAURATION (SCALE UP) DE LA PRODUCTION
127+ # PHASE 4 : PRODUCTION WORKLOAD RESTORATION
174128 # ==================================================
175- print ("\n 🔄 PHASE 4: Restoring production workloads to initial states..." )
129+ print ("\n PHASE 4: Restoring production workloads to initial states..." )
176130 for resource_key , info in backup_workloads .items ():
177131 if info ["initial_replicas" ] > 0 :
178- # On remet l'application exactement dans son état de départ (ex: replicas=1)
179132 kubernetes .scale_replicas (
180133 info ["resource_type" ],
181134 info ["resource_name" ],
182135 replicas = info ["initial_replicas" ]
183136 )
184- print (f" ✅ { resource_key } restored to { info ['initial_replicas' ]} replicas." )
137+ print (f" info: { resource_key } restored to { info ['initial_replicas' ]} replicas." )
185138
186139 print (f"\n ==================================================" )
187- print (f"🏁 Sequential orchestration process finished successfully." )
140+ print (f"Sequential orchestration process finished successfully." )
188141 print (f"==================================================" )
189142
190143
191144def main ():
192145 parser = argparse .ArgumentParser (description = "Backup Kubernetes volumes" )
193- parser .add_index = False
194146 parser .add_argument ("-c" , "--context" , type = str , default = None , help = "Local kubectl context" )
195147 parser .add_argument ("-n" , "--namespace" , type = str , default = None , help = "Kubernetes namespace" )
196148 parser .add_argument ("-j" , "--job" , action = "store_true" , help = "Run a backup job" )
@@ -210,4 +162,4 @@ def main():
210162
211163
212164if __name__ == "__main__" :
213- sys .exit (main ())
165+ sys .exit (main ())
0 commit comments