]>
Commit | Line | Data |
---|---|---|
85ce3f4f | 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 | # | |
6abf9225 AG |
16 | |
17 | """ | |
18 | Exceptions that can be raised by libzfs_core operations. | |
19 | """ | |
9de8c0cd | 20 | from __future__ import absolute_import, division, print_function |
6abf9225 AG |
21 | |
22 | import errno | |
c962fd6c | 23 | from ._constants import ( |
27641038 RM |
24 | ECHRNG, |
25 | ECKSUM, | |
26 | ETIME, | |
c962fd6c | 27 | ZFS_ERR_CHECKPOINT_EXISTS, |
28 | ZFS_ERR_DISCARDING_CHECKPOINT, | |
29 | ZFS_ERR_NO_CHECKPOINT, | |
30 | ZFS_ERR_DEVRM_IN_PROGRESS, | |
d8d418ff | 31 | ZFS_ERR_VDEV_TOO_BIG, |
7145123b | 32 | ZFS_ERR_WRONG_PARENT, |
5caeef02 | 33 | ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS, |
7145123b | 34 | zfs_errno |
c962fd6c | 35 | ) |
6abf9225 AG |
36 | |
37 | ||
38 | class ZFSError(Exception): | |
39 | errno = None | |
40 | message = None | |
41 | name = None | |
42 | ||
43 | def __str__(self): | |
44 | if self.name is not None: | |
85ce3f4f | 45 | return "[Errno %d] %s: '%s'" % ( |
46 | self.errno, self.message, self.name) | |
6abf9225 AG |
47 | else: |
48 | return "[Errno %d] %s" % (self.errno, self.message) | |
49 | ||
50 | def __repr__(self): | |
85ce3f4f | 51 | return "%s(%r, %r)" % ( |
52 | self.__class__.__name__, self.errno, self.message) | |
6abf9225 AG |
53 | |
54 | ||
55 | class ZFSGenericError(ZFSError): | |
56 | ||
57 | def __init__(self, errno, name, message): | |
58 | self.errno = errno | |
59 | self.message = message | |
60 | self.name = name | |
61 | ||
62 | ||
63 | class ZFSInitializationFailed(ZFSError): | |
64 | message = "Failed to initialize libzfs_core" | |
65 | ||
66 | def __init__(self, errno): | |
67 | self.errno = errno | |
68 | ||
69 | ||
70 | class 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 | |
85ce3f4f | 77 | # this many errors were encountered but not placed on the `errors` list |
6abf9225 AG |
78 | self.suppressed_count = suppressed_count |
79 | ||
80 | def __str__(self): | |
85ce3f4f | 81 | return "%s, %d errors included, %d suppressed" % ( |
82 | ZFSError.__str__(self), len(self.errors), self.suppressed_count) | |
6abf9225 AG |
83 | |
84 | def __repr__(self): | |
cd6b910b | 85 | return "%s(%r, %r, errors=%r, suppressed=%r)" % ( |
85ce3f4f | 86 | self.__class__.__name__, self.errno, self.message, self.errors, |
87 | self.suppressed_count) | |
6abf9225 AG |
88 | |
89 | ||
90 | class DatasetNotFound(ZFSError): | |
91 | ||
92 | """ | |
85ce3f4f | 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. | |
6abf9225 AG |
96 | """ |
97 | errno = errno.ENOENT | |
98 | message = "Dataset not found" | |
99 | ||
100 | def __init__(self, name): | |
101 | self.name = name | |
102 | ||
103 | ||
104 | class DatasetExists(ZFSError): | |
105 | ||
106 | """ | |
85ce3f4f | 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 | |
6abf9225 AG |
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 | ||
118 | class 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 | ||
126 | class FilesystemExists(DatasetExists): | |
127 | message = "Filesystem already exists" | |
128 | ||
129 | def __init__(self, name): | |
130 | self.name = name | |
131 | ||
132 | ||
133 | class FilesystemNotFound(DatasetNotFound): | |
134 | message = "Filesystem not found" | |
135 | ||
136 | def __init__(self, name): | |
137 | self.name = name | |
138 | ||
139 | ||
140 | class ParentNotFound(ZFSError): | |
141 | errno = errno.ENOENT | |
142 | message = "Parent not found" | |
143 | ||
144 | def __init__(self, name): | |
145 | self.name = name | |
146 | ||
147 | ||
148 | class WrongParent(ZFSError): | |
d8d418ff | 149 | errno = ZFS_ERR_WRONG_PARENT |
6abf9225 AG |
150 | message = "Parent dataset is not a filesystem" |
151 | ||
152 | def __init__(self, name): | |
153 | self.name = name | |
154 | ||
155 | ||
156 | class SnapshotExists(DatasetExists): | |
157 | message = "Snapshot already exists" | |
158 | ||
159 | def __init__(self, name): | |
160 | self.name = name | |
161 | ||
162 | ||
163 | class SnapshotNotFound(DatasetNotFound): | |
164 | message = "Snapshot not found" | |
165 | ||
166 | def __init__(self, name): | |
167 | self.name = name | |
168 | ||
85ce3f4f | 169 | |
6abf9225 AG |
170 | class SnapshotNotLatest(ZFSError): |
171 | errno = errno.EEXIST | |
172 | message = "Snapshot is not the latest" | |
173 | ||
174 | def __init__(self, name): | |
175 | self.name = name | |
176 | ||
85ce3f4f | 177 | |
6abf9225 AG |
178 | class SnapshotIsCloned(ZFSError): |
179 | errno = errno.EEXIST | |
180 | message = "Snapshot is cloned" | |
181 | ||
182 | def __init__(self, name): | |
183 | self.name = name | |
184 | ||
185 | ||
186 | class SnapshotIsHeld(ZFSError): | |
187 | errno = errno.EBUSY | |
188 | message = "Snapshot is held" | |
189 | ||
190 | def __init__(self, name): | |
191 | self.name = name | |
192 | ||
193 | ||
194 | class 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 | ||
202 | class 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 | ||
209 | class SnapshotDestructionFailure(MultipleOperationsFailure): | |
210 | message = "Destruction of snapshot(s) failed for one or more reasons" | |
211 | ||
212 | def __init__(self, errors, suppressed_count): | |
85ce3f4f | 213 | super(SnapshotDestructionFailure, self).__init__( |
214 | errors, suppressed_count) | |
6abf9225 AG |
215 | |
216 | ||
217 | class BookmarkExists(ZFSError): | |
218 | errno = errno.EEXIST | |
219 | message = "Bookmark already exists" | |
220 | ||
221 | def __init__(self, name): | |
222 | self.name = name | |
223 | ||
224 | ||
225 | class BookmarkNotFound(ZFSError): | |
226 | errno = errno.ENOENT | |
227 | message = "Bookmark not found" | |
228 | ||
229 | def __init__(self, name): | |
230 | self.name = name | |
231 | ||
232 | ||
233 | class BookmarkMismatch(ZFSError): | |
234 | errno = errno.EINVAL | |
a73f361f CS |
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 | ||
241 | class BookmarkSourceInvalid(ZFSError): | |
242 | errno = errno.EINVAL | |
243 | message = "Bookmark source is not a valid snapshot or existing bookmark" | |
6abf9225 AG |
244 | |
245 | def __init__(self, name): | |
246 | self.name = name | |
247 | ||
248 | ||
249 | class 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 | ||
257 | class 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 | ||
264 | class BookmarkDestructionFailure(MultipleOperationsFailure): | |
265 | message = "Destruction of bookmark(s) failed for one or more reasons" | |
266 | ||
267 | def __init__(self, errors, suppressed_count): | |
85ce3f4f | 268 | super(BookmarkDestructionFailure, self).__init__( |
269 | errors, suppressed_count) | |
6abf9225 AG |
270 | |
271 | ||
272 | class BadHoldCleanupFD(ZFSError): | |
273 | errno = errno.EBADF | |
274 | message = "Bad file descriptor as cleanup file descriptor" | |
275 | ||
276 | ||
277 | class 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 | ||
285 | class 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 | ||
293 | class 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 | ||
300 | class 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 | ||
307 | class 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 | ||
315 | class 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 | ||
323 | class 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 | ||
331 | class BadStream(ZFSError): | |
27641038 | 332 | errno = ECKSUM |
6abf9225 AG |
333 | message = "Bad backup stream" |
334 | ||
335 | ||
336 | class StreamFeatureNotSupported(ZFSError): | |
337 | errno = errno.ENOTSUP | |
338 | message = "Stream contains unsupported feature" | |
339 | ||
340 | ||
341 | class UnknownStreamFeature(ZFSError): | |
342 | errno = errno.ENOTSUP | |
343 | message = "Unknown feature requested for stream" | |
344 | ||
345 | ||
85ce3f4f | 346 | class StreamFeatureInvalid(ZFSError): |
347 | errno = errno.EINVAL | |
348 | message = "Kernel modules must be upgraded to receive this stream" | |
349 | ||
350 | ||
351 | class StreamFeatureIncompatible(ZFSError): | |
352 | errno = errno.EINVAL | |
353 | message = "Incompatible embedded feature with encrypted receive" | |
354 | ||
355 | ||
7145123b PD |
356 | class StreamTruncated(ZFSError): |
357 | errno = zfs_errno.ZFS_ERR_STREAM_TRUNCATED | |
358 | message = "incomplete stream" | |
6b7028ec | 359 | |
7145123b | 360 | |
85ce3f4f | 361 | class 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 | ||
6abf9225 AG |
368 | class StreamIOError(ZFSError): |
369 | message = "I/O error while writing or reading stream" | |
370 | ||
371 | def __init__(self, errno): | |
372 | self.errno = errno | |
373 | ||
374 | ||
375 | class ZIOError(ZFSError): | |
376 | errno = errno.EIO | |
377 | message = "I/O error" | |
378 | ||
379 | def __init__(self, name): | |
380 | self.name = name | |
381 | ||
382 | ||
383 | class NoSpace(ZFSError): | |
384 | errno = errno.ENOSPC | |
385 | message = "No space left" | |
386 | ||
387 | def __init__(self, name): | |
388 | self.name = name | |
389 | ||
390 | ||
391 | class QuotaExceeded(ZFSError): | |
392 | errno = errno.EDQUOT | |
cd6b910b | 393 | message = "Quota exceeded" |
6abf9225 AG |
394 | |
395 | def __init__(self, name): | |
396 | self.name = name | |
397 | ||
398 | ||
399 | class DatasetBusy(ZFSError): | |
400 | errno = errno.EBUSY | |
401 | message = "Dataset is busy" | |
402 | ||
403 | def __init__(self, name): | |
404 | self.name = name | |
405 | ||
406 | ||
407 | class 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 | ||
415 | class NameInvalid(ZFSError): | |
416 | errno = errno.EINVAL | |
417 | message = "Invalid name" | |
418 | ||
419 | def __init__(self, name): | |
420 | self.name = name | |
421 | ||
422 | ||
423 | class SnapshotNameInvalid(NameInvalid): | |
424 | message = "Invalid name for snapshot" | |
425 | ||
426 | def __init__(self, name): | |
427 | self.name = name | |
428 | ||
429 | ||
430 | class FilesystemNameInvalid(NameInvalid): | |
431 | message = "Invalid name for filesystem or volume" | |
432 | ||
433 | def __init__(self, name): | |
434 | self.name = name | |
435 | ||
436 | ||
437 | class BookmarkNameInvalid(NameInvalid): | |
438 | message = "Invalid name for bookmark" | |
439 | ||
440 | def __init__(self, name): | |
441 | self.name = name | |
442 | ||
443 | ||
444 | class ReadOnlyPool(ZFSError): | |
445 | errno = errno.EROFS | |
446 | message = "Pool is read-only" | |
447 | ||
448 | def __init__(self, name): | |
449 | self.name = name | |
450 | ||
451 | ||
452 | class SuspendedPool(ZFSError): | |
453 | errno = errno.EAGAIN | |
454 | message = "Pool is suspended" | |
455 | ||
456 | def __init__(self, name): | |
457 | self.name = name | |
458 | ||
459 | ||
460 | class PoolNotFound(ZFSError): | |
461 | errno = errno.EXDEV | |
462 | message = "No such pool" | |
463 | ||
464 | def __init__(self, name): | |
465 | self.name = name | |
466 | ||
467 | ||
468 | class 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 | ||
476 | class 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 | ||
484 | class 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 | ||
492 | class 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 | ||
500 | class 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 | ||
85ce3f4f | 508 | class 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 | ||
516 | class EncryptionKeyNotLoaded(ZFSError): | |
517 | errno = errno.EACCES | |
518 | message = "Encryption key is not currently loaded" | |
519 | ||
520 | ||
521 | class EncryptionKeyAlreadyLoaded(ZFSError): | |
522 | errno = errno.EEXIST | |
523 | message = "Encryption key is already loaded" | |
524 | ||
525 | ||
526 | class EncryptionKeyInvalid(ZFSError): | |
527 | errno = errno.EACCES | |
528 | message = "Incorrect encryption key provided" | |
529 | ||
530 | ||
531 | class ZCPError(ZFSError): | |
532 | errno = None | |
533 | message = None | |
534 | ||
535 | ||
536 | class 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 | ||
544 | class ZCPRuntimeError(ZCPError): | |
27641038 | 545 | errno = ECHRNG |
85ce3f4f | 546 | message = "Channel programs encountered a runtime error" |
547 | ||
548 | def __init__(self, details): | |
549 | self.details = details | |
550 | ||
551 | ||
552 | class ZCPLimitInvalid(ZCPError): | |
553 | errno = errno.EINVAL | |
554 | message = "Channel program called with invalid limits" | |
555 | ||
556 | ||
557 | class ZCPTimeout(ZCPError): | |
27641038 | 558 | errno = ETIME |
85ce3f4f | 559 | message = "Channel program timed out" |
560 | ||
561 | ||
562 | class ZCPSpaceError(ZCPError): | |
563 | errno = errno.ENOSPC | |
564 | message = "Channel program exhausted the memory limit" | |
565 | ||
566 | ||
567 | class ZCPMemoryError(ZCPError): | |
568 | errno = errno.ENOMEM | |
569 | message = "Channel program return value too large" | |
570 | ||
571 | ||
572 | class ZCPPermissionError(ZCPError): | |
573 | errno = errno.EPERM | |
574 | message = "Channel programs must be run as root" | |
575 | ||
576 | ||
c962fd6c | 577 | class CheckpointExists(ZFSError): |
578 | errno = ZFS_ERR_CHECKPOINT_EXISTS | |
579 | message = "Pool already has a checkpoint" | |
580 | ||
581 | ||
582 | class CheckpointNotFound(ZFSError): | |
583 | errno = ZFS_ERR_NO_CHECKPOINT | |
584 | message = "Pool does not have a checkpoint" | |
585 | ||
586 | ||
587 | class CheckpointDiscarding(ZFSError): | |
588 | errno = ZFS_ERR_DISCARDING_CHECKPOINT | |
589 | message = "Pool checkpoint is being discarded" | |
590 | ||
591 | ||
592 | class DeviceRemovalRunning(ZFSError): | |
593 | errno = ZFS_ERR_DEVRM_IN_PROGRESS | |
594 | message = "A vdev is currently being removed" | |
595 | ||
596 | ||
597 | class DeviceTooBig(ZFSError): | |
598 | errno = ZFS_ERR_VDEV_TOO_BIG | |
599 | message = "One or more top-level vdevs exceed the maximum vdev size" | |
600 | ||
601 | ||
5caeef02 DB |
602 | class RaidzExpansionRunning(ZFSError): |
603 | errno = ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS | |
604 | message = "A raidz device is currently expanding" | |
605 | ||
606 | ||
6abf9225 | 607 | # vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4 |