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:
parent
6abf922574
commit
85ce3f4fd1
|
@ -0,0 +1,125 @@
|
|||
dnl #
|
||||
dnl # ZFS_AC_PYTHON_MODULE(module_name, [action-if-true], [action-if-false])
|
||||
dnl #
|
||||
dnl # Checks for Python module. Freely inspired by AX_PYTHON_MODULE
|
||||
dnl # https://www.gnu.org/software/autoconf-archive/ax_python_module.html
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_PYTHON_MODULE],[
|
||||
PYTHON_NAME=`basename $PYTHON`
|
||||
AC_MSG_CHECKING([for $PYTHON_NAME module: $1])
|
||||
$PYTHON -c "import $1" 2>/dev/null
|
||||
if test $? -eq 0;
|
||||
then
|
||||
AC_MSG_RESULT(yes)
|
||||
m4_ifvaln([$2], [$2])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
m4_ifvaln([$3], [$3])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # ZFS_AC_PYTHON_VERSION(version, [action-if-true], [action-if-false])
|
||||
dnl #
|
||||
dnl # Verify Python version
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_PYTHON_VERSION], [
|
||||
AC_MSG_CHECKING([for a version of Python $1])
|
||||
version_check=`$PYTHON -c "import sys; print (sys.version.split()[[0]] $1)"`
|
||||
if test "$version_check" = "True";
|
||||
then
|
||||
AC_MSG_RESULT(yes)
|
||||
m4_ifvaln([$2], [$2])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
m4_ifvaln([$3], [$3])
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_PYZFS], [
|
||||
PYTHON_REQUIRED_VERSION="<= '2.7.x'"
|
||||
|
||||
AC_ARG_ENABLE([pyzfs],
|
||||
AC_HELP_STRING([--enable-pyzfs],
|
||||
[install libzfs_core python bindings @<:@default=check@:>@]),
|
||||
[enable_pyzfs=$enableval],
|
||||
[enable_pyzfs=check])
|
||||
|
||||
AM_PATH_PYTHON([2.7], [], [
|
||||
AS_IF([test ! "x$enable_pyzfs" = xyes], [
|
||||
AC_MSG_ERROR("python >= 2.7 is not installed")
|
||||
], [test ! "x$enable_pyzfs" = xno], [
|
||||
enable_pyzfs=no
|
||||
])
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :])
|
||||
|
||||
dnl #
|
||||
dnl # Python 2.7.x is supported, other versions (3.5) are not yet
|
||||
dnl #
|
||||
AS_IF([test "x$enable_pyzfs" = xcheck], [
|
||||
ZFS_AC_PYTHON_VERSION([$PYTHON_REQUIRED_VERSION], [], [
|
||||
AS_IF([test "x$enable_pyzfs" = xyes], [
|
||||
AC_MSG_ERROR("Python $PYTHON_REQUIRED_VERSION is not available")
|
||||
], [test ! "x$enable_pyzfs" = xno], [
|
||||
enable_pyzfs=no
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # Require python-devel libraries
|
||||
dnl #
|
||||
AS_IF([test "x$enable_pyzfs" = xcheck], [
|
||||
AX_PYTHON_DEVEL([$PYTHON_REQUIRED_VERSION], [
|
||||
AS_IF([test "x$enable_pyzfs" = xyes], [
|
||||
AC_MSG_ERROR("Python development library is not available")
|
||||
], [test ! "x$enable_pyzfs" = xno], [
|
||||
enable_pyzfs=no
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # Python "setuptools" module is required to build and install pyzfs
|
||||
dnl #
|
||||
AS_IF([test "x$enable_pyzfs" = xcheck], [
|
||||
ZFS_AC_PYTHON_MODULE([setuptools], [], [
|
||||
AS_IF([test "x$enable_pyzfs" = xyes], [
|
||||
AC_MSG_ERROR("python-setuptools is not installed")
|
||||
], [test ! "x$enable_pyzfs" = xno], [
|
||||
enable_pyzfs=no
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # Python "cffi" module is required to run pyzfs
|
||||
dnl #
|
||||
AS_IF([test "x$enable_pyzfs" = xcheck], [
|
||||
ZFS_AC_PYTHON_MODULE([cffi], [], [
|
||||
AS_IF([test "x$enable_pyzfs" = xyes], [
|
||||
AC_MSG_ERROR("python-cffi is not installed")
|
||||
], [test ! "x$enable_pyzfs" = xno], [
|
||||
enable_pyzfs=no
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # Set enable_pyzfs to 'yes' if every check passed
|
||||
dnl #
|
||||
AS_IF([test "x$enable_pyzfs" = xcheck], [enable_pyzfs=yes])
|
||||
|
||||
AM_CONDITIONAL([PYZFS_ENABLED], [test x$enable_pyzfs = xyes])
|
||||
AC_SUBST([PYZFS_ENABLED], [$enable_pyzfs])
|
||||
|
||||
AS_IF([test "x$enable_pyzfs" = xyes], [
|
||||
DEFINE_PYZFS='--define "_pyzfs 1"'
|
||||
],[
|
||||
DEFINE_PYZFS=''
|
||||
])
|
||||
AC_SUBST(DEFINE_PYZFS)
|
||||
AC_SUBST(pythonsitedir, [$PYTHON_SITE_PKG])
|
||||
])
|
|
@ -0,0 +1,345 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_python_devel.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PYTHON_DEVEL([version], [action-if-not-found])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
|
||||
# in your configure.ac.
|
||||
#
|
||||
# Note: this is a slightly modified version of the original AX_PYTHON_DEVEL
|
||||
# macro which accepts an additional [action-if-not-found] argument. This
|
||||
# allow to detect if Python development is available without aborting the
|
||||
# configure phase with an hard error in case it is not.
|
||||
#
|
||||
# This macro checks for Python and tries to get the include path to
|
||||
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
|
||||
# variables. It also exports $(PYTHON_EXTRA_LIBS) and
|
||||
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
|
||||
#
|
||||
# You can search for some particular version of Python by passing a
|
||||
# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
|
||||
# note that you *have* to pass also an operator along with the version to
|
||||
# match, and pay special attention to the single quotes surrounding the
|
||||
# version number. Don't use "PYTHON_VERSION" for this: that environment
|
||||
# variable is declared as precious and thus reserved for the end-user.
|
||||
#
|
||||
# This macro should work for all versions of Python >= 2.1.0. As an end
|
||||
# user, you can disable the check for the python version by setting the
|
||||
# PYTHON_NOVERSIONCHECK environment variable to something else than the
|
||||
# empty string.
|
||||
#
|
||||
# If you need to use this macro for an older Python version, please
|
||||
# contact the authors. We're always open for feedback.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
|
||||
# Copyright (c) 2009 Alan W. Irwin
|
||||
# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
|
||||
# Copyright (c) 2009 Andrew Collier
|
||||
# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
|
||||
# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
|
||||
# Copyright (c) 2013 Daniel Mullner <muellner@math.stanford.edu>
|
||||
# Copyright (c) 2018 loli10K <ezomori.nozomu@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 21
|
||||
|
||||
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
|
||||
AC_DEFUN([AX_PYTHON_DEVEL],[
|
||||
#
|
||||
# Allow the use of a (user set) custom python version
|
||||
#
|
||||
AC_ARG_VAR([PYTHON_VERSION],[The installed Python
|
||||
version to use, for example '2.3'. This string
|
||||
will be appended to the Python interpreter
|
||||
canonical name.])
|
||||
|
||||
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
|
||||
if test -z "$PYTHON"; then
|
||||
m4_ifvaln([$2],[$2],[
|
||||
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
|
||||
PYTHON_VERSION=""
|
||||
])
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for a version of Python >= 2.1.0
|
||||
#
|
||||
AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
|
||||
ac_supports_python_ver=`$PYTHON -c "import sys; \
|
||||
ver = sys.version.split ()[[0]]; \
|
||||
print (ver >= '2.1.0')"`
|
||||
if test "$ac_supports_python_ver" != "True"; then
|
||||
if test -z "$PYTHON_NOVERSIONCHECK"; then
|
||||
AC_MSG_RESULT([no])
|
||||
m4_ifvaln([$2],[$2],[
|
||||
AC_MSG_FAILURE([
|
||||
This version of the AC@&t@_PYTHON_DEVEL macro
|
||||
doesn't work properly with versions of Python before
|
||||
2.1.0. You may need to re-run configure, setting the
|
||||
variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
|
||||
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
|
||||
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
|
||||
to something else than an empty string.
|
||||
])
|
||||
])
|
||||
else
|
||||
AC_MSG_RESULT([skip at user request])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
#
|
||||
# if the macro parameter ``version'' is set, honour it
|
||||
#
|
||||
if test -n "$1"; then
|
||||
AC_MSG_CHECKING([for a version of Python $1])
|
||||
ac_supports_python_ver=`$PYTHON -c "import sys; \
|
||||
ver = sys.version.split ()[[0]]; \
|
||||
print (ver $1)"`
|
||||
if test "$ac_supports_python_ver" = "True"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
m4_ifvaln([$2],[$2],[
|
||||
AC_MSG_ERROR([this package requires Python $1.
|
||||
If you have it installed, but it isn't the default Python
|
||||
interpreter in your system path, please pass the PYTHON_VERSION
|
||||
variable to configure. See ``configure --help'' for reference.
|
||||
])
|
||||
PYTHON_VERSION=""
|
||||
])
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Check if you have distutils, else fail
|
||||
#
|
||||
AC_MSG_CHECKING([for the distutils Python package])
|
||||
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
|
||||
if test $? -eq 0; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
m4_ifvaln([$2],[$2],[
|
||||
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||
Please check your Python installation. The error was:
|
||||
$ac_distutils_result])
|
||||
PYTHON_VERSION=""
|
||||
])
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for Python include path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python include path])
|
||||
if test -z "$PYTHON_CPPFLAGS"; then
|
||||
python_path=`$PYTHON -c "import distutils.sysconfig; \
|
||||
print (distutils.sysconfig.get_python_inc ());"`
|
||||
plat_python_path=`$PYTHON -c "import distutils.sysconfig; \
|
||||
print (distutils.sysconfig.get_python_inc (plat_specific=1));"`
|
||||
if test -n "${python_path}"; then
|
||||
if test "${plat_python_path}" != "${python_path}"; then
|
||||
python_path="-I$python_path -I$plat_python_path"
|
||||
else
|
||||
python_path="-I$python_path"
|
||||
fi
|
||||
fi
|
||||
PYTHON_CPPFLAGS=$python_path
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_CPPFLAGS])
|
||||
AC_SUBST([PYTHON_CPPFLAGS])
|
||||
|
||||
#
|
||||
# Check for Python library path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python library path])
|
||||
if test -z "$PYTHON_LIBS"; then
|
||||
# (makes two attempts to ensure we've got a version number
|
||||
# from the interpreter)
|
||||
ac_python_version=`cat<<EOD | $PYTHON -
|
||||
|
||||
# join all versioning strings, on some systems
|
||||
# major/minor numbers could be in different list elements
|
||||
from distutils.sysconfig import *
|
||||
e = get_config_var('VERSION')
|
||||
if e is not None:
|
||||
print(e)
|
||||
EOD`
|
||||
|
||||
if test -z "$ac_python_version"; then
|
||||
if test -n "$PYTHON_VERSION"; then
|
||||
ac_python_version=$PYTHON_VERSION
|
||||
else
|
||||
ac_python_version=`$PYTHON -c "import sys; \
|
||||
print (sys.version[[:3]])"`
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make the versioning information available to the compiler
|
||||
AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
|
||||
[If available, contains the Python version number currently in use.])
|
||||
|
||||
# First, the library directory:
|
||||
ac_python_libdir=`cat<<EOD | $PYTHON -
|
||||
|
||||
# There should be only one
|
||||
import distutils.sysconfig
|
||||
e = distutils.sysconfig.get_config_var('LIBDIR')
|
||||
if e is not None:
|
||||
print (e)
|
||||
EOD`
|
||||
|
||||
# Now, for the library:
|
||||
ac_python_library=`cat<<EOD | $PYTHON -
|
||||
|
||||
import distutils.sysconfig
|
||||
c = distutils.sysconfig.get_config_vars()
|
||||
if 'LDVERSION' in c:
|
||||
print ('python'+c[['LDVERSION']])
|
||||
else:
|
||||
print ('python'+c[['VERSION']])
|
||||
EOD`
|
||||
|
||||
# This small piece shamelessly adapted from PostgreSQL python macro;
|
||||
# credits goes to momjian, I think. I'd like to put the right name
|
||||
# in the credits, if someone can point me in the right direction... ?
|
||||
#
|
||||
if test -n "$ac_python_libdir" -a -n "$ac_python_library"
|
||||
then
|
||||
# use the official shared library
|
||||
ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
|
||||
PYTHON_LIBS="-L$ac_python_libdir -l$ac_python_library"
|
||||
else
|
||||
# old way: use libpython from python_configdir
|
||||
ac_python_libdir=`$PYTHON -c \
|
||||
"from distutils.sysconfig import get_python_lib as f; \
|
||||
import os; \
|
||||
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
|
||||
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
|
||||
fi
|
||||
|
||||
if test -z "PYTHON_LIBS"; then
|
||||
m4_ifvaln([$2],[$2],[
|
||||
AC_MSG_ERROR([
|
||||
Cannot determine location of your Python DSO. Please check it was installed with
|
||||
dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
|
||||
])
|
||||
])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_LIBS])
|
||||
AC_SUBST([PYTHON_LIBS])
|
||||
|
||||
#
|
||||
# Check for site packages
|
||||
#
|
||||
AC_MSG_CHECKING([for Python site-packages path])
|
||||
if test -z "$PYTHON_SITE_PKG"; then
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
|
||||
print (distutils.sysconfig.get_python_lib(0,0));"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||
AC_SUBST([PYTHON_SITE_PKG])
|
||||
|
||||
#
|
||||
# libraries which must be linked in when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra libraries)
|
||||
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
||||
AC_SUBST(PYTHON_EXTRA_LIBS)
|
||||
|
||||
#
|
||||
# linking flags needed when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra linking flags)
|
||||
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
print (conf('LINKFORSHARED'))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||
AC_SUBST(PYTHON_EXTRA_LDFLAGS)
|
||||
|
||||
#
|
||||
# final check to see if everything compiles alright
|
||||
#
|
||||
AC_MSG_CHECKING([consistency of all components of python development environment])
|
||||
# save current global flags
|
||||
ac_save_LIBS="$LIBS"
|
||||
ac_save_LDFLAGS="$LDFLAGS"
|
||||
ac_save_CPPFLAGS="$CPPFLAGS"
|
||||
LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYTHON_EXTRA_LIBS"
|
||||
LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
|
||||
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
|
||||
AC_LANG_PUSH([C])
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_PROGRAM([[#include <Python.h>]],
|
||||
[[Py_Initialize();]])
|
||||
],[pythonexists=yes],[pythonexists=no])
|
||||
AC_LANG_POP([C])
|
||||
# turn back to default flags
|
||||
CPPFLAGS="$ac_save_CPPFLAGS"
|
||||
LIBS="$ac_save_LIBS"
|
||||
LDFLAGS="$ac_save_LDFLAGS"
|
||||
|
||||
AC_MSG_RESULT([$pythonexists])
|
||||
|
||||
if test ! "x$pythonexists" = "xyes"; then
|
||||
m4_ifvaln([$2],[$2],[
|
||||
AC_MSG_FAILURE([
|
||||
Could not link test program to Python. Maybe the main Python library has been
|
||||
installed in some non-standard library path. If so, pass it to configure,
|
||||
via the LIBS environment variable.
|
||||
Example: ./configure LIBS="-L/usr/non-standard-path/python/lib"
|
||||
============================================================================
|
||||
ERROR!
|
||||
You probably have to install the development version of the Python package
|
||||
for your distribution. The exact name of this package varies among them.
|
||||
============================================================================
|
||||
])
|
||||
PYTHON_VERSION=""
|
||||
])
|
||||
fi
|
||||
|
||||
#
|
||||
# all done!
|
||||
#
|
||||
])
|
|
@ -47,6 +47,7 @@ deb-utils: deb-local rpm-utils
|
|||
pkg7=$${name}-test-$${version}.$${arch}.rpm; \
|
||||
pkg8=$${name}-dracut-$${version}.$${arch}.rpm; \
|
||||
pkg9=$${name}-initramfs-$${version}.$${arch}.rpm; \
|
||||
pkg10=pyzfs-$${version}.noarch.rpm; \
|
||||
## Arguments need to be passed to dh_shlibdeps. Alien provides no mechanism
|
||||
## to do this, so we install a shim onto the path which calls the real
|
||||
## dh_shlibdeps with the required arguments.
|
||||
|
@ -62,10 +63,10 @@ deb-utils: deb-local rpm-utils
|
|||
env PATH=$${path_prepend}:$${PATH} \
|
||||
fakeroot $(ALIEN) --bump=0 --scripts --to-deb --target=$$debarch \
|
||||
$$pkg1 $$pkg2 $$pkg3 $$pkg4 $$pkg5 $$pkg6 $$pkg7 \
|
||||
$$pkg8 $$pkg9; \
|
||||
$$pkg8 $$pkg9 $$pkg10; \
|
||||
$(RM) $${path_prepend}/dh_shlibdeps; \
|
||||
rmdir $${path_prepend}; \
|
||||
$(RM) $$pkg1 $$pkg2 $$pkg3 $$pkg4 $$pkg5 $$pkg6 $$pkg7 \
|
||||
$$pkg8 $$pkg9;
|
||||
$$pkg8 $$pkg9 $$pkg10;
|
||||
|
||||
deb: deb-kmod deb-dkms deb-utils
|
||||
|
|
|
@ -103,6 +103,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [
|
|||
ZFS_AC_CONFIG_ALWAYS_CC_ASAN
|
||||
ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD
|
||||
ZFS_AC_CONFIG_ALWAYS_ARCH
|
||||
ZFS_AC_CONFIG_ALWAYS_PYZFS
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_CONFIG], [
|
||||
|
@ -204,6 +205,7 @@ AC_DEFUN([ZFS_AC_RPM], [
|
|||
])
|
||||
RPM_DEFINE_UTIL+=' $(DEFINE_INITRAMFS)'
|
||||
RPM_DEFINE_UTIL+=' $(DEFINE_SYSTEMD)'
|
||||
RPM_DEFINE_UTIL+=' $(DEFINE_PYZFS)'
|
||||
|
||||
dnl # Override default lib directory on Debian/Ubuntu systems. The provided
|
||||
dnl # /usr/lib/rpm/platform/<arch>/macros files do not specify the correct
|
||||
|
|
|
@ -126,6 +126,7 @@ AC_CONFIG_FILES([
|
|||
contrib/initramfs/hooks/Makefile
|
||||
contrib/initramfs/scripts/Makefile
|
||||
contrib/initramfs/scripts/local-top/Makefile
|
||||
contrib/pyzfs/Makefile
|
||||
module/Makefile
|
||||
module/avl/Makefile
|
||||
module/nvpair/Makefile
|
||||
|
@ -288,6 +289,7 @@ AC_CONFIG_FILES([
|
|||
tests/zfs-tests/tests/functional/poolversion/Makefile
|
||||
tests/zfs-tests/tests/functional/privilege/Makefile
|
||||
tests/zfs-tests/tests/functional/projectquota/Makefile
|
||||
tests/zfs-tests/tests/functional/pyzfs/Makefile
|
||||
tests/zfs-tests/tests/functional/quota/Makefile
|
||||
tests/zfs-tests/tests/functional/raidz/Makefile
|
||||
tests/zfs-tests/tests/functional/redundancy/Makefile
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
SUBDIRS = bash_completion.d dracut initramfs
|
||||
DIST_SUBDIRS = bash_completion.d dracut initramfs
|
||||
SUBDIRS = bash_completion.d dracut initramfs pyzfs
|
||||
DIST_SUBDIRS = bash_completion.d dracut initramfs pyzfs
|
||||
|
|
|
@ -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
|
|
@ -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",
|
||||
)
|
||||
|
|
|
@ -1185,7 +1185,7 @@ zfs_crypto_unload_key(zfs_handle_t *zhp)
|
|||
if (keystatus == ZFS_KEYSTATUS_UNAVAILABLE) {
|
||||
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
|
||||
"Key already unloaded for '%s'."), zfs_get_name(zhp));
|
||||
ret = ENOENT;
|
||||
ret = EACCES;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -1198,7 +1198,7 @@ zfs_crypto_unload_key(zfs_handle_t *zhp)
|
|||
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
|
||||
"Permission denied."));
|
||||
break;
|
||||
case ENOENT:
|
||||
case EACCES:
|
||||
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
|
||||
"Key already unloaded for '%s'."),
|
||||
zfs_get_name(zhp));
|
||||
|
|
|
@ -546,6 +546,15 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp)
|
|||
* to contain DRR_WRITE_EMBEDDED records with drr_etype==BP_EMBEDDED_TYPE_DATA,
|
||||
* which the receiving system must support (as indicated by support
|
||||
* for the "embedded_data" feature).
|
||||
*
|
||||
* If "flags" contains LZC_SEND_FLAG_COMPRESS, the stream is generated by using
|
||||
* compressed WRITE records for blocks which are compressed on disk and in
|
||||
* memory. If the lz4_compress feature is active on the sending system, then
|
||||
* the receiving system must have that feature enabled as well.
|
||||
*
|
||||
* If "flags" contains LZC_SEND_FLAG_RAW, the stream is generated, for encrypted
|
||||
* datasets, by sending data exactly as it exists on disk. This allows backups
|
||||
* to be taken even if encryption keys are not currently loaded.
|
||||
*/
|
||||
int
|
||||
lzc_send(const char *snapname, const char *from, int fd,
|
||||
|
@ -1156,9 +1165,9 @@ lzc_channel_program_nosync(const char *pool, const char *program,
|
|||
/*
|
||||
* Performs key management functions
|
||||
*
|
||||
* crypto_cmd should be a value from zfs_ioc_crypto_cmd_t. If the command
|
||||
* specifies to load or change a wrapping key, the key should be specified in
|
||||
* the hidden_args nvlist so that it is not logged
|
||||
* crypto_cmd should be a value from dcp_cmd_t. If the command specifies to
|
||||
* load or change a wrapping key, the key should be specified in the
|
||||
* hidden_args nvlist so that it is not logged.
|
||||
*/
|
||||
int
|
||||
lzc_load_key(const char *fsname, boolean_t noop, uint8_t *wkeydata,
|
||||
|
|
|
@ -1223,7 +1223,7 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
|
|||
* allocated. Rather than adding NULL checks throughout this code
|
||||
* or adding dummy dcp's to all of the callers we simply create a
|
||||
* dummy one here and use that. This zero dcp will have the same
|
||||
* effect as asking for inheritence of all encryption params.
|
||||
* effect as asking for inheritance of all encryption params.
|
||||
*/
|
||||
doca.doca_dcp = (dcp != NULL) ? dcp : &tmp_dcp;
|
||||
|
||||
|
|
|
@ -866,7 +866,7 @@ spa_keystore_unload_wkey_impl(spa_t *spa, uint64_t ddobj)
|
|||
found_wkey = avl_find(&spa->spa_keystore.sk_wkeys,
|
||||
&search_wkey, NULL);
|
||||
if (!found_wkey) {
|
||||
ret = SET_ERROR(ENOENT);
|
||||
ret = SET_ERROR(EACCES);
|
||||
goto error_unlock;
|
||||
} else if (refcount_count(&found_wkey->wk_refcnt) != 0) {
|
||||
ret = SET_ERROR(EBUSY);
|
||||
|
@ -1225,7 +1225,7 @@ spa_keystore_change_key_check(void *arg, dmu_tx_t *tx)
|
|||
if (ret != 0)
|
||||
goto error;
|
||||
|
||||
/* Handle inheritence */
|
||||
/* Handle inheritance */
|
||||
if (dcp->cp_cmd == DCP_CMD_INHERIT ||
|
||||
dcp->cp_cmd == DCP_CMD_FORCE_INHERIT) {
|
||||
/* no other encryption params should be given */
|
||||
|
@ -1757,7 +1757,7 @@ dmu_objset_create_crypt_check(dsl_dir_t *parentdd, dsl_crypto_params_t *dcp)
|
|||
return (SET_ERROR(EOPNOTSUPP));
|
||||
}
|
||||
|
||||
/* handle inheritence */
|
||||
/* handle inheritance */
|
||||
if (dcp->cp_wkey == NULL) {
|
||||
ASSERT3P(parentdd, !=, NULL);
|
||||
|
||||
|
|
|
@ -216,6 +216,26 @@ Requires: dracut
|
|||
This package contains a dracut module used to construct an initramfs
|
||||
image which is ZFS aware.
|
||||
|
||||
%if 0%{?_pyzfs}
|
||||
%package -n pyzfs
|
||||
Summary: Python wrapper for libzfs_core
|
||||
Group: Development/Languages/Python
|
||||
License: Apache-2.0
|
||||
BuildArch: noarch
|
||||
Requires: libzfs2 = %{version}
|
||||
Requires: libnvpair1 = %{version}
|
||||
Requires: libffi
|
||||
Requires: python >= 2.7
|
||||
Requires: python-cffi
|
||||
%if 0%{?rhel}%{?fedora}%{?suse_version}
|
||||
BuildRequires: python-devel
|
||||
BuildRequires: libffi-devel
|
||||
%endif
|
||||
|
||||
%description -n pyzfs
|
||||
This package provides a python wrapper for the libzfs_core C library.
|
||||
%endif
|
||||
|
||||
%if 0%{?_initramfs}
|
||||
%package initramfs
|
||||
Summary: Initramfs module
|
||||
|
@ -383,6 +403,15 @@ systemctl --system daemon-reload >/dev/null || true
|
|||
%doc contrib/dracut/README.dracut.markdown
|
||||
%{_dracutdir}/modules.d/*
|
||||
|
||||
%if 0%{?_pyzfs}
|
||||
%files -n pyzfs
|
||||
%doc contrib/pyzfs/README
|
||||
%doc contrib/pyzfs/LICENSE
|
||||
%defattr(-,root,root,-)
|
||||
%{python_sitelib}/libzfs_core/*
|
||||
%{python_sitelib}/pyzfs*
|
||||
%endif
|
||||
|
||||
%if 0%{?_initramfs}
|
||||
%files initramfs
|
||||
%doc contrib/initramfs/README.initramfs.markdown
|
||||
|
|
|
@ -31,11 +31,14 @@ export ZEDLET_ETC_DIR=$$CMD_DIR/zed/zed.d
|
|||
export ZEDLET_LIBEXEC_DIR=$$CMD_DIR/zed/zed.d
|
||||
export ZPOOL_SCRIPT_DIR=$$CMD_DIR/zpool/zpool.d
|
||||
export ZPOOL_SCRIPTS_PATH=$$CMD_DIR/zpool/zpool.d
|
||||
export CONTRIB_DIR=@abs_top_builddir@/contrib
|
||||
export LIB_DIR=@abs_top_builddir@/lib
|
||||
|
||||
export INSTALL_UDEV_DIR=@udevdir@
|
||||
export INSTALL_UDEV_RULE_DIR=@udevruledir@
|
||||
export INSTALL_MOUNT_HELPER_DIR=@mounthelperdir@
|
||||
export INSTALL_SYSCONF_DIR=@sysconfdir@
|
||||
export INSTALL_PYTHON_DIR=@pythonsitedir@
|
||||
|
||||
export KMOD_SPL=@SPL_OBJ@/module/spl/spl.ko
|
||||
export KMOD_SPLAT=@SPL_OBJ@/module/splat/splat.ko
|
||||
|
|
|
@ -110,6 +110,7 @@ if [ "$VERBOSE" = "yes" ]; then
|
|||
echo "udevruledir: $INSTALL_UDEV_RULE_DIR"
|
||||
echo "mounthelperdir: $INSTALL_MOUNT_HELPER_DIR"
|
||||
echo "sysconfdir: $INSTALL_SYSCONF_DIR"
|
||||
echo "pythonsitedir: $INSTALL_PYTHON_DIR"
|
||||
echo "dryrun: $DRYRUN"
|
||||
echo
|
||||
fi
|
||||
|
@ -165,6 +166,16 @@ if [ "${INSTALL}" = "yes" ]; then
|
|||
"$INSTALL_UDEV_RULE_DIR/90-zfs.rules"
|
||||
install "$CMD_DIR/zpool/zpool.d" \
|
||||
"$INSTALL_SYSCONF_DIR/zfs/zpool.d"
|
||||
install "$CONTRIB_DIR/pyzfs/libzfs_core" \
|
||||
"$INSTALL_PYTHON_DIR/libzfs_core"
|
||||
# Ideally we would install these in the configured ${libdir}, which is
|
||||
# by default "/usr/local/lib and unfortunately not included in the
|
||||
# dynamic linker search path.
|
||||
install "$(find "$LIB_DIR/libzfs_core" -type f -name 'libzfs_core.so*')" \
|
||||
"/lib/libzfs_core.so"
|
||||
install "$(find "$LIB_DIR/libnvpair" -type f -name 'libnvpair.so*')" \
|
||||
"/lib/libnvpair.so"
|
||||
ldconfig
|
||||
else
|
||||
remove "$INSTALL_MOUNT_HELPER_DIR/mount.zfs"
|
||||
remove "$INSTALL_MOUNT_HELPER_DIR/fsck.zfs"
|
||||
|
@ -174,6 +185,10 @@ else
|
|||
remove "$INSTALL_UDEV_RULE_DIR/69-vdev.rules"
|
||||
remove "$INSTALL_UDEV_RULE_DIR/90-zfs.rules"
|
||||
remove "$INSTALL_SYSCONF_DIR/zfs/zpool.d"
|
||||
remove "$INSTALL_PYTHON_DIR/libzfs_core"
|
||||
remove "/lib/libzfs_core.so"
|
||||
remove "/lib/libnvpair.so"
|
||||
ldconfig
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -646,6 +646,12 @@ tests = ['projectid_001_pos', 'projectid_002_pos', 'projectid_003_pos',
|
|||
'projecttree_001_pos', 'projecttree_002_pos', 'projecttree_003_neg' ]
|
||||
tags = ['functional', 'projectquota']
|
||||
|
||||
[tests/functional/pyzfs]
|
||||
tests = ['pyzfs_unittest']
|
||||
pre =
|
||||
post =
|
||||
tags = ['functional', 'pyzfs']
|
||||
|
||||
[tests/functional/quota]
|
||||
tests = ['quota_001_pos', 'quota_002_pos', 'quota_003_pos',
|
||||
'quota_004_pos', 'quota_005_pos', 'quota_006_neg']
|
||||
|
|
|
@ -31,6 +31,7 @@ SUBDIRS = \
|
|||
large_files \
|
||||
largest_pool \
|
||||
libzfs \
|
||||
pyzfs \
|
||||
link_count \
|
||||
migration \
|
||||
mmap \
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/pyzfs
|
||||
|
||||
dist_pkgdata_SCRIPTS = \
|
||||
pyzfs_unittest.ksh
|
|
@ -0,0 +1,52 @@
|
|||
#!/bin/ksh -p
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# Verify the libzfs_core Python test suite can be run successfully
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Run the nvlist and libzfs_core Python unittest
|
||||
# 2. Verify the exit code is 0 (no errors)
|
||||
#
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
# We don't just try to "import libzfs_core" because we want to skip these tests
|
||||
# only if pyzfs was not installed due to missing, build-time, dependencies; if
|
||||
# we cannot load "libzfs_core" due to other reasons, for instance an API/ABI
|
||||
# mismatch, we want to report it.
|
||||
python -c '
|
||||
import pkgutil, sys
|
||||
sys.exit(pkgutil.find_loader("libzfs_core") is None)'
|
||||
if [ $? -eq 1 ]
|
||||
then
|
||||
log_unsupported "libzfs_core not found by Python"
|
||||
fi
|
||||
|
||||
log_assert "Verify the nvlist and libzfs_core Python unittest run successfully"
|
||||
|
||||
# NOTE: don't use log_must() here because it makes output unreadable
|
||||
python -m unittest --verbose \
|
||||
libzfs_core.test.test_nvlist.TestNVList \
|
||||
libzfs_core.test.test_libzfs_core.ZFSTest
|
||||
if [ $? -ne 0 ]; then
|
||||
log_fail "Python unittest completed with errors"
|
||||
fi
|
||||
|
||||
log_pass "Python unittest completed without errors"
|
Loading…
Reference in New Issue