From 983ac8ad4155fedd88b42f5786ae839ab5844c37 Mon Sep 17 00:00:00 2001 From: "cl349@freefall.cl.cam.ac.uk" Date: Wed, 3 Nov 2004 22:51:40 +0000 Subject: bitkeeper revision 1.1159.155.6 (418960fcc8HEe_ZDfftWd3gpkqGjnw) Cleanup code to reconnect domain control channel after xend restart. Based on code by Mike Wray. --- tools/python/xen/lowlevel/xu/xu.c | 9 ++++++--- tools/python/xen/xend/XendConsole.py | 5 ++--- tools/python/xen/xend/XendDomainInfo.py | 21 +++++++++++++++++++-- tools/python/xen/xend/server/SrvDaemon.py | 21 +++++++++++++++------ tools/python/xen/xend/server/channel.py | 29 +++++++++++++++++++++++------ tools/python/xen/xend/server/console.py | 11 ++++------- tools/python/xen/xend/server/controller.py | 10 ++++------ 7 files changed, 73 insertions(+), 33 deletions(-) diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c index 29213e93ff..9a67693683 100644 --- a/tools/python/xen/lowlevel/xu/xu.c +++ b/tools/python/xen/lowlevel/xu/xu.c @@ -1054,13 +1054,16 @@ static PyMethodDef xu_port_methods[] = { staticforward PyTypeObject xu_port_type; -static PyObject *xu_port_new(PyObject *self, PyObject *args) +static PyObject *xu_port_new(PyObject *self, PyObject *args, PyObject *kwds) { xu_port_object *xup; u32 dom; int port1 = 0, port2 = 0; - if ( !PyArg_ParseTuple(args, "i|ii", &dom, &port1, &port2) ) + static char *kwd_list[] = { "dom", "local_port", "remote_port", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|ii", kwd_list, + &dom, &port1, &port2) ) return NULL; xup = PyObject_New(xu_port_object, &xu_port_type); @@ -1435,7 +1438,7 @@ static PyMethodDef xu_methods[] = { "Create a new notifier." }, { "message", xu_message_new, METH_VARARGS, "Create a new communications message." }, - { "port", xu_port_new, METH_VARARGS, + { "port", (PyCFunction)xu_port_new, METH_VARARGS | METH_KEYWORDS, "Create a new communications port." }, { "buffer", xu_buffer_new, METH_VARARGS, "Create a new ring buffer." }, diff --git a/tools/python/xen/xend/XendConsole.py b/tools/python/xen/xend/XendConsole.py index ea79645be9..6825dc5baa 100644 --- a/tools/python/xen/xend/XendConsole.py +++ b/tools/python/xen/xend/XendConsole.py @@ -32,9 +32,8 @@ class XendConsole: def consoles(self): return daemon.get_consoles() - def console_create(self, dom, console_port=None, remote_port=0): - consinfo = daemon.console_create(dom, console_port=console_port, - remote_port=remote_port) + def console_create(self, dom, console_port=None): + consinfo = daemon.console_create(dom, console_port=console_port) return consinfo def console_get(self, id): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 36d6a33361..70cd68db1c 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -753,17 +753,34 @@ class XendDomainInfo: @param ramdisk: kernel ramdisk @param cmdline: kernel commandline """ - #self.init_domain() + + self.create_channel() if self.console: self.console.registerChannel() else: self.console = xendConsole.console_create( - self.dom, console_port=self.console_port, remote_port=1) + self.dom, console_port=self.console_port) self.build_domain(ostype, kernel, ramdisk, cmdline) self.image = kernel self.ramdisk = ramdisk self.cmdline = cmdline + def create_channel(self): + """Create the channel to the domain. + If saved info is available recreate the channel using the saved ports. + + @return: channel + """ + local = 0 + remote = 1 + if self.savedinfo: + consinfo = sxp.child(self.savedinfo, "console") + if consinfo: + local = int(sxp.child_value(consinfo, "local_port", 0)) + remote = int(sxp.child_value(consinfo, "remote_port", 1)) + return xend.createDomChannel(self.dom, local_port=local, + remote_port=remote) + def create_devices(self): """Create the devices for a vm. diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index cc7da8ee43..41a5965221 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -638,12 +638,22 @@ class Daemon: def getDomChannel(self, dom): """Get the channel to a domain. - dom domain - - returns channel (or None) + @param dom: domain + @return: channel (or None) """ return self.channelF.getDomChannel(dom) + def createDomChannel(self, dom, local_port=0, remote_port=0): + """Get the channel to a domain, creating if necessary. + + @param dom: domain + @param local_port: optional local port to re-use + @param remote_port: optional remote port to re-use + @return: channel + """ + return self.channelF.domChannel(dom, local_port=local_port, + remote_port=remote_port) + def blkif_create(self, dom, recreate=0): """Create or get a block device interface controller. @@ -671,13 +681,12 @@ class Daemon: def netif_get(self, dom): return self.netifCF.getControllerByDom(dom) - def console_create(self, dom, console_port=None, remote_port=0): + def console_create(self, dom, console_port=None): """Create a console for a domain. """ console = self.consoleCF.getControllerByDom(dom) if console is None: - console = self.consoleCF.createController(dom, console_port, - remote_port=remote_port) + console = self.consoleCF.createController(dom, console_port) return console def consoles(self): diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index 1401c35435..127f38f2c0 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -45,7 +45,7 @@ class ChannelFactory: del self.channels[idx] self.notifier.unbind(idx) - def domChannel(self, dom, remote_port=0): + def domChannel(self, dom, local_port=0, remote_port=0): """Get the channel for the given domain. Construct if necessary. @@ -55,7 +55,8 @@ class ChannelFactory: """ chan = self.getDomChannel(dom) if not chan: - chan = Channel(self, dom, remote_port=remote_port) + chan = Channel(self, dom, local_port=local_port, + remote_port=remote_port) self.addChannel(chan) return chan @@ -91,10 +92,25 @@ class ChannelFactory: """ self.delChannel(channel.idx) - def createPort(self, dom, remote_port=0): + def createPort(self, dom, local_port=0, remote_port=0): """Create a port for a channel to the given domain. + If only the domain is specified, a new channel with new port ids is + created. If one port id is specified and the given port id is in use, + the other port id is filled. If one port id is specified and the + given port id is not in use, a new channel is created with one port + id equal to the given id and a new id for the other end. If both + port ids are specified, a port is reconnected using the given port + ids. + + @param dom: domain + @param local: local port id to use + @type local: int + @param remote: remote port id to use + @type remote: int + @return: port object """ - return xu.port(dom, 0, remote_port) + return xu.port(dom, local_port=int(local_port), + remote_port=int(remote_port)) def channelFactory(): """Singleton constructor for the channel factory. @@ -200,7 +216,7 @@ class Channel(BaseChannel): are multiplexed over the channel (console, block devs, net devs). """ - def __init__(self, factory, dom, remote_port=0): + def __init__(self, factory, dom, local_port=0, remote_port=0): """Create a channel to the given domain using the given factory. Do not call directly, use domChannel on the factory. @@ -209,7 +225,8 @@ class Channel(BaseChannel): # Domain. self.dom = int(dom) # Domain port (object). - self.port = self.factory.createPort(dom, remote_port=remote_port) + self.port = self.factory.createPort(dom, local_port=local_port, + remote_port=remote_port) # Channel port (int). self.idx = self.port.local_port # Registered devices. diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index 3d302dbe3f..ea4bf49921 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -48,7 +48,6 @@ class ConsoleProtocol(protocol.Protocol): self.loseConnection() def write(self, data): - #if not self.connected: return -1 self.transport.write(data) return len(data) @@ -81,14 +80,13 @@ class ConsoleControllerFactory(controller.ControllerFactory): """Factory for creating console controllers. """ - def createController(self, dom, console_port=None, remote_port=0): + def createController(self, dom, console_port=None): if console_port is None: console_port = CONSOLE_PORT_BASE + dom for c in self.getControllers(): if c.console_port == console_port: raise XendError('console port in use: ' + str(console_port)) - console = ConsoleController(self, dom, console_port, - remote_port=remote_port) + console = ConsoleController(self, dom, console_port) self.addController(console) log.info("Created console id=%s domain=%d port=%d", console.idx, console.dom, console.console_port) @@ -112,9 +110,8 @@ class ConsoleController(controller.Controller): STATUS_CONNECTED = 'connected' STATUS_LISTENING = 'listening' - def __init__(self, factory, dom, console_port, remote_port=0): - controller.Controller.__init__(self, factory, dom, - remote_port=remote_port) + def __init__(self, factory, dom, console_port): + controller.Controller.__init__(self, factory, dom) self.addMethod(CMSG_CONSOLE, 0, None) self.status = self.STATUS_NEW self.addr = None diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 5b2d7e25a0..c8962d4675 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -68,7 +68,7 @@ class CtrlMsgRcvr: @type responders: {int:Responder} """ - def __init__(self, remote_port=0): + def __init__(self): self.channelFactory = channel.channelFactory() self.majorTypes = {} self.dom = None @@ -76,7 +76,6 @@ class CtrlMsgRcvr: self.idx = None self.responders = {} self.timeout = 10 - self.remote_port = remote_port def setTimeout(self, timeout): self.timeout = timeout @@ -218,8 +217,7 @@ class CtrlMsgRcvr: channel to our domain. Once we have registered, the channel will call requestReceived or responseReceived for our messages. """ - self.channel = self.channelFactory.domChannel(self.dom, - self.remote_port) + self.channel = self.channelFactory.domChannel(self.dom) self.idx = self.channel.getIndex() if self.majorTypes: self.channel.registerDevice(self.getMajorTypes(), self) @@ -364,8 +362,8 @@ class Controller(CtrlMsgRcvr): @type idx: String """ - def __init__(self, factory, dom, remote_port=0): - CtrlMsgRcvr.__init__(self, remote_port=remote_port) + def __init__(self, factory, dom): + CtrlMsgRcvr.__init__(self) self.factory = factory self.dom = int(dom) self.channel = None -- cgit v1.2.3 From 5693a9fd4be82285e3cfc66840534f92b41f2c24 Mon Sep 17 00:00:00 2001 From: "cl349@freefall.cl.cam.ac.uk" Date: Wed, 3 Nov 2004 23:01:54 +0000 Subject: bitkeeper revision 1.1159.155.7 (41896362-2P6ibesMBXM0pV5gks0Bw) Apply changes from Mike Wray: - Get domain creation errors returned to the caller. - Add logging for domain create failures. --- tools/python/xen/xend/server/SrvBase.py | 24 ++++++++++++++---------- tools/python/xen/xend/server/SrvDomainDir.py | 27 +++------------------------ 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/tools/python/xen/xend/server/SrvBase.py b/tools/python/xen/xend/server/SrvBase.py index 6bc32b42bc..b32d102273 100644 --- a/tools/python/xen/xend/server/SrvBase.py +++ b/tools/python/xen/xend/server/SrvBase.py @@ -8,17 +8,18 @@ import types import StringIO from twisted.internet import defer -#defer.Deferred.debug = 1 from twisted.internet import reactor from twisted.protocols import http from twisted.web import error from twisted.web import resource from twisted.web import server +from twisted.python.failure import Failure from xen.xend import sxp from xen.xend import PrettyPrint from xen.xend.Args import ArgError from xen.xend.XendError import XendError +from xen.xend.XendLogging import log def uri_pathlist(p): """Split a path into a list. @@ -105,17 +106,17 @@ class SrvBase(resource.Resource): try: val = op_method(op, req) except Exception, err: - return self._perform_err(err, req) + return self._perform_err(err, op, req) if isinstance(val, defer.Deferred): - val.addCallback(self._perform_cb, req, dfr=1) - val.addErrback(self._perform_err, req, dfr=1) + val.addCallback(self._perform_cb, op, req, dfr=1) + val.addErrback(self._perform_err, op, req, dfr=1) return server.NOT_DONE_YET else: - self._perform_cb(val, req, 0) + self._perform_cb(val, op, req, dfr=0) return '' - def _perform_cb(self, val, req, dfr): + def _perform_cb(self, val, op, req, dfr=0): """Callback to complete the request. May be called from a Deferred. @@ -141,7 +142,7 @@ class SrvBase(resource.Resource): if dfr: req.finish() - def _perform_err(self, err, req, dfr=0): + def _perform_err(self, err, op, req, dfr=0): """Error callback to complete a request. May be called from a Deferred. @@ -149,13 +150,16 @@ class SrvBase(resource.Resource): @param req: request causing the error @param dfr: deferred flag """ - if not (isinstance(err, ArgError) or - isinstance(err, sxp.ParseError) or - isinstance(err, XendError)): + if isinstance(err, Failure): + err = err.getErrorMessage() + elif not (isinstance(err, ArgError) or + isinstance(err, sxp.ParseError) or + isinstance(err, XendError)): if dfr: return err else: raise + log.exception("op=%s: %s", op, str(err)) if self.use_sxp(req): req.setHeader("Content-Type", sxp.mime_type) sxp.show(['xend.err', str(err)], out=req) diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index 08eed6da38..2fc8ee4877 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -11,6 +11,7 @@ from xen.xend import sxp from xen.xend import XendDomain from xen.xend.Args import FormFn from xen.xend.XendError import XendError +from xen.xend.XendLogging import log from SrvDir import SrvDir from SrvDomain import SrvDomain @@ -59,18 +60,15 @@ class SrvDomainDir(SrvDir): except sxp.ParseError, ex: errmsg = 'Invalid configuration ' + str(ex) if not ok: - req.setResponseCode(http.BAD_REQUEST, errmsg) - return errmsg + raise XendError(errmsg) try: deferred = self.xd.domain_create(config) deferred.addCallback(self._op_create_cb, configstring, req) - deferred.addErrback(self._op_create_err, req) return deferred except Exception, ex: print 'op_create> Exception creating domain:' traceback.print_exc() - req.setResponseCode(http.BAD_REQUEST, "Error creating domain: " + str(ex)) - return str(ex) + raise XendError("Error creating domain: " + str(ex)) def _op_create_cb(self, dominfo, configstring, req): """Callback to handle deferred domain creation. @@ -92,27 +90,15 @@ class SrvDomainDir(SrvDir): out.close() return val - def _op_create_err(self, err, req): - """Callback to handle errors in deferred domain creation. - """ - if isinstance(err, Failure): - err = err.getErrorMessage() - print 'op_create> Deferred Exception creating domain:', err - traceback.print_exc() - req.setResponseCode(http.BAD_REQUEST, "Error creating domain: " + str(err)) - return str(err) - def op_restore(self, op, req): """Restore a domain from file. @return: deferred """ - #todo: return is deferred. May need ok and err callbacks. fn = FormFn(self.xd.domain_restore, [['file', 'str']]) deferred = fn(req.args) deferred.addCallback(self._op_restore_cb, req) - #deferred.addErrback(self._op_restore_err, req) return deferred def _op_restore_cb(self, dominfo, req): @@ -130,13 +116,6 @@ class SrvDomainDir(SrvDir): out.close() return val - def _op_restore_err(self, err, req): - if isinstance(err, Failure): - err = err.getErrorMessage() - print 'op_create> Deferred Exception restoring domain:', err - req.setResponseCode(http.BAD_REQUEST, "Error restoring domain: "+ str(err)) - return str(err) - def render_POST(self, req): return self.perform(req) -- cgit v1.2.3