From: francisco.garcia Date: Tue, 28 Nov 2023 08:28:33 +0000 (+0100) Subject: k8s: Fix pvc naming error in csi snapshots X-Git-Tag: Beta-15.0.1~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=563bbc5f06168ff4f577fe3238f7728213ba161e;p=thirdparty%2Fbacula.git k8s: Fix pvc naming error in csi snapshots --- diff --git a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/entities/file_info.py b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/entities/file_info.py index 2ef7f3a47..4f760ed30 100644 --- a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/entities/file_info.py +++ b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/entities/file_info.py @@ -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 diff --git a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/backup_job.py b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/backup_job.py index 4842dd630..38a31d8fb 100644 --- a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/backup_job.py +++ b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/backup_job.py @@ -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': } """ - 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) diff --git a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/job_pod_bacula.py b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/job_pod_bacula.py index 6cb8486e6..71ae364b8 100644 --- a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/job_pod_bacula.py +++ b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/jobs/job_pod_bacula.py @@ -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 diff --git a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/csi_snapshot.py b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/csi_snapshot.py index c0ae5d74f..18025bc67 100644 --- a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/csi_snapshot.py +++ b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/csi_snapshot.py @@ -17,16 +17,17 @@ # # 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')}} } } diff --git a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/kubernetes_plugin.py b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/kubernetes_plugin.py index 3940c42b5..d49d25c35 100644 --- a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/kubernetes_plugin.py +++ b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/kubernetes_plugin.py @@ -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