

def remote_compile(client, fn):
    def outer(fn):
        from functools import wraps
        @wraps(fn)
        def inner(*args, **kwargs):
            class RemoteException(Exception):

                def __init__(self, remote_traceback, err):
                    self.err = err
                    self.remote_traceback = remote_traceback

            try:
                fn(*args, **kwargs)
            except Exception as err:
                import traceback
                remote_trace = traceback.format_exc()
                raise RemoteException(remote_trace.split('\n'), err)
        return inner
    return client.compile(outer)(client.compile(fn))

@@ -1,8 +1,62 @@
+import logging%0Aimport sys%0Afrom functools import wraps%0A
 %0A%0Adef re
@@ -714,8 +714,1824 @@
 le(fn))%0A
+%0A%0Adef catches(catch=None, handler=None, exit=True):%0A    %22%22%22%0A    Very simple decorator that tries any of the exception(s) passed in as%0A    a single exception class or tuple (containing multiple ones) returning the%0A    exception message and optionally handling the problem if it rises with the%0A    handler if it is provided.%0A%0A    So instead of douing something like this::%0A%0A        def bar():%0A            try:%0A                some_call()%0A                print %22Success!%22%0A            except TypeError, exc:%0A                print %22Error while handling some call: %25s%22 %25 exc%0A                sys.exit(1)%0A%0A    You would need to decorate it like this to have the same effect::%0A%0A        @catches(TypeError)%0A        def bar():%0A            some_call()%0A            print %22Success!%22%0A%0A    If multiple exceptions need to be caught they need to be provided as a%0A    tuple::%0A%0A        @catches((TypeError, AttributeError))%0A        def bar():%0A            some_call()%0A            print %22Success!%22%0A    %22%22%22%0A    catch = catch or Exception%0A    logger = logging.getLogger('ceph_deploy')%0A%0A    def decorate(f):%0A%0A        @wraps(f)%0A        def newfunc(*a, **kw):%0A            try:%0A                return f(*a, **kw)%0A            except catch as e:%0A                if handler:%0A                    return handler(e)%0A                else:%0A                    logger.error(make_exception_message(e))%0A                    if exit:%0A                        sys.exit(1)%0A        return newfunc%0A%0A    return decorate%0A%0A#%0A# Decorator helpers%0A#%0A%0A%0Adef make_exception_message(exc):%0A    %22%22%22%0A    An exception is passed in and this function%0A    returns the proper string depending on the result%0A    so it is readable enough.%0A    %22%22%22%0A    if str(exc):%0A        return '%25s: %25s%5Cn' %25 (exc.__class__.__name__, exc)%0A    else:%0A        return '%25s%5Cn' %25 (exc.__class__.__name__)%0A%0A

create a catches decorator to handle exceptions