]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
k8s: Fix pvc naming error in csi snapshots
authorfrancisco.garcia <francisco.garcia@baculasystems.com>
Tue, 28 Nov 2023 08:28:33 +0000 (09:28 +0100)
committerEric Bollengier <eric@baculasystems.com>
Tue, 13 Feb 2024 09:36:02 +0000 (10:36 +0100)
bacula/src/plugins/fd/kubernetes-backend/baculak8s/entities/file_info.py
bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/backup_job.py
bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/job_pod_bacula.py
bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/csi_snapshot.py
bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/kubernetes_plugin.py

index 2ef7f3a47dc270bfb2cc12d9f5965901bd9a528b..4f760ed30245cdc8b94eb56cd8473bdbc34b0a66 100644 (file)
@@ -64,6 +64,11 @@ class FileInfo(object):
                     str(self.objtype),
                     self.objcache is not None)
 
+
+    def set_name(self, name: str):
+        self.name = name
+
+
     def is_bucket(self):
         return self.type == DIRECTORY and not self.name
 
index 4842dd6302d5902352ffc5a7c204ddd3b6aa025a..38a31d8fb6bda7ffbff132711a0c53f8181903da 100644 (file)
@@ -224,13 +224,13 @@ class BackupJob(EstimationJob):
             if backupmode == BaculaBackupMode.Snapshot:
                 vsnapshot, pvc_from_vsnap = self.handle_create_vsnapshot_backup(namespace, pvcname)
                 logging.debug("The vsnapshot created from pvc {} is: {}".format(pvcname, vsnapshot))
-                logging.debug("The pvc create from vsnapshot {} is: {}".format(vsnapshot, pvc_from_vsnap))
+                logging.debug("The pvc create from vsnapshot {} is: {}. FI: {}".format(vsnapshot, pvc_from_vsnap, pvc_from_vsnap.get('fi')))
                 if vsnapshot == None:
                     logging.debug(CHANGE_BACKUP_MODE_FOR_INCOMPATIBLITY_PVC.format(pvcname))
                     # backupmode = BaculaBackupMode.Clone
                     self._io.send_info(CHANGE_BACKUP_MODE_FOR_INCOMPATIBLITY_PVC.format(pvcname))
                 else:
-                    pvc = pvc_from_vsnap.get("name")
+                    pvc = pvc_from_vsnap
                     pvcname = pvc_from_vsnap.get("name")
 
             logging.debug("handling vol after snapshot/clone: {}".format(pvcname))
@@ -248,19 +248,24 @@ class BackupJob(EstimationJob):
         # iterate on requested volumes for backup
         logging.debug("iterate over requested vols for backup: {}".format(handledvolumes))
         for volumes in handledvolumes:
+            logging.debug('Volume in handlevolumes:\n{}'.format(volumes))
             pvc = volumes['pvc']
             pvcname = volumes['pvcname']
             # get pvcdata for this volume
             """
             PVCDATA:plugintest-pvc-alone:{'name': 'plugintest-pvc-alone-baculaclone-lfxrra', 'node_name': None, 'storage_class_name': 'ocs-storagecluster-cephfs', 'capacity': '1Gi', 'fi': <baculak8s.entities.file_info.FileInfo object at 0x7fc3c08bc668>}
             """
-            pvcdata = self._plugin.get_pvcdata_namespaced(namespace, pvcname, pvc)
+            pvcdata = self._plugin.get_pvcdata_namespaced(namespace, pvcname, pvcname)
             if isinstance(pvcdata, dict) and 'error' in pvcdata:
                 self._handle_error(PVCDATA_GET_ERROR.format(parse_json_descr(pvcdata)))
 
             else:
-                logging.debug('PVCDATA:{}:{}'.format(pvc, pvcdata))
-                logging.debug('PVCDATA FI.name:{}'.format(pvcdata.get('fi').name))
+                # Modify the name in FileInfo because we need save the file like original name 
+                # and not the new pvc (from vsnapshot) name.
+                if volumes.get('vsnapshot') is not None:
+                    logging.debug('We change the name of FileInfo to adapt the original pvc name with the new pvc name')
+                    pvcdata.get('fi').set_name(pvc.get('fi').name)
+
                 if len(pvcdata) > 0:
                     status = self.process_pvcdata(namespace, pvcdata, True)
 
index 6cb8486e6cee1022dccb91834f2c18a98066a6cf..71ae364b84df23e8453d964c7c24153116604d38 100644 (file)
@@ -343,9 +343,9 @@ class JobPodBacula(Job, metaclass=ABCMeta):
         # Check if pvc is compatible with vsnapshot
         if not self._plugin.check_pvc_compatiblity_with_vsnapshot(namespace, pvc.get('name')):
             return None, pvc
-
+        logging.debug('Origin pvcdata FileInfo:\n{}'.format(pvc.get('fi')))
         self._io.send_info(VSNAPSHOT_BACKUP_COMPATIBLE_INFO.format(pvc.get('name')))
-        vsnapshot = self._plugin.create_vsnapshot(namespace, pvc.get('name'))
+        vsnapshot = self._plugin.create_vsnapshot(namespace, pvc)
         if isinstance(vsnapshot, dict) and 'error' in vsnapshot:
             self._handle_error(CANNOT_CREATE_VSNAPSHOT_ERR.format(parse_json_descr(vsnapshot)))
             return None, None
index c0ae5d74f3a136b8f9ed2721a064031de068364b..18025bc675ba08821c797f2972c02c1677ffcb72 100644 (file)
 #
 #   Bacula(R) is a registered trademark of Kern Sibbald.
 #
