Yaniv Bronhaim has uploaded a new change for review. Change subject: Adding dependency on cpopen formal package ......................................................................
Adding dependency on cpopen formal package Removing cpopen code from vdsm and using formal package instead Change-Id: I6dfc943cbf7ac1e4c575069afca9c7df0624372f Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=903246 Signed-off-by: Yaniv Bronhaim <ybron...@redhat.com> --- M Makefile.am M configure.ac M debian/control D debian/vdsm-python-cpopen.docs D debian/vdsm-python-cpopen.install M lib/Makefile.am D lib/cpopen/.gitignore D lib/cpopen/Makefile.am D lib/cpopen/__init__.py D lib/cpopen/cpopen.c D lib/cpopen/setup.py D lib/cpopen/tests.py M vdsm.spec.in 13 files changed, 9 insertions(+), 755 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/42/20142/1 diff --git a/Makefile.am b/Makefile.am index 195688f..84e5e6e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,7 +56,6 @@ # checkd from now on PEP8_WHITELIST = \ client \ - lib/cpopen/*.py \ lib/vdsm/*.py \ lib/vdsm/*.py.in \ tests \ diff --git a/configure.ac b/configure.ac index 93b6b96..a1a5465 100644 --- a/configure.ac +++ b/configure.ac @@ -252,7 +252,6 @@ init/sysvinit/Makefile init/upstart/Makefile lib/Makefile - lib/cpopen/Makefile lib/vdsm/Makefile lib/vdsm/tool/Makefile lib/yajsonrpc/Makefile diff --git a/debian/control b/debian/control index da030ad..820bc26 100644 --- a/debian/control +++ b/debian/control @@ -31,13 +31,6 @@ Vcs-Git: git://gerrit.ovirt.org/vdsm Vcs-Browser: http://gerrit.ovirt.org/gitweb?p=vdsm.git -Package: vdsm-python-cpopen -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python (>=2.7.3) -Description: Creates a sub-process in simpler safer manner - Python package for creating sub-process in simpler and safer manner by using - C code. - Package: vdsm-yajsonrpc Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, python (>=2.7.3), @@ -54,7 +47,7 @@ Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, python (>=2.7.3), - vdsm-python-cpopen (>= ${source:Version}), + python-cpopen, vdsm-python (= ${source:Version}) Description: VDSM command line interface Call VDSM commands from the command line. Used for testing and debugging. @@ -93,7 +86,7 @@ policycoreutils (>= 2.1.10), psmisc (>= 22.6), python (>= 2.7.3), - vdsm-python-cpopen (= ${binary:Version}), + python-cpopen, python-dmidecode, python-ethtool (>= 0.8), python-ethtool (>= 0.8), diff --git a/debian/vdsm-python-cpopen.docs b/debian/vdsm-python-cpopen.docs deleted file mode 100644 index 5ecd9c6..0000000 --- a/debian/vdsm-python-cpopen.docs +++ /dev/null @@ -1 +0,0 @@ -COPYING diff --git a/debian/vdsm-python-cpopen.install b/debian/vdsm-python-cpopen.install deleted file mode 100644 index d38a40e..0000000 --- a/debian/vdsm-python-cpopen.install +++ /dev/null @@ -1,2 +0,0 @@ -./usr/lib/python2.7/dist-packages/cpopen/__init__.py -./usr/lib/python2.7/dist-packages/cpopen/cpopen.so diff --git a/lib/Makefile.am b/lib/Makefile.am index b1a1a12..ff46328 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -19,4 +19,4 @@ # include $(top_srcdir)/build-aux/Makefile.subs -SUBDIRS = vdsm cpopen yajsonrpc +SUBDIRS = vdsm yajsonrpc diff --git a/lib/cpopen/.gitignore b/lib/cpopen/.gitignore deleted file mode 100644 index d23b815..0000000 --- a/lib/cpopen/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build -*.so diff --git a/lib/cpopen/Makefile.am b/lib/cpopen/Makefile.am deleted file mode 100644 index c39ca24..0000000 --- a/lib/cpopen/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2012 Red Hat, 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 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# Refer to the README and COPYING files for full details of the license -# - -cpopendir = $(pyexecdir)/cpopen - -dist_cpopen_PYTHON = \ - __init__.py \ - $(NULL) - -cpopen.so: cpopen.c setup.py - (cd $(srcdir); $(PYTHON) setup.py build \ - --build-temp $(abs_builddir) --build-lib $(abs_builddir)) - -all-local: cpopen.so - -install-data-local: - $(MKDIR_P) $(DESTDIR)$(cpopendir) - $(INSTALL_PROGRAM) cpopen.so \ - $(DESTDIR)$(cpopendir)/cpopen.so - -check-local: tests.py - nosetests tests.py - -EXTRA_DIST = \ - cpopen.c \ - tests.py \ - setup.py - -CLEANFILES = \ - cpopen.o \ - cpopen.so diff --git a/lib/cpopen/__init__.py b/lib/cpopen/__init__.py deleted file mode 100644 index d671355..0000000 --- a/lib/cpopen/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -# -# Copyright 2012 Red Hat, 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 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# Refer to the README and COPYING files for full details of the license -# - -""" -Python's implementation of Popen forks back to python before execing. -Forking a python proc is a very complex and volatile process. - -This is a simpler method of execing that doesn't go back to python after -forking. This allows for faster safer exec. -""" - -import os -from subprocess import Popen, PIPE - -from cpopen import createProcess - - -class CPopen(Popen): - def __init__(self, args, close_fds=False, cwd=None, env=None, - deathSignal=0): - if not isinstance(args, list): - args = list(args) - - if env is not None and not isinstance(env, list): - env = list(("=".join(item) for item in env.iteritems())) - - self._deathSignal = int(deathSignal) - Popen.__init__(self, args, - close_fds=close_fds, cwd=cwd, env=env, - stdin=PIPE, stdout=PIPE, - stderr=PIPE) - - def _execute_child(self, args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite): - - try: - pid, stdin, stdout, stderr = \ - createProcess(args, close_fds, p2cread, p2cwrite, - c2pread, c2pwrite, errread, errwrite, - cwd, env, self._deathSignal) - - self.pid = pid - self._closed = False - self._returncode = None - except: - os.close(p2cwrite) - os.close(errread) - os.close(c2pread) - raise - finally: - os.close(p2cread) - os.close(errwrite) - os.close(c2pwrite) diff --git a/lib/cpopen/cpopen.c b/lib/cpopen/cpopen.c deleted file mode 100644 index 7b9ddce..0000000 --- a/lib/cpopen/cpopen.c +++ /dev/null @@ -1,392 +0,0 @@ -/* -* Copyright 2012 Red Hat, 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 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, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Refer to the README and COPYING files for full details of the license -*/ - -#include <Python.h> - -#include <dirent.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/prctl.h> - -static PyObject *createProcess(PyObject *self, PyObject *args); -static PyMethodDef CreateProcessMethods[]; -static void closeFDs(int errnofd); - -/* Python boilerplate */ -static PyMethodDef -CreateProcessMethods[] = { - {"createProcess", createProcess, METH_VARARGS, - "Execute a command."}, - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - -PyMODINIT_FUNC -initcpopen(void) -{ - PyObject *m; - - m = Py_InitModule("cpopen", CreateProcessMethods); - - /* In the future put other init code after this condition. */ - if (m == NULL) - return; -} - -/* Just like close() but retries on interrupt */ -static int -safeClose(int fd) { - int rv; - -retry: - rv = close(fd); - if ((rv < 0) && (errno == EINTR)) { - goto retry; - } - - return rv; -} - -/* Just like read() but retries on interrupt and tries to fill the buffer */ -static int -safeRead(int fd, void *buff, size_t count) { - size_t bread = 0; - char* cbuff = buff; - int rv = 0; - while (bread < count) { - rv = read(fd, cbuff + bread, count - bread); - if (rv == 0) { /* EOF */ - return bread; - } else if (rv < 0) { /* ERROR */ - switch (errno) { - case EINTR: - case EAGAIN: - break; - default: - return rv; - } - } else { /* Success */ - bread += rv; - } - } - - return bread; -} - -static int -setCloseOnExec(int fd) { - int flags; - - flags = fcntl(fd, F_GETFD); - if (flags == -1) { - return -1; - } - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { - return -1; - } - - return 0; -} - -/* Closes all open FDs except for stdin, stdout and stderr */ -static void -closeFDs(int errnofd) { - DIR *dp; - int dfd; - struct dirent *ep; - int fdNum = -1; - - dfd = open("/proc/self/fd/", O_RDONLY); - dp = fdopendir(dfd); - while ((ep = readdir(dp))) { - if(sscanf(ep->d_name, "%d", &fdNum) < 1) { - continue; - } - - if (fdNum < 3) { - continue; - } - - if (fdNum == dfd) { - continue; - } - - if (fdNum == errnofd) { - continue; - } - - safeClose(fdNum); - } - - closedir(dp); - safeClose(dfd); -} - -static void -freeStringArray(char** arr) { - char** item; - for (item = arr; *item != NULL; item++) { - PyMem_Free(*item); - } - - free(arr); -} - -/* Copies the strings from a python list to a null terminated array. - * The strings are shallow copied and are owned by python. - * Don't keep this array after the call. - * - * Returns a NULL terminated array of null strings. On error returns NULL and - * sets the python error accordingly - */ -static char** -pyListToArray(PyObject* list, int checkIfEmpty) { - int argn; - int i; - char** argv; - - if (!PyList_Check(list)) { - PyErr_SetString(PyExc_TypeError, "Argument must be a python list"); - return NULL; - } - - argn = PyList_Size(list); - if ((checkIfEmpty) && (argn < 1)) { - PyErr_SetString(PyExc_ValueError, "List must not be empty"); - return NULL; - } - - argv = calloc(argn + 1, sizeof(char*)); - if (!argv) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - for (i = 0; i < argn; i++) { - if (!PyArg_Parse(PyList_GetItem(list, i), - "et;", - Py_FileSystemDefaultEncoding, - &argv[i])) { - PyErr_SetString(PyExc_TypeError, - "createProcess() arg 2 must contain only strings"); - goto fail; - } - } - - return argv; - -fail: - freeStringArray(argv); - return NULL; -} - -/* Python's implementation of Popen forks back to python before execing. - * Forking a python proc is a very complex and volatile process. - * - * This is a simpler method of execing that doesn't go back to python after - * forking. This allows for faster safer exec. - * - * return NULL on error and sets the python error accordingly. - */ -static PyObject * -createProcess(PyObject *self, PyObject *args) -{ - int cpid; - int deathSignal = 0; - int rv; - - int outfd[2] = {-1, -1}; - int in1fd[2] = {-1, -1}; - int in2fd[2] = {-1, -1}; - - int errnofd[2] = {-1, -1}; - int childErrno = 0; - - PyObject* pyArgList; - PyObject* pyEnvList; - const char* cwd; - int close_fds = 0; - - char** argv = NULL; - char** envp = NULL; - - if (!PyArg_ParseTuple(args, "O!iiiiiiizOi:createProcess;", - &PyList_Type, &pyArgList, &close_fds, - &outfd[0], &outfd[1], - &in1fd[0], &in1fd[1], - &in2fd[0], &in2fd[1], - &cwd, &pyEnvList, &deathSignal)) { - return NULL; - } - - argv = pyListToArray(pyArgList, 1); - if (!argv) { - goto fail; - } - - if (PyList_Check(pyEnvList)) { - envp = pyListToArray(pyEnvList, 0); - if (!envp) { - goto fail; - } - } - - if(pipe(errnofd) < 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } - -try_fork: - cpid = fork(); - if (cpid < 0) { - if (errno == EAGAIN || - errno == EINTR ) { - goto try_fork; - } - - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } - - if (!cpid) { - safeClose(0); - safeClose(1); - safeClose(2); - - dup2(outfd[0], 0); - dup2(in1fd[1], 1); - dup2(in2fd[1], 2); - - safeClose(outfd[0]); - safeClose(outfd[1]); - safeClose(in1fd[0]); - safeClose(in1fd[1]); - safeClose(in2fd[0]); - safeClose(in2fd[1]); - safeClose(errnofd[0]); - - if (deathSignal) { - childErrno = prctl(PR_SET_PDEATHSIG, deathSignal); - if (childErrno < 0) { - childErrno = errno; - } - /* Check that parent did not already die between fork and us - * setting the death signal */ - if (write(errnofd[1], &childErrno, sizeof(int)) < sizeof(int)) { - exit(-1); - } - - if (childErrno != 0) { - exit(-1); - } - } - - if (setCloseOnExec(errnofd[1]) < 0) { - goto sendErrno; - } - - if (close_fds) { - closeFDs(errnofd[1]); - } - - if (cwd) { - if (chdir(cwd) < 0) { - goto sendErrno; - } - setenv("PWD", cwd, 1); - } -exec: - if (envp) { - execvpe(argv[0], argv, envp); - } else { - execvp(argv[0], argv); - } - - if (errno == EINTR || - errno == EAGAIN ) - { - goto exec; - } -sendErrno: - if (write(errnofd[1], &errno, sizeof(int)) < 0) { - exit(errno); - } - exit(-1); - } - - safeClose(errnofd[1]); - errnofd[1] = -1; - - if (deathSignal) { - /* death signal sync point */ - rv = safeRead(errnofd[0], &childErrno, sizeof(int)); - if (rv != sizeof(int)) { - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } else if (childErrno != 0) { - PyErr_SetString(PyExc_OSError, strerror(childErrno)); - goto fail; - } - } - - /* error sync point */ - rv = safeRead(errnofd[0], &childErrno, sizeof(int)); - if (rv == sizeof(int)) { - PyErr_SetString(PyExc_OSError, strerror(childErrno)); - goto fail; - } else if (rv < 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } - - safeClose(errnofd[0]); - errnofd[0] = -1; - - /* From this point errors shouldn't occur, if they do something is very - * very very wrong */ - - freeStringArray(argv); - - if (envp) { - freeStringArray(envp); - } - - return Py_BuildValue("(iiii)", cpid, outfd[1], in1fd[0], in2fd[0]); - -fail: - if (argv) { - freeStringArray(argv); - } - - if (envp) { - freeStringArray(envp); - } - - if (errnofd[0] >= 0) { - safeClose(errnofd[0]); - } - - if (errnofd[1] >= 0) { - safeClose(errnofd[1]); - } - - return NULL; -} diff --git a/lib/cpopen/setup.py b/lib/cpopen/setup.py deleted file mode 100644 index 66fc157..0000000 --- a/lib/cpopen/setup.py +++ /dev/null @@ -1,13 +0,0 @@ -from distutils.core import setup, Extension - -module1 = Extension('cpopen', - sources=['cpopen.c']) - -setup(name='cpopen', - version='1.2.1', - description='Creates a subprocess in simpler safer manner', - py_modules=['__init__'], - author='Yaniv Bronhaim', - author_email='ybron...@redhat.com', - url='redhat.com', - ext_modules=[module1]) diff --git a/lib/cpopen/tests.py b/lib/cpopen/tests.py deleted file mode 100644 index 9dd1906..0000000 --- a/lib/cpopen/tests.py +++ /dev/null @@ -1,196 +0,0 @@ -# -# Copyright 2012 Red Hat, 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 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# Refer to the README and COPYING files for full details of the license -# -import os -import sys -import subprocess -from nose.plugins.skip import SkipTest -import signal -import threading -import time - -from unittest import TestCase - -EXT_ECHO = "/bin/echo" - -if __name__ != "__main__": - # This will not be available when we use this module as a subprocess - import glob - for p in glob.glob("build/*/"): - sys.path.append(p) - - from . import CPopen - - -class TestCPopen(TestCase): - def testEcho(self): - data = "Hello" - p = CPopen([EXT_ECHO, "-n", data]) - p.wait() - self.assertTrue(p.returncode == 0, - "Process failed: %s" % os.strerror(p.returncode)) - self.assertEquals(p.stdout.read(), data) - - def testCat(self): - path = "/etc/passwd" - p = CPopen(["cat", path]) - p.wait() - self.assertTrue(p.returncode == 0, - "Process failed: %s" % os.strerror(p.returncode)) - with open(path, "r") as f: - self.assertEquals(p.stdout.read(), f.read()) - - def _subTest(self, name, params, *args, **kwargs): - p = CPopen(["python", __file__, name] + params, - *args, **kwargs) - p.wait() - self.assertTrue(p.returncode == 0, - "Process failed: %s" % os.strerror(p.returncode)) - self.assertEquals(p.stdout.read().strip(), "True") - - def testCloseFDs(self): - fds = os.pipe() - try: - self._subTest("fds", [str(fds[1])], close_fds=True) - finally: - os.close(fds[0]) - os.close(fds[1]) - - def testNoCloseFds(self): - fds = os.pipe() - try: - self._subTest("nofds", [str(fds[1])], close_fds=False) - finally: - os.close(fds[0]) - os.close(fds[1]) - - def testEnv(self): - env = os.environ.copy() - env["TEST"] = "True" - self._subTest("env", [], env=env) - - def testCwd(self): - cwd = "/proc" - p = CPopen(["python", "-c", "import os; print os.getcwd()"], - cwd=cwd) - p.wait() - self.assertTrue(p.returncode == 0, - "Process failed: %s" % os.strerror(p.returncode)) - self.assertEquals(p.stdout.read().strip(), cwd) - - def testRunNonExecutable(self): - self.assertRaises(OSError, CPopen, ["/tmp"]) - - def testBadCwd(self): - self.assertRaises(OSError, CPopen, ["echo", "hello"], - cwd="/~~~~~dasdas~~~~") - - def testUnicodeArg(self): - data = u'hello' - cmd = [EXT_ECHO, "-n", data] - - p = CPopen(cmd) - p.wait() - p2 = subprocess.Popen(cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p2.wait() - self.assertEquals(p.stdout.read(), p2.stdout.read()) - - def testNonASCIIUnicodeArg(self): - data = u'\u05e9\u05dc\u05d5\u05dd' - # If the default encoding is not utf-8 the test *should* fail as non - # ascii conversion shouldn't work - if sys.getfilesystemencoding() != "UTF-8": - raise SkipTest("The default encoding isn't unicode") - - cmd = [EXT_ECHO, "-n", data] - - p = CPopen(cmd) - p.wait() - p2 = subprocess.Popen(cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p2.wait() - self.assertEquals(p.stdout.read(), p2.stdout.read()) - - def testStdin(self): - data = "Hello World" - p = CPopen(["cat"]) - p.stdin.write(data) - p.stdin.flush() - p.stdin.close() - p.wait() - self.assertTrue(p.returncode == 0, - "Process failed: %s" % os.strerror(p.returncode)) - - self.assertEquals(p.stdout.read(), data) - - def testStdinEpoll(self): - import select - - data = "Hello World" - p = CPopen(["cat"]) - ep = select.epoll() - ep.register(p.stdin, select.EPOLLOUT) - fd, ev = ep.poll(1)[0] - ep.close() - os.write(fd, data) - p.stdin.close() - p.wait() - self.assertTrue(p.returncode == 0, - "Process failed: %s" % os.strerror(p.returncode)) - - self.assertEquals(p.stdout.read(), data) - - def testDeathSignal(self): - # This is done because assignment in python doesn't cross scopes - procPtr = [None] - - def spawn(): - procPtr[0] = CPopen(["sleep", "10"], - deathSignal=signal.SIGKILL) - - t = threading.Thread(target=spawn) - t.start() - t.join() - start = time.time() - procPtr[0].wait() - self.assertTrue(time.time() - start < 1) - - -if __name__ == "__main__": - cmd = sys.argv[1] - if cmd == "fds": - try: - os.close(int(sys.argv[2])) - print "False" - except: - print "True" - - elif cmd == "nofds": - try: - os.close(int(sys.argv[2])) - print "True" - except: - print "False" - - elif cmd == "env": - try: - print os.environ.get("TEST", "False") - except: - print "False" diff --git a/vdsm.spec.in b/vdsm.spec.in index f996bd8..203069f 100644 --- a/vdsm.spec.in +++ b/vdsm.spec.in @@ -237,7 +237,7 @@ Requires: %{name}-python = %{version}-%{release} Requires: %{name}-xmlrpc = %{version}-%{release} -Requires: %{name}-python-cpopen +Requires: python-cpopen %description cli Call VDSM commands from the command line. Used for testing and debugging. @@ -247,7 +247,7 @@ BuildArch: noarch Requires: %{name}-python = %{version}-%{release} -Requires: %{name}-python-cpopen +Requires: python-cpopen %description xmlrpc @@ -302,15 +302,6 @@ %description reg VDSM registration package. Used to register a Linux host to a Virtualization Manager. - -%package python-cpopen -Summary: Creates a sub-process in simpler safer manner. - -BuildRequires: python2-devel - -%description python-cpopen -Python package for creating sub-process in simpler and safer manner by using C -code. %package python Summary: VDSM python libraries @@ -1300,11 +1291,11 @@ %{_datadir}/%{vdsm_name}/gluster/tasks.py* %endif -%files python-cpopen -%{python_sitearch}/cpopen/__init__.py* -%attr(755, root, root) %{python_sitearch}/cpopen/cpopen.so* - %changelog +* Sun Oct 13 2013 Yaniv Bronhaim <ybron...@redhat.com> - 4.13.0 +- Removing vdsm-python-cpopen from the spec +- Adding dependency on formal cpopen package + * Sun Apr 07 2013 Yaniv Bronhaim <ybron...@redhat.com> - 4.9.0-1 - Adding cpopen package -- To view, visit http://gerrit.ovirt.org/20142 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6dfc943cbf7ac1e4c575069afca9c7df0624372f Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Yaniv Bronhaim <ybron...@redhat.com> _______________________________________________ vdsm-patches mailing list vdsm-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches