]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind/snap_schedule: config option to allow minute granularity snaps
authorJan Fajerski <jfajerski@suse.com>
Thu, 17 Sep 2020 06:09:03 +0000 (02:09 -0400)
committerVenky Shankar <vshankar@redhat.com>
Tue, 17 Nov 2020 06:15:46 +0000 (01:15 -0500)
Thsi allows setting and scheduling snapshots with minute granularity. If
the option is unset, adding these will fail and scheduling for them will
be skipped.

Signed-off-by: Jan Fajerski <jfajerski@suse.com>
src/pybind/mgr/snap_schedule/fs/schedule.py
src/pybind/mgr/snap_schedule/fs/schedule_client.py
src/pybind/mgr/snap_schedule/module.py

index d9246c1a3334fca20dbae0895e4c5500e77c8724..225bbf089750cca80b7b8b61934e82511894b785 100644 (file)
@@ -146,7 +146,8 @@ class Schedule(object):
                    table_row['last_pruned'],
                    table_row['created_count'],
                    table_row['pruned_count'],
-                   table_row['active'])
+                   table_row['active'],
+                  )
 
     def __str__(self):
         return f'''{self.path} {self.schedule} {dump_retention(self.retention)}'''
@@ -183,7 +184,7 @@ class Schedule(object):
         s.retention,
         sm.repeat - (strftime("%s", "now") - strftime("%s", sm.start)) %
         sm.repeat "until",
-        sm.start, sm.repeat
+        sm.start, sm.repeat, sm.schedule
         FROM schedules s
             INNER JOIN schedules_meta sm ON sm.schedule_id = s.id
         WHERE
@@ -355,10 +356,13 @@ class Schedule(object):
         return json.dumps(dict(self.__dict__),
                           default=lambda o: o.strftime(SNAP_DB_TS_FORMAT))
 
+    @classmethod
+    def parse_schedule(cls, schedule):
+        return int(schedule[0:-1]), schedule[-1]
+
     @property
     def repeat(self):
-        mult = self.schedule[-1]
-        period = int(self.schedule[0:-1])
+        period, mult = self.parse_schedule(self.schedule)
         if mult == 'M':
             return period * 60
         elif mult == 'h':
index 12298c1f97e3d1bc8ddeefd7d210b9510471b854..b7fffab09bd26a344527d4d9dfadb3903ab72a05 100644 (file)
@@ -104,6 +104,10 @@ class SnapSchedClient(CephfsClient):
         self.sqlite_connections = {}
         self.active_timers = {}
 
+    @property
+    def allow_minute_snaps(self):
+        return self.mgr.get_module_option('allow_m_granularity')
+
     def get_schedule_db(self, fs):
         if fs not in self.sqlite_connections:
             self.sqlite_connections[fs] = sqlite3.connect(
@@ -140,6 +144,18 @@ class SnapSchedClient(CephfsClient):
             ioctx.write_full(SNAP_DB_OBJECT_NAME,
                              '\n'.join(db_content).encode('utf-8'))
 
+    def _is_allowed_repeat(self, exec_row, path):
+        if Schedule.parse_schedule(exec_row['schedule'])[1] == 'M':
+            if self.allow_minute_snaps:
+                log.debug(f'Minute repeats allowed, scheduling snapshot on path {path}')
+                return True
+            else:
+                log.info(f'Minute repeats disabled, skipping snapshot on path {path}')
+                return False
+        else:
+            return True
+
+
     def refresh_snap_timers(self, fs, path):
         try:
             log.debug(f'SnapDB on {fs} changed for {path}, updating next Timer')
@@ -147,7 +163,8 @@ class SnapSchedClient(CephfsClient):
             rows = []
             with db:
                 cur = db.execute(Schedule.EXEC_QUERY, (path,))
-                rows = cur.fetchmany(1)
+                all_rows = cur.fetchall()
+                rows = [r for r in all_rows if self._is_allowed_repeat(r, path)][0:1]
             timers = self.active_timers.get((fs, path), [])
             for timer in timers:
                 timer.cancel()
@@ -238,6 +255,10 @@ class SnapSchedClient(CephfsClient):
     # TODO improve interface
     def store_snap_schedule(self, fs, path_, args):
         sched = Schedule(*args)
+        log.debug(f'repeat is {sched.repeat}')
+        if sched.parse_schedule(sched.schedule)[1] == 'M' and not self.allow_minute_snaps:
+            log.error('not allowed')
+            raise ValueError('no minute snaps allowed')
         log.debug(f'attempting to add schedule {sched}')
         db = self.get_schedule_db(fs)
         sched.store_schedule(db)
index 917aa5b78d29b2c4eb601ac454913320ba375dc1..83112c4cc324dd2833e22ba11c91bb3be54be658 100644 (file)
@@ -12,6 +12,15 @@ from threading import Event
 
 
 class Module(MgrModule):
+    MODULE_OPTIONS = [
+        {
+            'name':    'allow_m_granularity',
+            'type':    'bool',
+            'default': False,
+            'desc':    'allow minute scheduled snapshots',
+            'runtime': True,
+        },
+    ]
 
     def __init__(self, *args, **kwargs):
         super(Module, self).__init__(*args, **kwargs)