mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Adopt pyzfs from ClusterHQ
This commit introduces several changes: * Update LICENSE and project information * Give a good PEP8 talk to existing Python source code * Add RPM/DEB packaging for pyzfs * Fix some outstanding issues with the existing pyzfs code caused by changes in the ABI since the last time the code was updated * Integrate pyzfs Python unittest with the ZFS Test Suite * Add missing libzfs_core functions: lzc_change_key, lzc_channel_program, lzc_channel_program_nosync, lzc_load_key, lzc_receive_one, lzc_receive_resumable, lzc_receive_with_cmdprops, lzc_receive_with_header, lzc_reopen, lzc_send_resume, lzc_sync, lzc_unload_key, lzc_remap Note: this commit slightly changes zfs_ioc_unload_key() ABI. This allow to differentiate the case where we tried to unload a key on a non-existing dataset (ENOENT) from the situation where a dataset has no key loaded: this is consistent with the "change" case where trying to zfs_ioc_change_key() from a dataset with no key results in EACCES. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: loli10K <ezomori.nozomu@gmail.com> Closes #7230
This commit is contained in:
committed by
Brian Behlendorf
parent
6abf922574
commit
85ce3f4fd1
@@ -1,4 +1,5 @@
|
||||
Apache License
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
@@ -178,7 +179,7 @@
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
@@ -186,7 +187,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 ClusterHQ
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
EXTRA_DIST = libzfs_core setup.py README LICENSE docs
|
||||
|
||||
if PYZFS_ENABLED
|
||||
all:
|
||||
|
||||
all-local:
|
||||
$(PYTHON) setup.py build
|
||||
|
||||
#
|
||||
# On Debian (Ubuntu, and other downstream distros) the install location of
|
||||
# Python packages is "../dist-packages" instead of "../site-packages" [1].
|
||||
# The install location used by "$(PYTHON) setup.py install" must match the
|
||||
# location specified in the ZFS specfile (RPM macro "%{python_sitelib}") to
|
||||
# avoid errors during the rpmbuild process.
|
||||
# However we cannot pass "--install-layout=deb" to the setup script here because
|
||||
# it is not supported on RPM-based distros; we use the combination of
|
||||
# "--prefix", "--root" and "--install-lib" parameters instead which should work
|
||||
# on every supported system.
|
||||
#
|
||||
# [1] https://wiki.debian.org/Python#Deviations_from_upstream
|
||||
#
|
||||
# Using "--no-compile" will not generate .pyc files which, in turn, will not be
|
||||
# packaged: this could result in failures during the uninstall phase if these
|
||||
# files are later created by manually loading the Python modules.
|
||||
#
|
||||
install-exec-local:
|
||||
$(PYTHON) $(srcdir)/setup.py install \
|
||||
--prefix $(prefix) \
|
||||
--root $(DESTDIR)/ \
|
||||
--install-lib $(pythondir) \
|
||||
--single-version-externally-managed \
|
||||
--verbose
|
||||
|
||||
clean: clean-local
|
||||
|
||||
clean-local:
|
||||
|
||||
check-local: all
|
||||
endif
|
||||
@@ -25,4 +25,4 @@ a temporary directory specified by, for instance, TMP environment
|
||||
variable on a memory backed filesystem.
|
||||
|
||||
Package documentation: http://pyzfs.readthedocs.org
|
||||
Package development: https://github.com/ClusterHQ/pyzfs
|
||||
Package development: https://github.com/zfsonlinux/zfs
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# flake8: noqa
|
||||
#
|
||||
# pyzfs documentation build configuration file, created by
|
||||
# sphinx-quickstart on Mon Apr 6 23:48:40 2015.
|
||||
@@ -14,7 +15,6 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import shlex
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
'''
|
||||
Python wrappers for **libzfs_core** library.
|
||||
|
||||
@@ -17,7 +32,7 @@ of the error codes to the exceptions by interpreting a context
|
||||
in which the error code is produced.
|
||||
|
||||
To submit an issue or contribute to development of this package
|
||||
please visit its `GitHub repository <https://github.com/ClusterHQ/pyzfs>`_.
|
||||
please visit its `GitHub repository <https://github.com/zfsonlinux/zfs>`_.
|
||||
|
||||
.. data:: MAXNAMELEN
|
||||
|
||||
@@ -26,36 +41,53 @@ please visit its `GitHub repository <https://github.com/ClusterHQ/pyzfs>`_.
|
||||
|
||||
from ._constants import (
|
||||
MAXNAMELEN,
|
||||
ZCP_DEFAULT_INSTRLIMIT,
|
||||
ZCP_DEFAULT_MEMLIMIT,
|
||||
WRAPPING_KEY_LEN,
|
||||
zfs_key_location,
|
||||
zfs_keyformat,
|
||||
zio_encrypt
|
||||
)
|
||||
|
||||
from ._libzfs_core import (
|
||||
lzc_create,
|
||||
lzc_bookmark,
|
||||
lzc_change_key,
|
||||
lzc_channel_program,
|
||||
lzc_channel_program_nosync,
|
||||
lzc_clone,
|
||||
lzc_create,
|
||||
lzc_destroy_bookmarks,
|
||||
lzc_destroy_snaps,
|
||||
lzc_exists,
|
||||
lzc_get_bookmarks,
|
||||
lzc_get_holds,
|
||||
lzc_hold,
|
||||
lzc_load_key,
|
||||
lzc_promote,
|
||||
lzc_receive,
|
||||
lzc_receive_one,
|
||||
lzc_receive_resumable,
|
||||
lzc_receive_with_cmdprops,
|
||||
lzc_receive_with_header,
|
||||
lzc_release,
|
||||
lzc_reopen,
|
||||
lzc_rollback,
|
||||
lzc_rollback_to,
|
||||
lzc_snapshot,
|
||||
lzc_snap,
|
||||
lzc_destroy_snaps,
|
||||
lzc_bookmark,
|
||||
lzc_get_bookmarks,
|
||||
lzc_destroy_bookmarks,
|
||||
lzc_snaprange_space,
|
||||
lzc_hold,
|
||||
lzc_release,
|
||||
lzc_get_holds,
|
||||
lzc_send,
|
||||
lzc_send_resume,
|
||||
lzc_send_space,
|
||||
lzc_receive,
|
||||
lzc_receive_with_header,
|
||||
lzc_recv,
|
||||
lzc_exists,
|
||||
lzc_snaprange_space,
|
||||
lzc_snapshot,
|
||||
lzc_sync,
|
||||
lzc_unload_key,
|
||||
is_supported,
|
||||
lzc_promote,
|
||||
lzc_recv,
|
||||
lzc_snap,
|
||||
lzc_rename,
|
||||
lzc_destroy,
|
||||
lzc_inherit_prop,
|
||||
lzc_set_prop,
|
||||
lzc_get_props,
|
||||
lzc_set_props,
|
||||
lzc_list_children,
|
||||
lzc_list_snaps,
|
||||
receive_header,
|
||||
@@ -65,33 +97,50 @@ __all__ = [
|
||||
'ctypes',
|
||||
'exceptions',
|
||||
'MAXNAMELEN',
|
||||
'lzc_create',
|
||||
'ZCP_DEFAULT_INSTRLIMIT',
|
||||
'ZCP_DEFAULT_MEMLIMIT',
|
||||
'WRAPPING_KEY_LEN',
|
||||
'zfs_key_location',
|
||||
'zfs_keyformat',
|
||||
'zio_encrypt',
|
||||
'lzc_bookmark',
|
||||
'lzc_change_key',
|
||||
'lzc_channel_program',
|
||||
'lzc_channel_program_nosync',
|
||||
'lzc_clone',
|
||||
'lzc_create',
|
||||
'lzc_destroy_bookmarks',
|
||||
'lzc_destroy_snaps',
|
||||
'lzc_exists',
|
||||
'lzc_get_bookmarks',
|
||||
'lzc_get_holds',
|
||||
'lzc_hold',
|
||||
'lzc_load_key',
|
||||
'lzc_promote',
|
||||
'lzc_receive',
|
||||
'lzc_receive_one',
|
||||
'lzc_receive_resumable',
|
||||
'lzc_receive_with_cmdprops',
|
||||
'lzc_receive_with_header',
|
||||
'lzc_release',
|
||||
'lzc_reopen',
|
||||
'lzc_rollback',
|
||||
'lzc_rollback_to',
|
||||
'lzc_snapshot',
|
||||
'lzc_snap',
|
||||
'lzc_destroy_snaps',
|
||||
'lzc_bookmark',
|
||||
'lzc_get_bookmarks',
|
||||
'lzc_destroy_bookmarks',
|
||||
'lzc_snaprange_space',
|
||||
'lzc_hold',
|
||||
'lzc_release',
|
||||
'lzc_get_holds',
|
||||
'lzc_send',
|
||||
'lzc_send_resume',
|
||||
'lzc_send_space',
|
||||
'lzc_receive',
|
||||
'lzc_receive_with_header',
|
||||
'lzc_recv',
|
||||
'lzc_exists',
|
||||
'lzc_snaprange_space',
|
||||
'lzc_snapshot',
|
||||
'lzc_sync',
|
||||
'lzc_unload_key',
|
||||
'is_supported',
|
||||
'lzc_promote',
|
||||
'lzc_recv',
|
||||
'lzc_snap',
|
||||
'lzc_rename',
|
||||
'lzc_destroy',
|
||||
'lzc_inherit_prop',
|
||||
'lzc_set_prop',
|
||||
'lzc_get_props',
|
||||
'lzc_set_props',
|
||||
'lzc_list_children',
|
||||
'lzc_list_snaps',
|
||||
'receive_header',
|
||||
|
||||
@@ -1,10 +1,61 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Important `libzfs_core` constants.
|
||||
"""
|
||||
|
||||
|
||||
# https://stackoverflow.com/a/1695250
|
||||
def enum(*sequential, **named):
|
||||
enums = dict(zip(sequential, range(len(sequential))), **named)
|
||||
return type('Enum', (), enums)
|
||||
|
||||
|
||||
#: Maximum length of any ZFS name.
|
||||
MAXNAMELEN = 255
|
||||
#: Default channel program limits
|
||||
ZCP_DEFAULT_INSTRLIMIT = 10 * 1000 * 1000
|
||||
ZCP_DEFAULT_MEMLIMIT = 10 * 1024 * 1024
|
||||
#: Encryption wrapping key length
|
||||
WRAPPING_KEY_LEN = 32
|
||||
#: Encryption key location enum
|
||||
zfs_key_location = enum(
|
||||
'ZFS_KEYLOCATION_NONE',
|
||||
'ZFS_KEYLOCATION_PROMPT',
|
||||
'ZFS_KEYLOCATION_URI'
|
||||
)
|
||||
#: Encryption key format enum
|
||||
zfs_keyformat = enum(
|
||||
'ZFS_KEYFORMAT_NONE',
|
||||
'ZFS_KEYFORMAT_RAW',
|
||||
'ZFS_KEYFORMAT_HEX',
|
||||
'ZFS_KEYFORMAT_PASSPHRASE'
|
||||
)
|
||||
# Encryption algorithms enum
|
||||
zio_encrypt = enum(
|
||||
'ZIO_CRYPT_INHERIT',
|
||||
'ZIO_CRYPT_ON',
|
||||
'ZIO_CRYPT_OFF',
|
||||
'ZIO_CRYPT_AES_128_CCM',
|
||||
'ZIO_CRYPT_AES_192_CCM',
|
||||
'ZIO_CRYPT_AES_256_CCM',
|
||||
'ZIO_CRYPT_AES_128_GCM',
|
||||
'ZIO_CRYPT_AES_192_GCM',
|
||||
'ZIO_CRYPT_AES_256_GCM'
|
||||
)
|
||||
|
||||
# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Helper routines for converting ``errno`` style error codes from C functions
|
||||
@@ -24,9 +38,9 @@ def lzc_create_translate_error(ret, name, ds_type, props):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.EINVAL:
|
||||
# XXX: should raise lzc_exc.WrongParent if parent is ZVOL
|
||||
_validate_fs_name(name)
|
||||
raise lzc_exc.PropertyInvalid(name)
|
||||
|
||||
if ret == errno.EEXIST:
|
||||
raise lzc_exc.FilesystemExists(name)
|
||||
if ret == errno.ENOENT:
|
||||
@@ -40,11 +54,9 @@ def lzc_clone_translate_error(ret, name, origin, props):
|
||||
if ret == errno.EINVAL:
|
||||
_validate_fs_name(name)
|
||||
_validate_snap_name(origin)
|
||||
if _pool_name(name) != _pool_name(origin):
|
||||
raise lzc_exc.PoolsDiffer(name) # see https://www.illumos.org/issues/5824
|
||||
else:
|
||||
raise lzc_exc.PropertyInvalid(name)
|
||||
|
||||
raise lzc_exc.PropertyInvalid(name)
|
||||
if ret == errno.EXDEV:
|
||||
raise lzc_exc.PoolsDiffer(name)
|
||||
if ret == errno.EEXIST:
|
||||
raise lzc_exc.FilesystemExists(name)
|
||||
if ret == errno.ENOENT:
|
||||
@@ -57,9 +69,11 @@ def lzc_clone_translate_error(ret, name, origin, props):
|
||||
def lzc_rollback_translate_error(ret, name):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.ESRCH:
|
||||
raise lzc_exc.SnapshotNotFound(name)
|
||||
if ret == errno.EINVAL:
|
||||
_validate_fs_name(name)
|
||||
raise lzc_exc.SnapshotNotFound(name)
|
||||
raise lzc_exc.NameInvalid(name)
|
||||
if ret == errno.ENOENT:
|
||||
if not _is_valid_fs_name(name):
|
||||
raise lzc_exc.NameInvalid(name)
|
||||
@@ -67,12 +81,13 @@ def lzc_rollback_translate_error(ret, name):
|
||||
raise lzc_exc.FilesystemNotFound(name)
|
||||
raise _generic_exception(ret, name, "Failed to rollback")
|
||||
|
||||
|
||||
def lzc_rollback_to_translate_error(ret, name, snap):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.EEXIST:
|
||||
raise lzc_exc.SnapshotNotLatest(snap)
|
||||
raise _generic_exception(ret, name, "Failed to rollback")
|
||||
else:
|
||||
lzc_rollback_translate_error(ret, name)
|
||||
|
||||
|
||||
def lzc_snapshot_translate_errors(ret, errlist, snaps, props):
|
||||
if ret == 0:
|
||||
@@ -116,7 +131,8 @@ def lzc_destroy_snaps_translate_errors(ret, errlist, snaps, defer):
|
||||
return lzc_exc.SnapshotIsHeld(name)
|
||||
return _generic_exception(ret, name, "Failed to destroy snapshot")
|
||||
|
||||
_handle_err_list(ret, errlist, snaps, lzc_exc.SnapshotDestructionFailure, _map)
|
||||
_handle_err_list(
|
||||
ret, errlist, snaps, lzc_exc.SnapshotDestructionFailure, _map)
|
||||
|
||||
|
||||
def lzc_bookmark_translate_errors(ret, errlist, bookmarks):
|
||||
@@ -137,7 +153,8 @@ def lzc_bookmark_translate_errors(ret, errlist, bookmarks):
|
||||
elif any(x != _pool_name(name) for x in pool_names):
|
||||
return lzc_exc.PoolsDiffer(name)
|
||||
else:
|
||||
invalid_names = [b for b in bookmarks.keys() if not _is_valid_bmark_name(b)]
|
||||
invalid_names = [
|
||||
b for b in bookmarks.keys() if not _is_valid_bmark_name(b)]
|
||||
if invalid_names:
|
||||
return lzc_exc.BookmarkNameInvalid(invalid_names[0])
|
||||
if ret == errno.EEXIST:
|
||||
@@ -148,7 +165,8 @@ def lzc_bookmark_translate_errors(ret, errlist, bookmarks):
|
||||
return lzc_exc.BookmarkNotSupported(name)
|
||||
return _generic_exception(ret, name, "Failed to create bookmark")
|
||||
|
||||
_handle_err_list(ret, errlist, bookmarks.keys(), lzc_exc.BookmarkFailure, _map)
|
||||
_handle_err_list(
|
||||
ret, errlist, bookmarks.keys(), lzc_exc.BookmarkFailure, _map)
|
||||
|
||||
|
||||
def lzc_get_bookmarks_translate_error(ret, fsname, props):
|
||||
@@ -168,7 +186,8 @@ def lzc_destroy_bookmarks_translate_errors(ret, errlist, bookmarks):
|
||||
return lzc_exc.NameInvalid(name)
|
||||
return _generic_exception(ret, name, "Failed to destroy bookmark")
|
||||
|
||||
_handle_err_list(ret, errlist, bookmarks, lzc_exc.BookmarkDestructionFailure, _map)
|
||||
_handle_err_list(
|
||||
ret, errlist, bookmarks, lzc_exc.BookmarkDestructionFailure, _map)
|
||||
|
||||
|
||||
def lzc_snaprange_space_translate_error(ret, firstsnap, lastsnap):
|
||||
@@ -194,7 +213,8 @@ def lzc_snaprange_space_translate_error(ret, firstsnap, lastsnap):
|
||||
raise lzc_exc.SnapshotMismatch(lastsnap)
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.SnapshotNotFound(lastsnap)
|
||||
raise _generic_exception(ret, lastsnap, "Failed to calculate space used by range of snapshots")
|
||||
raise _generic_exception(
|
||||
ret, lastsnap, "Failed to calculate space used by range of snapshots")
|
||||
|
||||
|
||||
def lzc_hold_translate_errors(ret, errlist, holds, fd):
|
||||
@@ -214,7 +234,8 @@ def lzc_hold_translate_errors(ret, errlist, holds, fd):
|
||||
elif any(x != _pool_name(name) for x in pool_names):
|
||||
return lzc_exc.PoolsDiffer(name)
|
||||
else:
|
||||
invalid_names = [b for b in holds.keys() if not _is_valid_snap_name(b)]
|
||||
invalid_names = [
|
||||
b for b in holds.keys() if not _is_valid_snap_name(b)]
|
||||
if invalid_names:
|
||||
return lzc_exc.NameInvalid(invalid_names[0])
|
||||
fs_name = None
|
||||
@@ -259,7 +280,8 @@ def lzc_release_translate_errors(ret, errlist, holds):
|
||||
elif any(x != _pool_name(name) for x in pool_names):
|
||||
return lzc_exc.PoolsDiffer(name)
|
||||
else:
|
||||
invalid_names = [b for b in holds.keys() if not _is_valid_snap_name(b)]
|
||||
invalid_names = [
|
||||
b for b in holds.keys() if not _is_valid_snap_name(b)]
|
||||
if invalid_names:
|
||||
return lzc_exc.NameInvalid(invalid_names[0])
|
||||
elif ret == errno.ENOENT:
|
||||
@@ -274,9 +296,11 @@ def lzc_release_translate_errors(ret, errlist, holds):
|
||||
pool_name = _pool_name(name)
|
||||
return lzc_exc.FeatureNotSupported(pool_name)
|
||||
else:
|
||||
return _generic_exception(ret, name, "Failed to release snapshot hold")
|
||||
return _generic_exception(
|
||||
ret, name, "Failed to release snapshot hold")
|
||||
|
||||
_handle_err_list(ret, errlist, holds.keys(), lzc_exc.HoldReleaseFailure, _map)
|
||||
_handle_err_list(
|
||||
ret, errlist, holds.keys(), lzc_exc.HoldReleaseFailure, _map)
|
||||
|
||||
|
||||
def lzc_get_holds_translate_error(ret, snapname):
|
||||
@@ -303,13 +327,15 @@ def lzc_send_translate_error(ret, snapname, fromsnap, fd, flags):
|
||||
if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and
|
||||
not _is_valid_bmark_name(fromsnap)):
|
||||
raise lzc_exc.NameInvalid(fromsnap)
|
||||
elif not _is_valid_snap_name(snapname) and not _is_valid_fs_name(snapname):
|
||||
elif (not _is_valid_snap_name(snapname) and
|
||||
not _is_valid_fs_name(snapname)):
|
||||
raise lzc_exc.NameInvalid(snapname)
|
||||
elif fromsnap is not None and len(fromsnap) > MAXNAMELEN:
|
||||
raise lzc_exc.NameTooLong(fromsnap)
|
||||
elif len(snapname) > MAXNAMELEN:
|
||||
raise lzc_exc.NameTooLong(snapname)
|
||||
elif fromsnap is not None and _pool_name(fromsnap) != _pool_name(snapname):
|
||||
elif (fromsnap is not None and
|
||||
_pool_name(fromsnap) != _pool_name(snapname)):
|
||||
raise lzc_exc.PoolsDiffer(snapname)
|
||||
elif ret == errno.ENOENT:
|
||||
if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and
|
||||
@@ -341,26 +367,44 @@ def lzc_send_space_translate_error(ret, snapname, fromsnap):
|
||||
raise lzc_exc.NameTooLong(fromsnap)
|
||||
elif len(snapname) > MAXNAMELEN:
|
||||
raise lzc_exc.NameTooLong(snapname)
|
||||
elif fromsnap is not None and _pool_name(fromsnap) != _pool_name(snapname):
|
||||
elif (fromsnap is not None and
|
||||
_pool_name(fromsnap) != _pool_name(snapname)):
|
||||
raise lzc_exc.PoolsDiffer(snapname)
|
||||
elif ret == errno.ENOENT and fromsnap is not None:
|
||||
if not _is_valid_snap_name(fromsnap):
|
||||
raise lzc_exc.NameInvalid(fromsnap)
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.SnapshotNotFound(snapname)
|
||||
raise _generic_exception(ret, snapname, "Failed to estimate backup stream size")
|
||||
raise _generic_exception(
|
||||
ret, snapname, "Failed to estimate backup stream size")
|
||||
|
||||
|
||||
def lzc_receive_translate_error(ret, snapname, fd, force, origin, props):
|
||||
def lzc_receive_translate_errors(
|
||||
ret, snapname, fd, force, raw, resumable, embedded, origin, properrs
|
||||
):
|
||||
if ret == 0:
|
||||
return
|
||||
if properrs is not None and len(properrs) > 0:
|
||||
def _map(ret, name):
|
||||
if ret == errno.EINVAL:
|
||||
return lzc_exc.PropertyInvalid(name)
|
||||
return _generic_exception(ret, name, "Failed to set property")
|
||||
_handle_err_list(
|
||||
errno.EINVAL, properrs, [snapname],
|
||||
lzc_exc.ReceivePropertyFailure, _map)
|
||||
else:
|
||||
return
|
||||
if ret == errno.EINVAL:
|
||||
if not _is_valid_snap_name(snapname) and not _is_valid_fs_name(snapname):
|
||||
if (not _is_valid_snap_name(snapname) and
|
||||
not _is_valid_fs_name(snapname)):
|
||||
raise lzc_exc.NameInvalid(snapname)
|
||||
elif len(snapname) > MAXNAMELEN:
|
||||
raise lzc_exc.NameTooLong(snapname)
|
||||
elif origin is not None and not _is_valid_snap_name(origin):
|
||||
raise lzc_exc.NameInvalid(origin)
|
||||
elif resumable:
|
||||
raise lzc_exc.StreamFeatureInvalid()
|
||||
elif embedded and not raw:
|
||||
raise lzc_exc.StreamFeatureIncompatible()
|
||||
else:
|
||||
raise lzc_exc.BadStream()
|
||||
if ret == errno.ENOENT:
|
||||
@@ -388,6 +432,8 @@ def lzc_receive_translate_error(ret, snapname, fd, force, origin, props):
|
||||
raise lzc_exc.ReadOnlyPool(_pool_name(snapname))
|
||||
if ret == errno.EAGAIN:
|
||||
raise lzc_exc.SuspendedPool(_pool_name(snapname))
|
||||
if ret == errno.EBADE: # ECKSUM
|
||||
raise lzc_exc.BadStream()
|
||||
|
||||
raise lzc_exc.StreamIOError(ret)
|
||||
|
||||
@@ -407,6 +453,101 @@ def lzc_promote_translate_error(ret, name):
|
||||
raise _generic_exception(ret, name, "Failed to promote dataset")
|
||||
|
||||
|
||||
def lzc_change_key_translate_error(ret, name):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.EINVAL:
|
||||
_validate_fs_name(name)
|
||||
raise lzc_exc.PropertyInvalid(name)
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.FilesystemNotFound(name)
|
||||
if ret == errno.EACCES:
|
||||
raise lzc_exc.EncryptionKeyNotLoaded()
|
||||
raise _generic_exception(ret, name, "Failed to change encryption key")
|
||||
|
||||
|
||||
def lzc_load_key_translate_error(ret, name, noop):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.EINVAL:
|
||||
_validate_fs_name(name)
|
||||
raise lzc_exc.PropertyInvalid(name)
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.FilesystemNotFound(name)
|
||||
if ret == errno.EACCES:
|
||||
raise lzc_exc.EncryptionKeyInvalid()
|
||||
if ret == errno.EEXIST:
|
||||
raise lzc_exc.EncryptionKeyAlreadyLoaded()
|
||||
if noop:
|
||||
raise _generic_exception(ret, name, "Failed to load encryption key")
|
||||
else:
|
||||
raise _generic_exception(ret, name, "Failed to verify encryption key")
|
||||
|
||||
|
||||
def lzc_unload_key_translate_error(ret, name):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.EINVAL:
|
||||
_validate_fs_name(name)
|
||||
raise lzc_exc.PropertyInvalid(name)
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.FilesystemNotFound(name)
|
||||
if ret == errno.EACCES:
|
||||
raise lzc_exc.EncryptionKeyNotLoaded()
|
||||
raise _generic_exception(ret, name, "Failed to unload encryption key")
|
||||
|
||||
|
||||
def lzc_sync_translate_error(ret, name):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.PoolNotFound(name)
|
||||
raise _generic_exception(ret, name, "Failed to sync pool")
|
||||
|
||||
|
||||
def lzc_reopen_translate_error(ret, name):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.PoolNotFound(name)
|
||||
raise _generic_exception(ret, name, "Failed to reopen pool")
|
||||
|
||||
|
||||
def lzc_channel_program_translate_error(ret, name, error):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.PoolNotFound(name)
|
||||
if ret == errno.ETIME:
|
||||
raise lzc_exc.ZCPTimeout()
|
||||
if ret == errno.ENOMEM:
|
||||
raise lzc_exc.ZCPMemoryError()
|
||||
if ret == errno.ENOSPC:
|
||||
raise lzc_exc.ZCPSpaceError()
|
||||
if ret == errno.EPERM:
|
||||
raise lzc_exc.ZCPPermissionError()
|
||||
if ret == errno.ECHRNG:
|
||||
raise lzc_exc.ZCPRuntimeError(error)
|
||||
if ret == errno.EINVAL:
|
||||
if error is None:
|
||||
raise lzc_exc.ZCPLimitInvalid()
|
||||
else:
|
||||
raise lzc_exc.ZCPSyntaxError(error)
|
||||
raise _generic_exception(ret, name, "Failed to execute channel program")
|
||||
|
||||
|
||||
def lzc_remap_translate_error(ret, name):
|
||||
if ret == 0:
|
||||
return
|
||||
if ret == errno.ENOENT:
|
||||
raise lzc_exc.DatasetNotFound(name)
|
||||
if ret == errno.EINVAL:
|
||||
_validate_fs_name(name)
|
||||
if ret == errno.ENOTSUP:
|
||||
return lzc_exc.FeatureNotSupported(name)
|
||||
raise _generic_exception(ret, name, "Failed to remap dataset")
|
||||
|
||||
|
||||
def lzc_rename_translate_error(ret, source, target):
|
||||
if ret == 0:
|
||||
return
|
||||
@@ -495,28 +636,36 @@ def _handle_err_list(ret, errlist, names, exception, mapper):
|
||||
Convert one or more errors from an operation into the requested exception.
|
||||
|
||||
:param int ret: the overall return code.
|
||||
:param errlist: the dictionary that maps entity names to their specific error codes.
|
||||
:param errlist: the dictionary that maps entity names to their specific
|
||||
error codes.
|
||||
:type errlist: dict of bytes:int
|
||||
:param names: the list of all names of the entities on which the operation was attempted.
|
||||
:param type exception: the type of the exception to raise if an error occurred.
|
||||
The exception should be a subclass of `MultipleOperationsFailure`.
|
||||
:param function mapper: the function that maps an error code and a name to a Python exception.
|
||||
:param names: the list of all names of the entities on which the operation
|
||||
was attempted.
|
||||
:param type exception: the type of the exception to raise if an error
|
||||
occurred. The exception should be a subclass of
|
||||
``MultipleOperationsFailure``.
|
||||
:param function mapper: the function that maps an error code and a name to
|
||||
a Python exception.
|
||||
|
||||
Unless ``ret`` is zero this function will raise the ``exception``.
|
||||
If the ``errlist`` is not empty, then the compound exception will contain a list of exceptions
|
||||
corresponding to each individual error code in the ``errlist``.
|
||||
Otherwise, the ``exception`` will contain a list with a single exception corresponding to the
|
||||
``ret`` value. If the ``names`` list contains only one element, that is, the operation was
|
||||
attempted on a single entity, then the name of that entity is passed to the ``mapper``.
|
||||
If the operation was attempted on multiple entities, but the ``errlist`` is empty, then we
|
||||
can not know which entity caused the error and, thus, ``None`` is used as a name to signify
|
||||
thati fact.
|
||||
If the ``errlist`` is not empty, then the compound exception will contain
|
||||
a list of exceptions corresponding to each individual error code in the
|
||||
``errlist``.
|
||||
Otherwise, the ``exception`` will contain a list with a single exception
|
||||
corresponding to the ``ret`` value. If the ``names`` list contains only one
|
||||
element, that is, the operation was attempted on a single entity, then the
|
||||
name of that entity is passed to the ``mapper``.
|
||||
If the operation was attempted on multiple entities, but the ``errlist``
|
||||
is empty, then we can not know which entity caused the error and, thus,
|
||||
``None`` is used as a name to signify that fact.
|
||||
|
||||
.. note::
|
||||
Note that the ``errlist`` can contain a special element with a key of "N_MORE_ERRORS".
|
||||
That element means that there were too many errors to place on the ``errlist``.
|
||||
Those errors are suppressed and only their count is provided as a value of the special
|
||||
``N_MORE_ERRORS`` element.
|
||||
Note that the ``errlist`` can contain a special element with a key of
|
||||
"N_MORE_ERRORS".
|
||||
That element means that there were too many errors to place on the
|
||||
``errlist``.
|
||||
Those errors are suppressed and only their count is provided as a
|
||||
value of the special ``N_MORE_ERRORS`` element.
|
||||
'''
|
||||
if ret == 0:
|
||||
return
|
||||
@@ -613,6 +762,7 @@ def _generic_exception(err, name, message):
|
||||
else:
|
||||
return lzc_exc.ZFSGenericError(err, message, name)
|
||||
|
||||
|
||||
_error_to_exception = {e.errno: e for e in [
|
||||
lzc_exc.ZIOError,
|
||||
lzc_exc.NoSpace,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,18 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
nvlist_in and nvlist_out provide support for converting between
|
||||
@@ -19,14 +33,17 @@ will follow the same format.
|
||||
|
||||
Format:
|
||||
- keys are always byte strings
|
||||
- a value can be None in which case it represents boolean truth by its mere presence
|
||||
- a value can be None in which case it represents boolean truth by its mere
|
||||
presence
|
||||
- a value can be a bool
|
||||
- a value can be a byte string
|
||||
- a value can be an integer
|
||||
- a value can be a CFFI CData object representing one of the following C types:
|
||||
int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, boolean_t, uchar_t
|
||||
int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t,
|
||||
boolean_t, uchar_t
|
||||
- a value can be a dictionary that recursively adheres to this format
|
||||
- a value can be a list of bools, byte strings, integers or CData objects of types specified above
|
||||
- a value can be a list of bools, byte strings, integers or CData objects of
|
||||
types specified above
|
||||
- a value can be a list of dictionaries that adhere to this format
|
||||
- all elements of a list value must be of the same type
|
||||
"""
|
||||
@@ -70,7 +87,8 @@ def nvlist_out(props):
|
||||
and also populates the 'props' dictionary with data from the nvlist_t
|
||||
upon leaving the 'with' block.
|
||||
|
||||
:param dict props: the dictionary to be populated with data from the nvlist.
|
||||
:param dict props: the dictionary to be populated with data from the
|
||||
nvlist.
|
||||
:return: an FFI CData object representing the pointer to nvlist_t pointer.
|
||||
:rtype: CData
|
||||
"""
|
||||
@@ -87,39 +105,58 @@ def nvlist_out(props):
|
||||
nvlistp[0] = _ffi.NULL
|
||||
|
||||
|
||||
def packed_nvlist_out(packed_nvlist, packed_size):
|
||||
"""
|
||||
This function converts a packed C nvlist_t to a python dictionary and
|
||||
provides automatic memory management for the former.
|
||||
|
||||
:param bytes packed_nvlist: packed nvlist_t.
|
||||
:param int packed_size: nvlist_t packed size.
|
||||
:return: an `dict` of values representing the data containted by nvlist_t.
|
||||
:rtype: dict
|
||||
"""
|
||||
props = {}
|
||||
with nvlist_out(props) as nvp:
|
||||
ret = _lib.nvlist_unpack(packed_nvlist, packed_size, nvp, 0)
|
||||
if ret != 0:
|
||||
raise MemoryError('nvlist_unpack failed')
|
||||
return props
|
||||
|
||||
|
||||
_TypeInfo = namedtuple('_TypeInfo', ['suffix', 'ctype', 'is_array', 'convert'])
|
||||
|
||||
|
||||
def _type_info(typeid):
|
||||
return {
|
||||
_lib.DATA_TYPE_BOOLEAN: _TypeInfo(None, None, None, None),
|
||||
_lib.DATA_TYPE_BOOLEAN_VALUE: _TypeInfo("boolean_value", "boolean_t *", False, bool),
|
||||
_lib.DATA_TYPE_BYTE: _TypeInfo("byte", "uchar_t *", False, int),
|
||||
_lib.DATA_TYPE_INT8: _TypeInfo("int8", "int8_t *", False, int),
|
||||
_lib.DATA_TYPE_UINT8: _TypeInfo("uint8", "uint8_t *", False, int),
|
||||
_lib.DATA_TYPE_INT16: _TypeInfo("int16", "int16_t *", False, int),
|
||||
_lib.DATA_TYPE_UINT16: _TypeInfo("uint16", "uint16_t *", False, int),
|
||||
_lib.DATA_TYPE_INT32: _TypeInfo("int32", "int32_t *", False, int),
|
||||
_lib.DATA_TYPE_UINT32: _TypeInfo("uint32", "uint32_t *", False, int),
|
||||
_lib.DATA_TYPE_INT64: _TypeInfo("int64", "int64_t *", False, int),
|
||||
_lib.DATA_TYPE_UINT64: _TypeInfo("uint64", "uint64_t *", False, int),
|
||||
_lib.DATA_TYPE_STRING: _TypeInfo("string", "char **", False, _ffi.string),
|
||||
_lib.DATA_TYPE_NVLIST: _TypeInfo("nvlist", "nvlist_t **", False, lambda x: _nvlist_to_dict(x, {})),
|
||||
_lib.DATA_TYPE_BOOLEAN_ARRAY: _TypeInfo("boolean_array", "boolean_t **", True, bool),
|
||||
_lib.DATA_TYPE_BOOLEAN_VALUE: _TypeInfo("boolean_value", "boolean_t *", False, bool), # noqa: E501
|
||||
_lib.DATA_TYPE_BYTE: _TypeInfo("byte", "uchar_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT8: _TypeInfo("int8", "int8_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT8: _TypeInfo("uint8", "uint8_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT16: _TypeInfo("int16", "int16_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT16: _TypeInfo("uint16", "uint16_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT32: _TypeInfo("int32", "int32_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT32: _TypeInfo("uint32", "uint32_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT64: _TypeInfo("int64", "int64_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT64: _TypeInfo("uint64", "uint64_t *", False, int), # noqa: E501
|
||||
_lib.DATA_TYPE_STRING: _TypeInfo("string", "char **", False, _ffi.string), # noqa: E501
|
||||
_lib.DATA_TYPE_NVLIST: _TypeInfo("nvlist", "nvlist_t **", False, lambda x: _nvlist_to_dict(x, {})), # noqa: E501
|
||||
_lib.DATA_TYPE_BOOLEAN_ARRAY: _TypeInfo("boolean_array", "boolean_t **", True, bool), # noqa: E501
|
||||
# XXX use bytearray ?
|
||||
_lib.DATA_TYPE_BYTE_ARRAY: _TypeInfo("byte_array", "uchar_t **", True, int),
|
||||
_lib.DATA_TYPE_INT8_ARRAY: _TypeInfo("int8_array", "int8_t **", True, int),
|
||||
_lib.DATA_TYPE_UINT8_ARRAY: _TypeInfo("uint8_array", "uint8_t **", True, int),
|
||||
_lib.DATA_TYPE_INT16_ARRAY: _TypeInfo("int16_array", "int16_t **", True, int),
|
||||
_lib.DATA_TYPE_UINT16_ARRAY: _TypeInfo("uint16_array", "uint16_t **", True, int),
|
||||
_lib.DATA_TYPE_INT32_ARRAY: _TypeInfo("int32_array", "int32_t **", True, int),
|
||||
_lib.DATA_TYPE_UINT32_ARRAY: _TypeInfo("uint32_array", "uint32_t **", True, int),
|
||||
_lib.DATA_TYPE_INT64_ARRAY: _TypeInfo("int64_array", "int64_t **", True, int),
|
||||
_lib.DATA_TYPE_UINT64_ARRAY: _TypeInfo("uint64_array", "uint64_t **", True, int),
|
||||
_lib.DATA_TYPE_STRING_ARRAY: _TypeInfo("string_array", "char ***", True, _ffi.string),
|
||||
_lib.DATA_TYPE_NVLIST_ARRAY: _TypeInfo("nvlist_array", "nvlist_t ***", True, lambda x: _nvlist_to_dict(x, {})),
|
||||
_lib.DATA_TYPE_BYTE_ARRAY: _TypeInfo("byte_array", "uchar_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT8_ARRAY: _TypeInfo("int8_array", "int8_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT8_ARRAY: _TypeInfo("uint8_array", "uint8_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT16_ARRAY: _TypeInfo("int16_array", "int16_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT16_ARRAY: _TypeInfo("uint16_array", "uint16_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT32_ARRAY: _TypeInfo("int32_array", "int32_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT32_ARRAY: _TypeInfo("uint32_array", "uint32_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_INT64_ARRAY: _TypeInfo("int64_array", "int64_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_UINT64_ARRAY: _TypeInfo("uint64_array", "uint64_t **", True, int), # noqa: E501
|
||||
_lib.DATA_TYPE_STRING_ARRAY: _TypeInfo("string_array", "char ***", True, _ffi.string), # noqa: E501
|
||||
_lib.DATA_TYPE_NVLIST_ARRAY: _TypeInfo("nvlist_array", "nvlist_t ***", True, lambda x: _nvlist_to_dict(x, {})), # noqa: E501
|
||||
}[typeid]
|
||||
|
||||
|
||||
# only integer properties need to be here
|
||||
_prop_name_to_type_str = {
|
||||
"rewind-request": "uint32",
|
||||
@@ -180,7 +217,8 @@ def _nvlist_add_array(nvlist, key, array):
|
||||
suffix = _prop_name_to_type_str.get(key, "uint64")
|
||||
cfunc = getattr(_lib, "nvlist_add_%s_array" % (suffix,))
|
||||
ret = cfunc(nvlist, key, array, len(array))
|
||||
elif isinstance(specimen, _ffi.CData) and _ffi.typeof(specimen) in _type_to_suffix:
|
||||
elif isinstance(
|
||||
specimen, _ffi.CData) and _ffi.typeof(specimen) in _type_to_suffix:
|
||||
suffix = _type_to_suffix[_ffi.typeof(specimen)][True]
|
||||
cfunc = getattr(_lib, "nvlist_add_%s_array" % (suffix,))
|
||||
ret = cfunc(nvlist, key, array, len(array))
|
||||
@@ -196,10 +234,7 @@ def _nvlist_to_dict(nvlist, props):
|
||||
name = _ffi.string(_lib.nvpair_name(pair))
|
||||
typeid = int(_lib.nvpair_type(pair))
|
||||
typeinfo = _type_info(typeid)
|
||||
# XXX nvpair_type_is_array() is broken for DATA_TYPE_INT8_ARRAY at the moment
|
||||
# see https://www.illumos.org/issues/5778
|
||||
# is_array = bool(_lib.nvpair_type_is_array(pair))
|
||||
is_array = typeinfo.is_array
|
||||
is_array = bool(_lib.nvpair_type_is_array(pair))
|
||||
cfunc = getattr(_lib, "nvpair_value_%s" % (typeinfo.suffix,), None)
|
||||
val = None
|
||||
ret = 0
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
The package that contains a module per each C library that
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Python bindings for ``libnvpair``.
|
||||
@@ -64,7 +78,8 @@ CDEF = """
|
||||
int nvlist_add_uint64(nvlist_t *, const char *, uint64_t);
|
||||
int nvlist_add_string(nvlist_t *, const char *, const char *);
|
||||
int nvlist_add_nvlist(nvlist_t *, const char *, nvlist_t *);
|
||||
int nvlist_add_boolean_array(nvlist_t *, const char *, boolean_t *, uint_t);
|
||||
int nvlist_add_boolean_array(nvlist_t *, const char *, boolean_t *,
|
||||
uint_t);
|
||||
int nvlist_add_byte_array(nvlist_t *, const char *, uchar_t *, uint_t);
|
||||
int nvlist_add_int8_array(nvlist_t *, const char *, int8_t *, uint_t);
|
||||
int nvlist_add_uint8_array(nvlist_t *, const char *, uint8_t *, uint_t);
|
||||
@@ -74,7 +89,8 @@ CDEF = """
|
||||
int nvlist_add_uint32_array(nvlist_t *, const char *, uint32_t *, uint_t);
|
||||
int nvlist_add_int64_array(nvlist_t *, const char *, int64_t *, uint_t);
|
||||
int nvlist_add_uint64_array(nvlist_t *, const char *, uint64_t *, uint_t);
|
||||
int nvlist_add_string_array(nvlist_t *, const char *, char *const *, uint_t);
|
||||
int nvlist_add_string_array(nvlist_t *, const char *, char *const *,
|
||||
uint_t);
|
||||
int nvlist_add_nvlist_array(nvlist_t *, const char *, nvlist_t **, uint_t);
|
||||
|
||||
nvpair_t *nvlist_next_nvpair(nvlist_t *, nvpair_t *);
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Python bindings for ``libzfs_core``.
|
||||
"""
|
||||
|
||||
CDEF = """
|
||||
|
||||
enum lzc_send_flags {
|
||||
LZC_SEND_FLAG_EMBED_DATA = 1,
|
||||
LZC_SEND_FLAG_LARGE_BLOCK = 2
|
||||
LZC_SEND_FLAG_EMBED_DATA = 1,
|
||||
LZC_SEND_FLAG_LARGE_BLOCK = 2,
|
||||
LZC_SEND_FLAG_COMPRESS = 4,
|
||||
LZC_SEND_FLAG_RAW = 8
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@@ -34,7 +51,7 @@ CDEF = """
|
||||
};
|
||||
|
||||
typedef struct zio_cksum {
|
||||
uint64_t zc_word[4];
|
||||
uint64_t zc_word[4];
|
||||
} zio_cksum_t;
|
||||
|
||||
typedef struct dmu_replay_record {
|
||||
@@ -54,35 +71,63 @@ CDEF = """
|
||||
} drr_u;
|
||||
} dmu_replay_record_t;
|
||||
|
||||
typedef enum {
|
||||
DCP_CMD_NONE,
|
||||
DCP_CMD_RAW_RECV,
|
||||
DCP_CMD_NEW_KEY,
|
||||
DCP_CMD_INHERIT,
|
||||
DCP_CMD_FORCE_NEW_KEY,
|
||||
DCP_CMD_FORCE_INHERIT
|
||||
} dcp_cmd_t;
|
||||
|
||||
int libzfs_core_init(void);
|
||||
void libzfs_core_fini(void);
|
||||
|
||||
int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
|
||||
int lzc_create(const char *, dmu_objset_type_t, nvlist_t *);
|
||||
int lzc_clone(const char *, const char *, nvlist_t *);
|
||||
int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
|
||||
int lzc_bookmark(nvlist_t *, nvlist_t **);
|
||||
int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **);
|
||||
int lzc_change_key(const char *, uint64_t, nvlist_t *, uint8_t *, uint_t);
|
||||
int lzc_channel_program(const char *, const char *, uint64_t, uint64_t,
|
||||
nvlist_t *, nvlist_t **);
|
||||
int lzc_channel_program_nosync(const char *, const char *, uint64_t,
|
||||
uint64_t, nvlist_t *, nvlist_t **);
|
||||
int lzc_clone(const char *, const char *, nvlist_t *);
|
||||
int lzc_create(const char *, dmu_objset_type_t, nvlist_t *, uint8_t *,
|
||||
uint_t);
|
||||
int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **);
|
||||
|
||||
int lzc_snaprange_space(const char *, const char *, uint64_t *);
|
||||
|
||||
int lzc_hold(nvlist_t *, int, nvlist_t **);
|
||||
int lzc_release(nvlist_t *, nvlist_t **);
|
||||
int lzc_get_holds(const char *, nvlist_t **);
|
||||
|
||||
int lzc_send(const char *, const char *, int, enum lzc_send_flags);
|
||||
int lzc_send_space(const char *, const char *, enum lzc_send_flags, uint64_t *);
|
||||
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
|
||||
int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
|
||||
boolean_t, int, const struct dmu_replay_record *);
|
||||
|
||||
int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
|
||||
boolean_t lzc_exists(const char *);
|
||||
|
||||
int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **);
|
||||
int lzc_get_holds(const char *, nvlist_t **);
|
||||
int lzc_hold(nvlist_t *, int, nvlist_t **);
|
||||
int lzc_load_key(const char *, boolean_t, uint8_t *, uint_t);
|
||||
int lzc_promote(const char *, nvlist_t *, nvlist_t **);
|
||||
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t,
|
||||
boolean_t, int);
|
||||
int lzc_receive_one(const char *, nvlist_t *, const char *, boolean_t,
|
||||
boolean_t, boolean_t, int, const dmu_replay_record_t *, int,
|
||||
uint64_t *, uint64_t *, uint64_t *, nvlist_t **);
|
||||
int lzc_receive_resumable(const char *, nvlist_t *, const char *,
|
||||
boolean_t, boolean_t, int);
|
||||
int lzc_receive_with_cmdprops(const char *, nvlist_t *, nvlist_t *,
|
||||
const char *, boolean_t, boolean_t, boolean_t, int,
|
||||
const dmu_replay_record_t *, int, uint64_t *, uint64_t *, uint64_t *,
|
||||
nvlist_t **);
|
||||
int lzc_receive_with_header(const char *, nvlist_t *, const char *,
|
||||
boolean_t, boolean_t, boolean_t, int, const dmu_replay_record_t *);
|
||||
int lzc_release(nvlist_t *, nvlist_t **);
|
||||
int lzc_reopen(const char *, boolean_t);
|
||||
int lzc_rollback(const char *, char *, int);
|
||||
int lzc_rollback_to(const char *, const char *);
|
||||
int lzc_send(const char *, const char *, int, enum lzc_send_flags);
|
||||
int lzc_send_resume(const char *, const char *, int, enum lzc_send_flags,
|
||||
uint64_t, uint64_t);
|
||||
int lzc_send_space(const char *, const char *, enum lzc_send_flags,
|
||||
uint64_t *);
|
||||
int lzc_snaprange_space(const char *, const char *, uint64_t *);
|
||||
int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
|
||||
int lzc_sync(const char *, nvlist_t *, nvlist_t **);
|
||||
int lzc_unload_key(const char *);
|
||||
int lzc_remap(const char *);
|
||||
|
||||
int lzc_promote(const char *, nvlist_t *, nvlist_t **);
|
||||
int lzc_rename(const char *, const char *, nvlist_t *, char **);
|
||||
int lzc_destroy_one(const char *fsname, nvlist_t *);
|
||||
int lzc_inherit(const char *fsname, const char *name, nvlist_t *);
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Utility functions for casting to a specific C type.
|
||||
@@ -25,16 +39,16 @@ def _ffi_cast(type_name):
|
||||
return _func
|
||||
|
||||
|
||||
uint8_t = _ffi_cast('uint8_t')
|
||||
int8_t = _ffi_cast('int8_t')
|
||||
uint16_t = _ffi_cast('uint16_t')
|
||||
int16_t = _ffi_cast('int16_t')
|
||||
uint32_t = _ffi_cast('uint32_t')
|
||||
int32_t = _ffi_cast('int32_t')
|
||||
uint64_t = _ffi_cast('uint64_t')
|
||||
int64_t = _ffi_cast('int64_t')
|
||||
boolean_t = _ffi_cast('boolean_t')
|
||||
uchar_t = _ffi_cast('uchar_t')
|
||||
uint8_t = _ffi_cast('uint8_t')
|
||||
int8_t = _ffi_cast('int8_t')
|
||||
uint16_t = _ffi_cast('uint16_t')
|
||||
int16_t = _ffi_cast('int16_t')
|
||||
uint32_t = _ffi_cast('uint32_t')
|
||||
int32_t = _ffi_cast('int32_t')
|
||||
uint64_t = _ffi_cast('uint64_t')
|
||||
int64_t = _ffi_cast('int64_t')
|
||||
boolean_t = _ffi_cast('boolean_t')
|
||||
uchar_t = _ffi_cast('uchar_t')
|
||||
|
||||
|
||||
# First element of the value tuple is a suffix for a single value function
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Exceptions that can be raised by libzfs_core operations.
|
||||
@@ -14,12 +28,14 @@ class ZFSError(Exception):
|
||||
|
||||
def __str__(self):
|
||||
if self.name is not None:
|
||||
return "[Errno %d] %s: '%s'" % (self.errno, self.message, self.name)
|
||||
return "[Errno %d] %s: '%s'" % (
|
||||
self.errno, self.message, self.name)
|
||||
else:
|
||||
return "[Errno %d] %s" % (self.errno, self.message)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%r, %r)" % (self.__class__.__name__, self.errno, self.message)
|
||||
return "%s(%r, %r)" % (
|
||||
self.__class__.__name__, self.errno, self.message)
|
||||
|
||||
|
||||
class ZFSGenericError(ZFSError):
|
||||
@@ -44,24 +60,25 @@ class MultipleOperationsFailure(ZFSError):
|
||||
# as an overall error code. This is more consistent.
|
||||
self.errno = errors[0].errno
|
||||
self.errors = errors
|
||||
#: this many errors were encountered but not placed on the `errors` list
|
||||
# this many errors were encountered but not placed on the `errors` list
|
||||
self.suppressed_count = suppressed_count
|
||||
|
||||
def __str__(self):
|
||||
return "%s, %d errors included, %d suppressed" % (ZFSError.__str__(self),
|
||||
len(self.errors), self.suppressed_count)
|
||||
return "%s, %d errors included, %d suppressed" % (
|
||||
ZFSError.__str__(self), len(self.errors), self.suppressed_count)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%r, %r, errors=%r, supressed=%r)" % (self.__class__.__name__,
|
||||
self.errno, self.message, self.errors, self.suppressed_count)
|
||||
return "%s(%r, %r, errors=%r, supressed=%r)" % (
|
||||
self.__class__.__name__, self.errno, self.message, self.errors,
|
||||
self.suppressed_count)
|
||||
|
||||
|
||||
class DatasetNotFound(ZFSError):
|
||||
|
||||
"""
|
||||
This exception is raised when an operation failure can be caused by a missing
|
||||
snapshot or a missing filesystem and it is impossible to distinguish between
|
||||
the causes.
|
||||
This exception is raised when an operation failure can be caused by a
|
||||
missing snapshot or a missing filesystem and it is impossible to
|
||||
distinguish between the causes.
|
||||
"""
|
||||
errno = errno.ENOENT
|
||||
message = "Dataset not found"
|
||||
@@ -73,8 +90,8 @@ class DatasetNotFound(ZFSError):
|
||||
class DatasetExists(ZFSError):
|
||||
|
||||
"""
|
||||
This exception is raised when an operation failure can be caused by an existing
|
||||
snapshot or filesystem and it is impossible to distinguish between
|
||||
This exception is raised when an operation failure can be caused by an
|
||||
existing snapshot or filesystem and it is impossible to distinguish between
|
||||
the causes.
|
||||
"""
|
||||
errno = errno.EEXIST
|
||||
@@ -135,6 +152,7 @@ class SnapshotNotFound(DatasetNotFound):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
class SnapshotNotLatest(ZFSError):
|
||||
errno = errno.EEXIST
|
||||
message = "Snapshot is not the latest"
|
||||
@@ -142,6 +160,7 @@ class SnapshotNotLatest(ZFSError):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
class SnapshotIsCloned(ZFSError):
|
||||
errno = errno.EEXIST
|
||||
message = "Snapshot is cloned"
|
||||
@@ -177,7 +196,8 @@ class SnapshotDestructionFailure(MultipleOperationsFailure):
|
||||
message = "Destruction of snapshot(s) failed for one or more reasons"
|
||||
|
||||
def __init__(self, errors, suppressed_count):
|
||||
super(SnapshotDestructionFailure, self).__init__(errors, suppressed_count)
|
||||
super(SnapshotDestructionFailure, self).__init__(
|
||||
errors, suppressed_count)
|
||||
|
||||
|
||||
class BookmarkExists(ZFSError):
|
||||
@@ -223,7 +243,8 @@ class BookmarkDestructionFailure(MultipleOperationsFailure):
|
||||
message = "Destruction of bookmark(s) failed for one or more reasons"
|
||||
|
||||
def __init__(self, errors, suppressed_count):
|
||||
super(BookmarkDestructionFailure, self).__init__(errors, suppressed_count)
|
||||
super(BookmarkDestructionFailure, self).__init__(
|
||||
errors, suppressed_count)
|
||||
|
||||
|
||||
class BadHoldCleanupFD(ZFSError):
|
||||
@@ -286,7 +307,7 @@ class DestinationModified(ZFSError):
|
||||
|
||||
|
||||
class BadStream(ZFSError):
|
||||
errno = errno.EINVAL
|
||||
errno = errno.EBADE
|
||||
message = "Bad backup stream"
|
||||
|
||||
|
||||
@@ -300,6 +321,23 @@ class UnknownStreamFeature(ZFSError):
|
||||
message = "Unknown feature requested for stream"
|
||||
|
||||
|
||||
class StreamFeatureInvalid(ZFSError):
|
||||
errno = errno.EINVAL
|
||||
message = "Kernel modules must be upgraded to receive this stream"
|
||||
|
||||
|
||||
class StreamFeatureIncompatible(ZFSError):
|
||||
errno = errno.EINVAL
|
||||
message = "Incompatible embedded feature with encrypted receive"
|
||||
|
||||
|
||||
class ReceivePropertyFailure(MultipleOperationsFailure):
|
||||
message = "Receiving of properties failed for one or more reasons"
|
||||
|
||||
def __init__(self, errors, suppressed_count):
|
||||
super(ReceivePropertyFailure, self).__init__(errors, suppressed_count)
|
||||
|
||||
|
||||
class StreamIOError(ZFSError):
|
||||
message = "I/O error while writing or reading stream"
|
||||
|
||||
@@ -440,4 +478,73 @@ class DatasetTypeInvalid(ZFSError):
|
||||
self.name = name
|
||||
|
||||
|
||||
class UnknownCryptCommand(ZFSError):
|
||||
errno = errno.EINVAL
|
||||
message = "Specified crypt command is invalid"
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
class EncryptionKeyNotLoaded(ZFSError):
|
||||
errno = errno.EACCES
|
||||
message = "Encryption key is not currently loaded"
|
||||
|
||||
|
||||
class EncryptionKeyAlreadyLoaded(ZFSError):
|
||||
errno = errno.EEXIST
|
||||
message = "Encryption key is already loaded"
|
||||
|
||||
|
||||
class EncryptionKeyInvalid(ZFSError):
|
||||
errno = errno.EACCES
|
||||
message = "Incorrect encryption key provided"
|
||||
|
||||
|
||||
class ZCPError(ZFSError):
|
||||
errno = None
|
||||
message = None
|
||||
|
||||
|
||||
class ZCPSyntaxError(ZCPError):
|
||||
errno = errno.EINVAL
|
||||
message = "Channel program contains syntax errors"
|
||||
|
||||
def __init__(self, details):
|
||||
self.details = details
|
||||
|
||||
|
||||
class ZCPRuntimeError(ZCPError):
|
||||
errno = errno.ECHRNG
|
||||
message = "Channel programs encountered a runtime error"
|
||||
|
||||
def __init__(self, details):
|
||||
self.details = details
|
||||
|
||||
|
||||
class ZCPLimitInvalid(ZCPError):
|
||||
errno = errno.EINVAL
|
||||
message = "Channel program called with invalid limits"
|
||||
|
||||
|
||||
class ZCPTimeout(ZCPError):
|
||||
errno = errno.ETIME
|
||||
message = "Channel program timed out"
|
||||
|
||||
|
||||
class ZCPSpaceError(ZCPError):
|
||||
errno = errno.ENOSPC
|
||||
message = "Channel program exhausted the memory limit"
|
||||
|
||||
|
||||
class ZCPMemoryError(ZCPError):
|
||||
errno = errno.ENOMEM
|
||||
message = "Channel program return value too large"
|
||||
|
||||
|
||||
class ZCPPermissionError(ZCPError):
|
||||
errno = errno.EPERM
|
||||
message = "Channel programs must be run as root"
|
||||
|
||||
|
||||
# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,18 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
"""
|
||||
Tests for _nvlist module.
|
||||
@@ -27,16 +41,21 @@ class TestNVList(unittest.TestCase):
|
||||
return res
|
||||
|
||||
def _assertIntDictsEqual(self, dict1, dict2):
|
||||
self.assertEqual(len(dict1), len(dict1), "resulting dictionary is of different size")
|
||||
self.assertEqual(
|
||||
len(dict1), len(dict1),
|
||||
"resulting dictionary is of different size")
|
||||
for key in dict1.keys():
|
||||
self.assertEqual(int(dict1[key]), int(dict2[key]))
|
||||
|
||||
def _assertIntArrayDictsEqual(self, dict1, dict2):
|
||||
self.assertEqual(len(dict1), len(dict1), "resulting dictionary is of different size")
|
||||
self.assertEqual(
|
||||
len(dict1), len(dict1),
|
||||
"resulting dictionary is of different size")
|
||||
for key in dict1.keys():
|
||||
val1 = dict1[key]
|
||||
val2 = dict2[key]
|
||||
self.assertEqual(len(val1), len(val2), "array values of different sizes")
|
||||
self.assertEqual(
|
||||
len(val1), len(val2), "array values of different sizes")
|
||||
for x, y in zip(val1, val2):
|
||||
self.assertEqual(int(x), int(y))
|
||||
|
||||
@@ -455,7 +474,8 @@ class TestNVList(unittest.TestCase):
|
||||
self._dict_to_nvlist_to_dict(props)
|
||||
|
||||
def test_explict_int64_array(self):
|
||||
props = {"key": [int64_t(0), int64_t(1), int64_t(2 ** 63 - 1), int64_t(-(2 ** 63))]}
|
||||
props = {"key": [
|
||||
int64_t(0), int64_t(1), int64_t(2 ** 63 - 1), int64_t(-(2 ** 63))]}
|
||||
res = self._dict_to_nvlist_to_dict(props)
|
||||
self._assertIntArrayDictsEqual(props, res)
|
||||
|
||||
@@ -470,7 +490,8 @@ class TestNVList(unittest.TestCase):
|
||||
self._dict_to_nvlist_to_dict(props)
|
||||
|
||||
def test_explict_int32_array(self):
|
||||
props = {"key": [int32_t(0), int32_t(1), int32_t(2 ** 31 - 1), int32_t(-(2 ** 31))]}
|
||||
props = {"key": [
|
||||
int32_t(0), int32_t(1), int32_t(2 ** 31 - 1), int32_t(-(2 ** 31))]}
|
||||
res = self._dict_to_nvlist_to_dict(props)
|
||||
self._assertIntArrayDictsEqual(props, res)
|
||||
|
||||
@@ -485,7 +506,8 @@ class TestNVList(unittest.TestCase):
|
||||
self._dict_to_nvlist_to_dict(props)
|
||||
|
||||
def test_explict_int16_array(self):
|
||||
props = {"key": [int16_t(0), int16_t(1), int16_t(2 ** 15 - 1), int16_t(-(2 ** 15))]}
|
||||
props = {"key": [
|
||||
int16_t(0), int16_t(1), int16_t(2 ** 15 - 1), int16_t(-(2 ** 15))]}
|
||||
res = self._dict_to_nvlist_to_dict(props)
|
||||
self._assertIntArrayDictsEqual(props, res)
|
||||
|
||||
@@ -500,7 +522,8 @@ class TestNVList(unittest.TestCase):
|
||||
self._dict_to_nvlist_to_dict(props)
|
||||
|
||||
def test_explict_int8_array(self):
|
||||
props = {"key": [int8_t(0), int8_t(1), int8_t(2 ** 7 - 1), int8_t(-(2 ** 7))]}
|
||||
props = {"key": [
|
||||
int8_t(0), int8_t(1), int8_t(2 ** 7 - 1), int8_t(-(2 ** 7))]}
|
||||
res = self._dict_to_nvlist_to_dict(props)
|
||||
self._assertIntArrayDictsEqual(props, res)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
cffi
|
||||
+17
-2
@@ -1,10 +1,24 @@
|
||||
# Copyright 2015 ClusterHQ. See LICENSE file for details.
|
||||
#
|
||||
# Copyright 2015 ClusterHQ
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="pyzfs",
|
||||
version="0.2.3",
|
||||
version="1.0.0",
|
||||
description="Wrapper for libzfs_core",
|
||||
author="ClusterHQ",
|
||||
author_email="support@clusterhq.com",
|
||||
@@ -33,6 +47,7 @@ setup(
|
||||
setup_requires=[
|
||||
"cffi",
|
||||
],
|
||||
python_requires='>=2.7,<3',
|
||||
zip_safe=False,
|
||||
test_suite="libzfs_core.test",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user