mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-17 06:04:23 +03:00
lvmdbus: Add new daemon.
This commit is contained in:
parent
055c628e38
commit
5987562cf9
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,6 +7,8 @@
|
||||
*.orig
|
||||
*.pc
|
||||
*.pot
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
|
@ -1,5 +1,7 @@
|
||||
Version 2.02.143 -
|
||||
=====================================
|
||||
Add configure --enable-dbus-service for an LVM D-Bus service.
|
||||
Replace configure --enable-python-bindings with python2 and python3 vsns.
|
||||
If PV belongs to some VG and metadata missing, skip it if system ID is used.
|
||||
Automatically change PV header extension to latest version if writing PV/VG.
|
||||
Identify used PVs in pv_attr field by new 'u' character.
|
||||
|
311
aclocal.m4
vendored
311
aclocal.m4
vendored
@ -12,6 +12,63 @@
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PYTHON_MODULE(modname[, fatal, python])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Checks for Python module.
|
||||
#
|
||||
# If fatal is non-empty then absence of a module will trigger an error.
|
||||
# The third parameter can either be "python" for Python 2 or "python3" for
|
||||
# Python 3; defaults to Python 3.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Andrew Collier
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 8
|
||||
|
||||
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
|
||||
AC_DEFUN([AX_PYTHON_MODULE],[
|
||||
if test -z $PYTHON;
|
||||
then
|
||||
if test -z "$3";
|
||||
then
|
||||
PYTHON="python3"
|
||||
else
|
||||
PYTHON="$3"
|
||||
fi
|
||||
fi
|
||||
PYTHON_NAME=`basename $PYTHON`
|
||||
AC_MSG_CHECKING($PYTHON_NAME module: $1)
|
||||
$PYTHON -c "import $1" 2>/dev/null
|
||||
if test $? -eq 0;
|
||||
then
|
||||
AC_MSG_RESULT(yes)
|
||||
eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
eval AS_TR_CPP(HAVE_PYMOD_$1)=no
|
||||
#
|
||||
if test -n "$2"
|
||||
then
|
||||
AC_MSG_ERROR(failed to find required module $1)
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
@ -29,7 +86,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
@ -227,4 +284,256 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])# PKG_CHECK_VAR
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
|
||||
# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# ---------------------------------------------------------------------------
|
||||
# Adds support for distributing Python modules and packages. To
|
||||
# install modules, copy them to $(pythondir), using the python_PYTHON
|
||||
# automake variable. To install a package with the same name as the
|
||||
# automake package, install to $(pkgpythondir), or use the
|
||||
# pkgpython_PYTHON automake variable.
|
||||
#
|
||||
# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
|
||||
# locations to install python extension modules (shared libraries).
|
||||
# Another macro is required to find the appropriate flags to compile
|
||||
# extension modules.
|
||||
#
|
||||
# If your package is configured with a different prefix to python,
|
||||
# users will have to add the install directory to the PYTHONPATH
|
||||
# environment variable, or create a .pth file (see the python
|
||||
# documentation for details).
|
||||
#
|
||||
# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
|
||||
# cause an error if the version of python installed on the system
|
||||
# doesn't meet the requirement. MINIMUM-VERSION should consist of
|
||||
# numbers and dots only.
|
||||
AC_DEFUN([AM_PATH_PYTHON],
|
||||
[
|
||||
dnl Find a Python interpreter. Python versions prior to 2.0 are not
|
||||
dnl supported. (2.0 was released on October 16, 2000).
|
||||
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
|
||||
[python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
|
||||
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
|
||||
|
||||
AC_ARG_VAR([PYTHON], [the Python interpreter])
|
||||
|
||||
m4_if([$1],[],[
|
||||
dnl No version check is needed.
|
||||
# Find any Python interpreter.
|
||||
if test -z "$PYTHON"; then
|
||||
AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
|
||||
fi
|
||||
am_display_PYTHON=python
|
||||
], [
|
||||
dnl A version check is needed.
|
||||
if test -n "$PYTHON"; then
|
||||
# If the user set $PYTHON, use it and don't search something else.
|
||||
AC_MSG_CHECKING([whether $PYTHON version is >= $1])
|
||||
AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Python interpreter is too old])])
|
||||
am_display_PYTHON=$PYTHON
|
||||
else
|
||||
# Otherwise, try each interpreter until we find one that satisfies
|
||||
# VERSION.
|
||||
AC_CACHE_CHECK([for a Python interpreter with version >= $1],
|
||||
[am_cv_pathless_PYTHON],[
|
||||
for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
|
||||
test "$am_cv_pathless_PYTHON" = none && break
|
||||
AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
|
||||
done])
|
||||
# Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
|
||||
if test "$am_cv_pathless_PYTHON" = none; then
|
||||
PYTHON=:
|
||||
else
|
||||
AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
|
||||
fi
|
||||
am_display_PYTHON=$am_cv_pathless_PYTHON
|
||||
fi
|
||||
])
|
||||
|
||||
if test "$PYTHON" = :; then
|
||||
dnl Run any user-specified action, or abort.
|
||||
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
|
||||
else
|
||||
|
||||
dnl Query Python for its version number. Getting [:3] seems to be
|
||||
dnl the best way to do this; it's what "site.py" does in the standard
|
||||
dnl library.
|
||||
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
|
||||
[am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
|
||||
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
|
||||
|
||||
dnl Use the values of $prefix and $exec_prefix for the corresponding
|
||||
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
|
||||
dnl distinct variables so they can be overridden if need be. However,
|
||||
dnl general consensus is that you shouldn't need this ability.
|
||||
|
||||
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
|
||||
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
|
||||
|
||||
dnl At times (like when building shared libraries) you may want
|
||||
dnl to know which OS platform Python thinks this is.
|
||||
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
|
||||
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
|
||||
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
|
||||
|
||||
# Just factor out some code duplication.
|
||||
am_python_setup_sysconfig="\
|
||||
import sys
|
||||
# Prefer sysconfig over distutils.sysconfig, for better compatibility
|
||||
# with python 3.x. See automake bug#10227.
|
||||
try:
|
||||
import sysconfig
|
||||
except ImportError:
|
||||
can_use_sysconfig = 0
|
||||
else:
|
||||
can_use_sysconfig = 1
|
||||
# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs:
|
||||
# <https://github.com/pypa/virtualenv/issues/118>
|
||||
try:
|
||||
from platform import python_implementation
|
||||
if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
|
||||
can_use_sysconfig = 0
|
||||
except ImportError:
|
||||
pass"
|
||||
|
||||
dnl Set up 4 directories:
|
||||
|
||||
dnl pythondir -- where to install python scripts. This is the
|
||||
dnl site-packages directory, not the python standard library
|
||||
dnl directory like in previous automake betas. This behavior
|
||||
dnl is more consistent with lispdir.m4 for example.
|
||||
dnl Query distutils for this directory.
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
|
||||
[am_cv_python_pythondir],
|
||||
[if test "x$prefix" = xNONE
|
||||
then
|
||||
am_py_prefix=$ac_default_prefix
|
||||
else
|
||||
am_py_prefix=$prefix
|
||||
fi
|
||||
am_cv_python_pythondir=`$PYTHON -c "
|
||||
$am_python_setup_sysconfig
|
||||
if can_use_sysconfig:
|
||||
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
|
||||
else:
|
||||
from distutils import sysconfig
|
||||
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
|
||||
sys.stdout.write(sitedir)"`
|
||||
case $am_cv_python_pythondir in
|
||||
$am_py_prefix*)
|
||||
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
|
||||
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
|
||||
;;
|
||||
*)
|
||||
case $am_py_prefix in
|
||||
/usr|/System*) ;;
|
||||
*)
|
||||
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
])
|
||||
AC_SUBST([pythondir], [$am_cv_python_pythondir])
|
||||
|
||||
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
|
||||
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
|
||||
dnl more consistent with the rest of automake.
|
||||
|
||||
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
|
||||
|
||||
dnl pyexecdir -- directory for installing python extension modules
|
||||
dnl (shared libraries)
|
||||
dnl Query distutils for this directory.
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
|
||||
[am_cv_python_pyexecdir],
|
||||
[if test "x$exec_prefix" = xNONE
|
||||
then
|
||||
am_py_exec_prefix=$am_py_prefix
|
||||
else
|
||||
am_py_exec_prefix=$exec_prefix
|
||||
fi
|
||||
am_cv_python_pyexecdir=`$PYTHON -c "
|
||||
$am_python_setup_sysconfig
|
||||
if can_use_sysconfig:
|
||||
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
|
||||
else:
|
||||
from distutils import sysconfig
|
||||
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
|
||||
sys.stdout.write(sitedir)"`
|
||||
case $am_cv_python_pyexecdir in
|
||||
$am_py_exec_prefix*)
|
||||
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
|
||||
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
|
||||
;;
|
||||
*)
|
||||
case $am_py_exec_prefix in
|
||||
/usr|/System*) ;;
|
||||
*)
|
||||
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
])
|
||||
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
|
||||
|
||||
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
|
||||
|
||||
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
|
||||
|
||||
dnl Run any user-specified action.
|
||||
$2
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
|
||||
# ---------------------------------------------------------------------------
|
||||
# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
|
||||
# Run ACTION-IF-FALSE otherwise.
|
||||
# This test uses sys.hexversion instead of the string equivalent (first
|
||||
# word of sys.version), in order to cope with versions such as 2.2c1.
|
||||
# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
|
||||
AC_DEFUN([AM_PYTHON_CHECK_VERSION],
|
||||
[prog="import sys
|
||||
# split strings by '.' and convert to numeric. Append some zeros
|
||||
# because we need at least 4 digits for the hex conversion.
|
||||
# map returns an iterator in Python 3.0 and a list in 2.x
|
||||
minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]]
|
||||
minverhex = 0
|
||||
# xrange is not present in Python 3.0 and range returns an iterator
|
||||
for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
|
||||
sys.exit(sys.hexversion < minverhex)"
|
||||
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_RUN_LOG(COMMAND)
|
||||
# -------------------
|
||||
# Run COMMAND, save the exit status in ac_status, and log it.
|
||||
# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
|
||||
AC_DEFUN([AM_RUN_LOG],
|
||||
[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
|
||||
($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
|
||||
(exit $ac_status); }])
|
||||
|
||||
m4_include([acinclude.m4])
|
||||
|
170
autoconf/py-compile
Normal file
170
autoconf/py-compile
Normal file
@ -0,0 +1,170 @@
|
||||
#!/bin/sh
|
||||
# py-compile - Compile a Python program
|
||||
|
||||
scriptversion=2011-06-08.12; # UTC
|
||||
|
||||
# Copyright (C) 2000-2014 Free Software Foundation, Inc.
|
||||
|
||||
# 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 2, 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
if [ -z "$PYTHON" ]; then
|
||||
PYTHON=python
|
||||
fi
|
||||
|
||||
me=py-compile
|
||||
|
||||
usage_error ()
|
||||
{
|
||||
echo "$me: $*" >&2
|
||||
echo "Try '$me --help' for more information." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
basedir=
|
||||
destdir=
|
||||
while test $# -ne 0; do
|
||||
case "$1" in
|
||||
--basedir)
|
||||
if test $# -lt 2; then
|
||||
usage_error "option '--basedir' requires an argument"
|
||||
else
|
||||
basedir=$2
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
--destdir)
|
||||
if test $# -lt 2; then
|
||||
usage_error "option '--destdir' requires an argument"
|
||||
else
|
||||
destdir=$2
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
cat <<\EOF
|
||||
Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
|
||||
|
||||
Byte compile some python scripts FILES. Use --destdir to specify any
|
||||
leading directory path to the FILES that you don't want to include in the
|
||||
byte compiled file. Specify --basedir for any additional path information you
|
||||
do want to be shown in the byte compiled file.
|
||||
|
||||
Example:
|
||||
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v|--version)
|
||||
echo "$me $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
usage_error "unrecognized option '$1'"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
files=$*
|
||||
if test -z "$files"; then
|
||||
usage_error "no files given"
|
||||
fi
|
||||
|
||||
# if basedir was given, then it should be prepended to filenames before
|
||||
# byte compilation.
|
||||
if [ -z "$basedir" ]; then
|
||||
pathtrans="path = file"
|
||||
else
|
||||
pathtrans="path = os.path.join('$basedir', file)"
|
||||
fi
|
||||
|
||||
# if destdir was given, then it needs to be prepended to the filename to
|
||||
# byte compile but not go into the compiled file.
|
||||
if [ -z "$destdir" ]; then
|
||||
filetrans="filepath = path"
|
||||
else
|
||||
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
|
||||
fi
|
||||
|
||||
$PYTHON -c "
|
||||
import sys, os, py_compile, imp
|
||||
|
||||
files = '''$files'''
|
||||
|
||||
sys.stdout.write('Byte-compiling python modules...\n')
|
||||
for file in files.split():
|
||||
$pathtrans
|
||||
$filetrans
|
||||
if not os.path.exists(filepath) or not (len(filepath) >= 3
|
||||
and filepath[-3:] == '.py'):
|
||||
continue
|
||||
sys.stdout.write(file)
|
||||
sys.stdout.flush()
|
||||
if hasattr(imp, 'get_tag'):
|
||||
py_compile.compile(filepath, imp.cache_from_source(filepath), path)
|
||||
else:
|
||||
py_compile.compile(filepath, filepath + 'c', path)
|
||||
sys.stdout.write('\n')" || exit $?
|
||||
|
||||
# this will fail for python < 1.5, but that doesn't matter ...
|
||||
$PYTHON -O -c "
|
||||
import sys, os, py_compile, imp
|
||||
|
||||
# pypy does not use .pyo optimization
|
||||
if hasattr(sys, 'pypy_translation_info'):
|
||||
sys.exit(0)
|
||||
|
||||
files = '''$files'''
|
||||
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
|
||||
for file in files.split():
|
||||
$pathtrans
|
||||
$filetrans
|
||||
if not os.path.exists(filepath) or not (len(filepath) >= 3
|
||||
and filepath[-3:] == '.py'):
|
||||
continue
|
||||
sys.stdout.write(file)
|
||||
sys.stdout.flush()
|
||||
if hasattr(imp, 'get_tag'):
|
||||
py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
|
||||
else:
|
||||
py_compile.compile(filepath, filepath + 'o', path)
|
||||
sys.stdout.write('\n')" 2>/dev/null || :
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
90
configure.in
90
configure.in
@ -1,6 +1,6 @@
|
||||
###############################################################################
|
||||
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
||||
## Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
## Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
##
|
||||
## This copyrighted material is made available to anyone wishing to use,
|
||||
## modify, copy, or redistribute it subject to the terms and conditions
|
||||
@ -11,7 +11,7 @@
|
||||
## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
################################################################################
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_PREREQ(2.69)
|
||||
################################################################################
|
||||
dnl -- Process this file with autoconf to produce a configure script.
|
||||
AC_INIT
|
||||
@ -85,6 +85,7 @@ AC_PROG_MKDIR_P
|
||||
AC_PROG_RANLIB
|
||||
AC_PATH_TOOL(CFLOW_CMD, cflow)
|
||||
AC_PATH_TOOL(CSCOPE_CMD, cscope)
|
||||
AC_PATH_TOOL(CHMOD, chmod)
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for header files.
|
||||
@ -1437,25 +1438,75 @@ test "$CMDLIB" = yes \
|
||||
&& LVM2CMD_LIB=-llvm2cmd \
|
||||
|| LVM2CMD_LIB=
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable D-Bus service
|
||||
AC_MSG_CHECKING(whether to include Python D-Bus support)
|
||||
AC_ARG_ENABLE(dbus-service,
|
||||
AC_HELP_STRING([--enable-dbus-service], [install D-Bus support]),
|
||||
BUILD_LVMDBUSD=$enableval, BUILD_LVMDBUSD=no)
|
||||
AC_MSG_RESULT($BUILD_LVMDBUSD)
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable Python liblvm2app bindings
|
||||
AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python_bindings,
|
||||
AC_HELP_STRING([--enable-python_bindings], [build Python applib bindings]),
|
||||
AC_HELP_STRING([--enable-python_bindings], [build default Python applib bindings]),
|
||||
PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON_BINDINGS)
|
||||
|
||||
AC_MSG_CHECKING(whether to build Python2 wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python2_bindings,
|
||||
AC_HELP_STRING([--enable-python2_bindings], [build Python2 applib bindings]),
|
||||
PYTHON2_BINDINGS=$enableval, PYTHON2_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON2_BINDINGS)
|
||||
|
||||
|
||||
AC_MSG_CHECKING(whether to build Python3 wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python3_bindings,
|
||||
AC_HELP_STRING([--enable-python3_bindings], [build Python3 applib bindings]),
|
||||
PYTHON3_BINDINGS=$enableval, PYTHON3_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON3_BINDINGS)
|
||||
|
||||
if test "$PYTHON_BINDINGS" = yes; then
|
||||
test "$APPLIB" != yes && AC_MSG_ERROR([--enable-python_bindings requires --enable-applib])
|
||||
AC_MSG_ERROR([--enable-python-bindings is replaced by --enable-python2-bindings and --enable-python3-bindings])
|
||||
fi
|
||||
|
||||
AC_PATH_TOOL(PYTHON, python)
|
||||
test -z "$PYTHON" && AC_MSG_ERROR([python is required for --enable-python_bindings but cannot be found])
|
||||
if test "$PYTHON2_BINDINGS" = yes; then
|
||||
AM_PATH_PYTHON([2])
|
||||
AC_PATH_TOOL(PYTHON2, python2)
|
||||
test -z "$PYTHON2" && AC_MSG_ERROR([python2 is required for --enable-python2_bindings but cannot be found])
|
||||
AC_PATH_TOOL(PYTHON2_CONFIG, python2-config)
|
||||
test -z "$PYTHON2_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python2_bindings but cannot be found])
|
||||
PYTHON2_INCDIRS=`"$PYTHON2_CONFIG" --includes`
|
||||
PYTHON2_LIBDIRS=`"$PYTHON2_CONFIG" --libs`
|
||||
PYTHON2DIR=$pythondir
|
||||
PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
|
||||
unset PYTHON PYTHON_CONFIG
|
||||
unset am_cv_pathless_PYTHON ac_cv_path_PYTHON am_cv_python_platform
|
||||
unset am_cv_python_pythondir am_cv_python_version am_cv_python_pyexecdir
|
||||
unset ac_cv_path_PYTHON_CONFIG ac_cv_path_ac_pt_PYTHON_CONFIG
|
||||
AM_PATH_PYTHON([3])
|
||||
PYTHON3=$PYTHON
|
||||
test -z "$PYTHON3" && AC_MSG_ERROR([python3 is required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
|
||||
AC_PATH_TOOL(PYTHON3_CONFIG, python3-config)
|
||||
test -z "$PYTHON3_CONFIG" && AC_MSG_ERROR([python3 headers are required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
|
||||
PYTHON3_INCDIRS=`"$PYTHON3_CONFIG" --includes`
|
||||
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
|
||||
PYTHON3DIR=$pythondir
|
||||
PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
AC_PATH_TOOL(PYTHON_CONFIG, python-config)
|
||||
test -z "$PYTHON_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python_bindings but cannot be found])
|
||||
if test "$BUILD_LVMDBUSD" = yes; then
|
||||
# To get this macro, install autoconf-archive package then run autoreconf
|
||||
AC_PYTHON_MODULE([pyudev], [Required], python3)
|
||||
AC_PYTHON_MODULE([dbus], [Required], python3)
|
||||
fi
|
||||
|
||||
PYTHON_INCDIRS=`"$PYTHON_CONFIG" --includes`
|
||||
PYTHON_LIBDIRS=`"$PYTHON_CONFIG" --libs`
|
||||
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
|
||||
test "$APPLIB" != yes && AC_MSG_ERROR([Python_bindings require --enable-applib])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@ -1907,6 +1958,7 @@ AC_SUBST(AWK)
|
||||
AC_SUBST(BLKID_PC)
|
||||
AC_SUBST(BUILD_CMIRRORD)
|
||||
AC_SUBST(BUILD_DMEVENTD)
|
||||
AC_SUBST(BUILD_LVMDBUSD)
|
||||
AC_SUBST(BUILD_LVMETAD)
|
||||
AC_SUBST(BUILD_LVMPOLLD)
|
||||
AC_SUBST(BUILD_LVMLOCKD)
|
||||
@ -1915,6 +1967,7 @@ AC_SUBST(BUILD_LOCKDDLM)
|
||||
AC_SUBST(CACHE)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CFLOW_CMD)
|
||||
AC_SUBST(CHMOD)
|
||||
AC_SUBST(CLDFLAGS)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(CLDWHOLEARCHIVE)
|
||||
@ -1991,10 +2044,17 @@ AC_SUBST(PKGCONFIG)
|
||||
AC_SUBST(POOL)
|
||||
AC_SUBST(M_LIBS)
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PYTHON)
|
||||
AC_SUBST(PYTHON2)
|
||||
AC_SUBST(PYTHON3)
|
||||
AC_SUBST(PYTHON_BINDINGS)
|
||||
AC_SUBST(PYTHON_INCDIRS)
|
||||
AC_SUBST(PYTHON_LIBDIRS)
|
||||
AC_SUBST(PYTHON2_BINDINGS)
|
||||
AC_SUBST(PYTHON3_BINDINGS)
|
||||
AC_SUBST(PYTHON2_INCDIRS)
|
||||
AC_SUBST(PYTHON3_INCDIRS)
|
||||
AC_SUBST(PYTHON2_LIBDIRS)
|
||||
AC_SUBST(PYTHON3_LIBDIRS)
|
||||
AC_SUBST(PYTHON2DIR)
|
||||
AC_SUBST(PYTHON3DIR)
|
||||
AC_SUBST(QUORUM_CFLAGS)
|
||||
AC_SUBST(QUORUM_LIBS)
|
||||
AC_SUBST(RAID)
|
||||
@ -2066,6 +2126,8 @@ daemons/dmeventd/plugins/raid/Makefile
|
||||
daemons/dmeventd/plugins/mirror/Makefile
|
||||
daemons/dmeventd/plugins/snapshot/Makefile
|
||||
daemons/dmeventd/plugins/thin/Makefile
|
||||
daemons/lvmdbusd/Makefile
|
||||
daemons/lvmdbusd/path.py
|
||||
daemons/lvmetad/Makefile
|
||||
daemons/lvmpolld/Makefile
|
||||
daemons/lvmlockd/Makefile
|
||||
@ -2103,12 +2165,14 @@ scripts/blk_availability_init_red_hat
|
||||
scripts/blk_availability_systemd_red_hat.service
|
||||
scripts/clvmd_init_red_hat
|
||||
scripts/cmirrord_init_red_hat
|
||||
scripts/com.redhat.lvmdbus1.service
|
||||
scripts/dm_event_systemd_red_hat.service
|
||||
scripts/dm_event_systemd_red_hat.socket
|
||||
scripts/lvm2_cluster_activation_red_hat.sh
|
||||
scripts/lvm2_cluster_activation_systemd_red_hat.service
|
||||
scripts/lvm2_clvmd_systemd_red_hat.service
|
||||
scripts/lvm2_cmirrord_systemd_red_hat.service
|
||||
scripts/lvm2_lvmdbusd_systemd_red_hat.service
|
||||
scripts/lvm2_lvmetad_init_red_hat
|
||||
scripts/lvm2_lvmetad_systemd_red_hat.service
|
||||
scripts/lvm2_lvmetad_systemd_red_hat.socket
|
||||
|
@ -44,8 +44,12 @@ ifeq ("@BUILD_LVMLOCKD@", "yes")
|
||||
SUBDIRS += lvmlockd
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMDBUSD@", "yes")
|
||||
SUBDIRS += lvmdbusd
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd
|
||||
endif
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
65
daemons/lvmdbusd/Makefile.in
Normal file
65
daemons/lvmdbusd/Makefile.in
Normal file
@ -0,0 +1,65 @@
|
||||
#
|
||||
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
lvmdbusdir = $(python3dir)/lvmdbus
|
||||
|
||||
LVMDBUS_SRCDIR_FILES = \
|
||||
automatedproperties.py \
|
||||
background.py \
|
||||
cfg.py \
|
||||
cmdhandler.py \
|
||||
fetch.py \
|
||||
__init__.py \
|
||||
job.py \
|
||||
loader.py \
|
||||
lvmdb.py \
|
||||
lvmdbus.py \
|
||||
lvm_shell_proxy.py \
|
||||
lv.py \
|
||||
manager.py \
|
||||
objectmanager.py \
|
||||
pv.py \
|
||||
refresh.py \
|
||||
request.py \
|
||||
state.py \
|
||||
udevwatch.py \
|
||||
utils.py \
|
||||
vg.py
|
||||
|
||||
LVMDBUS_BUILDDIR_FILES = \
|
||||
path.py
|
||||
|
||||
LVMDBUSD = $(srcdir)/lvmdbusd
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
.PHONY: install_lvmdbusd
|
||||
|
||||
install_lvmdbusd:
|
||||
$(INSTALL_DIR) $(sbindir)
|
||||
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||
$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
|
||||
(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
|
||||
$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
|
||||
PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||
$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
|
||||
$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.pyc $(DESTDIR)$(lvmdbusdir)/__pycache__/*.pyo
|
||||
|
||||
install_lvm2: install_lvmdbusd
|
||||
|
||||
install: install_lvm2
|
||||
|
10
daemons/lvmdbusd/__init__.py
Normal file
10
daemons/lvmdbusd/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .lvmdbus import main
|
175
daemons/lvmdbusd/automatedproperties.py
Normal file
175
daemons/lvmdbusd/automatedproperties.py
Normal file
@ -0,0 +1,175 @@
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import dbus
|
||||
from . import cfg
|
||||
from .utils import get_properties, add_properties, get_object_property_diff, \
|
||||
log_debug
|
||||
from .state import State
|
||||
|
||||
|
||||
# noinspection PyPep8Naming,PyUnresolvedReferences
|
||||
class AutomatedProperties(dbus.service.Object):
|
||||
"""
|
||||
This class implements the needed interfaces for:
|
||||
org.freedesktop.DBus.Properties
|
||||
|
||||
Other classes inherit from it to get the same behavior
|
||||
"""
|
||||
|
||||
def __init__(self, object_path, search_method=None):
|
||||
dbus.service.Object.__init__(self, cfg.bus, object_path)
|
||||
self._ap_interface = []
|
||||
self._ap_o_path = object_path
|
||||
self._ap_search_method = search_method
|
||||
self.state = None
|
||||
|
||||
def dbus_object_path(self):
|
||||
return self._ap_o_path
|
||||
|
||||
def emit_data(self):
|
||||
props = {}
|
||||
|
||||
for i in self.interface():
|
||||
props[i] = self.GetAll(i)
|
||||
|
||||
return self._ap_o_path, props
|
||||
|
||||
def set_interface(self, interface):
|
||||
"""
|
||||
With inheritance we can't easily tell what interfaces a class provides
|
||||
so we will have each class that implements an interface tell the
|
||||
base AutomatedProperties what it is they do provide. This is kind of
|
||||
clunky and perhaps we can figure out a better way to do this later.
|
||||
:param interface: An interface the object supports
|
||||
:return:
|
||||
"""
|
||||
if interface not in self._ap_interface:
|
||||
self._ap_interface.append(interface)
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def interface(self, all_interfaces=False):
|
||||
if all_interfaces:
|
||||
cpy = list(self._ap_interface)
|
||||
cpy.extend(
|
||||
["org.freedesktop.DBus.Introspectable",
|
||||
"org.freedesktop.DBus.Properties"])
|
||||
return cpy
|
||||
|
||||
return self._ap_interface
|
||||
|
||||
# Properties
|
||||
# noinspection PyUnusedLocal
|
||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
in_signature='ss', out_signature='v')
|
||||
def Get(self, interface_name, property_name):
|
||||
value = getattr(self, property_name)
|
||||
# Note: If we get an exception in this handler we won't know about it,
|
||||
# only the side effect of no returned value!
|
||||
log_debug('Get (%s), type (%s), value(%s)' %
|
||||
(property_name, str(type(value)), str(value)))
|
||||
return value
|
||||
|
||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
in_signature='s', out_signature='a{sv}')
|
||||
def GetAll(self, interface_name):
|
||||
if interface_name in self.interface(True):
|
||||
# Using introspection, lets build this dynamically
|
||||
properties = get_properties(self)
|
||||
if interface_name in properties:
|
||||
return properties[interface_name][1]
|
||||
return {}
|
||||
raise dbus.exceptions.DBusException(
|
||||
self._ap_interface,
|
||||
'The object %s does not implement the %s interface'
|
||||
% (self.__class__, interface_name))
|
||||
|
||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
in_signature='ssv')
|
||||
def Set(self, interface_name, property_name, new_value):
|
||||
setattr(self, property_name, new_value)
|
||||
self.PropertiesChanged(interface_name,
|
||||
{property_name: new_value}, [])
|
||||
|
||||
# As dbus-python does not support introspection for properties we will
|
||||
# get the autogenerated xml and then add our wanted properties to it.
|
||||
@dbus.service.method(dbus_interface=dbus.INTROSPECTABLE_IFACE,
|
||||
out_signature='s')
|
||||
def Introspect(self):
|
||||
r = dbus.service.Object.Introspect(self, self._ap_o_path, cfg.bus)
|
||||
# Look at the properties in the class
|
||||
props = get_properties(self)
|
||||
|
||||
for int_f, v in props.items():
|
||||
r = add_properties(r, int_f, v[0])
|
||||
|
||||
return r
|
||||
|
||||
@dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
signature='sa{sv}as')
|
||||
def PropertiesChanged(self, interface_name, changed_properties,
|
||||
invalidated_properties):
|
||||
log_debug(('SIGNAL: PropertiesChanged(%s, %s, %s, %s)' %
|
||||
(str(self._ap_o_path), str(interface_name),
|
||||
str(changed_properties), str(invalidated_properties))))
|
||||
|
||||
def refresh(self, search_key=None, object_state=None):
|
||||
"""
|
||||
Take the values (properties) of an object and update them with what
|
||||
lvm currently has. You can either fetch the new ones or supply the
|
||||
new state to be updated with
|
||||
:param search_key: The value to use to search for
|
||||
:param object_state: Use this as the new object state
|
||||
"""
|
||||
num_changed = 0
|
||||
|
||||
# If we can't do a lookup, bail now, this happens if we blindly walk
|
||||
# through all dbus objects as some don't have a search method, like
|
||||
# 'Manager' object.
|
||||
if not self._ap_search_method:
|
||||
return
|
||||
|
||||
search = self.lvm_id
|
||||
if search_key:
|
||||
search = search_key
|
||||
|
||||
# Either we have the new object state or we need to go fetch it
|
||||
if object_state:
|
||||
new_state = object_state
|
||||
else:
|
||||
new_state = self._ap_search_method([search])[0]
|
||||
assert isinstance(new_state, State)
|
||||
|
||||
assert new_state
|
||||
|
||||
# When we refresh an object the object identifiers might have changed
|
||||
# because LVM allows the user to change them (name & uuid), thus if
|
||||
# they have changed we need to update the object manager so that
|
||||
# look-ups will happen correctly
|
||||
old_id = self.state.identifiers()
|
||||
new_id = new_state.identifiers()
|
||||
if old_id[0] != new_id[0] or old_id[1] != new_id[1]:
|
||||
cfg.om.lookup_update(self, new_id[0], new_id[1])
|
||||
|
||||
# Grab the properties values, then replace the state of the object
|
||||
# and retrieve the new values
|
||||
# TODO: We need to add locking to prevent concurrent access to the
|
||||
# properties so that a client is not accessing while we are
|
||||
# replacing.
|
||||
o_prop = get_properties(self)
|
||||
self.state = new_state
|
||||
n_prop = get_properties(self)
|
||||
|
||||
changed = get_object_property_diff(o_prop, n_prop)
|
||||
|
||||
if changed:
|
||||
for int_f, v in changed.items():
|
||||
self.PropertiesChanged(int_f, v, [])
|
||||
num_changed += 1
|
||||
return num_changed
|
195
daemons/lvmdbusd/background.py
Normal file
195
daemons/lvmdbusd/background.py
Normal file
@ -0,0 +1,195 @@
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import threading
|
||||
import subprocess
|
||||
from . import cfg
|
||||
import time
|
||||
from .cmdhandler import options_to_cli_args
|
||||
import dbus
|
||||
from .job import Job, JobState
|
||||
from .utils import pv_range_append, pv_dest_ranges
|
||||
from .request import RequestEntry
|
||||
|
||||
_rlock = threading.RLock()
|
||||
_thread_list = list()
|
||||
|
||||
|
||||
def pv_move_lv_cmd(move_options, lv_full_name,
|
||||
pv_source, pv_source_range, pv_dest_range_list):
|
||||
cmd = ['pvmove', '-i', '1']
|
||||
cmd.extend(options_to_cli_args(move_options))
|
||||
|
||||
if lv_full_name:
|
||||
cmd.extend(['-n', lv_full_name])
|
||||
|
||||
pv_range_append(cmd, pv_source, *pv_source_range)
|
||||
pv_dest_ranges(cmd, pv_dest_range_list)
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
def lv_merge_cmd(merge_options, lv_full_name):
|
||||
cmd = ['lvconvert', '--merge', '-i', '1']
|
||||
cmd.extend(options_to_cli_args(merge_options))
|
||||
cmd.append(lv_full_name)
|
||||
return cmd
|
||||
|
||||
|
||||
def _create_background_dbus_job(job_state):
|
||||
job_obj = Job(None, job_state)
|
||||
cfg.om.register_object(job_obj)
|
||||
return job_obj.dbus_object_path()
|
||||
|
||||
|
||||
def _move_merge(interface_name, cmd, time_out, skip_first_line=False):
|
||||
# Create job object to be used while running the command
|
||||
rc = '/'
|
||||
job_state = JobState(None)
|
||||
add(cmd, job_state, skip_first_line)
|
||||
|
||||
if time_out == -1:
|
||||
# Waiting forever
|
||||
done = job_state.Wait(time_out)
|
||||
if not done:
|
||||
ec, err_msg = job_state.GetError
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'Exit code %s, stderr = %s' % (str(ec), err_msg))
|
||||
elif time_out == 0:
|
||||
# Immediately create and return a job
|
||||
rc = _create_background_dbus_job(job_state)
|
||||
else:
|
||||
# Willing to wait for a bit
|
||||
done = job_state.Wait(time_out)
|
||||
if not done:
|
||||
rc = _create_background_dbus_job(job_state)
|
||||
|
||||
return rc
|
||||
|
||||
|
||||
def move(interface_name, lv_name, pv_src_obj, pv_source_range,
|
||||
pv_dests_and_ranges, move_options, time_out):
|
||||
"""
|
||||
Common code for the pvmove handling.
|
||||
:param interface_name: What dbus interface we are providing for
|
||||
:param lv_name: Optional (None or name of LV to move)
|
||||
:param pv_src_obj: dbus object patch for source PV
|
||||
:param pv_source_range: (0,0 to ignore, else start, end segments)
|
||||
:param pv_dests_and_ranges: Array of PV object paths and start/end segs
|
||||
:param move_options: Hash with optional arguments
|
||||
:param time_out:
|
||||
:return: Object path to job object
|
||||
"""
|
||||
pv_dests = []
|
||||
pv_src = cfg.om.get_object_by_path(pv_src_obj)
|
||||
if pv_src:
|
||||
|
||||
# Check to see if we are handling a move to a specific
|
||||
# destination(s)
|
||||
if len(pv_dests_and_ranges):
|
||||
for pr in pv_dests_and_ranges:
|
||||
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
|
||||
if not pv_dbus_obj:
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'PV Destination (%s) not found' % pr[0])
|
||||
|
||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||
|
||||
# Generate the command line for this command, but don't
|
||||
# execute it.
|
||||
cmd = pv_move_lv_cmd(move_options,
|
||||
lv_name,
|
||||
pv_src.lvm_id,
|
||||
pv_source_range,
|
||||
pv_dests)
|
||||
|
||||
return _move_merge(interface_name, cmd, time_out)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name, 'pv_src_obj (%s) not found' % pv_src_obj)
|
||||
|
||||
|
||||
def merge(interface_name, lv_uuid, lv_name, merge_options, time_out):
|
||||
# Make sure we have a dbus object representing it
|
||||
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
|
||||
if dbo:
|
||||
cmd = lv_merge_cmd(merge_options, dbo.lvm_id)
|
||||
return _move_merge(interface_name, cmd, time_out, True)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
|
||||
|
||||
|
||||
def background_reaper():
|
||||
while cfg.run.value != 0:
|
||||
with _rlock:
|
||||
num_threads = len(_thread_list) - 1
|
||||
if num_threads >= 0:
|
||||
for i in range(num_threads, -1, -1):
|
||||
_thread_list[i].join(0)
|
||||
if not _thread_list[i].is_alive():
|
||||
_thread_list.pop(i)
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
def process_background_result(job_object, exit_code, error_msg):
|
||||
cfg.load()
|
||||
job_object.set_result(exit_code, error_msg)
|
||||
return None
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def empty_cb(disregard):
|
||||
pass
|
||||
|
||||
|
||||
def background_execute(command, background_job, skip_first_line=False):
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, close_fds=True)
|
||||
lines_iterator = iter(process.stdout.readline, b"")
|
||||
for line in lines_iterator:
|
||||
# Merge ouputs a line before updates, move does not
|
||||
if skip_first_line:
|
||||
skip_first_line = False
|
||||
continue
|
||||
|
||||
if len(line) > 10:
|
||||
(device, ignore, percentage) = line.decode("utf-8").split(':')
|
||||
background_job.Percent = round(float(percentage.strip()[:-1]), 1)
|
||||
|
||||
out = process.communicate()
|
||||
|
||||
# print "DEBUG: EC %d, STDOUT %s, STDERR %s" % \
|
||||
# (process.returncode, out[0], out[1])
|
||||
|
||||
if process.returncode == 0:
|
||||
background_job.Percent = 100
|
||||
|
||||
# Queue up the result so that it gets executed in same thread as others.
|
||||
r = RequestEntry(
|
||||
-1, process_background_result,
|
||||
(background_job, process.returncode, out[1]),
|
||||
empty_cb, empty_cb, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
|
||||
def add(command, reporting_job, skip_first_line=False):
|
||||
# Create the thread, get it running and then add it to the list
|
||||
t = threading.Thread(
|
||||
target=background_execute,
|
||||
name="thread: " + ' '.join(command),
|
||||
args=(command, reporting_job, skip_first_line))
|
||||
t.start()
|
||||
|
||||
with _rlock:
|
||||
_thread_list.append(t)
|
80
daemons/lvmdbusd/cfg.py
Normal file
80
daemons/lvmdbusd/cfg.py
Normal file
@ -0,0 +1,80 @@
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import multiprocessing
|
||||
import queue
|
||||
import itertools
|
||||
try:
|
||||
from . import path
|
||||
except SystemError:
|
||||
import path
|
||||
|
||||
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
|
||||
|
||||
# This is the global object manager
|
||||
om = None
|
||||
|
||||
# This is the global bus connection
|
||||
bus = None
|
||||
|
||||
# Shared state variable across all processes
|
||||
run = multiprocessing.Value('i', 1)
|
||||
|
||||
# Debug
|
||||
DEBUG = True
|
||||
|
||||
# Use lvm shell
|
||||
USE_SHELL = False
|
||||
|
||||
# Lock used by pprint
|
||||
stdout_lock = multiprocessing.Lock()
|
||||
|
||||
kick_q = multiprocessing.Queue()
|
||||
worker_q = queue.Queue()
|
||||
|
||||
# Main event loop
|
||||
loop = None
|
||||
|
||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
||||
VG_INTERFACE = BASE_INTERFACE + '.Vg'
|
||||
LV_INTERFACE = BASE_INTERFACE + '.Lv'
|
||||
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
|
||||
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
|
||||
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
|
||||
LV_CACHED = BASE_INTERFACE + '.CachedLv'
|
||||
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
|
||||
MANAGER_INTERFACE = BASE_INTERFACE + '.Manager'
|
||||
JOB_INTERFACE = BASE_INTERFACE + '.Job'
|
||||
|
||||
BASE_OBJ_PATH = '/' + BASE_INTERFACE.replace('.', '/')
|
||||
PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv'
|
||||
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
|
||||
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
|
||||
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
|
||||
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
|
||||
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
|
||||
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
|
||||
JOB_OBJ_PATH = BASE_OBJ_PATH + '/Job'
|
||||
|
||||
# Counters for object path generation
|
||||
pv_id = itertools.count()
|
||||
vg_id = itertools.count()
|
||||
lv_id = itertools.count()
|
||||
thin_id = itertools.count()
|
||||
cache_pool_id = itertools.count()
|
||||
job_id = itertools.count()
|
||||
hidden_lv = itertools.count()
|
||||
|
||||
# Used to prevent circular imports...
|
||||
load = None
|
||||
|
||||
# Global cached state
|
||||
db = None
|
619
daemons/lvmdbusd/cmdhandler.py
Normal file
619
daemons/lvmdbusd/cmdhandler.py
Normal file
@ -0,0 +1,619 @@
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
import time
|
||||
import threading
|
||||
from itertools import chain
|
||||
|
||||
try:
|
||||
from . import cfg
|
||||
from .utils import pv_dest_ranges, log_debug, log_error
|
||||
from .lvm_shell_proxy import LVMShellProxy
|
||||
except SystemError:
|
||||
import cfg
|
||||
from utils import pv_dest_ranges, log_debug, log_error
|
||||
from lvm_shell_proxy import LVMShellProxy
|
||||
|
||||
SEP = '{|}'
|
||||
|
||||
total_time = 0.0
|
||||
total_count = 0
|
||||
|
||||
# We need to prevent different threads from using the same lvm shell
|
||||
# at the same time.
|
||||
cmd_lock = threading.Lock()
|
||||
|
||||
# The actual method which gets called to invoke the lvm command, can vary
|
||||
# from forking a new process to using lvm shell
|
||||
_t_call = None
|
||||
|
||||
|
||||
def _debug_c(cmd, exit_code, out):
|
||||
log_error('CMD= %s' % ' '.join(cmd))
|
||||
log_error(("EC= %d" % exit_code))
|
||||
log_error(("STDOUT=\n %s\n" % out[0]))
|
||||
log_error(("STDERR=\n %s\n" % out[1]))
|
||||
|
||||
|
||||
def call_lvm(command, debug=False):
|
||||
"""
|
||||
Call an executable and return a tuple of exitcode, stdout, stderr
|
||||
:param command: Command to execute
|
||||
:param debug: Dump debug to stdout
|
||||
"""
|
||||
# print 'STACK:'
|
||||
# for line in traceback.format_stack():
|
||||
# print line.strip()
|
||||
|
||||
# Prepend the full lvm executable so that we can run different versions
|
||||
# in different locations on the same box
|
||||
command.insert(0, cfg.LVM_CMD)
|
||||
|
||||
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True)
|
||||
out = process.communicate()
|
||||
|
||||
stdout_text = bytes(out[0]).decode("utf-8")
|
||||
stderr_text = bytes(out[1]).decode("utf-8")
|
||||
|
||||
if debug or process.returncode != 0:
|
||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
||||
|
||||
if process.returncode == 0:
|
||||
if cfg.DEBUG and out[1] and len(out[1]):
|
||||
log_error('WARNING: lvm is out-putting text to STDERR on success!')
|
||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
||||
|
||||
return process.returncode, stdout_text, stderr_text
|
||||
|
||||
|
||||
def _shell_cfg():
|
||||
global _t_call
|
||||
log_debug('Using lvm shell!')
|
||||
lvm_shell = LVMShellProxy()
|
||||
_t_call = lvm_shell.call_lvm
|
||||
|
||||
|
||||
if cfg.USE_SHELL:
|
||||
_shell_cfg()
|
||||
else:
|
||||
_t_call = call_lvm
|
||||
|
||||
|
||||
def set_execution(shell):
|
||||
global _t_call
|
||||
with cmd_lock:
|
||||
_t_call = None
|
||||
if shell:
|
||||
log_debug('Using lvm shell!')
|
||||
lvm_shell = LVMShellProxy()
|
||||
_t_call = lvm_shell.call_lvm
|
||||
else:
|
||||
_t_call = call_lvm
|
||||
|
||||
|
||||
def time_wrapper(command, debug=False):
|
||||
global total_time
|
||||
global total_count
|
||||
|
||||
with cmd_lock:
|
||||
start = time.time()
|
||||
results = _t_call(command, debug)
|
||||
total_time += (time.time() - start)
|
||||
total_count += 1
|
||||
|
||||
return results
|
||||
|
||||
|
||||
call = time_wrapper
|
||||
|
||||
|
||||
# Default cmd
|
||||
# Place default arguments for every command here.
|
||||
def _dc(cmd, args):
|
||||
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
|
||||
'--unbuffered', '--units', 'b']
|
||||
c.extend(args)
|
||||
return c
|
||||
|
||||
|
||||
def parse(out):
|
||||
rc = []
|
||||
|
||||
for line in out.split('\n'):
|
||||
# This line includes separators, so process them
|
||||
if SEP in line:
|
||||
elem = line.split(SEP)
|
||||
cleaned_elem = []
|
||||
for e in elem:
|
||||
e = e.strip()
|
||||
cleaned_elem.append(e)
|
||||
|
||||
if len(cleaned_elem) > 1:
|
||||
rc.append(cleaned_elem)
|
||||
else:
|
||||
t = line.strip()
|
||||
if len(t) > 0:
|
||||
rc.append(t)
|
||||
return rc
|
||||
|
||||
|
||||
def parse_column_names(out, column_names):
|
||||
lines = parse(out)
|
||||
rc = []
|
||||
|
||||
for i in range(0, len(lines)):
|
||||
d = dict(list(zip(column_names, lines[i])))
|
||||
rc.append(d)
|
||||
|
||||
return rc
|
||||
|
||||
|
||||
def options_to_cli_args(options):
|
||||
rc = []
|
||||
for k, v in list(dict(options).items()):
|
||||
if k.startswith("-"):
|
||||
rc.append(k)
|
||||
else:
|
||||
rc.append("--%s" % k)
|
||||
if v != "":
|
||||
rc.append(str(v))
|
||||
return rc
|
||||
|
||||
|
||||
def pv_remove(device, remove_options):
|
||||
cmd = ['pvremove']
|
||||
cmd.extend(options_to_cli_args(remove_options))
|
||||
cmd.append(device)
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def _tag(operation, what, add, rm, tag_options):
|
||||
cmd = [operation]
|
||||
cmd.extend(options_to_cli_args(tag_options))
|
||||
|
||||
if isinstance(what, list):
|
||||
cmd.extend(what)
|
||||
else:
|
||||
cmd.append(what)
|
||||
|
||||
if add:
|
||||
cmd.extend(list(chain.from_iterable(('--addtag', x) for x in add)))
|
||||
if rm:
|
||||
cmd.extend(list(chain.from_iterable(('--deltag', x) for x in rm)))
|
||||
|
||||
return call(cmd, False)
|
||||
|
||||
|
||||
def pv_tag(pv_devices, add, rm, tag_options):
|
||||
return _tag('pvchange', pv_devices, add, rm, tag_options)
|
||||
|
||||
|
||||
def vg_tag(vg_name, add, rm, tag_options):
|
||||
return _tag('vgchange', vg_name, add, rm, tag_options)
|
||||
|
||||
|
||||
def lv_tag(lv_name, add, rm, tag_options):
|
||||
return _tag('lvchange', lv_name, add, rm, tag_options)
|
||||
|
||||
|
||||
def vg_rename(vg, new_name, rename_options):
|
||||
cmd = ['vgrename']
|
||||
cmd.extend(options_to_cli_args(rename_options))
|
||||
cmd.extend([vg, new_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_remove(vg_name, remove_options):
|
||||
cmd = ['vgremove']
|
||||
cmd.extend(options_to_cli_args(remove_options))
|
||||
cmd.extend(['-f', vg_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
|
||||
cmd = ['lvcreate']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||
cmd.extend(['--name', name, vg_name])
|
||||
pv_dest_ranges(cmd, pv_dests)
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
|
||||
cmd = ['lvcreate']
|
||||
cmd.extend(options_to_cli_args(snapshot_options))
|
||||
cmd.extend(["-s"])
|
||||
|
||||
if size_bytes != 0:
|
||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||
|
||||
cmd.extend(['--name', name, vg_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
|
||||
cmd = ['lvcreate']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
|
||||
if not thin_pool:
|
||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||
else:
|
||||
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
|
||||
cmd.extend(['--name', name, vg_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
|
||||
num_stripes, stripe_size_kb, thin_pool):
|
||||
cmd = ['lvcreate']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
|
||||
if not thin_pool:
|
||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||
else:
|
||||
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
|
||||
|
||||
cmd.extend(['--stripes', str(num_stripes)])
|
||||
|
||||
if stripe_size_kb != 0:
|
||||
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
||||
|
||||
cmd.extend(['--name', name, vg_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
|
||||
num_stripes, stripe_size_kb):
|
||||
cmd = ['lvcreate']
|
||||
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
|
||||
cmd.extend(['--type', raid_type])
|
||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||
|
||||
if num_stripes != 0:
|
||||
cmd.extend(['--stripes', str(num_stripes)])
|
||||
|
||||
if stripe_size_kb != 0:
|
||||
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
||||
|
||||
cmd.extend(['--name', name, vg_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
|
||||
num_stripes, stripe_size_kb):
|
||||
cmd = ['lvcreate']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
|
||||
return _vg_lv_create_raid(vg_name, create_options, name, raid_type,
|
||||
size_bytes, num_stripes, stripe_size_kb)
|
||||
|
||||
|
||||
def vg_lv_create_mirror(vg_name, create_options, name, size_bytes, num_copies):
|
||||
cmd = ['lvcreate']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
|
||||
cmd.extend(['--type', 'mirror'])
|
||||
cmd.extend(['--mirrors', str(num_copies)])
|
||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||
cmd.extend(['--name', name, vg_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_create_cache_pool(md_full_name, data_full_name, create_options):
|
||||
cmd = ['lvconvert']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
cmd.extend(['--type', 'cache-pool', '--force', '-y',
|
||||
'--poolmetadata', md_full_name, data_full_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_create_thin_pool(md_full_name, data_full_name, create_options):
|
||||
cmd = ['lvconvert']
|
||||