1 # Copyright 2015 ClusterHQ. See LICENSE file for details.
4 Python wrappers for libzfs_core interfaces.
6 As a rule, there is a Python function for each C function.
7 The signatures of the Python functions generally follow those of the
8 functions, but the argument types are natural to Python.
9 nvlists are wrapped as dictionaries or lists depending on their usage.
10 Some parameters have default values depending on typical use for
11 increased convenience. Output parameters are not used and return values
12 are directly returned. Error conditions are signalled by exceptions
13 rather than by integer error codes.
22 from . import exceptions
23 from . import _error_translation
as errors
24 from .bindings
import libzfs_core
25 from ._constants
import MAXNAMELEN
26 from .ctypes
import int32_t
27 from ._nvlist
import nvlist_in
, nvlist_out
30 def lzc_create(name
, ds_type
='zfs', props
=None):
32 Create a ZFS filesystem or a ZFS volume ("zvol").
34 :param bytes name: a name of the dataset to be created.
35 :param str ds_type: the type of the dataset to be create, currently supported
36 types are "zfs" (the default) for a filesystem
37 and "zvol" for a volume.
38 :param props: a `dict` of ZFS dataset property name-value pairs (empty by default).
39 :type props: dict of bytes:Any
41 :raises FilesystemExists: if a dataset with the given name already exists.
42 :raises ParentNotFound: if a parent dataset of the requested dataset does not exist.
43 :raises PropertyInvalid: if one or more of the specified properties is invalid
44 or has an invalid type or value.
45 :raises NameInvalid: if the name is not a valid dataset name.
46 :raises NameTooLong: if the name is too long.
51 ds_type
= _lib
.DMU_OST_ZFS
52 elif ds_type
== 'zvol':
53 ds_type
= _lib
.DMU_OST_ZVOL
55 raise exceptions
.DatasetTypeInvalid(ds_type
)
56 nvlist
= nvlist_in(props
)
57 ret
= _lib
.lzc_create(name
, ds_type
, nvlist
)
58 errors
.lzc_create_translate_error(ret
, name
, ds_type
, props
)
61 def lzc_clone(name
, origin
, props
=None):
63 Clone a ZFS filesystem or a ZFS volume ("zvol") from a given snapshot.
65 :param bytes name: a name of the dataset to be created.
66 :param bytes origin: a name of the origin snapshot.
67 :param props: a `dict` of ZFS dataset property name-value pairs (empty by default).
68 :type props: dict of bytes:Any
70 :raises FilesystemExists: if a dataset with the given name already exists.
71 :raises DatasetNotFound: if either a parent dataset of the requested dataset
72 or the origin snapshot does not exist.
73 :raises PropertyInvalid: if one or more of the specified properties is invalid
74 or has an invalid type or value.
75 :raises FilesystemNameInvalid: if the name is not a valid dataset name.
76 :raises SnapshotNameInvalid: if the origin is not a valid snapshot name.
77 :raises NameTooLong: if the name or the origin name is too long.
78 :raises PoolsDiffer: if the clone and the origin have different pool names.
81 Because of a deficiency of the underlying C interface
82 :exc:`.DatasetNotFound` can mean that either a parent filesystem of the target
83 or the origin snapshot does not exist.
84 It is currently impossible to distinguish between the cases.
85 :func:`lzc_hold` can be used to check that the snapshot exists and ensure that
86 it is not destroyed before cloning.
90 nvlist
= nvlist_in(props
)
91 ret
= _lib
.lzc_clone(name
, origin
, nvlist
)
92 errors
.lzc_clone_translate_error(ret
, name
, origin
, props
)
95 def lzc_rollback(name
):
97 Roll back a filesystem or volume to its most recent snapshot.
99 Note that the latest snapshot may change if a new one is concurrently
100 created or the current one is destroyed. lzc_rollback_to can be used
101 to roll back to a specific latest snapshot.
103 :param bytes name: a name of the dataset to be rolled back.
104 :return: a name of the most recent snapshot.
107 :raises FilesystemNotFound: if the dataset does not exist.
108 :raises SnapshotNotFound: if the dataset does not have any snapshots.
109 :raises NameInvalid: if the dataset name is invalid.
110 :raises NameTooLong: if the dataset name is too long.
112 # Account for terminating NUL in C strings.
113 snapnamep
= _ffi
.new('char[]', MAXNAMELEN
+ 1)
114 ret
= _lib
.lzc_rollback(name
, snapnamep
, MAXNAMELEN
+ 1)
115 errors
.lzc_rollback_translate_error(ret
, name
)
116 return _ffi
.string(snapnamep
)
118 def lzc_rollback_to(name
, snap
):
120 Roll back this filesystem or volume to the specified snapshot, if possible.
122 :param bytes name: a name of the dataset to be rolled back.
123 :param bytes snap: a name of the snapshot to be rolled back.
125 :raises FilesystemNotFound: if the dataset does not exist.
126 :raises SnapshotNotFound: if the dataset does not have any snapshots.
127 :raises NameInvalid: if the dataset name is invalid.
128 :raises NameTooLong: if the dataset name is too long.
129 :raises SnapshotNotLatest: if the snapshot is not the latest.
131 ret
= _lib
.lzc_rollback_to(name
, snap
)
132 errors
.lzc_rollback_to_translate_error(ret
, name
, snap
)
134 def lzc_snapshot(snaps
, props
=None):
138 All snapshots must be in the same pool.
140 Optionally snapshot properties can be set on all snapshots.
141 Currently only user properties (prefixed with "user:") are supported.
143 Either all snapshots are successfully created or none are created if
144 an exception is raised.
146 :param snaps: a list of names of snapshots to be created.
147 :type snaps: list of bytes
148 :param props: a `dict` of ZFS dataset property name-value pairs (empty by default).
149 :type props: dict of bytes:bytes
151 :raises SnapshotFailure: if one or more snapshots could not be created.
154 :exc:`.SnapshotFailure` is a compound exception that provides at least
155 one detailed error object in :attr:`SnapshotFailure.errors` `list`.
158 The underlying implementation reports an individual, per-snapshot error
159 only for :exc:`.SnapshotExists` condition and *sometimes* for
161 In all other cases a single error is reported without connection to any
162 specific snapshot name(s).
164 This has the following implications:
166 * if multiple error conditions are encountered only one of them is reported
168 * unless only one snapshot is requested then it is impossible to tell
169 how many snapshots are problematic and what they are
171 * only if there are no other error conditions :exc:`.SnapshotExists`
172 is reported for all affected snapshots
174 * :exc:`.NameTooLong` can behave either in the same way as
175 :exc:`.SnapshotExists` or as all other exceptions.
176 The former is the case where the full snapshot name exceeds the maximum
177 allowed length but the short snapshot name (after '@') is within
179 The latter is the case when the short name alone exceeds the maximum
182 snaps_dict
= {name
: None for name
in snaps
}
184 snaps_nvlist
= nvlist_in(snaps_dict
)
187 props_nvlist
= nvlist_in(props
)
188 with
nvlist_out(errlist
) as errlist_nvlist
:
189 ret
= _lib
.lzc_snapshot(snaps_nvlist
, props_nvlist
, errlist_nvlist
)
190 errors
.lzc_snapshot_translate_errors(ret
, errlist
, snaps
, props
)
193 lzc_snap
= lzc_snapshot
196 def lzc_destroy_snaps(snaps
, defer
):
200 They must all be in the same pool.
201 Snapshots that do not exist will be silently ignored.
203 If 'defer' is not set, and a snapshot has user holds or clones, the
204 destroy operation will fail and none of the snapshots will be
207 If 'defer' is set, and a snapshot has user holds or clones, it will be
208 marked for deferred destruction, and will be destroyed when the last hold
209 or clone is removed/destroyed.
211 The operation succeeds if all snapshots were destroyed (or marked for
212 later destruction if 'defer' is set) or didn't exist to begin with.
214 :param snaps: a list of names of snapshots to be destroyed.
215 :type snaps: list of bytes
216 :param bool defer: whether to mark busy snapshots for deferred destruction
217 rather than immediately failing.
219 :raises SnapshotDestructionFailure: if one or more snapshots could not be created.
222 :exc:`.SnapshotDestructionFailure` is a compound exception that provides at least
223 one detailed error object in :attr:`SnapshotDestructionFailure.errors` `list`.
225 Typical error is :exc:`SnapshotIsCloned` if `defer` is `False`.
226 The snapshot names are validated quite loosely and invalid names are typically
227 ignored as nonexisiting snapshots.
229 A snapshot name referring to a filesystem that doesn't exist is ignored.
230 However, non-existent pool name causes :exc:`PoolNotFound`.
232 snaps_dict
= {name
: None for name
in snaps
}
234 snaps_nvlist
= nvlist_in(snaps_dict
)
235 with
nvlist_out(errlist
) as errlist_nvlist
:
236 ret
= _lib
.lzc_destroy_snaps(snaps_nvlist
, defer
, errlist_nvlist
)
237 errors
.lzc_destroy_snaps_translate_errors(ret
, errlist
, snaps
, defer
)
240 def lzc_bookmark(bookmarks
):
244 :param bookmarks: a dict that maps names of wanted bookmarks to names of existing snapshots.
245 :type bookmarks: dict of bytes to bytes
247 :raises BookmarkFailure: if any of the bookmarks can not be created for any reason.
249 The bookmarks `dict` maps from name of the bookmark (e.g. :file:`{pool}/{fs}#{bmark}`) to
250 the name of the snapshot (e.g. :file:`{pool}/{fs}@{snap}`). All the bookmarks and
251 snapshots must be in the same pool.
254 nvlist
= nvlist_in(bookmarks
)
255 with
nvlist_out(errlist
) as errlist_nvlist
:
256 ret
= _lib
.lzc_bookmark(nvlist
, errlist_nvlist
)
257 errors
.lzc_bookmark_translate_errors(ret
, errlist
, bookmarks
)
260 def lzc_get_bookmarks(fsname
, props
=None):
262 Retrieve a listing of bookmarks for the given file system.
264 :param bytes fsname: a name of the filesystem.
265 :param props: a `list` of properties that will be returned for each bookmark.
266 :type props: list of bytes
267 :return: a `dict` that maps the bookmarks' short names to their properties.
268 :rtype: dict of bytes:dict
270 :raises FilesystemNotFound: if the filesystem is not found.
272 The following are valid properties on bookmarks:
275 globally unique identifier of the snapshot the bookmark refers to
277 txg when the snapshot the bookmark refers to was created
279 timestamp when the snapshot the bookmark refers to was created
281 Any other properties passed in ``props`` are ignored without reporting
283 Values in the returned dictionary map the names of the requested properties
284 to their respective values.
289 props_dict
= {name
: None for name
in props
}
290 nvlist
= nvlist_in(props_dict
)
291 with
nvlist_out(bmarks
) as bmarks_nvlist
:
292 ret
= _lib
.lzc_get_bookmarks(fsname
, nvlist
, bmarks_nvlist
)
293 errors
.lzc_get_bookmarks_translate_error(ret
, fsname
, props
)
297 def lzc_destroy_bookmarks(bookmarks
):
301 :param bookmarks: a list of the bookmarks to be destroyed.
302 The bookmarks are specified as :file:`{fs}#{bmark}`.
303 :type bookmarks: list of bytes
305 :raises BookmarkDestructionFailure: if any of the bookmarks may not be destroyed.
307 The bookmarks must all be in the same pool.
308 Bookmarks that do not exist will be silently ignored.
309 This also includes the case where the filesystem component of the bookmark
311 However, an invalid bookmark name will cause :exc:`.NameInvalid` error
312 reported in :attr:`SnapshotDestructionFailure.errors`.
314 Either all bookmarks that existed are destroyed or an exception is raised.
317 bmarks_dict
= {name
: None for name
in bookmarks
}
318 nvlist
= nvlist_in(bmarks_dict
)
319 with
nvlist_out(errlist
) as errlist_nvlist
:
320 ret
= _lib
.lzc_destroy_bookmarks(nvlist
, errlist_nvlist
)
321 errors
.lzc_destroy_bookmarks_translate_errors(ret
, errlist
, bookmarks
)
324 def lzc_snaprange_space(firstsnap
, lastsnap
):
326 Calculate a size of data referenced by snapshots in the inclusive range between
327 the ``firstsnap`` and the ``lastsnap`` and not shared with any other datasets.
329 :param bytes firstsnap: the name of the first snapshot in the range.
330 :param bytes lastsnap: the name of the last snapshot in the range.
331 :return: the calculated stream size, in bytes.
332 :rtype: `int` or `long`
334 :raises SnapshotNotFound: if either of the snapshots does not exist.
335 :raises NameInvalid: if the name of either snapshot is invalid.
336 :raises NameTooLong: if the name of either snapshot is too long.
337 :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of ``snapname``.
338 :raises PoolsDiffer: if the snapshots belong to different pools.
340 ``lzc_snaprange_space`` calculates total size of blocks that exist
341 because they are referenced only by one or more snapshots in the given range
342 but no other dataset.
343 In other words, this is the set of blocks that were born after the snap before
344 firstsnap, and died before the snap after the last snap.
345 Yet another interpretation is that the result of ``lzc_snaprange_space`` is the size
346 of the space that would be freed if the snapshots in the range are destroyed.
348 If the same snapshot is given as both the ``firstsnap`` and the ``lastsnap``.
349 In that case ``lzc_snaprange_space`` calculates space used by the snapshot.
351 valp
= _ffi
.new('uint64_t *')
352 ret
= _lib
.lzc_snaprange_space(firstsnap
, lastsnap
, valp
)
353 errors
.lzc_snaprange_space_translate_error(ret
, firstsnap
, lastsnap
)
357 def lzc_hold(holds
, fd
=None):
359 Create *user holds* on snapshots. If there is a hold on a snapshot,
360 the snapshot can not be destroyed. (However, it can be marked for deletion
361 by :func:`lzc_destroy_snaps` ( ``defer`` = `True` ).)
363 :param holds: the dictionary of names of the snapshots to hold mapped to the hold names.
364 :type holds: dict of bytes : bytes
365 :type fd: int or None
366 :param fd: if not None then it must be the result of :func:`os.open` called as ``os.open("/dev/zfs", O_EXCL)``.
367 :type fd: int or None
368 :return: a list of the snapshots that do not exist.
369 :rtype: list of bytes
371 :raises HoldFailure: if a hold was impossible on one or more of the snapshots.
372 :raises BadHoldCleanupFD: if ``fd`` is not a valid file descriptor associated with :file:`/dev/zfs`.
374 The snapshots must all be in the same pool.
376 If ``fd`` is not None, then when the ``fd`` is closed (including on process
377 termination), the holds will be released. If the system is shut down
378 uncleanly, the holds will be released when the pool is next opened
381 Holds for snapshots which don't exist will be skipped and have an entry
382 added to the return value, but will not cause an overall failure.
383 No exceptions is raised if all holds, for snapshots that existed, were succesfully created.
384 Otherwise :exc:`.HoldFailure` exception is raised and no holds will be created.
385 :attr:`.HoldFailure.errors` may contain a single element for an error that is not
386 specific to any hold / snapshot, or it may contain one or more elements
387 detailing specific error per each affected hold.
392 nvlist
= nvlist_in(holds
)
393 with
nvlist_out(errlist
) as errlist_nvlist
:
394 ret
= _lib
.lzc_hold(nvlist
, fd
, errlist_nvlist
)
395 errors
.lzc_hold_translate_errors(ret
, errlist
, holds
, fd
)
396 # If there is no error (no exception raised by _handleErrList), but errlist
397 # is not empty, then it contains missing snapshots.
398 assert all(x
== errno
.ENOENT
for x
in errlist
.itervalues())
399 return errlist
.keys()
402 def lzc_release(holds
):
404 Release *user holds* on snapshots.
406 If the snapshot has been marked for
407 deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
408 any clones, and all the user holds are removed, then the snapshot will be
411 The snapshots must all be in the same pool.
413 :param holds: a ``dict`` where keys are snapshot names and values are
414 lists of hold tags to remove.
415 :type holds: dict of bytes : list of bytes
416 :return: a list of any snapshots that do not exist and of any tags that do not
417 exist for existing snapshots.
418 Such tags are qualified with a corresponding snapshot name
419 using the following format :file:`{pool}/{fs}@{snap}#{tag}`
420 :rtype: list of bytes
422 :raises HoldReleaseFailure: if one or more existing holds could not be released.
424 Holds which failed to release because they didn't exist will have an entry
425 added to errlist, but will not cause an overall failure.
427 This call is success if ``holds`` was empty or all holds that
428 existed, were successfully removed.
429 Otherwise an exception will be raised.
433 for snap
, hold_list
in holds
.iteritems():
434 if not isinstance(hold_list
, list):
435 raise TypeError('holds must be in a list')
436 holds_dict
[snap
] = {hold
: None for hold
in hold_list
}
437 nvlist
= nvlist_in(holds_dict
)
438 with
nvlist_out(errlist
) as errlist_nvlist
:
439 ret
= _lib
.lzc_release(nvlist
, errlist_nvlist
)
440 errors
.lzc_release_translate_errors(ret
, errlist
, holds
)
441 # If there is no error (no exception raised by _handleErrList), but errlist
442 # is not empty, then it contains missing snapshots and tags.
443 assert all(x
== errno
.ENOENT
for x
in errlist
.itervalues())
444 return errlist
.keys()
447 def lzc_get_holds(snapname
):
449 Retrieve list of *user holds* on the specified snapshot.
451 :param bytes snapname: the name of the snapshot.
452 :return: holds on the snapshot along with their creation times
453 in seconds since the epoch
454 :rtype: dict of bytes : int
457 with
nvlist_out(holds
) as nvlist
:
458 ret
= _lib
.lzc_get_holds(snapname
, nvlist
)
459 errors
.lzc_get_holds_translate_error(ret
, snapname
)
463 def lzc_send(snapname
, fromsnap
, fd
, flags
=None):
465 Generate a zfs send stream for the specified snapshot and write it to
466 the specified file descriptor.
468 :param bytes snapname: the name of the snapshot to send.
469 :param fromsnap: if not None the name of the starting snapshot
470 for the incremental stream.
471 :type fromsnap: bytes or None
472 :param int fd: the file descriptor to write the send stream to.
473 :param flags: the flags that control what enhanced features can be used
475 :type flags: list of bytes
477 :raises SnapshotNotFound: if either the starting snapshot is not `None` and does not exist,
478 or if the ending snapshot does not exist.
479 :raises NameInvalid: if the name of either snapshot is invalid.
480 :raises NameTooLong: if the name of either snapshot is too long.
481 :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of ``snapname``.
482 :raises PoolsDiffer: if the snapshots belong to different pools.
483 :raises IOError: if an input / output error occurs while writing to ``fd``.
484 :raises UnknownStreamFeature: if the ``flags`` contain an unknown flag name.
486 If ``fromsnap`` is None, a full (non-incremental) stream will be sent.
487 If ``fromsnap`` is not None, it must be the full name of a snapshot or
488 bookmark to send an incremental from, e.g. :file:`{pool}/{fs}@{earlier_snap}`
489 or :file:`{pool}/{fs}#{earlier_bmark}`.
491 The specified snapshot or bookmark must represent an earlier point in the history
493 It can be an earlier snapshot in the same filesystem or zvol as ``snapname``,
494 or it can be the origin of ``snapname``'s filesystem, or an earlier
495 snapshot in the origin, etc.
496 ``fromsnap`` must be strictly an earlier snapshot, specifying the same snapshot
497 as both ``fromsnap`` and ``snapname`` is an error.
499 If ``flags`` contains *"large_blocks"*, the stream is permitted
500 to contain ``DRR_WRITE`` records with ``drr_length`` > 128K, and ``DRR_OBJECT``
501 records with ``drr_blksz`` > 128K.
503 If ``flags`` contains *"embedded_data"*, the stream is permitted
504 to contain ``DRR_WRITE_EMBEDDED`` records with
505 ``drr_etype`` == ``BP_EMBEDDED_TYPE_DATA``,
506 which the receiving system must support (as indicated by support
507 for the *embedded_data* feature).
510 ``lzc_send`` can actually accept a filesystem name as the ``snapname``.
511 In that case ``lzc_send`` acts as if a temporary snapshot was created
512 after the start of the call and before the stream starts being produced.
515 ``lzc_send`` does not return until all of the stream is written to ``fd``.
518 ``lzc_send`` does *not* close ``fd`` upon returning.
520 if fromsnap
is not None:
521 c_fromsnap
= fromsnap
523 c_fromsnap
= _ffi
.NULL
529 'embedded_data': _lib
.LZC_SEND_FLAG_EMBED_DATA
,
530 'large_blocks': _lib
.LZC_SEND_FLAG_LARGE_BLOCK
,
533 raise exceptions
.UnknownStreamFeature(flag
)
536 ret
= _lib
.lzc_send(snapname
, c_fromsnap
, fd
, c_flags
)
537 errors
.lzc_send_translate_error(ret
, snapname
, fromsnap
, fd
, flags
)
540 def lzc_send_space(snapname
, fromsnap
=None, flags
=None):
542 Estimate size of a full or incremental backup stream
543 given the optional starting snapshot and the ending snapshot.
545 :param bytes snapname: the name of the snapshot for which the estimate should be done.
546 :param fromsnap: the optional starting snapshot name.
547 If not `None` then an incremental stream size is estimated,
548 otherwise a full stream is esimated.
549 :type fromsnap: `bytes` or `None`
550 :param flags: the flags that control what enhanced features can be used
552 :type flags: list of bytes
554 :return: the estimated stream size, in bytes.
555 :rtype: `int` or `long`
557 :raises SnapshotNotFound: if either the starting snapshot is not `None` and does not exist,
558 or if the ending snapshot does not exist.
559 :raises NameInvalid: if the name of either snapshot is invalid.
560 :raises NameTooLong: if the name of either snapshot is too long.
561 :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of ``snapname``.
562 :raises PoolsDiffer: if the snapshots belong to different pools.
564 ``fromsnap``, if not ``None``, must be strictly an earlier snapshot,
565 specifying the same snapshot as both ``fromsnap`` and ``snapname`` is an error.
567 if fromsnap
is not None:
568 c_fromsnap
= fromsnap
570 c_fromsnap
= _ffi
.NULL
576 'embedded_data': _lib
.LZC_SEND_FLAG_EMBED_DATA
,
577 'large_blocks': _lib
.LZC_SEND_FLAG_LARGE_BLOCK
,
580 raise exceptions
.UnknownStreamFeature(flag
)
582 valp
= _ffi
.new('uint64_t *')
584 ret
= _lib
.lzc_send_space(snapname
, c_fromsnap
, c_flags
, valp
)
585 errors
.lzc_send_space_translate_error(ret
, snapname
, fromsnap
)
589 def lzc_receive(snapname
, fd
, force
=False, raw
=False, origin
=None, props
=None):
591 Receive from the specified ``fd``, creating the specified snapshot.
593 :param bytes snapname: the name of the snapshot to create.
594 :param int fd: the file descriptor from which to read the stream.
595 :param bool force: whether to roll back or destroy the target filesystem
596 if that is required to receive the stream.
597 :param bool raw: whether this is a "raw" stream.
598 :param origin: the optional origin snapshot name if the stream is for a clone.
599 :type origin: bytes or None
600 :param props: the properties to set on the snapshot as *received* properties.
601 :type props: dict of bytes : Any
603 :raises IOError: if an input / output error occurs while reading from the ``fd``.
604 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
605 :raises DatasetExists: if the stream is a full stream and the destination filesystem already exists.
606 :raises DatasetExists: if ``force`` is `True` but the destination filesystem could not
607 be rolled back to a matching snapshot because a newer snapshot
608 exists and it is an origin of a cloned filesystem.
609 :raises StreamMismatch: if an incremental stream is received and the latest
610 snapshot of the destination filesystem does not match
611 the source snapshot of the stream.
612 :raises StreamMismatch: if a full stream is received and the destination
613 filesystem already exists and it has at least one snapshot,
614 and ``force`` is `False`.
615 :raises StreamMismatch: if an incremental clone stream is received but the specified
616 ``origin`` is not the actual received origin.
617 :raises DestinationModified: if an incremental stream is received and the destination
618 filesystem has been modified since the last snapshot
619 and ``force`` is `False`.
620 :raises DestinationModified: if a full stream is received and the destination
621 filesystem already exists and it does not have any
622 snapshots, and ``force`` is `False`.
623 :raises DatasetNotFound: if the destination filesystem and its parent do not exist.
624 :raises DatasetNotFound: if the ``origin`` is not `None` and does not exist.
625 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem could not
626 be rolled back to a matching snapshot because a newer snapshot
627 is held and could not be destroyed.
628 :raises DatasetBusy: if another receive operation is being performed on the
629 destination filesystem.
630 :raises BadStream: if the stream is corrupt or it is not recognized or it is
631 a compound stream or it is a clone stream, but ``origin``
633 :raises BadStream: if a clone stream is received and the destination filesystem
635 :raises StreamFeatureNotSupported: if the stream has a feature that is not
636 supported on this side.
637 :raises PropertyInvalid: if one or more of the specified properties is invalid
638 or has an invalid type or value.
639 :raises NameInvalid: if the name of either snapshot is invalid.
640 :raises NameTooLong: if the name of either snapshot is too long.
643 The ``origin`` is ignored if the actual stream is an incremental stream
644 that is not a clone stream and the destination filesystem exists.
645 If the stream is a full stream and the destination filesystem does not
646 exist then the ``origin`` is checked for existence: if it does not exist
647 :exc:`.DatasetNotFound` is raised, otherwise :exc:`.StreamMismatch` is
648 raised, because that snapshot can not have any relation to the stream.
651 If ``force`` is `True` and the stream is incremental then the destination
652 filesystem is rolled back to a matching source snapshot if necessary.
653 Intermediate snapshots are destroyed in that case.
655 However, none of the existing snapshots may have the same name as
656 ``snapname`` even if such a snapshot were to be destroyed.
657 The existing ``snapname`` snapshot always causes :exc:`.SnapshotExists`
660 If ``force`` is `True` and the stream is a full stream then the destination
661 filesystem is replaced with the received filesystem unless the former
662 has any snapshots. This prevents the destination filesystem from being
663 rolled back / replaced.
666 This interface does not work on dedup'd streams
667 (those with ``DMU_BACKUP_FEATURE_DEDUP``).
670 ``lzc_receive`` does not return until all of the stream is read from ``fd``
671 and applied to the pool.
674 ``lzc_receive`` does *not* close ``fd`` upon returning.
677 if origin
is not None:
683 nvlist
= nvlist_in(props
)
684 ret
= _lib
.lzc_receive(snapname
, nvlist
, c_origin
, force
, raw
, fd
)
685 errors
.lzc_receive_translate_error(ret
, snapname
, fd
, force
, origin
, props
)
688 lzc_recv
= lzc_receive
691 def lzc_receive_with_header(snapname
, fd
, header
, force
=False, origin
=None, props
=None):
693 Like :func:`lzc_receive`, but allows the caller to read the begin record
694 and then to pass it in.
696 That could be useful if the caller wants to derive, for example,
697 the snapname or the origin parameters based on the information contained in
699 :func:`receive_header` can be used to receive the begin record from the file
702 :param bytes snapname: the name of the snapshot to create.
703 :param int fd: the file descriptor from which to read the stream.
704 :param header: the stream's begin header.
705 :type header: ``cffi`` `CData` representing the header structure.
706 :param bool force: whether to roll back or destroy the target filesystem
707 if that is required to receive the stream.
708 :param origin: the optional origin snapshot name if the stream is for a clone.
709 :type origin: bytes or None
710 :param props: the properties to set on the snapshot as *received* properties.
711 :type props: dict of bytes : Any
713 :raises IOError: if an input / output error occurs while reading from the ``fd``.
714 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
715 :raises DatasetExists: if the stream is a full stream and the destination filesystem already exists.
716 :raises DatasetExists: if ``force`` is `True` but the destination filesystem could not
717 be rolled back to a matching snapshot because a newer snapshot
718 exists and it is an origin of a cloned filesystem.
719 :raises StreamMismatch: if an incremental stream is received and the latest
720 snapshot of the destination filesystem does not match
721 the source snapshot of the stream.
722 :raises StreamMismatch: if a full stream is received and the destination
723 filesystem already exists and it has at least one snapshot,
724 and ``force`` is `False`.
725 :raises StreamMismatch: if an incremental clone stream is received but the specified
726 ``origin`` is not the actual received origin.
727 :raises DestinationModified: if an incremental stream is received and the destination
728 filesystem has been modified since the last snapshot
729 and ``force`` is `False`.
730 :raises DestinationModified: if a full stream is received and the destination
731 filesystem already exists and it does not have any
732 snapshots, and ``force`` is `False`.
733 :raises DatasetNotFound: if the destination filesystem and its parent do not exist.
734 :raises DatasetNotFound: if the ``origin`` is not `None` and does not exist.
735 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem could not
736 be rolled back to a matching snapshot because a newer snapshot
737 is held and could not be destroyed.
738 :raises DatasetBusy: if another receive operation is being performed on the
739 destination filesystem.
740 :raises BadStream: if the stream is corrupt or it is not recognized or it is
741 a compound stream or it is a clone stream, but ``origin``
743 :raises BadStream: if a clone stream is received and the destination filesystem
745 :raises StreamFeatureNotSupported: if the stream has a feature that is not
746 supported on this side.
747 :raises PropertyInvalid: if one or more of the specified properties is invalid
748 or has an invalid type or value.
749 :raises NameInvalid: if the name of either snapshot is invalid.
750 :raises NameTooLong: if the name of either snapshot is too long.
753 if origin
is not None:
759 nvlist
= nvlist_in(props
)
760 ret
= _lib
.lzc_receive_with_header(snapname
, nvlist
, c_origin
, force
,
762 errors
.lzc_receive_translate_error(ret
, snapname
, fd
, force
, origin
, props
)
765 def receive_header(fd
):
767 Read the begin record of the ZFS backup stream from the given file descriptor.
769 This is a helper function for :func:`lzc_receive_with_header`.
771 :param int fd: the file descriptor from which to read the stream.
772 :return: a tuple with two elements where the first one is a Python `dict` representing
773 the fields of the begin record and the second one is an opaque object
774 suitable for passing to :func:`lzc_receive_with_header`.
775 :raises IOError: if an input / output error occurs while reading from the ``fd``.
777 At present the following fields can be of interest in the header:
780 the name of the snapshot for which the stream has been created
782 the GUID of the snapshot for which the stream has been created
783 drr_fromguid : integer
784 the GUID of the starting snapshot in the case the stream is incremental,
787 the flags describing the stream's properties
789 the type of the dataset for which the stream has been created
792 # read sizeof(dmu_replay_record_t) bytes directly into the memort backing 'record'
793 record
= _ffi
.new("dmu_replay_record_t *")
794 _ffi
.buffer(record
)[:] = os
.read(fd
, _ffi
.sizeof(record
[0]))
795 # get drr_begin member and its representation as a Pythn dict
796 drr_begin
= record
.drr_u
.drr_begin
798 for field
, descr
in _ffi
.typeof(drr_begin
).fields
:
799 if descr
.type.kind
== 'primitive':
800 header
[field
] = getattr(drr_begin
, field
)
801 elif descr
.type.kind
== 'enum':
802 header
[field
] = getattr(drr_begin
, field
)
803 elif descr
.type.kind
== 'array' and descr
.type.item
.cname
== 'char':
804 header
[field
] = _ffi
.string(getattr(drr_begin
, field
))
806 raise TypeError('Unexpected field type in drr_begin: ' + str(descr
.type))
807 return (header
, record
)
810 def lzc_exists(name
):
812 Check if a dataset (a filesystem, or a volume, or a snapshot)
813 with the given name exists.
815 :param bytes name: the dataset name to check.
816 :return: `True` if the dataset exists, `False` otherwise.
820 ``lzc_exists`` can not be used to check for existence of bookmarks.
822 ret
= _lib
.lzc_exists(name
)
826 def is_supported(func
):
828 Check whether C *libzfs_core* provides implementation required
829 for the given Python wrapper.
831 If `is_supported` returns ``False`` for the function, then
832 calling the function would result in :exc:`NotImplementedError`.
834 :param function func: the function to check.
835 :return bool: whether the function can be used.
837 fname
= func
.__name
__
838 if fname
not in globals():
839 raise ValueError(fname
+ ' is not from libzfs_core')
840 if not callable(func
):
841 raise ValueError(fname
+ ' is not a function')
842 if not fname
.startswith("lzc_"):
843 raise ValueError(fname
+ ' is not a libzfs_core API function')
844 check_func
= getattr(func
, "_check_func", None)
845 if check_func
is not None:
846 return is_supported(check_func
)
847 return getattr(_lib
, fname
, None) is not None
850 def _uncommitted(depends_on
=None):
852 Mark an API function as being an uncommitted extension that might not be
855 :param function depends_on: the function that would be checked
856 instead of a decorated function.
857 For example, if the decorated function uses
858 another uncommitted function.
860 This decorator transforms a decorated function to raise
861 :exc:`NotImplementedError` if the C libzfs_core library does not provide
862 a function with the same name as the decorated function.
864 The optional `depends_on` parameter can be provided if the decorated
865 function does not directly call the C function but instead calls another
866 Python function that follows the typical convention.
867 One example is :func:`lzc_list_snaps` that calls :func:`lzc_list` that
868 calls ``lzc_list`` in libzfs_core.
870 This decorator is implemented using :func:`is_supported`.
872 def _uncommitted_decorator(func
, depends_on
=depends_on
):
873 @functools.wraps(func
)
874 def _f(*args
, **kwargs
):
875 if not is_supported(_f
):
876 raise NotImplementedError(func
.__name
__)
877 return func(*args
, **kwargs
)
878 if depends_on
is not None:
879 _f
._check
_func
= depends_on
881 return _uncommitted_decorator
885 def lzc_promote(name
):
887 Promotes the ZFS dataset.
889 :param bytes name: the name of the dataset to promote.
890 :raises NameInvalid: if the dataset name is invalid.
891 :raises NameTooLong: if the dataset name is too long.
892 :raises NameTooLong: if the dataset's origin has a snapshot that,
893 if transferred to the dataset, would get
895 :raises NotClone: if the dataset is not a clone.
896 :raises FilesystemNotFound: if the dataset does not exist.
897 :raises SnapshotExists: if the dataset already has a snapshot with
898 the same name as one of the origin's snapshots.
900 ret
= _lib
.lzc_promote(name
, _ffi
.NULL
, _ffi
.NULL
)
901 errors
.lzc_promote_translate_error(ret
, name
)
905 def lzc_rename(source
, target
):
907 Rename the ZFS dataset.
909 :param source name: the current name of the dataset to rename.
910 :param target name: the new name of the dataset.
911 :raises NameInvalid: if either the source or target name is invalid.
912 :raises NameTooLong: if either the source or target name is too long.
913 :raises NameTooLong: if a snapshot of the source would get a too long
915 :raises FilesystemNotFound: if the source does not exist.
916 :raises FilesystemNotFound: if the target's parent does not exist.
917 :raises FilesystemExists: if the target already exists.
918 :raises PoolsDiffer: if the source and target belong to different pools.
920 ret
= _lib
.lzc_rename(source
, target
, _ffi
.NULL
, _ffi
.NULL
)
921 errors
.lzc_rename_translate_error(ret
, source
, target
)
925 def lzc_destroy_one(name
):
927 Destroy the ZFS dataset.
929 :param bytes name: the name of the dataset to destroy.
930 :raises NameInvalid: if the dataset name is invalid.
931 :raises NameTooLong: if the dataset name is too long.
932 :raises FilesystemNotFound: if the dataset does not exist.
934 ret
= _lib
.lzc_destroy_one(name
, _ffi
.NULL
)
935 errors
.lzc_destroy_translate_error(ret
, name
)
938 # As the extended API is not committed yet, the names of the new interfaces
939 # are not settled down yet.
940 # lzc_destroy() might make more sense as we do not have lzc_create_one().
941 lzc_destroy
= lzc_destroy_one
945 def lzc_inherit(name
, prop
):
947 Inherit properties from a parent dataset of the given ZFS dataset.
949 :param bytes name: the name of the dataset.
950 :param bytes prop: the name of the property to inherit.
951 :raises NameInvalid: if the dataset name is invalid.
952 :raises NameTooLong: if the dataset name is too long.
953 :raises DatasetNotFound: if the dataset does not exist.
954 :raises PropertyInvalid: if one or more of the specified properties is invalid
955 or has an invalid type or value.
957 Inheriting a property actually resets it to its default value
958 or removes it if it's a user property, so that the property could be
959 inherited if it's inheritable. If the property is not inheritable
960 then it would just have its default value.
962 This function can be used on snapshots to inherit user defined properties.
964 ret
= _lib
.lzc_inherit(name
, prop
, _ffi
.NULL
)
965 errors
.lzc_inherit_prop_translate_error(ret
, name
, prop
)
968 # As the extended API is not committed yet, the names of the new interfaces
969 # are not settled down yet.
970 # lzc_inherit_prop makes it clearer what is to be inherited.
971 lzc_inherit_prop
= lzc_inherit
975 def lzc_set_props(name
, prop
, val
):
977 Set properties of the ZFS dataset.
979 :param bytes name: the name of the dataset.
980 :param bytes prop: the name of the property.
981 :param Any val: the value of the property.
982 :raises NameInvalid: if the dataset name is invalid.
983 :raises NameTooLong: if the dataset name is too long.
984 :raises DatasetNotFound: if the dataset does not exist.
985 :raises NoSpace: if the property controls a quota and the values is
986 too small for that quota.
987 :raises PropertyInvalid: if one or more of the specified properties is invalid
988 or has an invalid type or value.
990 This function can be used on snapshots to set user defined properties.
993 An attempt to set a readonly / statistic property is ignored
994 without reporting any error.
997 props_nv
= nvlist_in(props
)
998 ret
= _lib
.lzc_set_props(name
, props_nv
, _ffi
.NULL
, _ffi
.NULL
)
999 errors
.lzc_set_prop_translate_error(ret
, name
, prop
, val
)
1002 # As the extended API is not committed yet, the names of the new interfaces
1003 # are not settled down yet.
1004 # It's not clear if atomically setting multiple properties is an achievable
1005 # goal and an interface acting on mutiple entities must do so atomically
1007 # Being able to set a single property at a time is sufficient for ClusterHQ.
1008 lzc_set_prop
= lzc_set_props
1012 def lzc_list(name
, options
):
1014 List subordinate elements of the given dataset.
1016 This function can be used to list child datasets and snapshots
1017 of the given dataset. The listed elements can be filtered by
1018 their type and by their depth relative to the starting dataset.
1020 :param bytes name: the name of the dataset to be listed, could
1021 be a snapshot or a dataset.
1022 :param options: a `dict` of the options that control the listing
1024 :type options: dict of bytes:Any
1025 :return: a pair of file descriptors the first of which can be
1026 used to read the listing.
1027 :rtype: tuple of (int, int)
1028 :raises DatasetNotFound: if the dataset does not exist.
1030 Two options are currently available:
1032 recurse : integer or None
1033 specifies depth of the recursive listing. If ``None`` the
1034 depth is not limited.
1035 Absence of this option means that only the given dataset
1038 type : dict of bytes:None
1039 specifies dataset types to include into the listing.
1040 Currently allowed keys are "filesystem", "volume", "snapshot".
1041 Absence of this option implies all types.
1043 The first of the returned file descriptors can be used to
1044 read the listing in a binary encounded format. The data is
1045 a series of variable sized records each starting with a fixed
1046 size header, the header is followed by a serialized ``nvlist``.
1047 Each record describes a single element and contains the element's
1048 name as well as its properties.
1049 The file descriptor must be closed after reading from it.
1051 The second file descriptor represents a pipe end to which the
1052 kernel driver is writing information. It should not be closed
1053 until all interesting information has been read and it must
1054 be explicitly closed afterwards.
1056 (rfd
, wfd
) = os
.pipe()
1057 fcntl
.fcntl(rfd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
1058 fcntl
.fcntl(wfd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
1059 options
= options
.copy()
1060 options
['fd'] = int32_t(wfd
)
1061 opts_nv
= nvlist_in(options
)
1062 ret
= _lib
.lzc_list(name
, opts_nv
)
1063 if ret
== errno
.ESRCH
:
1065 errors
.lzc_list_translate_error(ret
, name
, options
)
1069 # Description of the binary format used to pass data from the kernel.
1070 _PIPE_RECORD_FORMAT
= 'IBBBB'
1071 _PIPE_RECORD_SIZE
= struct
.calcsize(_PIPE_RECORD_FORMAT
)
1074 def _list(name
, recurse
=None, types
=None):
1076 A wrapper for :func:`lzc_list` that hides details of working
1077 with the file descriptors and provides data in an easy to
1080 :param bytes name: the name of the dataset to be listed, could
1081 be a snapshot, a volume or a filesystem.
1082 :param recurse: specifies depth of the recursive listing.
1083 If ``None`` the depth is not limited.
1084 :param types: specifies dataset types to include into the listing.
1085 Currently allowed keys are "filesystem", "volume", "snapshot".
1086 ``None`` is equivalent to specifying the type of the dataset
1088 :type types: list of bytes or None
1089 :type recurse: integer or None
1090 :return: a list of dictionaries each describing a single listed
1092 :rtype: list of dict
1096 # Convert types to a dict suitable for mapping to an nvlist.
1097 if types
is not None:
1098 types
= {x
: None for x
in types
}
1099 options
['type'] = types
1100 if recurse
is None or recurse
> 0:
1101 options
['recurse'] = recurse
1103 # Note that other_fd is used by the kernel side to write
1104 # the data, so we have to keep that descriptor open until
1106 # Also, we have to explicitly close the descriptor as the
1107 # kernel doesn't do that.
1108 (fd
, other_fd
) = lzc_list(name
, options
)
1114 record_bytes
= os
.read(fd
, _PIPE_RECORD_SIZE
)
1115 if not record_bytes
:
1117 (size
, _
, err
, _
, _
) = struct
.unpack(
1118 _PIPE_RECORD_FORMAT
, record_bytes
)
1119 if err
== errno
.ESRCH
:
1121 errors
.lzc_list_translate_error(err
, name
, options
)
1124 data_bytes
= os
.read(fd
, size
)
1126 with
nvlist_out(result
) as nvp
:
1127 ret
= _lib
.nvlist_unpack(data_bytes
, size
, nvp
, 0)
1129 raise exceptions
.ZFSGenericError(ret
, None,
1130 "Failed to unpack list data")
1137 @_uncommitted(lzc_list
)
1138 def lzc_get_props(name
):
1140 Get properties of the ZFS dataset.
1142 :param bytes name: the name of the dataset.
1143 :raises DatasetNotFound: if the dataset does not exist.
1144 :raises NameInvalid: if the dataset name is invalid.
1145 :raises NameTooLong: if the dataset name is too long.
1146 :return: a dictionary mapping the property names to their values.
1147 :rtype: dict of bytes:Any
1150 The value of ``clones`` property is a `list` of clone names
1154 The returned dictionary does not contain entries for properties
1155 with default values. One exception is the ``mountpoint`` property
1156 for which the default value is derived from the dataset name.
1158 result
= next(_list(name
, recurse
=0))
1159 is_snapshot
= result
['dmu_objset_stats']['dds_is_snapshot']
1160 result
= result
['properties']
1161 # In most cases the source of the property is uninteresting and the
1162 # value alone is sufficient. One exception is the 'mountpoint'
1163 # property the final value of which is not the same as the inherited
1165 mountpoint
= result
.get('mountpoint')
1166 if mountpoint
is not None:
1167 mountpoint_src
= mountpoint
['source']
1168 mountpoint_val
= mountpoint
['value']
1169 # 'source' is the name of the dataset that has 'mountpoint' set
1170 # to a non-default value and from which the current dataset inherits
1171 # the property. 'source' can be the current dataset if its
1172 # 'mountpoint' is explicitly set.
1173 # 'source' can also be a special value like '$recvd', that case
1174 # is equivalent to the property being set on the current dataset.
1175 # Note that a normal mountpoint value should start with '/'
1176 # unlike the special values "none" and "legacy".
1177 if mountpoint_val
.startswith('/') and not mountpoint_src
.startswith('$'):
1178 mountpoint_val
= mountpoint_val
+ name
[len(mountpoint_src
):]
1179 elif not is_snapshot
:
1180 mountpoint_val
= '/' + name
1182 mountpoint_val
= None
1183 result
= {k
: v
['value'] for k
, v
in result
.iteritems()}
1184 if 'clones' in result
:
1185 result
['clones'] = result
['clones'].keys()
1186 if mountpoint_val
is not None:
1187 result
['mountpoint'] = mountpoint_val
1191 @_uncommitted(lzc_list
)
1192 def lzc_list_children(name
):
1194 List the children of the ZFS dataset.
1196 :param bytes name: the name of the dataset.
1197 :return: an iterator that produces the names of the children.
1198 :raises NameInvalid: if the dataset name is invalid.
1199 :raises NameTooLong: if the dataset name is too long.
1200 :raises DatasetNotFound: if the dataset does not exist.
1203 If the dataset does not exist, then the returned iterator would produce
1204 no results and no error is reported.
1205 That case is indistinguishable from the dataset having no children.
1207 An attempt to list children of a snapshot is silently ignored as well.
1210 for entry
in _list(name
, recurse
=1, types
=['filesystem', 'volume']):
1211 child
= entry
['name']
1213 children
.append(child
)
1215 return iter(children
)
1218 @_uncommitted(lzc_list
)
1219 def lzc_list_snaps(name
):
1221 List the snapshots of the ZFS dataset.
1223 :param bytes name: the name of the dataset.
1224 :return: an iterator that produces the names of the snapshots.
1225 :raises NameInvalid: if the dataset name is invalid.
1226 :raises NameTooLong: if the dataset name is too long.
1227 :raises DatasetNotFound: if the dataset does not exist.
1230 If the dataset does not exist, then the returned iterator would produce
1231 no results and no error is reported.
1232 That case is indistinguishable from the dataset having no snapshots.
1234 An attempt to list snapshots of a snapshot is silently ignored as well.
1237 for entry
in _list(name
, recurse
=1, types
=['snapshot']):
1238 snap
= entry
['name']
1245 # TODO: a better way to init and uninit the library
1247 class LazyInit(object):
1249 def __init__(self
, lib
):
1251 self
._inited
= False
1252 self
._lock
= threading
.Lock()
1254 def __getattr__(self
, name
):
1255 if not self
._inited
:
1257 if not self
._inited
:
1258 ret
= self
._lib
.libzfs_core_init()
1260 raise exceptions
.ZFSInitializationFailed(ret
)
1262 return getattr(self
._lib
, name
)
1264 return LazyInit(libzfs_core
.lib
)
1266 _ffi
= libzfs_core
.ffi
1267 _lib
= _initialize()
1270 # vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4