From: Alfredo Deza Date: Mon, 19 Aug 2013 20:56:11 +0000 (-0400) Subject: create a Popen wrapper that can do remote stuff for us X-Git-Tag: v1.2.2~4^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=bd5e871b907e0065fcc839d33af65c31dfaf0028;p=ceph-deploy.git create a Popen wrapper that can do remote stuff for us Signed-off-by: Alfredo Deza --- diff --git a/ceph_deploy/util/wrappers.py b/ceph_deploy/util/wrappers.py index 4bff77b..fe41856 100644 --- a/ceph_deploy/util/wrappers.py +++ b/ceph_deploy/util/wrappers.py @@ -5,7 +5,6 @@ logging and remote execution. This allows us to only remote-execute the actual calls, not whole functions. """ -from ceph_deploy.util.decorators import remote_compile from ceph_deploy.util import context @@ -23,6 +22,8 @@ def check_call(conn, logger, args, *a, **kw): """ command = ' '.join(args) patch = kw.pop('patch', True) # Always patch unless explicitly told to + mangle = kw.pop('mangle_exc', False) # Default to not mangle exceptions + stop_on_error = kw.pop('stop_on_error', True) # Halt on remote exceptions logger.info('Running command: %s' % command) def remote_call(args, *a, **kw): @@ -33,6 +34,60 @@ def check_call(conn, logger, args, *a, **kw): **kw ) + with context.remote(conn, logger, remote_call, mangle_exc=mangle, patch=patch) as call: + try: + return call(args, *a, **kw) + except Exception as err: + import inspect + stack = inspect.getframeinfo(inspect.currentframe().f_back) + if hasattr(err, 'remote_traceback'): + logger.error('Traceback (most recent call last):') + logger.error(' File "%s", line %s, in %s' % ( + stack[0], + stack[1], + stack[2]) + ) + err.remote_traceback.pop(0) + for line in err.remote_traceback: + if line: + logger.error(line) + if stop_on_error: + raise RuntimeError( + 'Failed to execute command: %s' % ' '.join(args) + ) + else: + if stop_on_error: + raise err + + +def Popen(conn, logger, args, *a, **kw): + """ + Wraps ``subprocess.Popen`` for a remote call via ``pushy`` + doing all the capturing and logging nicely upon failure/success + + The mangling of the traceback when an exception ocurrs, is because the + caller gets eating up by not being executed in the actual function of + a given module (e.g. ``centos/install.py``) but rather here, where the + stack trace is no longer relevant. + + :param args: The args to be passed onto ``Popen`` + """ + command = ' '.join(args) + patch = kw.pop('patch', True) # Always patch unless explicitly told to + logger.info('Running command: %s' % command) + + def remote_call(args, *a, **kw): + import subprocess + process = subprocess.Popen( + args, + *a, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + **kw + ) + stdout, stderr = process.communicate() + return stdout, stderr, process.wait() + with context.remote(conn, logger, remote_call, mangle_exc=False, patch=patch) as call: try: return call(args, *a, **kw)