From: Alfredo Deza Date: Thu, 22 Jun 2017 19:37:55 +0000 (-0400) Subject: ceph-volume: process: module for running system commands X-Git-Tag: ses5-milestone10~3^2~5^2~96 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7b8cb78e05cf91861c98cb1dd43a3423c730d66b;p=ceph.git ceph-volume: process: module for running system commands Signed-off-by: Alfredo Deza --- diff --git a/src/ceph-volume/ceph_volume/process.py b/src/ceph-volume/ceph_volume/process.py new file mode 100644 index 00000000000..abd8f9daeb4 --- /dev/null +++ b/src/ceph-volume/ceph_volume/process.py @@ -0,0 +1,86 @@ +import subprocess +import sys +from select import select +from ceph_volume import terminal + +import logging + +logger = logging.getLogger(__name__) + + +def log_output(descriptor, message, terminal_logging): + """ + log output to both the logger and the terminal if terminal_logging is + enabled + """ + line = '%s %s' % (descriptor, message) + if terminal_logging: + getattr(terminal, descriptor)(message) + logger.info(line) + + +def log_descriptors(reads, process, terminal_logging): + """ + Helper to send output to the terminal while polling the subprocess + """ + err_read = out_read = None + while True: + for descriptor in reads: + if descriptor == process.stdout.fileno(): + out_read = process.stdout.readline() + if out_read: + log_output('stdout', out_read, terminal_logging) + sys.stdout.flush() + + if descriptor == process.stderr.fileno(): + err_read = process.stderr.readline() + if err_read: + log_output('stderr', err_read, terminal_logging) + sys.stderr.flush() + if not err_read and not out_read: + break + + +def run(command, **kw): + """ + A real-time-logging implementation of a remote subprocess.Popen call where + a command is just executed on the remote end and no other handling is done. + + :param command: The command to pass in to the remote subprocess.Popen as a list + :param stop_on_error: If a nonzero exit status is return, it raises a ``RuntimeError`` + """ + stop_on_error = kw.pop('stop_on_error', True) + command_msg = "Running command: %s" % ' '.join(command) + logger.info(command_msg) + terminal.write(command_msg) + terminal_logging = kw.get('terminal_logging', True) + + process = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True, + **kw + ) + + while True: + reads, _, _ = select( + [process.stdout.fileno(), process.stderr.fileno()], + [], [] + ) + log_descriptors(reads, process, terminal_logging) + + if process.poll() is not None: + # ensure we do not have anything pending in stdout or stderr + log_descriptors(reads, process, terminal_logging) + + break + + returncode = process.wait() + if returncode != 0: + msg = "command returned non-zero exit status: %s" % returncode + if stop_on_error: + raise RuntimeError(msg) + else: + terminal.warning(msg) + logger.warning(msg)