@@ -262,7 +262,7 @@ def updateTektonDefinitions(namespace: str, yamlFile: str) -> None:
262262 logger .debug (line )
263263
264264
265- def preparePipelinesNamespace (dynClient : DynamicClient , instanceId : str = None , storageClass : str = None , accessMode : str = None , waitForBind : bool = True , configureRBAC : bool = True ):
265+ def preparePipelinesNamespace (dynClient : DynamicClient , instanceId : str = None , storageClass : str = None , accessMode : str = None , waitForBind : bool = True , configureRBAC : bool = True , createBackupPVC : bool = False , backupStorageSize : str = "20Gi" ):
266266 """
267267 Prepare a namespace for MAS pipelines by creating RBAC and PVC resources.
268268
@@ -276,6 +276,8 @@ def preparePipelinesNamespace(dynClient: DynamicClient, instanceId: str = None,
276276 accessMode (str, optional): Access mode for the PVC. Defaults to None.
277277 waitForBind (bool, optional): Whether to wait for PVC to bind. Defaults to True.
278278 configureRBAC (bool, optional): Whether to configure RBAC. Defaults to True.
279+ createBackupPVC (bool, optional): Whether to create backup PVC. Defaults to False.
280+ backupStorageSize (str, optional): Size of the backup PVC storage. Defaults to "20Gi".
279281
280282 Returns:
281283 None
@@ -304,6 +306,9 @@ def preparePipelinesNamespace(dynClient: DynamicClient, instanceId: str = None,
304306
305307 # Create PVC (instanceId namespace only)
306308 if instanceId is not None :
309+ pvcAPI = dynClient .resources .get (api_version = "v1" , kind = "PersistentVolumeClaim" )
310+
311+ # Create config PVC
307312 template = env .get_template ("pipelines-pvc.yml.j2" )
308313 renderedTemplate = template .render (
309314 mas_instance_id = instanceId ,
@@ -312,24 +317,51 @@ def preparePipelinesNamespace(dynClient: DynamicClient, instanceId: str = None,
312317 )
313318 logger .debug (renderedTemplate )
314319 pvc = yaml .safe_load (renderedTemplate )
315- pvcAPI = dynClient .resources .get (api_version = "v1" , kind = "PersistentVolumeClaim" )
316320 pvcAPI .apply (body = pvc , namespace = namespace )
321+
317322 # Automatically determine if we should wait for PVC binding based on storage class
318323 volumeBindingMode = getStorageClassVolumeBindingMode (dynClient , storageClass )
319324 waitForBind = (volumeBindingMode == "Immediate" )
320325 if waitForBind :
321- logger .info (f"Storage class { storageClass } uses volumeBindingMode={ volumeBindingMode } , waiting for PVC to bind" )
326+ logger .info (f"Storage class { storageClass } uses volumeBindingMode={ volumeBindingMode } , waiting for config PVC to bind" )
322327 pvcIsBound = False
323328 while not pvcIsBound :
324329 configPVC = pvcAPI .get (name = "config-pvc" , namespace = namespace )
325330 if configPVC .status .phase == "Bound" :
326331 pvcIsBound = True
327332 else :
328- logger .debug ("Waiting 15s before checking status of PVC again" )
333+ logger .debug ("Waiting 15s before checking status of config PVC again" )
329334 logger .debug (configPVC )
330335 sleep (15 )
331336 else :
332- logger .info (f"Storage class { storageClass } uses volumeBindingMode={ volumeBindingMode } , skipping PVC bind wait" )
337+ logger .info (f"Storage class { storageClass } uses volumeBindingMode={ volumeBindingMode } , skipping config PVC bind wait" )
338+
339+ # Create backup PVC if requested
340+ if createBackupPVC :
341+ logger .info ("Creating backup PVC" )
342+ backupTemplate = env .get_template ("pipelines-backup-pvc.yml.j2" )
343+ renderedBackupTemplate = backupTemplate .render (
344+ mas_instance_id = instanceId ,
345+ pipeline_storage_class = storageClass ,
346+ pipeline_storage_accessmode = accessMode
347+ )
348+ logger .debug (renderedBackupTemplate )
349+ backupPvc = yaml .safe_load (renderedBackupTemplate )
350+ pvcAPI .apply (body = backupPvc , namespace = namespace )
351+
352+ if waitForBind :
353+ logger .info (f"Storage class { storageClass } uses volumeBindingMode={ volumeBindingMode } , waiting for backup PVC to bind" )
354+ backupPvcIsBound = False
355+ while not backupPvcIsBound :
356+ backupPVC = pvcAPI .get (name = "backup-pvc" , namespace = namespace )
357+ if backupPVC .status .phase == "Bound" :
358+ backupPvcIsBound = True
359+ else :
360+ logger .debug ("Waiting 15s before checking status of backup PVC again" )
361+ logger .debug (backupPVC )
362+ sleep (15 )
363+ else :
364+ logger .info (f"Storage class { storageClass } uses volumeBindingMode={ volumeBindingMode } , skipping backup PVC bind wait" )
333365
334366
335367def prepareAiServicePipelinesNamespace (dynClient : DynamicClient , instanceId : str = None , storageClass : str = None , accessMode : str = None , waitForBind : bool = True , configureRBAC : bool = True ):
@@ -697,6 +729,28 @@ def launchUpdatePipeline(dynClient: DynamicClient, params: dict) -> str:
697729 return pipelineURL
698730
699731
732+ def launchBackupPipeline (dynClient : DynamicClient , params : dict ) -> str :
733+ """
734+ Create a PipelineRun to backup a MAS instance.
735+
736+ Parameters:
737+ dynClient (DynamicClient): OpenShift Dynamic Client
738+ params (dict): Backup parameters including instance ID and configuration
739+
740+ Returns:
741+ str: URL to the PipelineRun in the OpenShift console
742+
743+ Raises:
744+ NotFoundError: If resources cannot be created
745+ """
746+ instanceId = params ["mas_instance_id" ]
747+ namespace = f"mas-{ instanceId } -pipelines"
748+ timestamp = launchPipelineRun (dynClient , namespace , "pipelinerun-backup" , params )
749+
750+ pipelineURL = f"{ getConsoleURL (dynClient )} /k8s/ns/mas-{ instanceId } -pipelines/tekton.dev~v1beta1~PipelineRun/{ instanceId } -backup-{ timestamp } "
751+ return pipelineURL
752+
753+
700754def launchAiServiceUpgradePipeline (dynClient : DynamicClient ,
701755 aiserviceInstanceId : str ,
702756 skipPreCheck : bool = False ,
0 commit comments