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