Fix serialization of exceptions

This commit is contained in:
Anders Ingemann 2014-11-30 19:16:27 +01:00
parent 056d279b65
commit 2b6fefd789
7 changed files with 56 additions and 29 deletions

View file

@ -136,3 +136,10 @@ class Manifest(object):
return {'__class__': 'bootstrapvz.base.manifest.Manifest',
'path': self.path,
'data': self.data}
def __setstate__(self, state):
self.path = state['path']
self.load(state['data'])
self.initialize()
self.validate()
self.parse()

View file

@ -2,6 +2,7 @@
class ManifestError(Exception):
def __init__(self, message, manifest_path, data_path=None):
super(ManifestError, self).__init__(message)
self.message = message
self.manifest_path = manifest_path
self.data_path = data_path
@ -16,6 +17,7 @@ class ManifestError(Exception):
class TaskListError(Exception):
def __init__(self, message):
super(TaskListError, self).__init__(message)
self.message = message
def __str__(self):

View file

@ -1,22 +1,31 @@
"""Remote module containing methods to bootstrap remotely
"""
import bootstrapvz.common.exceptions
def register_deserialization_handlers():
from Pyro4.util import SerializerBase
SerializerBase.register_dict_to_class('bootstrapvz.base.manifest.Manifest', deserialize_manifest)
SerializerBase.register_dict_to_class('bootstrapvz.base.bootstrapinfo.BootstrapInformation', deserialize_bootstrapinfo)
SerializerBase.register_dict_to_class('bootstrapvz.common.exceptions.ManifestError', deserialize_exception)
SerializerBase.register_dict_to_class('bootstrapvz.common.exceptions.TaskListError', deserialize_exception)
SerializerBase.register_dict_to_class('bootstrapvz.common.exceptions.TaskError', deserialize_exception)
def unregister_deserialization_handlers():
from Pyro4.util import SerializerBase
SerializerBase.unregister_dict_to_class('bootstrapvz.base.manifest.Manifest')
SerializerBase.unregister_dict_to_class('bootstrapvz.base.bootstrapinfo.BootstrapInformation')
SerializerBase.unregister_dict_to_class('bootstrapvz.common.exceptions.ManifestError')
SerializerBase.unregister_dict_to_class('bootstrapvz.common.exceptions.TaskListError')
SerializerBase.unregister_dict_to_class('bootstrapvz.common.exceptions.TaskError')
def deserialize_manifest(classname, state):
from bootstrapvz.base.manifest import Manifest
return Manifest(path=state['path'], data=state['data'])
manifest = Manifest.__new__(Manifest)
manifest.__setstate__(state)
return manifest
def deserialize_bootstrapinfo(classname, state):
@ -24,3 +33,13 @@ def deserialize_bootstrapinfo(classname, state):
bootstrap_info = BootstrapInformation.__new__(BootstrapInformation)
bootstrap_info.__setstate__(state)
return bootstrap_info
deserialize_map = {'bootstrapvz.common.exceptions.ManifestError': bootstrapvz.common.exceptions.ManifestError,
'bootstrapvz.common.exceptions.TaskListError': bootstrapvz.common.exceptions.TaskListError,
'bootstrapvz.common.exceptions.TaskError': bootstrapvz.common.exceptions.TaskError,
}
def deserialize_exception(classname, data):
from Pyro4.util import SerializerBase
return SerializerBase.make_exception(deserialize_map[classname], data)

View file

@ -1,20 +1,19 @@
import Pyro4
import logging
Pyro4.config.REQUIRE_EXPOSE = True
log = logging.getLogger(__name__)
class CallbackServer(object):
def __init__(self, listen_port, remote_port):
self.listen_port = listen_port
self.remote_port = remote_port
def start(self, log_server):
import Pyro4
self.daemon = Pyro4.Daemon(host='localhost', port=self.listen_port,
nathost='localhost', natport=self.remote_port,
self.daemon = Pyro4.Daemon(host='localhost', port=listen_port,
nathost='localhost', natport=remote_port,
unixsocket=None)
self.daemon.register(log_server)
self.daemon.register(self)
def start(self):
def serve():
self.daemon.requestLoop()
from threading import Thread
@ -27,3 +26,13 @@ class CallbackServer(object):
self.daemon.shutdown()
if hasattr(self, 'thread'):
self.thread.join()
@Pyro4.expose
def handle_log(self, pickled_record):
import pickle
record = pickle.loads(pickled_record)
log = logging.getLogger()
record.extra = getattr(record, 'extra', {})
record.extra['source'] = 'remote'
log.handle(record)

View file

@ -15,18 +15,9 @@ class LogForwarder(logging.Handler):
if record.exc_info is not None:
import traceback
exc_type, exc_value, exc_traceback = record.exc_info
record.exc_info = traceback.print_exception(exc_type, exc_value, exc_traceback)
record.extra = getattr(record, 'extra', {})
record.extra['traceback'] = traceback.format_exception(exc_type, exc_value, exc_traceback)
record.exc_info = None
# TODO: Use serpent instead
import pickle
self.server.handle(pickle.dumps(record))
class LogServer(object):
def handle(self, pickled_record):
import pickle
record = pickle.loads(pickled_record)
log = logging.getLogger()
record.extra = getattr(record, 'extra', {})
record.extra['source'] = 'remote'
log.handle(record)
self.server.handle_log(pickle.dumps(record))

View file

@ -82,13 +82,11 @@ def run(manifest, build_server, debug=False, dry_run=False):
from callback import CallbackServer
callback_server = CallbackServer(listen_port=build_server.local_callback_port,
remote_port=build_server.remote_callback_port)
from log import LogServer
log_server = LogServer()
try:
# Start the callback server (in a background thread)
callback_server.start(log_server)
callback_server.start()
# Tell the RPC daemon about the callback server
connection.set_log_server(log_server)
connection.set_callback_server(callback_server)
# Everything has been set up, begin the bootstrapping process
bootstrap_info = connection.run(manifest,

View file

@ -56,9 +56,10 @@ class Server(object):
return run(*args, **kwargs)
@Pyro4.expose
def set_log_server(self, server):
self.log_forwarder.set_server(server)
log.debug('Successfully set the log forwarding server')
def set_callback_server(self, server):
self.callback_server = server
self.log_forwarder.set_server(self.callback_server)
log.debug('Forwarding logs to the callback server now')
@Pyro4.expose
def ping(self):