+import logging
 
 SNAPSHOT_DRIVER_COMPATIBLE='csi'
 
 K8SOBJ_SNAPSHOT_GROUP = 'snapshot.storage.k8s.io'
-K8SOBJ_SNAPSHOT_VERSION = 'v1beta1'
+K8SOBJ_SNAPSHOT_VERSION = 'v1'
+K8SOBJ_SNAPSHOTCLASS_PLURAL = 'volumesnapshotclasses'
 K8SOBJ_SNAPSHOT_PLURAL = 'volumesnapshots'
 K8SOBJ_SNAPSHOT_KIND = 'VolumeSnapshot'
 K8SOBJ_SNAPSHOT_NAME_TEMPLATE = 'bacula-vsnap-{pvc}-{jobid}'
 BACKUP_PVC_FROM_SNAPSHOT_TEMPLATE = 'bacula-pvcfs-{pvc}-{jobid}'
-K8SOBJ_SNAPSHOT_CLASS = 'csi-hostpath-snapclass'
 
 def csi_snapshots_read_namespaced(crd_api, namespace, name):
     return crd_api.get_namespaced_custom_object(K8SOBJ_SNAPSHOT_GROUP, K8SOBJ_SNAPSHOT_VERSION, namespace, K8SOBJ_SNAPSHOT_PLURAL, name)
@@ -51,8 +52,20 @@ def csi_snapshots_namespaced_names(crd_api, namespace, labels=""):
         }
     return snapdict
 
+def get_volume_snapshot_class_name(crd_api, pvc_storageclass_provisioner):
+    volume_snapshot_classes = crd_api.list_cluster_custom_object(K8SOBJ_SNAPSHOT_GROUP, K8SOBJ_SNAPSHOT_VERSION, K8SOBJ_SNAPSHOTCLASS_PLURAL, watch=False)
+    logging.debug("Provisioner of PVC Storage class:\n{}".format(pvc_storageclass_provisioner))
+    logging.debug("VolumeSnapshotClasses available:\n {}".format(volume_snapshot_classes))
+    for snap in volume_snapshot_classes.get('items'):
+        if pvc_storageclass_provisioner == snap.get('driver'):
+            logging.debug("VolumesnapshotClass selected:\n{}".format(snap.get('metadata').get('name')))
+            return snap.get('metadata').get('name')
+    raise ValueError("VolumeSnapshotClass not found for this provisioner: {}. Please contact with Bacula support".format(pvc_storageclass_provisioner))
 
-def prepare_create_snapshot_body(namespace, pvc_name, jobid):
+
+
+def prepare_create_snapshot_body(crd_api, namespace, pvc_name, jobid, pvc_storageclass_provisioner):
+    volumeSnapshotClassName = get_volume_snapshot_class_name(crd_api, pvc_storageclass_provisioner)
     return {
         "group": K8SOBJ_SNAPSHOT_GROUP,
         "version": K8SOBJ_SNAPSHOT_VERSION,
@@ -66,7 +79,7 @@ def prepare_create_snapshot_body(namespace, pvc_name, jobid):
                 "namespace": namespace
             },
             "spec": {
-                "volumeSnapshotClassName": K8SOBJ_SNAPSHOT_CLASS,
+                "volumeSnapshotClassName": volumeSnapshotClassName,
                 "source": {
                     "persistentVolumeClaimName": pvc_name
                 }
@@ -99,7 +112,7 @@ def prepare_pvc_from_vsnapshot_body(namespace, pvcdata, jobid):
                 'kind': K8SOBJ_SNAPSHOT_KIND,
                 'apiGroup': K8SOBJ_SNAPSHOT_GROUP
             },
-            'accessModes': ['ReadOnlyMany'],
+            'accessModes': ['ReadWriteOnce'],
             'resources': { 'requests': {'storage': pvcdata.get('capacity')}}
         }
     }
index 3940c42b5e2bbbf39fbb7b96545f3904fdc731d8..d49d25c353201e2a419c18feb8d2d0b1da30d17f 100644 (file)
@@ -802,9 +802,12 @@ class KubernetesPlugin(Plugin):
             return False
         return status.get('readyToUse')
 
-    def create_vsnapshot(self, namespace, pvcname):
-        logging.info("Creating vsnapshot of pvc `{}`".format(pvcname))
-        snapshot = prepare_create_snapshot_body(namespace, pvcname, self._params.get('jobid'))
+    def create_vsnapshot(self, namespace, pvc):
+        pvcname = pvc.get('name')
+        logging.info("Creating vsnapshot of pvc `{}`".format(pvc))
+        storage_provisioner =  get_provisioner(self.storagev1api, pvc.get('storage_class_name'))
+        snapshot = prepare_create_snapshot_body(self.crd_api, namespace, pvcname, self._params.get('jobid'), storage_provisioner)
+        logging.debug("Body to create vsnapshot:\n`{}`\n".format(snapshot))
         response = self.__execute(lambda: self.crd_api.create_namespaced_custom_object(**snapshot, pretty=True))
         if isinstance(response, dict) and "error" in response:
             return response
@@ -825,6 +828,7 @@ class KubernetesPlugin(Plugin):
 
     def create_pvc_from_vsnapshot(self, namespace, pvcdata):
         new_pvc = prepare_pvc_from_vsnapshot_body(namespace, pvcdata, self._params.get('jobid'))
+        logging.debug("Body to create pvc from vsnapshot: `{}`".format(new_pvc))
         response = self.create_pvc_clone(namespace, new_pvc)
         if isinstance(response, dict) and 'error' in response:
             return response