From: francisco.garcia Date: Sat, 3 Feb 2024 11:59:25 +0000 (+0100) Subject: k8s:Add check snapshot api-resource available X-Git-Tag: Release-15.0.2~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=508ad8dd57c06f7f059a7132ceab4082c82b5f19;p=thirdparty%2Fbacula.git k8s:Add check snapshot api-resource available --- 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 38a31d8fb..47166ec01 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 @@ -16,6 +16,7 @@ # Bacula(R) is a registered trademark of Kern Sibbald. import logging +import time from baculak8s.entities.file_info import DIRECTORY from baculak8s.entities.plugin_object import PluginObject @@ -126,15 +127,25 @@ class BackupJob(EstimationJob): self._handle_error(response['error']) return False return True - + def process_pvcdata(self, namespace, pvcdata, backup_with_pod = False): status = None vsnapshot = None + is_cloned = False + cloned_pvc_name = None # Detect if pvcdata is compatible with snapshots if not backup_with_pod: + logging.debug('Backup without pod') vsnapshot, pvcdata = self.handle_create_vsnapshot_backup(namespace, pvcdata.get('name')) - - logging.debug('Process_pvcdata (Backup_job): {} {}'.format(vsnapshot, pvcdata)) + logging.debug('Process_pvcdata (Backup_job): {} --- {}'.format(vsnapshot, pvcdata)) + # if vsnapshot is None: + # self._io.send_info(CHANGE_BACKUP_MODE_FOR_INCOMPATIBLITY_PVC.format(pvcdata.get('name'))) + # cloned_pvc_name = self.create_pvcclone(namespace, pvcdata.get('name')) + # cloned_pvc = self._plugin.get_pvcdata_namespaced(namespace, cloned_pvc_name) + # logging.debug('Cloned pvc fi:{}'.format(cloned_pvc.get('fi'))) + # cloned_pvc.get('fi').set_name(pvcdata.get('fi').name) + # pvcdata = cloned_pvc + # is_cloned = True if self.prepare_bacula_pod(pvcdata, namespace=namespace, mode='backup'): super()._estimate_file(pvcdata) # here to send info about pvcdata to plugin status = self.__backup_pvcdata(namespace=namespace) @@ -145,6 +156,8 @@ class BackupJob(EstimationJob): # Both prepare_bacula_pod fails or not, we must remove snapshot and pvc if not backup_with_pod: self.handle_delete_vsnapshot_backup(namespace, vsnapshot, pvcdata) + if is_cloned: + self.delete_pvcclone(namespace, cloned_pvc_name) return status def handle_pod_container_exec_command(self, corev1api, namespace, pod, runjobparam, failonerror=False): @@ -222,6 +235,7 @@ class BackupJob(EstimationJob): return False if backupmode == BaculaBackupMode.Snapshot: + logging.debug('Snapshot mode chosen') 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: {}. FI: {}".format(vsnapshot, pvc_from_vsnap, pvc_from_vsnap.get('fi'))) 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 3f2b0d7a2..88b4c0793 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 @@ -342,8 +342,10 @@ class JobPodBacula(Job, metaclass=ABCMeta): Manage operations to create snapshot and new pvc from this snapshot to do backup. """ pvc = self._plugin.get_pvcdata_namespaced(namespace, pvcname) + # Check if pvc is compatible with vsnapshot if not self._plugin.check_pvc_compatiblity_with_vsnapshot(namespace, pvc.get('name')): + logging.debug('The pvc is not compatible with vsnapshots. Name:{}'.format(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'))) diff --git a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/pvcdata.py b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/pvcdata.py index 0773ff3ca..315c981ed 100644 --- a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/pvcdata.py +++ b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/pvcdata.py @@ -48,9 +48,9 @@ def pvcdata_list_update_node_names(corev1api, namespace, pvcdatalist): dict: updated pvc data list as dictionary """ # here we collect node_names for proper backup pod deployment - logging.debug('Init PVCDATALIST: {}'.format(pvcdatalist)) + logging.debug('Init PVCDATALIST') pods = pods_namespaced_specs(corev1api, namespace=namespace) - logging.debug('Get pods:{}'.format(pods)) + # logging.debug('Get pods:{}'.format(pods)) for pod in pods: if pod.spec is not None and pod.spec.volumes is not None: for vol in pod.spec.volumes: @@ -61,7 +61,7 @@ def pvcdata_list_update_node_names(corev1api, namespace, pvcdatalist): logging.debug('[CUSTOM] Enter in pvcdatalist') logging.debug('Pvcf: {} -- Node_name: {}'.format(pvcf, pod.spec.node_name)) pvcdatalist[pvcf]['node_name'] = pod.spec.node_name - logging.debug('END PVCDATALIST: {}'.format(pvcdatalist)) + logging.debug('END PVCDATALIST') return pvcdatalist diff --git a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/volumesnapshotclass.py b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/volumesnapshotclass.py index fd3861553..c87a21d84 100644 --- a/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/volumesnapshotclass.py +++ b/bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/volumesnapshotclass.py @@ -22,6 +22,7 @@ import logging import pathlib +from kubernetes import client K8SOBJ_SNAPSHOT_GROUP = 'snapshot.storage.k8s.io' K8SOBJ_SNAPSHOT_VERSION = 'v1' @@ -29,27 +30,43 @@ K8SOBJ_SNAPSHOT_PLURAL = 'volumesnapshotclasses' def volumesnapshotclass_list_all(custom_api, filter_names=None): vol_snap_list = {} + # volume_snapshot_classes = [] volume_snapshot_classes = custom_api.list_cluster_custom_object(K8SOBJ_SNAPSHOT_GROUP, K8SOBJ_SNAPSHOT_VERSION, K8SOBJ_SNAPSHOT_PLURAL, watch=False) logging.debug("Volume snapshot classes:{}".format(volume_snapshot_classes)) - for vol_snap in volume_snapshot_classes.get('items'): - if filter_names is not None and len(filter_names) > 0: - logging.debug("filter_names-glob-for: {}".format(vol_snap.get('metadata').get('name'))) - found = False - for vol_glob in filter_names: - logging.debug("checking vol_glob: {}".format(vol_glob)) - if pathlib.Path(vol_snap.get('metadata').get('name')).match(vol_glob): - found = True - logging.debug('Found volSnap.') - break - if not found: - continue - vol_snap_list[vol_snap.get('metadata').get('name')] = vol_snap + if volume_snapshot_classes: + for vol_snap in volume_snapshot_classes.get('items'): + if filter_names is not None and len(filter_names) > 0: + logging.debug("filter_names-glob-for: {}".format(vol_snap.get('metadata').get('name'))) + found = False + for vol_glob in filter_names: + logging.debug("checking vol_glob: {}".format(vol_glob)) + if pathlib.Path(vol_snap.get('metadata').get('name')).match(vol_glob): + found = True + logging.debug('Found volSnap.') + break + if not found: + continue + vol_snap_list[vol_snap.get('metadata').get('name')] = vol_snap return vol_snap_list +def snapshot_api_is_supported(): + for api in client.ApisApi().get_api_versions().groups: + if api.name == K8SOBJ_SNAPSHOT_GROUP: + for v in api.versions: + if v.version == K8SOBJ_SNAPSHOT_VERSION: + logging.debug('Cluster support snapshots API') + return True + logging.debug('Cluster does not support snapshots API') + return False + def get_snapshot_drivers_compatible(custom_api): compatible_drivers = [] + if not snapshot_api_is_supported(): + return compatible_drivers + volume_snapshot_classes = [] try: + # raise Exception("This is a probe") volume_snapshot_classes = volumesnapshotclass_list_all(custom_api) except Exception as e: logging.error('Controlled exception. This exception is because the volumesnapshotclasses is nos available. We can confirm this fact with `kubectl api-resources`') 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 814764af3..96d07dbf0 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 @@ -534,7 +534,7 @@ class KubernetesPlugin(Plugin): # TODO: export/move all checks into k8sbackend def check_storage_compatibility_with_vsnapshot(self, storage_class_name): - logging.debug("Check Storage compatibility. {}".format(storage_class_name)) + logging.debug("Check Storage class compatibility.{}".format(storage_class_name)) storage_provisioner = get_provisioner(self.storagev1api, storage_class_name) logging.debug("Provisioner {}".format(storage_provisioner)) logging.debug('Compatible Drivers: {} '.format(get_snapshot_drivers_compatible(self.crd_api))) @@ -544,8 +544,8 @@ class KubernetesPlugin(Plugin): def check_pvc_compatiblity_with_vsnapshot(self, namespace, pvc_name): pvc = self.get_pvcdata_namespaced(namespace, pvc_name) - logging.debug('[CUSTOM] Check Compatibilidy with Snapshots. Name: {}'.format(pvc_name)) - logging.debug('[CUSTOM] PVC: {}'.format(pvc)) + logging.debug('Check Compatibility with Snapshots. Name: {}'.format(pvc_name)) + logging.debug('PVC: {}'.format(pvc)) return self.check_storage_compatibility_with_vsnapshot(pvc.get('storage_class_name')) def _check_config_map(self, file_info):