]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
k8s:Add check snapshot api-resource available
authorfrancisco.garcia <francisco.garcia@baculasystems.com>
Sat, 3 Feb 2024 11:59:25 +0000 (12:59 +0100)
committerEric Bollengier <eric@baculasystems.com>
Thu, 21 Mar 2024 16:14:19 +0000 (17:14 +0100)
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/pvcdata.py
bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/k8sbackend/volumesnapshotclass.py
bacula/src/plugins/fd/kubernetes-backend/baculak8s/plugins/kubernetes_plugin.py

index 38a31d8fb6bda7ffbff132711a0c53f8181903da..47166ec01afc84ed56fddd783e7949d5c1fd3cb1 100644 (file)
@@ -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')))
index 3f2b0d7a238a643c7a8b851ca0a07555745f6edf..88b4c07931d23debcc08ce82535c8d2c390a016a 100644 (file)
@@ -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')))
index 0773ff3ca25f38b68b08d073b3200dff1ce6412b..315c981ed31342b10c3d5a4ee2a105330cbca307 100644 (file)
@@ -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
 
 
index fd3861553a96343f8d9851890dfd3c9ba3a2aac0..c87a21d842f30ea7795ad612890823486fc8d1e2 100644 (file)
@@ -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`')
index 814764af313b1c48037d859d5e953bfef2a7ffe6..96d07dbf029f044f3666f30b63e5ff1705876da5 100644 (file)
@@ -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):