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_ERR_RAIDZ_EXPAND_IN_PROGRESS, 47 zfs_errno 48) 49 50 51def 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") 66 67 68def 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") 84 85 86def 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") 100 101 102def 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) 107 108 109def lzc_snapshot_translate_errors(ret, errlist, snaps, props): 110 if ret == 0: 111 return 112 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) 129 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") 135 136 _handle_err_list(ret, errlist, snaps, lzc_exc.SnapshotFailure, _map) 137 138 139def lzc_destroy_snaps_translate_errors(ret, errlist, snaps, defer): 140 if ret == 0: 141 return 142 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") 151 152 _handle_err_list( 153 ret, errlist, snaps, lzc_exc.SnapshotDestructionFailure, _map) 154 155 156def lzc_bookmark_translate_errors(ret, errlist, bookmarks): 157 158 if ret == 0: 159 return 160 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()) 166 167 # use _validate* functions for MAXNAMELEN check 168 try: 169 _validate_bmark_name(name) 170 except lzc_exc.ZFSError as e: 171 return e 172 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) 185 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") 202 203 _handle_err_list( 204 ret, errlist, bookmarks.keys(), lzc_exc.BookmarkFailure, _map) 205 206 207def 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") 213 214 215def lzc_destroy_bookmarks_translate_errors(ret, errlist, bookmarks): 216 if ret == 0: 217 return 218 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") 223 224 _handle_err_list( 225 ret, errlist, bookmarks, lzc_exc.BookmarkDestructionFailure, _map) 226 227 228def 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") 253 254 255def lzc_hold_translate_errors(ret, errlist, holds, fd): 256 if ret == 0: 257 return 258 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") 292 293 if ret == errno.EBADF: 294 raise lzc_exc.BadHoldCleanupFD() 295 _handle_err_list(ret, errlist, holds.keys(), lzc_exc.HoldFailure, _map) 296 297 298def 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') 305 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") 337 338 _handle_err_list( 339 ret, errlist, holds.keys(), lzc_exc.HoldReleaseFailure, _map) 340 341 342def 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") 352 353 354def 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) 387 388 389def 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") 416 417 418def lzc_receive_translate_errors( 419 ret, snapname, fd, force, raw, resumable, embedded, origin, properrs 420): 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) 483 484 raise lzc_exc.StreamIOError(ret) 485 486 487def 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") 500 501 502def 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") 513 514 515def 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") 531 532 533def 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") 544 545 546def 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") 552 553 554def 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") 560 561 562def 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") 583 584 585def 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") 607 608 609def lzc_pool_checkpoint_discard_translate_error(ret, name): 610 lzc_pool_checkpoint_translate_error(ret, name, discard=True) 611 612 613def 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") 628 629 630def 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") 638 639 640def 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") 649 650 651def 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") 660 661 662def 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") 670 671 672def 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") 678 679 680def 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") 686 687 688def 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") 696 697 698def _handle_err_list(ret, errlist, names, exception, mapper): 699 ''' 700 Convert one or more errors from an operation into the requested exception. 701 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. 713 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. 725 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. 733 ''' 734 if ret == 0: 735 return 736 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)) 751 752 raise exception(errors, suppressed_count) 753 754 755def _pool_name(name): 756 ''' 757 Extract a pool name from the given dataset or bookmark name. 758 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. 762 ''' 763 return re.split(b'[/@#]', name, 1)[0] 764 765 766def _fs_name(name): 767 ''' 768 Extract a dataset name from the given snapshot or bookmark name. 769 770 '@' separates a snapshot name from the rest of the dataset name. 771 '#' separates a bookmark name from the rest of the dataset name. 772 ''' 773 return re.split(b'[@#]', name, 1)[0] 774 775 776def _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) 779 780 781def _is_valid_fs_name(name): 782 return name and all(_is_valid_name_component(c) for c in name.split(b'/')) 783 784 785def _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])) 789 790 791def _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])) 795 796 797def _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) 802 803 804def _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) 809 810 811def _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) 816 817 818def _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) 823 824 825def _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) 830 831 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, 842]} 843 844 845# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4 846