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