[node-patches] Change in ovirt-node[master]: process: pipe() can raise exception

fabiand at fedoraproject.org fabiand at fedoraproject.org
Fri Sep 27 14:16:16 UTC 2013


Fabian Deutsch has uploaded a new change for review.

Change subject: process: pipe() can raise exception
......................................................................

process: pipe() can raise exception

Previously the failed start of a service was not detected n el6, because
the fallback of check_output - pipe() - didn't throw exceptions on
failed starts. This is now fixed, pipe() is throwing (if asked)
exceptions to signla if th ecmd failed (the service didi not start).

Change-Id: I588d1b97d31553a1aaf05c0cd0462b118369179d
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=991375
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M src/ovirt/node/utils/process.py
1 file changed, 79 insertions(+), 7 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/21/19621/1

diff --git a/src/ovirt/node/utils/process.py b/src/ovirt/node/utils/process.py
index 70e1954..56d2e53 100644
--- a/src/ovirt/node/utils/process.py
+++ b/src/ovirt/node/utils/process.py
@@ -44,9 +44,25 @@
 
 
 def __check_for_problems(args, kwargs):
+    """This checks for one well known problem.
+
+    If a string is used as the cmd, then shell=True needs to be passed
+    >>> __check_for_problems(["true"], {"shell": True})
+
+    When the cmd is a list, then shell must be False (which it is by default)
+    >>> __check_for_problems([["true"]], {"shell": False})
+    >>> __check_for_problems([["true"]], {})
+
+    If a list is used as the cmd, then shell is not allowed.
+    >>> __check_for_problems([["true"]],
+    ... {"shell": True}) #doctest: +IGNORE_EXCEPTION_DETAIL
+    Traceback (most recent call last):
+    ...
+    RuntimeError:
+    """
     if ("shell" in kwargs and kwargs["shell"] is True) and \
             (args and type(args[0]) is list):
-        raise RuntimeError("Combining  shell=True and a command list does " +
+        raise RuntimeError("Combining shell=True and a command list does " +
                            "not work. With shell=True the first argument" +
                            "must be a string. A list otherwise.")
 
@@ -62,6 +78,15 @@
 
 def call(*args, **kwargs):
     """subprocess.call wrapper to not leak file descriptors
+
+    >>> call(["true"])
+    0
+    >>> call(["false"])
+    1
+    >>> call(["echo", "42"], stdout=PIPE)
+    0
+    >>> call("echo 42", shell=True, stdout=PIPE)
+    0
     """
     kwargs = __update_kwargs(kwargs)
     LOGGER.debug("Calling with: %s %s" % (args, kwargs))
@@ -80,6 +105,15 @@
 
 def check_output(*args, **kwargs):
     """subprocess.check_output wrapper to not leak file descriptors
+
+    >>> check_output(["echo", "-n", "42"])
+    u'42'
+    >>> check_output("echo -n 42", shell=True)
+    u'42'
+    >>> check_output("false", shell=True)
+    Traceback (most recent call last):
+    ...
+    CalledProcessError: Command 'false' returned non-zero exit status 1
     """
     kwargs = __update_kwargs(kwargs)
     LOGGER.debug("Checking output with: %s %s" % (args, kwargs))
@@ -88,25 +122,63 @@
         return unicode(subprocess.check_output(*args, **kwargs),
                        encoding=sys.stdin.encoding or "utf-8")
     except AttributeError:
-        # We're probably on Python 2.7, which doesn't have check_output
+        # We're probably on Python 2.6, which doesn't have check_output
         # http://docs.python.org/2.6/library/subprocess.html#module-subprocess
-        # Working around by using pipe, which doesn't check, but returns the
-        # output
-        return pipe(*args, **kwargs)
+        # Working around by using pipe with it's check feature
+        return pipe(*args, check=True, **kwargs)
 
 
-def pipe(cmd, stdin=None, **kwargs):
+def pipe(cmd, stdin=None, check=False, **kwargs):
     """Run a non-interactive command and return it's output
 
     Args:
         cmd: Cmdline to be run
         stdin: (optional) Data passed to stdin
+        check: Raise an CalledProcessException if the cmd fails
 
     Returns:
         stdout, stderr of the process (as one blob)
+
+    >>> pipe("echo 1")
+    u'1\\n'
+    >>> pipe("false ; echo -n 42")
+    u'42'
+    >>> pipe("true")
+    u''
+    >>> pipe("false")
+    u''
+
+    When asked, pipe() can also throw Exceptions
+    >>> pipe("false", check=True)
+    Traceback (most recent call last):
+    ...
+    CalledProcessError: Command 'false' returned non-zero exit status 1
+
+    This is how pipe is used in check_output as a fallback, so let's check
+    it here too:
+    >>> args = ["false"]
+    >>> kwargs = {}
+    >>> pipe(*args, check=True, **kwargs)
+    Traceback (most recent call last):
+    ...
+    CalledProcessError: Command 'false' returned non-zero exit status 1
     """
     kwargs.update({"stdin": PIPE,
                    "stdout": PIPE,
                    "stderr": STDOUT})
+    if type(cmd) in [str, unicode]:
+        kwargs["shell"] = True
     __check_for_problems(cmd, kwargs)
-    return unicode(popen(cmd, **kwargs).communicate(stdin)[0])
+    proc = popen(cmd, **kwargs)
+    stdout, stderr = proc.communicate(stdin)
+
+    #
+    # We need to handle the checking ourselfs, mainly for el6 comapatability
+    # as a fallback for check_output
+    #
+    if check and proc.returncode != 0:
+        err = CalledProcessError(proc.returncode, cmd)
+        err.output = stderr
+        raise err
+
+    return unicode(stdout)


-- 
To view, visit http://gerrit.ovirt.org/19621
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I588d1b97d31553a1aaf05c0cd0462b118369179d
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Fabian Deutsch <fabiand at fedoraproject.org>



More information about the node-patches mailing list