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