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