]> git.proxmox.com Git - mirror_zfs.git/blame - contrib/pyzfs/libzfs_core/_error_translation.py
pyzfs: add missing libzfs_core functions
[mirror_zfs.git] / contrib / pyzfs / libzfs_core / _error_translation.py
CommitLineData
85ce3f4f 1#
2# Copyright 2015 ClusterHQ
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
6abf9225
AG
16
17"""
18Helper routines for converting ``errno`` style error codes from C functions
19to Python exceptions defined by `libzfs_core` API.
20
21The conversion heavily depends on the context of the error: the attempted
22operation and the input parameters. For this reason, there is a conversion
23routine for each `libzfs_core` interface function. The conversion routines
24have the return code as a parameter as well as all the parameters of the
25corresponding interface functions.
26
27The parameters and exceptions are documented in the `libzfs_core` interfaces.
28"""
29
30import errno
31import re
32import string
33from . import exceptions as lzc_exc
c962fd6c 34from ._constants import (
35 MAXNAMELEN,
36 ZFS_ERR_CHECKPOINT_EXISTS,
37 ZFS_ERR_DISCARDING_CHECKPOINT,
38 ZFS_ERR_NO_CHECKPOINT,
39 ZFS_ERR_DEVRM_IN_PROGRESS,
40 ZFS_ERR_VDEV_TOO_BIG
41)
6abf9225
AG
42
43
44def lzc_create_translate_error(ret, name, ds_type, props):
45 if ret == 0:
46 return
47 if ret == errno.EINVAL:
85ce3f4f 48 # XXX: should raise lzc_exc.WrongParent if parent is ZVOL
6abf9225
AG
49 _validate_fs_name(name)
50 raise lzc_exc.PropertyInvalid(name)
6abf9225
AG
51 if ret == errno.EEXIST:
52 raise lzc_exc.FilesystemExists(name)
53 if ret == errno.ENOENT:
54 raise lzc_exc.ParentNotFound(name)
55 raise _generic_exception(ret, name, "Failed to create filesystem")
56
57
58def lzc_clone_translate_error(ret, name, origin, props):
59 if ret == 0:
60 return
61 if ret == errno.EINVAL:
62 _validate_fs_name(name)
63 _validate_snap_name(origin)
85ce3f4f 64 raise lzc_exc.PropertyInvalid(name)
65 if ret == errno.EXDEV:
66 raise lzc_exc.PoolsDiffer(name)
6abf9225
AG
67 if ret == errno.EEXIST:
68 raise lzc_exc.FilesystemExists(name)
69 if ret == errno.ENOENT:
70 if not _is_valid_snap_name(origin):
71 raise lzc_exc.SnapshotNameInvalid(origin)
72 raise lzc_exc.DatasetNotFound(name)
73 raise _generic_exception(ret, name, "Failed to create clone")
74
75
76def lzc_rollback_translate_error(ret, name):
77 if ret == 0:
78 return
85ce3f4f 79 if ret == errno.ESRCH:
80 raise lzc_exc.SnapshotNotFound(name)
6abf9225
AG
81 if ret == errno.EINVAL:
82 _validate_fs_name(name)
85ce3f4f 83 raise lzc_exc.NameInvalid(name)
6abf9225
AG
84 if ret == errno.ENOENT:
85 if not _is_valid_fs_name(name):
86 raise lzc_exc.NameInvalid(name)
87 else:
88 raise lzc_exc.FilesystemNotFound(name)
89 raise _generic_exception(ret, name, "Failed to rollback")
90
85ce3f4f 91
6abf9225 92def lzc_rollback_to_translate_error(ret, name, snap):
6abf9225
AG
93 if ret == errno.EEXIST:
94 raise lzc_exc.SnapshotNotLatest(snap)
85ce3f4f 95 else:
96 lzc_rollback_translate_error(ret, name)
97
6abf9225
AG
98
99def lzc_snapshot_translate_errors(ret, errlist, snaps, props):
100 if ret == 0:
101 return
102
103 def _map(ret, name):
104 if ret == errno.EXDEV:
105 pool_names = map(_pool_name, snaps)
106 same_pool = all(x == pool_names[0] for x in pool_names)
107 if same_pool:
108 return lzc_exc.DuplicateSnapshots(name)
109 else:
110 return lzc_exc.PoolsDiffer(name)
111 elif ret == errno.EINVAL:
112 if any(not _is_valid_snap_name(s) for s in snaps):
113 return lzc_exc.NameInvalid(name)
114 elif any(len(s) > MAXNAMELEN for s in snaps):
115 return lzc_exc.NameTooLong(name)
116 else:
117 return lzc_exc.PropertyInvalid(name)
118
119 if ret == errno.EEXIST:
120 return lzc_exc.SnapshotExists(name)
121 if ret == errno.ENOENT:
122 return lzc_exc.FilesystemNotFound(name)
123 return _generic_exception(ret, name, "Failed to create snapshot")
124
125 _handle_err_list(ret, errlist, snaps, lzc_exc.SnapshotFailure, _map)
126
127
128def lzc_destroy_snaps_translate_errors(ret, errlist, snaps, defer):
129 if ret == 0:
130 return
131
132 def _map(ret, name):
133 if ret == errno.EEXIST:
134 return lzc_exc.SnapshotIsCloned(name)
135 if ret == errno.ENOENT:
136 return lzc_exc.PoolNotFound(name)
137 if ret == errno.EBUSY:
138 return lzc_exc.SnapshotIsHeld(name)
139 return _generic_exception(ret, name, "Failed to destroy snapshot")
140
85ce3f4f 141 _handle_err_list(
142 ret, errlist, snaps, lzc_exc.SnapshotDestructionFailure, _map)
6abf9225
AG
143
144
145def lzc_bookmark_translate_errors(ret, errlist, bookmarks):
146 if ret == 0:
147 return
148
149 def _map(ret, name):
150 if ret == errno.EINVAL:
151 if name:
152 snap = bookmarks[name]
153 pool_names = map(_pool_name, bookmarks.keys())
154 if not _is_valid_bmark_name(name):
155 return lzc_exc.BookmarkNameInvalid(name)
156 elif not _is_valid_snap_name(snap):
157 return lzc_exc.SnapshotNameInvalid(snap)
158 elif _fs_name(name) != _fs_name(snap):
159 return lzc_exc.BookmarkMismatch(name)
160 elif any(x != _pool_name(name) for x in pool_names):
161 return lzc_exc.PoolsDiffer(name)
162 else:
85ce3f4f 163 invalid_names = [
164 b for b in bookmarks.keys() if not _is_valid_bmark_name(b)]
6abf9225
AG
165 if invalid_names:
166 return lzc_exc.BookmarkNameInvalid(invalid_names[0])
167 if ret == errno.EEXIST:
168 return lzc_exc.BookmarkExists(name)
169 if ret == errno.ENOENT:
170 return lzc_exc.SnapshotNotFound(name)
171 if ret == errno.ENOTSUP:
172 return lzc_exc.BookmarkNotSupported(name)
173 return _generic_exception(ret, name, "Failed to create bookmark")
174
85ce3f4f 175 _handle_err_list(
176 ret, errlist, bookmarks.keys(), lzc_exc.BookmarkFailure, _map)
6abf9225
AG
177
178
179def lzc_get_bookmarks_translate_error(ret, fsname, props):
180 if ret == 0:
181 return
182 if ret == errno.ENOENT:
183 raise lzc_exc.FilesystemNotFound(fsname)
184 raise _generic_exception(ret, fsname, "Failed to list bookmarks")
185
186
187def lzc_destroy_bookmarks_translate_errors(ret, errlist, bookmarks):
188 if ret == 0:
189 return
190
191 def _map(ret, name):
192 if ret == errno.EINVAL:
193 return lzc_exc.NameInvalid(name)
194 return _generic_exception(ret, name, "Failed to destroy bookmark")
195
85ce3f4f 196 _handle_err_list(
197 ret, errlist, bookmarks, lzc_exc.BookmarkDestructionFailure, _map)
6abf9225
AG
198
199
200def lzc_snaprange_space_translate_error(ret, firstsnap, lastsnap):
201 if ret == 0:
202 return
203 if ret == errno.EXDEV and firstsnap is not None:
204 if _pool_name(firstsnap) != _pool_name(lastsnap):
205 raise lzc_exc.PoolsDiffer(lastsnap)
206 else:
207 raise lzc_exc.SnapshotMismatch(lastsnap)
208 if ret == errno.EINVAL:
209 if not _is_valid_snap_name(firstsnap):
210 raise lzc_exc.NameInvalid(firstsnap)
211 elif not _is_valid_snap_name(lastsnap):
212 raise lzc_exc.NameInvalid(lastsnap)
213 elif len(firstsnap) > MAXNAMELEN:
214 raise lzc_exc.NameTooLong(firstsnap)
215 elif len(lastsnap) > MAXNAMELEN:
216 raise lzc_exc.NameTooLong(lastsnap)
217 elif _pool_name(firstsnap) != _pool_name(lastsnap):
218 raise lzc_exc.PoolsDiffer(lastsnap)
219 else:
220 raise lzc_exc.SnapshotMismatch(lastsnap)
221 if ret == errno.ENOENT:
222 raise lzc_exc.SnapshotNotFound(lastsnap)
85ce3f4f 223 raise _generic_exception(
224 ret, lastsnap, "Failed to calculate space used by range of snapshots")
6abf9225
AG
225
226
227def lzc_hold_translate_errors(ret, errlist, holds, fd):
228 if ret == 0:
229 return
230
231 def _map(ret, name):
232 if ret == errno.EXDEV:
233 return lzc_exc.PoolsDiffer(name)
234 elif ret == errno.EINVAL:
235 if name:
236 pool_names = map(_pool_name, holds.keys())
237 if not _is_valid_snap_name(name):
238 return lzc_exc.NameInvalid(name)
239 elif len(name) > MAXNAMELEN:
240 return lzc_exc.NameTooLong(name)
241 elif any(x != _pool_name(name) for x in pool_names):
242 return lzc_exc.PoolsDiffer(name)
243 else:
85ce3f4f 244 invalid_names = [
245 b for b in holds.keys() if not _is_valid_snap_name(b)]
6abf9225
AG
246 if invalid_names:
247 return lzc_exc.NameInvalid(invalid_names[0])
248 fs_name = None
249 hold_name = None
250 pool_name = None
251 if name is not None:
252 fs_name = _fs_name(name)
253 pool_name = _pool_name(name)
254 hold_name = holds[name]
255 if ret == errno.ENOENT:
256 return lzc_exc.FilesystemNotFound(fs_name)
257 if ret == errno.EEXIST:
258 return lzc_exc.HoldExists(name)
259 if ret == errno.E2BIG:
260 return lzc_exc.NameTooLong(hold_name)
261 if ret == errno.ENOTSUP:
262 return lzc_exc.FeatureNotSupported(pool_name)
263 return _generic_exception(ret, name, "Failed to hold snapshot")
264
265 if ret == errno.EBADF:
266 raise lzc_exc.BadHoldCleanupFD()
267 _handle_err_list(ret, errlist, holds.keys(), lzc_exc.HoldFailure, _map)
268
269
270def lzc_release_translate_errors(ret, errlist, holds):
271 if ret == 0:
272 return
273 for _, hold_list in holds.iteritems():
274 if not isinstance(hold_list, list):
275 raise lzc_exc.TypeError('holds must be in a list')
276
277 def _map(ret, name):
278 if ret == errno.EXDEV:
279 return lzc_exc.PoolsDiffer(name)
280 elif ret == errno.EINVAL:
281 if name:
282 pool_names = map(_pool_name, holds.keys())
283 if not _is_valid_snap_name(name):
284 return lzc_exc.NameInvalid(name)
285 elif len(name) > MAXNAMELEN:
286 return lzc_exc.NameTooLong(name)
287 elif any(x != _pool_name(name) for x in pool_names):
288 return lzc_exc.PoolsDiffer(name)
289 else:
85ce3f4f 290 invalid_names = [
291 b for b in holds.keys() if not _is_valid_snap_name(b)]
6abf9225
AG
292 if invalid_names:
293 return lzc_exc.NameInvalid(invalid_names[0])
294 elif ret == errno.ENOENT:
295 return lzc_exc.HoldNotFound(name)
296 elif ret == errno.E2BIG:
297 tag_list = holds[name]
298 too_long_tags = [t for t in tag_list if len(t) > MAXNAMELEN]
299 return lzc_exc.NameTooLong(too_long_tags[0])
300 elif ret == errno.ENOTSUP:
301 pool_name = None
302 if name is not None:
303 pool_name = _pool_name(name)
304 return lzc_exc.FeatureNotSupported(pool_name)
305 else:
85ce3f4f 306 return _generic_exception(
307 ret, name, "Failed to release snapshot hold")
6abf9225 308
85ce3f4f 309 _handle_err_list(
310 ret, errlist, holds.keys(), lzc_exc.HoldReleaseFailure, _map)
6abf9225
AG
311
312
313def lzc_get_holds_translate_error(ret, snapname):
314 if ret == 0:
315 return
316 if ret == errno.EINVAL:
317 _validate_snap_name(snapname)
318 if ret == errno.ENOENT:
319 raise lzc_exc.SnapshotNotFound(snapname)
320 if ret == errno.ENOTSUP:
321 raise lzc_exc.FeatureNotSupported(_pool_name(snapname))
322 raise _generic_exception(ret, snapname, "Failed to get holds on snapshot")
323
324
325def lzc_send_translate_error(ret, snapname, fromsnap, fd, flags):
326 if ret == 0:
327 return
328 if ret == errno.EXDEV and fromsnap is not None:
329 if _pool_name(fromsnap) != _pool_name(snapname):
330 raise lzc_exc.PoolsDiffer(snapname)
331 else:
332 raise lzc_exc.SnapshotMismatch(snapname)
333 elif ret == errno.EINVAL:
334 if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and
335 not _is_valid_bmark_name(fromsnap)):
336 raise lzc_exc.NameInvalid(fromsnap)
85ce3f4f 337 elif (not _is_valid_snap_name(snapname) and
338 not _is_valid_fs_name(snapname)):
6abf9225
AG
339 raise lzc_exc.NameInvalid(snapname)
340 elif fromsnap is not None and len(fromsnap) > MAXNAMELEN:
341 raise lzc_exc.NameTooLong(fromsnap)
342 elif len(snapname) > MAXNAMELEN:
343 raise lzc_exc.NameTooLong(snapname)
85ce3f4f 344 elif (fromsnap is not None and
345 _pool_name(fromsnap) != _pool_name(snapname)):
6abf9225
AG
346 raise lzc_exc.PoolsDiffer(snapname)
347 elif ret == errno.ENOENT:
348 if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and
349 not _is_valid_bmark_name(fromsnap)):
350 raise lzc_exc.NameInvalid(fromsnap)
351 raise lzc_exc.SnapshotNotFound(snapname)
352 elif ret == errno.ENAMETOOLONG:
353 if fromsnap is not None and len(fromsnap) > MAXNAMELEN:
354 raise lzc_exc.NameTooLong(fromsnap)
355 else:
356 raise lzc_exc.NameTooLong(snapname)
357 raise lzc_exc.StreamIOError(ret)
358
359
360def lzc_send_space_translate_error(ret, snapname, fromsnap):
361 if ret == 0:
362 return
363 if ret == errno.EXDEV and fromsnap is not None:
364 if _pool_name(fromsnap) != _pool_name(snapname):
365 raise lzc_exc.PoolsDiffer(snapname)
366 else:
367 raise lzc_exc.SnapshotMismatch(snapname)
368 elif ret == errno.EINVAL:
369 if fromsnap is not None and not _is_valid_snap_name(fromsnap):
370 raise lzc_exc.NameInvalid(fromsnap)
371 elif not _is_valid_snap_name(snapname):
372 raise lzc_exc.NameInvalid(snapname)
373 elif fromsnap is not None and len(fromsnap) > MAXNAMELEN:
374 raise lzc_exc.NameTooLong(fromsnap)
375 elif len(snapname) > MAXNAMELEN:
376 raise lzc_exc.NameTooLong(snapname)
85ce3f4f 377 elif (fromsnap is not None and
378 _pool_name(fromsnap) != _pool_name(snapname)):
6abf9225
AG
379 raise lzc_exc.PoolsDiffer(snapname)
380 elif ret == errno.ENOENT and fromsnap is not None:
381 if not _is_valid_snap_name(fromsnap):
382 raise lzc_exc.NameInvalid(fromsnap)
383 if ret == errno.ENOENT:
384 raise lzc_exc.SnapshotNotFound(snapname)
85ce3f4f 385 raise _generic_exception(
386 ret, snapname, "Failed to estimate backup stream size")
6abf9225
AG
387
388
85ce3f4f 389def lzc_receive_translate_errors(
390 ret, snapname, fd, force, raw, resumable, embedded, origin, properrs
391):
6abf9225 392 if ret == 0:
85ce3f4f 393 if properrs is not None and len(properrs) > 0:
394 def _map(ret, name):
395 if ret == errno.EINVAL:
396 return lzc_exc.PropertyInvalid(name)
397 return _generic_exception(ret, name, "Failed to set property")
398 _handle_err_list(
399 errno.EINVAL, properrs, [snapname],
400 lzc_exc.ReceivePropertyFailure, _map)
401 else:
402 return
6abf9225 403 if ret == errno.EINVAL:
85ce3f4f 404 if (not _is_valid_snap_name(snapname) and
405 not _is_valid_fs_name(snapname)):
6abf9225
AG
406 raise lzc_exc.NameInvalid(snapname)
407 elif len(snapname) > MAXNAMELEN:
408 raise lzc_exc.NameTooLong(snapname)
409 elif origin is not None and not _is_valid_snap_name(origin):
410 raise lzc_exc.NameInvalid(origin)
85ce3f4f 411 elif resumable:
412 raise lzc_exc.StreamFeatureInvalid()
413 elif embedded and not raw:
414 raise lzc_exc.StreamFeatureIncompatible()
6abf9225
AG
415 else:
416 raise lzc_exc.BadStream()
417 if ret == errno.ENOENT:
418 if not _is_valid_snap_name(snapname):
419 raise lzc_exc.NameInvalid(snapname)
420 else:
421 raise lzc_exc.DatasetNotFound(snapname)
422 if ret == errno.EEXIST:
423 raise lzc_exc.DatasetExists(snapname)
424 if ret == errno.ENOTSUP:
425 raise lzc_exc.StreamFeatureNotSupported()
426 if ret == errno.ENODEV:
427 raise lzc_exc.StreamMismatch(_fs_name(snapname))
428 if ret == errno.ETXTBSY:
429 raise lzc_exc.DestinationModified(_fs_name(snapname))
430 if ret == errno.EBUSY:
431 raise lzc_exc.DatasetBusy(_fs_name(snapname))
432 if ret == errno.ENOSPC:
433 raise lzc_exc.NoSpace(_fs_name(snapname))
434 if ret == errno.EDQUOT:
435 raise lzc_exc.QuotaExceeded(_fs_name(snapname))
436 if ret == errno.ENAMETOOLONG:
437 raise lzc_exc.NameTooLong(snapname)
438 if ret == errno.EROFS:
439 raise lzc_exc.ReadOnlyPool(_pool_name(snapname))
440 if ret == errno.EAGAIN:
441 raise lzc_exc.SuspendedPool(_pool_name(snapname))
85ce3f4f 442 if ret == errno.EBADE: # ECKSUM
443 raise lzc_exc.BadStream()
6abf9225
AG
444
445 raise lzc_exc.StreamIOError(ret)
446
447
448def lzc_promote_translate_error(ret, name):
449 if ret == 0:
450 return
451 if ret == errno.EINVAL:
452 _validate_fs_name(name)
453 raise lzc_exc.NotClone(name)
454 if ret == errno.ENOTSOCK:
455 raise lzc_exc.NotClone(name)
456 if ret == errno.ENOENT:
457 raise lzc_exc.FilesystemNotFound(name)
458 if ret == errno.EEXIST:
459 raise lzc_exc.SnapshotExists(name)
460 raise _generic_exception(ret, name, "Failed to promote dataset")
461
462
85ce3f4f 463def lzc_change_key_translate_error(ret, name):
464 if ret == 0:
465 return
466 if ret == errno.EINVAL:
467 _validate_fs_name(name)
468 raise lzc_exc.PropertyInvalid(name)
469 if ret == errno.ENOENT:
470 raise lzc_exc.FilesystemNotFound(name)
471 if ret == errno.EACCES:
472 raise lzc_exc.EncryptionKeyNotLoaded()
473 raise _generic_exception(ret, name, "Failed to change encryption key")
474
475
476def lzc_load_key_translate_error(ret, name, noop):
477 if ret == 0:
478 return
479 if ret == errno.EINVAL:
480 _validate_fs_name(name)
481 raise lzc_exc.PropertyInvalid(name)
482 if ret == errno.ENOENT:
483 raise lzc_exc.FilesystemNotFound(name)
484 if ret == errno.EACCES:
485 raise lzc_exc.EncryptionKeyInvalid()
486 if ret == errno.EEXIST:
487 raise lzc_exc.EncryptionKeyAlreadyLoaded()
488 if noop:
489 raise _generic_exception(ret, name, "Failed to load encryption key")
490 else:
491 raise _generic_exception(ret, name, "Failed to verify encryption key")
492
493
494def lzc_unload_key_translate_error(ret, name):
495 if ret == 0:
496 return
497 if ret == errno.EINVAL:
498 _validate_fs_name(name)
499 raise lzc_exc.PropertyInvalid(name)
500 if ret == errno.ENOENT:
501 raise lzc_exc.FilesystemNotFound(name)
502 if ret == errno.EACCES:
503 raise lzc_exc.EncryptionKeyNotLoaded()
504 raise _generic_exception(ret, name, "Failed to unload encryption key")
505
506
507def lzc_sync_translate_error(ret, name):
508 if ret == 0:
509 return
510 if ret == errno.ENOENT:
511 raise lzc_exc.PoolNotFound(name)
512 raise _generic_exception(ret, name, "Failed to sync pool")
513
514
515def lzc_reopen_translate_error(ret, name):
516 if ret == 0:
517 return
518 if ret == errno.ENOENT:
519 raise lzc_exc.PoolNotFound(name)
520 raise _generic_exception(ret, name, "Failed to reopen pool")
521
522
523def lzc_channel_program_translate_error(ret, name, error):
524 if ret == 0:
525 return
526 if ret == errno.ENOENT:
527 raise lzc_exc.PoolNotFound(name)
528 if ret == errno.ETIME:
529 raise lzc_exc.ZCPTimeout()
530 if ret == errno.ENOMEM:
531 raise lzc_exc.ZCPMemoryError()
532 if ret == errno.ENOSPC:
533 raise lzc_exc.ZCPSpaceError()
534 if ret == errno.EPERM:
535 raise lzc_exc.ZCPPermissionError()
536 if ret == errno.ECHRNG:
537 raise lzc_exc.ZCPRuntimeError(error)
538 if ret == errno.EINVAL:
539 if error is None:
540 raise lzc_exc.ZCPLimitInvalid()
541 else:
542 raise lzc_exc.ZCPSyntaxError(error)
543 raise _generic_exception(ret, name, "Failed to execute channel program")
544
545
546def lzc_remap_translate_error(ret, name):
547 if ret == 0:
548 return
549 if ret == errno.ENOENT:
550 raise lzc_exc.DatasetNotFound(name)
551 if ret == errno.EINVAL:
552 _validate_fs_name(name)
553 if ret == errno.ENOTSUP:
554 return lzc_exc.FeatureNotSupported(name)
555 raise _generic_exception(ret, name, "Failed to remap dataset")
556
557
c962fd6c 558def lzc_pool_checkpoint_translate_error(ret, name, discard=False):
559 if ret == 0:
560 return
561 if ret == errno.ENOENT:
562 raise lzc_exc.PoolNotFound(name)
563 if ret == ZFS_ERR_CHECKPOINT_EXISTS:
564 raise lzc_exc.CheckpointExists()
565 if ret == ZFS_ERR_NO_CHECKPOINT:
566 raise lzc_exc.CheckpointNotFound()
567 if ret == ZFS_ERR_DISCARDING_CHECKPOINT:
568 raise lzc_exc.CheckpointDiscarding()
569 if ret == ZFS_ERR_DEVRM_IN_PROGRESS:
570 raise lzc_exc.DeviceRemovalRunning()
571 if ret == ZFS_ERR_VDEV_TOO_BIG:
572 raise lzc_exc.DeviceTooBig()
573 if discard:
574 raise _generic_exception(
575 ret, name, "Failed to discard pool checkpoint")
576 else:
577 raise _generic_exception(ret, name, "Failed to create pool checkpoint")
578
579
580def lzc_pool_checkpoint_discard_translate_error(ret, name):
581 lzc_pool_checkpoint_translate_error(ret, name, discard=True)
582
583
6abf9225
AG
584def lzc_rename_translate_error(ret, source, target):
585 if ret == 0:
586 return
587 if ret == errno.EINVAL:
588 _validate_fs_name(source)
589 _validate_fs_name(target)
590 if _pool_name(source) != _pool_name(target):
591 raise lzc_exc.PoolsDiffer(source)
592 if ret == errno.EEXIST:
593 raise lzc_exc.FilesystemExists(target)
594 if ret == errno.ENOENT:
595 raise lzc_exc.FilesystemNotFound(source)
596 raise _generic_exception(ret, source, "Failed to rename dataset")
597
598
599def lzc_destroy_translate_error(ret, name):
600 if ret == 0:
601 return
602 if ret == errno.EINVAL:
603 _validate_fs_name(name)
604 if ret == errno.ENOENT:
605 raise lzc_exc.FilesystemNotFound(name)
606 raise _generic_exception(ret, name, "Failed to destroy dataset")
607
608
609def lzc_inherit_prop_translate_error(ret, name, prop):
610 if ret == 0:
611 return
612 if ret == errno.EINVAL:
613 _validate_fs_name(name)
614 raise lzc_exc.PropertyInvalid(prop)
615 if ret == errno.ENOENT:
616 raise lzc_exc.DatasetNotFound(name)
617 raise _generic_exception(ret, name, "Failed to inherit a property")
618
619
620def lzc_set_prop_translate_error(ret, name, prop, val):
621 if ret == 0:
622 return
623 if ret == errno.EINVAL:
624 _validate_fs_or_snap_name(name)
625 raise lzc_exc.PropertyInvalid(prop)
626 if ret == errno.ENOENT:
627 raise lzc_exc.DatasetNotFound(name)
628 raise _generic_exception(ret, name, "Failed to set a property")
629
630
631def lzc_get_props_translate_error(ret, name):
632 if ret == 0:
633 return
634 if ret == errno.EINVAL:
635 _validate_fs_or_snap_name(name)
636 if ret == errno.ENOENT:
637 raise lzc_exc.DatasetNotFound(name)
638 raise _generic_exception(ret, name, "Failed to get properties")
639
640
641def lzc_list_children_translate_error(ret, name):
642 if ret == 0:
643 return
644 if ret == errno.EINVAL:
645 _validate_fs_name(name)
646 raise _generic_exception(ret, name, "Error while iterating children")
647
648
649def lzc_list_snaps_translate_error(ret, name):
650 if ret == 0:
651 return
652 if ret == errno.EINVAL:
653 _validate_fs_name(name)
654 raise _generic_exception(ret, name, "Error while iterating snapshots")
655
656
657def lzc_list_translate_error(ret, name, opts):
658 if ret == 0:
659 return
660 if ret == errno.ENOENT:
661 raise lzc_exc.DatasetNotFound(name)
662 if ret == errno.EINVAL:
663 _validate_fs_or_snap_name(name)
664 raise _generic_exception(ret, name, "Error obtaining a list")
665
666
667def _handle_err_list(ret, errlist, names, exception, mapper):
668 '''
669 Convert one or more errors from an operation into the requested exception.
670
671 :param int ret: the overall return code.
85ce3f4f 672 :param errlist: the dictionary that maps entity names to their specific
673 error codes.
6abf9225 674 :type errlist: dict of bytes:int
85ce3f4f 675 :param names: the list of all names of the entities on which the operation
676 was attempted.
677 :param type exception: the type of the exception to raise if an error
678 occurred. The exception should be a subclass of
679 ``MultipleOperationsFailure``.
680 :param function mapper: the function that maps an error code and a name to
681 a Python exception.
6abf9225
AG
682
683 Unless ``ret`` is zero this function will raise the ``exception``.
85ce3f4f 684 If the ``errlist`` is not empty, then the compound exception will contain
685 a list of exceptions corresponding to each individual error code in the
686 ``errlist``.
687 Otherwise, the ``exception`` will contain a list with a single exception
688 corresponding to the ``ret`` value. If the ``names`` list contains only one
689 element, that is, the operation was attempted on a single entity, then the
690 name of that entity is passed to the ``mapper``.
691 If the operation was attempted on multiple entities, but the ``errlist``
692 is empty, then we can not know which entity caused the error and, thus,
693 ``None`` is used as a name to signify that fact.
6abf9225
AG
694
695 .. note::
85ce3f4f 696 Note that the ``errlist`` can contain a special element with a key of
697 "N_MORE_ERRORS".
698 That element means that there were too many errors to place on the
699 ``errlist``.
700 Those errors are suppressed and only their count is provided as a
701 value of the special ``N_MORE_ERRORS`` element.
6abf9225
AG
702 '''
703 if ret == 0:
704 return
705
706 if len(errlist) == 0:
707 suppressed_count = 0
708 if len(names) == 1:
709 name = names[0]
710 else:
711 name = None
712 errors = [mapper(ret, name)]
713 else:
714 errors = []
715 suppressed_count = errlist.pop('N_MORE_ERRORS', 0)
716 for name, err in errlist.iteritems():
717 errors.append(mapper(err, name))
718
719 raise exception(errors, suppressed_count)
720
721
722def _pool_name(name):
723 '''
724 Extract a pool name from the given dataset or bookmark name.
725
726 '/' separates dataset name components.
727 '@' separates a snapshot name from the rest of the dataset name.
728 '#' separates a bookmark name from the rest of the dataset name.
729 '''
730 return re.split('[/@#]', name, 1)[0]
731
732
733def _fs_name(name):
734 '''
735 Extract a dataset name from the given snapshot or bookmark name.
736
737 '@' separates a snapshot name from the rest of the dataset name.
738 '#' separates a bookmark name from the rest of the dataset name.
739 '''
740 return re.split('[@#]', name, 1)[0]
741
742
743def _is_valid_name_component(component):
744 allowed = string.ascii_letters + string.digits + '-_.: '
745 return component and all(x in allowed for x in component)
746
747
748def _is_valid_fs_name(name):
749 return name and all(_is_valid_name_component(c) for c in name.split('/'))
750
751
752def _is_valid_snap_name(name):
753 parts = name.split('@')
754 return (len(parts) == 2 and _is_valid_fs_name(parts[0]) and
755 _is_valid_name_component(parts[1]))
756
757
758def _is_valid_bmark_name(name):
759 parts = name.split('#')
760 return (len(parts) == 2 and _is_valid_fs_name(parts[0]) and
761 _is_valid_name_component(parts[1]))
762
763
764def _validate_fs_name(name):
765 if not _is_valid_fs_name(name):
766 raise lzc_exc.FilesystemNameInvalid(name)
767 elif len(name) > MAXNAMELEN:
768 raise lzc_exc.NameTooLong(name)
769
770
771def _validate_snap_name(name):
772 if not _is_valid_snap_name(name):
773 raise lzc_exc.SnapshotNameInvalid(name)
774 elif len(name) > MAXNAMELEN:
775 raise lzc_exc.NameTooLong(name)
776
777
778def _validate_bmark_name(name):
779 if not _is_valid_bmark_name(name):
780 raise lzc_exc.BookmarkNameInvalid(name)
781 elif len(name) > MAXNAMELEN:
782 raise lzc_exc.NameTooLong(name)
783
784
785def _validate_fs_or_snap_name(name):
786 if not _is_valid_fs_name(name) and not _is_valid_snap_name(name):
787 raise lzc_exc.NameInvalid(name)
788 elif len(name) > MAXNAMELEN:
789 raise lzc_exc.NameTooLong(name)
790
791
792def _generic_exception(err, name, message):
793 if err in _error_to_exception:
794 return _error_to_exception[err](name)
795 else:
796 return lzc_exc.ZFSGenericError(err, message, name)
797
85ce3f4f 798
6abf9225
AG
799_error_to_exception = {e.errno: e for e in [
800 lzc_exc.ZIOError,
801 lzc_exc.NoSpace,
802 lzc_exc.QuotaExceeded,
803 lzc_exc.DatasetBusy,
804 lzc_exc.NameTooLong,
805 lzc_exc.ReadOnlyPool,
806 lzc_exc.SuspendedPool,
807 lzc_exc.PoolsDiffer,
808 lzc_exc.PropertyNotSupported,
809]}
810
811
812# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4