From: Jan Fajerski Date: Thu, 17 Sep 2020 06:09:03 +0000 (-0400) Subject: pybind/snap_schedule: config option to allow minute granularity snaps X-Git-Tag: v16.1.0~562^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1b38fc26bcfbe29cae040c9a6be2b632972f775c;p=ceph.git pybind/snap_schedule: config option to allow minute granularity snaps 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 --- diff --git a/src/pybind/mgr/snap_schedule/fs/schedule.py b/src/pybind/mgr/snap_schedule/fs/schedule.py index d9246c1a3334..225bbf089750 100644 --- a/src/pybind/mgr/snap_schedule/fs/schedule.py +++ b/src/pybind/mgr/snap_schedule/fs/schedule.py @@ -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': diff --git a/src/pybind/mgr/snap_schedule/fs/schedule_client.py b/src/pybind/mgr/snap_schedule/fs/schedule_client.py index 12298c1f97e3..b7fffab09bd2 100644 --- a/src/pybind/mgr/snap_schedule/fs/schedule_client.py +++ b/src/pybind/mgr/snap_schedule/fs/schedule_client.py @@ -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) diff --git a/src/pybind/mgr/snap_schedule/module.py b/src/pybind/mgr/snap_schedule/module.py index 917aa5b78d29..83112c4cc324 100644 --- a/src/pybind/mgr/snap_schedule/module.py +++ b/src/pybind/mgr/snap_schedule/module.py @@ -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)