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""" 18Exceptions that can be raised by libzfs_core operations. 19""" 20from __future__ import absolute_import, division, print_function 21 22import errno 23from ._constants import ( 24 ECHRNG, 25 ECKSUM, 26 ETIME, 27 ZFS_ERR_CHECKPOINT_EXISTS, 28 ZFS_ERR_DISCARDING_CHECKPOINT, 29 ZFS_ERR_NO_CHECKPOINT, 30 ZFS_ERR_DEVRM_IN_PROGRESS, 31 ZFS_ERR_VDEV_TOO_BIG, 32 ZFS_ERR_WRONG_PARENT, 33 ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS, 34 zfs_errno 35) 36 37 38class ZFSError(Exception): 39 errno = None 40 message = None 41 name = None 42 43 def __str__(self): 44 if self.name is not None: 45 return "[Errno %d] %s: '%s'" % ( 46 self.errno, self.message, self.name) 47 else: 48 return "[Errno %d] %s" % (self.errno, self.message) 49 50 def __repr__(self): 51 return "%s(%r, %r)" % ( 52 self.__class__.__name__, self.errno, self.message) 53 54 55class ZFSGenericError(ZFSError): 56 57 def __init__(self, errno, name, message): 58 self.errno = errno 59 self.message = message 60 self.name = name 61 62 63class ZFSInitializationFailed(ZFSError): 64 message = "Failed to initialize libzfs_core" 65 66 def __init__(self, errno): 67 self.errno = errno 68 69 70class MultipleOperationsFailure(ZFSError): 71 72 def __init__(self, errors, suppressed_count): 73 # Use first of the individual error codes 74 # as an overall error code. This is more consistent. 75 self.errno = errors[0].errno 76 self.errors = errors 77 # this many errors were encountered but not placed on the `errors` list 78 self.suppressed_count = suppressed_count 79 80 def __str__(self): 81 return "%s, %d errors included, %d suppressed" % ( 82 ZFSError.__str__(self), len(self.errors), self.suppressed_count) 83 84 def __repr__(self): 85 return "%s(%r, %r, errors=%r, suppressed=%r)" % ( 86 self.__class__.__name__, self.errno, self.message, self.errors, 87 self.suppressed_count) 88 89 90class DatasetNotFound(ZFSError): 91 92 """ 93 This exception is raised when an operation failure can be caused by a 94 missing snapshot or a missing filesystem and it is impossible to 95 distinguish between the causes. 96 """ 97 errno = errno.ENOENT 98 message = "Dataset not found" 99 100 def __init__(self, name): 101 self.name = name 102 103 104class DatasetExists(ZFSError): 105 106 """ 107 This exception is raised when an operation failure can be caused by an 108 existing snapshot or filesystem and it is impossible to distinguish between 109 the causes. 110 """ 111 errno = errno.EEXIST 112 message = "Dataset already exists" 113 114 def __init__(self, name): 115 self.name = name 116 117 118class NotClone(ZFSError): 119 errno = errno.EINVAL 120 message = "Filesystem is not a clone, can not promote" 121 122 def __init__(self, name): 123 self.name = name 124 125 126class FilesystemExists(DatasetExists): 127 message = "Filesystem already exists" 128 129 def __init__(self, name): 130 self.name = name 131 132 133class FilesystemNotFound(DatasetNotFound): 134 message = "Filesystem not found" 135 136 def __init__(self, name): 137 self.name = name 138 139 140class ParentNotFound(ZFSError): 141 errno = errno.ENOENT 142 message = "Parent not found" 143 144 def __init__(self, name): 145 self.name = name 146 147 148class WrongParent(ZFSError): 149 errno = ZFS_ERR_WRONG_PARENT 150 message = "Parent dataset is not a filesystem" 151 152 def __init__(self, name): 153 self.name = name 154 155 156class SnapshotExists(DatasetExists): 157 message = "Snapshot already exists" 158 159 def __init__(self, name): 160 self.name = name 161 162 163class SnapshotNotFound(DatasetNotFound): 164 message = "Snapshot not found" 165 166 def __init__(self, name): 167 self.name = name 168 169 170class SnapshotNotLatest(ZFSError): 171 errno = errno.EEXIST 172 message = "Snapshot is not the latest" 173 174 def __init__(self, name): 175 self.name = name 176 177 178class SnapshotIsCloned(ZFSError): 179 errno = errno.EEXIST 180 message = "Snapshot is cloned" 181 182 def __init__(self, name): 183 self.name = name 184 185 186class SnapshotIsHeld(ZFSError): 187 errno = errno.EBUSY 188 message = "Snapshot is held" 189 190 def __init__(self, name): 191 self.name = name 192 193 194class DuplicateSnapshots(ZFSError): 195 errno = errno.EXDEV 196 message = "Requested multiple snapshots of the same filesystem" 197 198 def __init__(self, name): 199 self.name = name 200 201 202class SnapshotFailure(MultipleOperationsFailure): 203 message = "Creation of snapshot(s) failed for one or more reasons" 204 205 def __init__(self, errors, suppressed_count): 206 super(SnapshotFailure, self).__init__(errors, suppressed_count) 207 208 209class SnapshotDestructionFailure(MultipleOperationsFailure): 210 message = "Destruction of snapshot(s) failed for one or more reasons" 211 212 def __init__(self, errors, suppressed_count): 213 super(SnapshotDestructionFailure, self).__init__( 214 errors, suppressed_count) 215 216 217class BookmarkExists(ZFSError): 218 errno = errno.EEXIST 219 message = "Bookmark already exists" 220 221 def __init__(self, name): 222 self.name = name 223 224 225class BookmarkNotFound(ZFSError): 226 errno = errno.ENOENT 227 message = "Bookmark not found" 228 229 def __init__(self, name): 230 self.name = name 231 232 233class BookmarkMismatch(ZFSError): 234 errno = errno.EINVAL 235 message = "source is not an ancestor of the new bookmark's dataset" 236 237 def __init__(self, name): 238 self.name = name 239 240 241class BookmarkSourceInvalid(ZFSError): 242 errno = errno.EINVAL 243 message = "Bookmark source is not a valid snapshot or existing bookmark" 244 245 def __init__(self, name): 246 self.name = name 247 248 249class BookmarkNotSupported(ZFSError): 250 errno = errno.ENOTSUP 251 message = "Bookmark feature is not supported" 252 253 def __init__(self, name): 254 self.name = name 255 256 257class BookmarkFailure(MultipleOperationsFailure): 258 message = "Creation of bookmark(s) failed for one or more reasons" 259 260 def __init__(self, errors, suppressed_count): 261 super(BookmarkFailure, self).__init__(errors, suppressed_count) 262 263 264class BookmarkDestructionFailure(MultipleOperationsFailure): 265 message = "Destruction of bookmark(s) failed for one or more reasons" 266 267 def __init__(self, errors, suppressed_count): 268 super(BookmarkDestructionFailure, self).__init__( 269 errors, suppressed_count) 270 271 272class BadHoldCleanupFD(ZFSError): 273 errno = errno.EBADF 274 message = "Bad file descriptor as cleanup file descriptor" 275 276 277class HoldExists(ZFSError): 278 errno = errno.EEXIST 279 message = "Hold with a given tag already exists on snapshot" 280 281 def __init__(self, name): 282 self.name = name 283 284 285class HoldNotFound(ZFSError): 286 errno = errno.ENOENT 287 message = "Hold with a given tag does not exist on snapshot" 288 289 def __init__(self, name): 290 self.name = name 291 292 293class HoldFailure(MultipleOperationsFailure): 294 message = "Placement of hold(s) failed for one or more reasons" 295 296 def __init__(self, errors, suppressed_count): 297 super(HoldFailure, self).__init__(errors, suppressed_count) 298 299 300class HoldReleaseFailure(MultipleOperationsFailure): 301 message = "Release of hold(s) failed for one or more reasons" 302 303 def __init__(self, errors, suppressed_count): 304 super(HoldReleaseFailure, self).__init__(errors, suppressed_count) 305 306 307class SnapshotMismatch(ZFSError): 308 errno = errno.ENODEV 309 message = "Snapshot is not descendant of source snapshot" 310 311 def __init__(self, name): 312 self.name = name 313 314 315class StreamMismatch(ZFSError): 316 errno = errno.ENODEV 317 message = "Stream is not applicable to destination dataset" 318 319 def __init__(self, name): 320 self.name = name 321 322 323class DestinationModified(ZFSError): 324 errno = errno.ETXTBSY 325 message = "Destination dataset has modifications that can not be undone" 326 327 def __init__(self, name): 328 self.name = name 329 330 331class BadStream(ZFSError): 332 errno = ECKSUM 333 message = "Bad backup stream" 334 335 336class StreamFeatureNotSupported(ZFSError): 337 errno = errno.ENOTSUP 338 message = "Stream contains unsupported feature" 339 340 341class UnknownStreamFeature(ZFSError): 342 errno = errno.ENOTSUP 343 message = "Unknown feature requested for stream" 344 345 346class StreamFeatureInvalid(ZFSError): 347 errno = errno.EINVAL 348 message = "Kernel modules must be upgraded to receive this stream" 349 350 351class StreamFeatureIncompatible(ZFSError): 352 errno = errno.EINVAL 353 message = "Incompatible embedded feature with encrypted receive" 354 355 356class StreamTruncated(ZFSError): 357 errno = zfs_errno.ZFS_ERR_STREAM_TRUNCATED 358 message = "incomplete stream" 359 360 361class ReceivePropertyFailure(MultipleOperationsFailure): 362 message = "Receiving of properties failed for one or more reasons" 363 364 def __init__(self, errors, suppressed_count): 365 super(ReceivePropertyFailure, self).__init__(errors, suppressed_count) 366 367 368class StreamIOError(ZFSError): 369 message = "I/O error while writing or reading stream" 370 371 def __init__(self, errno): 372 self.errno = errno 373 374 375class ZIOError(ZFSError): 376 errno = errno.EIO 377 message = "I/O error" 378 379 def __init__(self, name): 380 self.name = name 381 382 383class NoSpace(ZFSError): 384 errno = errno.ENOSPC 385 message = "No space left" 386 387 def __init__(self, name): 388 self.name = name 389 390 391class QuotaExceeded(ZFSError): 392 errno = errno.EDQUOT 393 message = "Quota exceeded" 394 395 def __init__(self, name): 396 self.name = name 397 398 399class DatasetBusy(ZFSError): 400 errno = errno.EBUSY 401 message = "Dataset is busy" 402 403 def __init__(self, name): 404 self.name = name 405 406 407class NameTooLong(ZFSError): 408 errno = errno.ENAMETOOLONG 409 message = "Dataset name is too long" 410 411 def __init__(self, name): 412 self.name = name 413 414 415class NameInvalid(ZFSError): 416 errno = errno.EINVAL 417 message = "Invalid name" 418 419 def __init__(self, name): 420 self.name = name 421 422 423class SnapshotNameInvalid(NameInvalid): 424 message = "Invalid name for snapshot" 425 426 def __init__(self, name): 427 self.name = name 428 429 430class FilesystemNameInvalid(NameInvalid): 431 message = "Invalid name for filesystem or volume" 432 433 def __init__(self, name): 434 self.name = name 435 436 437class BookmarkNameInvalid(NameInvalid): 438 message = "Invalid name for bookmark" 439 440 def __init__(self, name): 441 self.name = name 442 443 444class ReadOnlyPool(ZFSError): 445 errno = errno.EROFS 446 message = "Pool is read-only" 447 448 def __init__(self, name): 449 self.name = name 450 451 452class SuspendedPool(ZFSError): 453 errno = errno.EAGAIN 454 message = "Pool is suspended" 455 456 def __init__(self, name): 457 self.name = name 458 459 460class PoolNotFound(ZFSError): 461 errno = errno.EXDEV 462 message = "No such pool" 463 464 def __init__(self, name): 465 self.name = name 466 467 468class PoolsDiffer(ZFSError): 469 errno = errno.EXDEV 470 message = "Source and target belong to different pools" 471 472 def __init__(self, name): 473 self.name = name 474 475 476class FeatureNotSupported(ZFSError): 477 errno = errno.ENOTSUP 478 message = "Feature is not supported in this version" 479 480 def __init__(self, name): 481 self.name = name 482 483 484class PropertyNotSupported(ZFSError): 485 errno = errno.ENOTSUP 486 message = "Property is not supported in this version" 487 488 def __init__(self, name): 489 self.name = name 490 491 492class PropertyInvalid(ZFSError): 493 errno = errno.EINVAL 494 message = "Invalid property or property value" 495 496 def __init__(self, name): 497 self.name = name 498 499 500class DatasetTypeInvalid(ZFSError): 501 errno = errno.EINVAL 502 message = "Specified dataset type is unknown" 503 504 def __init__(self, name): 505 self.name = name 506 507 508class UnknownCryptCommand(ZFSError): 509 errno = errno.EINVAL 510 message = "Specified crypt command is invalid" 511 512 def __init__(self, name): 513 self.name = name 514 515 516class EncryptionKeyNotLoaded(ZFSError): 517 errno = errno.EACCES 518 message = "Encryption key is not currently loaded" 519 520 521class EncryptionKeyAlreadyLoaded(ZFSError): 522 errno = errno.EEXIST 523 message = "Encryption key is already loaded" 524 525 526class EncryptionKeyInvalid(ZFSError): 527 errno = errno.EACCES 528 message = "Incorrect encryption key provided" 529 530 531class ZCPError(ZFSError): 532 errno = None 533 message = None 534 535 536class ZCPSyntaxError(ZCPError): 537 errno = errno.EINVAL 538 message = "Channel program contains syntax errors" 539 540 def __init__(self, details): 541 self.details = details 542 543 544class ZCPRuntimeError(ZCPError): 545 errno = ECHRNG 546 message = "Channel programs encountered a runtime error" 547 548 def __init__(self, details): 549 self.details = details 550 551 552class ZCPLimitInvalid(ZCPError): 553 errno = errno.EINVAL 554 message = "Channel program called with invalid limits" 555 556 557class ZCPTimeout(ZCPError): 558 errno = ETIME 559 message = "Channel program timed out" 560 561 562class ZCPSpaceError(ZCPError): 563 errno = errno.ENOSPC 564 message = "Channel program exhausted the memory limit" 565 566 567class ZCPMemoryError(ZCPError): 568 errno = errno.ENOMEM 569 message = "Channel program return value too large" 570 571 572class ZCPPermissionError(ZCPError): 573 errno = errno.EPERM 574 message = "Channel programs must be run as root" 575 576 577class CheckpointExists(ZFSError): 578 errno = ZFS_ERR_CHECKPOINT_EXISTS 579 message = "Pool already has a checkpoint" 580 581 582class CheckpointNotFound(ZFSError): 583 errno = ZFS_ERR_NO_CHECKPOINT 584 message = "Pool does not have a checkpoint" 585 586 587class CheckpointDiscarding(ZFSError): 588 errno = ZFS_ERR_DISCARDING_CHECKPOINT 589 message = "Pool checkpoint is being discarded" 590 591 592class DeviceRemovalRunning(ZFSError): 593 errno = ZFS_ERR_DEVRM_IN_PROGRESS 594 message = "A vdev is currently being removed" 595 596 597class DeviceTooBig(ZFSError): 598 errno = ZFS_ERR_VDEV_TOO_BIG 599 message = "One or more top-level vdevs exceed the maximum vdev size" 600 601 602class RaidzExpansionRunning(ZFSError): 603 errno = ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS 604 message = "A raidz device is currently expanding" 605 606 607# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4 608