]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/snap_schedule/module.py
572e26815c00e057c85db9bf2a52b2d84b85cb50
[ceph.git] / ceph / src / pybind / mgr / snap_schedule / module.py
1 """
2 Copyright (C) 2019 SUSE
3
4 LGPL2.1. See file COPYING.
5 """
6 import errno
7 import json
8 import sqlite3
9 from typing import Any, Dict, Optional, Tuple
10 from .fs.schedule_client import SnapSchedClient
11 from mgr_module import MgrModule, CLIReadCommand, CLIWriteCommand, Option
12 from mgr_util import CephfsConnectionException
13 from threading import Event
14
15
16 class Module(MgrModule):
17 MODULE_OPTIONS = [
18 Option(
19 'allow_m_granularity',
20 type='bool',
21 default=False,
22 desc='allow minute scheduled snapshots',
23 runtime=True,
24 ),
25 Option(
26 'dump_on_update',
27 type='bool',
28 default=False,
29 desc='dump database to debug log on update',
30 runtime=True,
31 ),
32
33 ]
34
35 def __init__(self, *args: Any, **kwargs: Any) -> None:
36 super(Module, self).__init__(*args, **kwargs)
37 self._initialized = Event()
38 self.client = SnapSchedClient(self)
39
40 @property
41 def default_fs(self) -> str:
42 fs_map = self.get('fs_map')
43 if fs_map['filesystems']:
44 return fs_map['filesystems'][0]['mdsmap']['fs_name']
45 else:
46 self.log.error('No filesystem instance could be found.')
47 raise CephfsConnectionException(
48 -errno.ENOENT, "no filesystem found")
49
50 def has_fs(self, fs_name: str) -> bool:
51 return fs_name in self.client.get_all_filesystems()
52
53 def serve(self) -> None:
54 self._initialized.set()
55
56 def handle_command(self, inbuf: str, cmd: Dict[str, str]) -> Tuple[int, str, str]:
57 self._initialized.wait()
58 return -errno.EINVAL, "", "Unknown command"
59
60 @CLIReadCommand('fs snap-schedule status')
61 def snap_schedule_get(self,
62 path: str = '/',
63 fs: Optional[str] = None,
64 format: Optional[str] = 'plain') -> Tuple[int, str, str]:
65 '''
66 List current snapshot schedules
67 '''
68 use_fs = fs if fs else self.default_fs
69 if not self.has_fs(use_fs):
70 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
71 try:
72 ret_scheds = self.client.get_snap_schedules(use_fs, path)
73 except CephfsConnectionException as e:
74 return e.to_tuple()
75 if format == 'json':
76 json_report = ','.join([ret_sched.report_json() for ret_sched in ret_scheds])
77 return 0, f'[{json_report}]', ''
78 return 0, '\n===\n'.join([ret_sched.report() for ret_sched in ret_scheds]), ''
79
80 @CLIReadCommand('fs snap-schedule list')
81 def snap_schedule_list(self, path: str,
82 recursive: bool = False,
83 fs: Optional[str] = None,
84 format: Optional[str] = 'plain') -> Tuple[int, str, str]:
85 '''
86 Get current snapshot schedule for <path>
87 '''
88 try:
89 use_fs = fs if fs else self.default_fs
90 if not self.has_fs(use_fs):
91 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
92 scheds = self.client.list_snap_schedules(use_fs, path, recursive)
93 self.log.debug(f'recursive is {recursive}')
94 except CephfsConnectionException as e:
95 return e.to_tuple()
96 if not scheds:
97 if format == 'json':
98 output: Dict[str, str] = {}
99 return 0, json.dumps(output), ''
100 return -errno.ENOENT, '', f'SnapSchedule for {path} not found'
101 if format == 'json':
102 # json_list = ','.join([sched.json_list() for sched in scheds])
103 schedule_list = [sched.schedule for sched in scheds]
104 retention_list = [sched.retention for sched in scheds]
105 out = {'path': path, 'schedule': schedule_list, 'retention': retention_list}
106 return 0, json.dumps(out), ''
107 return 0, '\n'.join([str(sched) for sched in scheds]), ''
108
109 @CLIWriteCommand('fs snap-schedule add')
110 def snap_schedule_add(self,
111 path: str,
112 snap_schedule: str,
113 start: Optional[str] = None,
114 fs: Optional[str] = None) -> Tuple[int, str, str]:
115 '''
116 Set a snapshot schedule for <path>
117 '''
118 try:
119 use_fs = fs if fs else self.default_fs
120 if not self.has_fs(use_fs):
121 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
122 abs_path = path
123 subvol = None
124 self.client.store_snap_schedule(use_fs,
125 abs_path,
126 (abs_path, snap_schedule,
127 use_fs, path, start, subvol))
128 suc_msg = f'Schedule set for path {path}'
129 except sqlite3.IntegrityError:
130 existing_scheds = self.client.get_snap_schedules(use_fs, path)
131 report = [s.report() for s in existing_scheds]
132 error_msg = f'Found existing schedule {report}'
133 self.log.error(error_msg)
134 return -errno.EEXIST, '', error_msg
135 except ValueError as e:
136 return -errno.ENOENT, '', str(e)
137 except CephfsConnectionException as e:
138 return e.to_tuple()
139 return 0, suc_msg, ''
140
141 @CLIWriteCommand('fs snap-schedule remove')
142 def snap_schedule_rm(self,
143 path: str,
144 repeat: Optional[str] = None,
145 start: Optional[str] = None,
146 fs: Optional[str] = None) -> Tuple[int, str, str]:
147 '''
148 Remove a snapshot schedule for <path>
149 '''
150 try:
151 use_fs = fs if fs else self.default_fs
152 if not self.has_fs(use_fs):
153 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
154 abs_path = path
155 self.client.rm_snap_schedule(use_fs, abs_path, repeat, start)
156 except CephfsConnectionException as e:
157 return e.to_tuple()
158 except ValueError as e:
159 return -errno.ENOENT, '', str(e)
160 return 0, 'Schedule removed for path {}'.format(path), ''
161
162 @CLIWriteCommand('fs snap-schedule retention add')
163 def snap_schedule_retention_add(self,
164 path: str,
165 retention_spec_or_period: str,
166 retention_count: Optional[str] = None,
167 fs: Optional[str] = None) -> Tuple[int, str, str]:
168 '''
169 Set a retention specification for <path>
170 '''
171 try:
172 use_fs = fs if fs else self.default_fs
173 if not self.has_fs(use_fs):
174 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
175 abs_path = path
176 self.client.add_retention_spec(use_fs, abs_path,
177 retention_spec_or_period,
178 retention_count)
179 except CephfsConnectionException as e:
180 return e.to_tuple()
181 except ValueError as e:
182 return -errno.ENOENT, '', str(e)
183 return 0, 'Retention added to path {}'.format(path), ''
184
185 @CLIWriteCommand('fs snap-schedule retention remove')
186 def snap_schedule_retention_rm(self,
187 path: str,
188 retention_spec_or_period: str,
189 retention_count: Optional[str] = None,
190 fs: Optional[str] = None) -> Tuple[int, str, str]:
191 '''
192 Remove a retention specification for <path>
193 '''
194 try:
195 use_fs = fs if fs else self.default_fs
196 if not self.has_fs(use_fs):
197 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
198 abs_path = path
199 self.client.rm_retention_spec(use_fs, abs_path,
200 retention_spec_or_period,
201 retention_count)
202 except CephfsConnectionException as e:
203 return e.to_tuple()
204 except ValueError as e:
205 return -errno.ENOENT, '', str(e)
206 return 0, 'Retention removed from path {}'.format(path), ''
207
208 @CLIWriteCommand('fs snap-schedule activate')
209 def snap_schedule_activate(self,
210 path: str,
211 repeat: Optional[str] = None,
212 start: Optional[str] = None,
213 fs: Optional[str] = None) -> Tuple[int, str, str]:
214 '''
215 Activate a snapshot schedule for <path>
216 '''
217 try:
218 use_fs = fs if fs else self.default_fs
219 if not self.has_fs(use_fs):
220 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
221 abs_path = path
222 self.client.activate_snap_schedule(use_fs, abs_path, repeat, start)
223 except CephfsConnectionException as e:
224 return e.to_tuple()
225 except ValueError as e:
226 return -errno.ENOENT, '', str(e)
227 return 0, 'Schedule activated for path {}'.format(path), ''
228
229 @CLIWriteCommand('fs snap-schedule deactivate')
230 def snap_schedule_deactivate(self,
231 path: str,
232 repeat: Optional[str] = None,
233 start: Optional[str] = None,
234 fs: Optional[str] = None) -> Tuple[int, str, str]:
235 '''
236 Deactivate a snapshot schedule for <path>
237 '''
238 try:
239 use_fs = fs if fs else self.default_fs
240 if not self.has_fs(use_fs):
241 return -errno.EINVAL, '', f"no such filesystem: {use_fs}"
242 abs_path = path
243 self.client.deactivate_snap_schedule(use_fs, abs_path, repeat, start)
244 except CephfsConnectionException as e:
245 return e.to_tuple()
246 except ValueError as e:
247 return -errno.ENOENT, '', str(e)
248 return 0, 'Schedule deactivated for path {}'.format(path), ''