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