]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | from threading import Event |
2 | import errno | |
3 | import json | |
4 | try: | |
5 | import queue as Queue | |
6 | except ImportError: | |
7 | import Queue | |
8 | ||
9 | from mgr_module import MgrModule | |
10 | import orchestrator | |
11 | ||
81eedcae | 12 | from .fs.volume import VolumeClient |
11fdf7f2 TL |
13 | |
14 | class PurgeJob(object): | |
15 | def __init__(self, volume_fscid, subvolume_path): | |
16 | """ | |
17 | Purge tasks work in terms of FSCIDs, so that if we process | |
18 | a task later when a volume was deleted and recreated with | |
19 | the same name, we can correctly drop the task that was | |
20 | operating on the original volume. | |
21 | """ | |
22 | self.fscid = volume_fscid | |
23 | self.subvolume_path = subvolume_path | |
24 | ||
11fdf7f2 TL |
25 | class Module(orchestrator.OrchestratorClientMixin, MgrModule): |
26 | COMMANDS = [ | |
27 | { | |
28 | 'cmd': 'fs volume ls', | |
29 | 'desc': "List volumes", | |
30 | 'perm': 'r' | |
31 | }, | |
32 | { | |
33 | 'cmd': 'fs volume create ' | |
34 | 'name=name,type=CephString ' | |
35 | 'name=size,type=CephString,req=false ', | |
36 | 'desc': "Create a CephFS volume", | |
37 | 'perm': 'rw' | |
38 | }, | |
39 | { | |
40 | 'cmd': 'fs volume rm ' | |
41 | 'name=vol_name,type=CephString', | |
42 | 'desc': "Delete a CephFS volume", | |
43 | 'perm': 'rw' | |
44 | }, | |
81eedcae TL |
45 | { |
46 | 'cmd': 'fs subvolumegroup create ' | |
47 | 'name=vol_name,type=CephString ' | |
48 | 'name=group_name,type=CephString ' | |
49 | 'name=pool_layout,type=CephString,req=false ' | |
50 | 'name=mode,type=CephString,req=false ', | |
51 | 'desc': "Create a CephFS subvolume group in a volume, and optionally, " | |
52 | "with a specific data pool layout, and a specific numeric mode", | |
53 | 'perm': 'rw' | |
54 | }, | |
55 | { | |
56 | 'cmd': 'fs subvolumegroup rm ' | |
57 | 'name=vol_name,type=CephString ' | |
58 | 'name=group_name,type=CephString ' | |
59 | 'name=force,type=CephBool,req=false ', | |
60 | 'desc': "Delete a CephFS subvolume group in a volume", | |
61 | 'perm': 'rw' | |
62 | }, | |
11fdf7f2 TL |
63 | { |
64 | 'cmd': 'fs subvolume create ' | |
65 | 'name=vol_name,type=CephString ' | |
66 | 'name=sub_name,type=CephString ' | |
81eedcae TL |
67 | 'name=size,type=CephInt,req=false ' |
68 | 'name=group_name,type=CephString,req=false ' | |
69 | 'name=pool_layout,type=CephString,req=false ' | |
70 | 'name=mode,type=CephString,req=false ', | |
71 | 'desc': "Create a CephFS subvolume in a volume, and optionally, " | |
72 | "with a specific size (in bytes), a specific data pool layout, " | |
73 | "a specific mode, and in a specific subvolume group", | |
11fdf7f2 TL |
74 | 'perm': 'rw' |
75 | }, | |
76 | { | |
77 | 'cmd': 'fs subvolume rm ' | |
78 | 'name=vol_name,type=CephString ' | |
81eedcae TL |
79 | 'name=sub_name,type=CephString ' |
80 | 'name=group_name,type=CephString,req=false ' | |
81 | 'name=force,type=CephBool,req=false ', | |
82 | 'desc': "Delete a CephFS subvolume in a volume, and optionally, " | |
83 | "in a specific subvolume group", | |
84 | 'perm': 'rw' | |
85 | }, | |
494da23a TL |
86 | { |
87 | 'cmd': 'fs subvolumegroup getpath ' | |
88 | 'name=vol_name,type=CephString ' | |
89 | 'name=group_name,type=CephString ', | |
90 | 'desc': "Get the mountpath of a CephFS subvolume group in a volume", | |
91 | 'perm': 'r' | |
92 | }, | |
81eedcae TL |
93 | { |
94 | 'cmd': 'fs subvolume getpath ' | |
95 | 'name=vol_name,type=CephString ' | |
96 | 'name=sub_name,type=CephString ' | |
97 | 'name=group_name,type=CephString,req=false ', | |
98 | 'desc': "Get the mountpath of a CephFS subvolume in a volume, " | |
99 | "and optionally, in a specific subvolume group", | |
100 | 'perm': 'rw' | |
101 | }, | |
102 | { | |
103 | 'cmd': 'fs subvolumegroup snapshot create ' | |
104 | 'name=vol_name,type=CephString ' | |
105 | 'name=group_name,type=CephString ' | |
106 | 'name=snap_name,type=CephString ', | |
107 | 'desc': "Create a snapshot of a CephFS subvolume group in a volume", | |
108 | 'perm': 'rw' | |
109 | }, | |
110 | { | |
111 | 'cmd': 'fs subvolumegroup snapshot rm ' | |
112 | 'name=vol_name,type=CephString ' | |
113 | 'name=group_name,type=CephString ' | |
114 | 'name=snap_name,type=CephString ' | |
115 | 'name=force,type=CephBool,req=false ', | |
116 | 'desc': "Delete a snapshot of a CephFS subvolume group in a volume", | |
117 | 'perm': 'rw' | |
118 | }, | |
119 | { | |
120 | 'cmd': 'fs subvolume snapshot create ' | |
121 | 'name=vol_name,type=CephString ' | |
122 | 'name=sub_name,type=CephString ' | |
123 | 'name=snap_name,type=CephString ' | |
124 | 'name=group_name,type=CephString,req=false ', | |
125 | 'desc': "Create a snapshot of a CephFS subvolume in a volume, " | |
126 | "and optionally, in a specific subvolume group", | |
127 | 'perm': 'rw' | |
128 | }, | |
129 | { | |
130 | 'cmd': 'fs subvolume snapshot rm ' | |
131 | 'name=vol_name,type=CephString ' | |
132 | 'name=sub_name,type=CephString ' | |
133 | 'name=snap_name,type=CephString ' | |
134 | 'name=group_name,type=CephString,req=false ' | |
135 | 'name=force,type=CephBool,req=false ', | |
136 | 'desc': "Delete a snapshot of a CephFS subvolume in a volume, " | |
137 | "and optionally, in a specific subvolume group", | |
11fdf7f2 TL |
138 | 'perm': 'rw' |
139 | }, | |
140 | ||
141 | # volume ls [recursive] | |
142 | # subvolume ls <volume> | |
143 | # volume authorize/deauthorize | |
144 | # subvolume authorize/deauthorize | |
145 | ||
146 | # volume describe (free space, etc) | |
147 | # volume auth list (vc.get_authorized_ids) | |
148 | ||
149 | # snapshots? | |
150 | ||
151 | # FIXME: we're doing CephFSVolumeClient.recover on every | |
152 | # path where we instantiate and connect a client. Perhaps | |
153 | # keep clients alive longer, or just pass a "don't recover" | |
154 | # flag in if it's the >1st time we connected a particular | |
155 | # volume in the lifetime of this module instance. | |
156 | ] | |
157 | ||
158 | def __init__(self, *args, **kwargs): | |
159 | super(Module, self).__init__(*args, **kwargs) | |
160 | self._initialized = Event() | |
81eedcae | 161 | self.vc = VolumeClient(self) |
11fdf7f2 TL |
162 | |
163 | self._background_jobs = Queue.Queue() | |
164 | ||
165 | def serve(self): | |
166 | # TODO: discover any subvolumes pending purge, and enqueue | |
167 | # them in background_jobs at startup | |
168 | ||
169 | # TODO: consume background_jobs | |
170 | # skip purge jobs if their fscid no longer exists | |
171 | ||
172 | # TODO: on volume delete, cancel out any background jobs that | |
173 | # affect subvolumes within that volume. | |
174 | ||
175 | # ... any background init needed? Can get rid of this | |
176 | # and _initialized if not | |
177 | self._initialized.set() | |
178 | ||
179 | def handle_command(self, inbuf, cmd): | |
180 | self._initialized.wait() | |
181 | ||
182 | handler_name = "_cmd_" + cmd['prefix'].replace(" ", "_") | |
183 | try: | |
184 | handler = getattr(self, handler_name) | |
185 | except AttributeError: | |
186 | return -errno.EINVAL, "", "Unknown command" | |
187 | ||
188 | return handler(inbuf, cmd) | |
189 | ||
11fdf7f2 | 190 | def _cmd_fs_volume_create(self, inbuf, cmd): |
11fdf7f2 TL |
191 | # TODO: validate name against any rules for pool/fs names |
192 | # (...are there any?) | |
81eedcae | 193 | vol_id = cmd['name'] |
11fdf7f2 TL |
194 | size = cmd.get('size', None) |
195 | ||
81eedcae | 196 | return self.vc.create_volume(vol_id, size) |
11fdf7f2 | 197 | |
81eedcae | 198 | def _cmd_fs_volume_rm(self, inbuf, cmd): |
11fdf7f2 | 199 | vol_name = cmd['vol_name'] |
81eedcae | 200 | return self.vc.delete_volume(vol_name) |
11fdf7f2 | 201 | |
81eedcae TL |
202 | def _cmd_fs_volume_ls(self, inbuf, cmd): |
203 | return self.vc.list_volumes() | |
11fdf7f2 | 204 | |
81eedcae TL |
205 | def _cmd_fs_subvolumegroup_create(self, inbuf, cmd): |
206 | """ | |
207 | :return: a 3-tuple of return code(int), empty string(str), error message (str) | |
208 | """ | |
494da23a TL |
209 | return self.vc.create_subvolume_group( |
210 | None, vol_name=cmd['vol_name'], group_name=cmd['group_name'], | |
211 | pool_layout=cmd.get('pool_layout', None), mode=cmd.get('mode', '755')) | |
11fdf7f2 | 212 | |
81eedcae TL |
213 | def _cmd_fs_subvolumegroup_rm(self, inbuf, cmd): |
214 | """ | |
215 | :return: a 3-tuple of return code(int), empty string(str), error message (str) | |
216 | """ | |
494da23a TL |
217 | return self.vc.remove_subvolume_group(None, vol_name=cmd['vol_name'], |
218 | group_name=cmd['group_name'], | |
219 | force=cmd.get('force', False)) | |
11fdf7f2 | 220 | |
81eedcae TL |
221 | def _cmd_fs_subvolume_create(self, inbuf, cmd): |
222 | """ | |
223 | :return: a 3-tuple of return code(int), empty string(str), error message (str) | |
224 | """ | |
494da23a TL |
225 | return self.vc.create_subvolume(None, vol_name=cmd['vol_name'], |
226 | sub_name=cmd['sub_name'], | |
227 | group_name=cmd.get('group_name', None), | |
228 | size=cmd.get('size', None), | |
229 | pool_layout=cmd.get('pool_layout', None), | |
230 | mode=cmd.get('mode', '755')) | |
11fdf7f2 TL |
231 | |
232 | def _cmd_fs_subvolume_rm(self, inbuf, cmd): | |
81eedcae TL |
233 | """ |
234 | :return: a 3-tuple of return code(int), empty string(str), error message (str) | |
235 | """ | |
494da23a TL |
236 | return self.vc.remove_subvolume(None, vol_name=cmd['vol_name'], |
237 | sub_name=cmd['sub_name'], | |
238 | group_name=cmd.get('group_name', None), | |
239 | force=cmd.get('force', False)) | |
11fdf7f2 | 240 | |
494da23a TL |
241 | def _cmd_fs_subvolumegroup_getpath(self, inbuf, cmd): |
242 | return self.vc.getpath_subvolume_group( | |
243 | None, vol_name=cmd['vol_name'], group_name=cmd['group_name']) | |
11fdf7f2 | 244 | |
81eedcae | 245 | def _cmd_fs_subvolume_getpath(self, inbuf, cmd): |
494da23a TL |
246 | return self.vc.subvolume_getpath(None, vol_name=cmd['vol_name'], |
247 | sub_name=cmd['sub_name'], | |
248 | group_name=cmd.get('group_name', None)) | |
11fdf7f2 | 249 | |
81eedcae | 250 | def _cmd_fs_subvolumegroup_snapshot_create(self, inbuf, cmd): |
494da23a TL |
251 | return self.vc.create_subvolume_group_snapshot(None, vol_name=cmd['vol_name'], |
252 | group_name=cmd['group_name'], | |
253 | snap_name=cmd['snap_name']) | |
11fdf7f2 | 254 | |
81eedcae | 255 | def _cmd_fs_subvolumegroup_snapshot_rm(self, inbuf, cmd): |
494da23a TL |
256 | return self.vc.remove_subvolume_group_snapshot(None, vol_name=cmd['vol_name'], |
257 | group_name=cmd['group_name'], | |
258 | snap_name=cmd['snap_name'], | |
259 | force=cmd.get('force', False)) | |
11fdf7f2 | 260 | |
81eedcae | 261 | def _cmd_fs_subvolume_snapshot_create(self, inbuf, cmd): |
494da23a TL |
262 | return self.vc.create_subvolume_snapshot(None, vol_name=cmd['vol_name'], |
263 | sub_name=cmd['sub_name'], | |
264 | snap_name=cmd['snap_name'], | |
265 | group_name=cmd.get('group_name', None)) | |
11fdf7f2 | 266 | |
81eedcae | 267 | def _cmd_fs_subvolume_snapshot_rm(self, inbuf, cmd): |
494da23a TL |
268 | return self.vc.remove_subvolume_snapshot(None, vol_name=cmd['vol_name'], |
269 | sub_name=cmd['sub_name'], | |
270 | snap_name=cmd['snap_name'], | |
271 | group_name=cmd.get('group_name', None), | |
272 | force=cmd.get('force', False)) |