diff --git a/.rootkeys b/.rootkeys index 812f49c65a..f11d07c06a 100644 --- a/.rootkeys +++ b/.rootkeys @@ -240,6 +240,7 @@ 40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/python/xen/xend/XendDomain.py 40c9c468bbKq3uC7_fuNUkiMMjArdw tools/python/xen/xend/XendDomainConfig.py 40c9c4685ykq87_n1kVUbMr9flx9fg tools/python/xen/xend/XendDomainInfo.py +40f50d99YiiaMI1fZBh1VCDFLD57qg tools/python/xen/xend/XendError.py 40c9c46854nsHmuxHQHncKk5rAs5NA tools/python/xen/xend/XendMigrate.py 40c9c468M96gA1EYDvNa5w5kQNYLFA tools/python/xen/xend/XendNode.py 40c9c4686jruMyZIqiaZRMiMoqMJtg tools/python/xen/xend/XendRoot.py diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index e412c1e749..91ba071dc0 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -13,6 +13,8 @@ import types from StringIO import StringIO import urlparse +from twisted.protocols import http + from encode import * import sxp import PrettyPrint @@ -121,9 +123,9 @@ def xend_request(url, method, data=None): resp = conn.getresponse() if DEBUG: print resp.status, resp.reason if DEBUG: print resp.msg.headers - if resp.status in [204, 404]: + if resp.status in [ http.NO_CONTENT ]: return None - if resp.status not in [200, 201, 202, 203]: + if resp.status not in [ http.OK, http.CREATED, http.ACCEPTED ]: raise XendError(resp.reason) pin = sxp.Parser() data = resp.read() @@ -135,7 +137,7 @@ def xend_request(url, method, data=None): val = pin.get_val() #if isinstance(val, types.ListType) and sxp.name(val) == 'val': # val = val[1] - if isinstance(val, types.ListType) and sxp.name(val) == 'err': + if isinstance(val, types.ListType) and sxp.name(val) == 'xend.err': raise XendError(val[1]) if DEBUG: print '**val='; sxp.show(val); print return val diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index a7877bd6cf..6715b57f6a 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -21,6 +21,7 @@ import XendDomainInfo import XendConsole import XendMigrate import EventServer +from XendError import XendError from xen.xend.server import SrvDaemon xend = SrvDaemon.instance() @@ -324,9 +325,9 @@ class XendDomain: dom = int(id) dominfo = self.domain_get(dom) if not dominfo: - raise ValueError("Invalid domain: " + str(id)) + raise XendError("Invalid domain: " + str(id)) if dominfo.config: - raise ValueError("Domain already configured: " + str(id)) + raise XendError("Domain already configured: " + str(id)) def fn(dominfo): self._add_domain(dominfo.id, dominfo) return dominfo @@ -575,7 +576,7 @@ class XendDomain: dom = int(dom) dominfo = self.domain_get(dom) if not dominfo: - raise ValueError("invalid domain:" + str(dom)) + raise XendError("invalid domain:" + str(dom)) self.refresh_schedule() return dominfo.device_create(devconfig) @@ -589,7 +590,7 @@ class XendDomain: dom = int(dom) dominfo = self.domain_get(dom) if not dominfo: - raise ValueError("invalid domain:" + str(dom)) + raise XendError("invalid domain:" + str(dom)) self.refresh_schedule() return dominfo.device_destroy(type, idx) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index a9c4f5b492..be7803f721 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -29,6 +29,8 @@ xendConsole = XendConsole.instance() import server.SrvDaemon xend = server.SrvDaemon.instance() +from XendError import VmError + """Flag for a block device backend domain.""" SIF_BLK_BE_DOMAIN = (1<<4) @@ -58,16 +60,6 @@ def shutdown_reason(code): """ return shutdown_reasons.get(code, "?") -class VmError(ValueError): - """Vm construction error.""" - - def __init__(self, value): - self.value = value - - def __str__(self): - return self.value - - def blkdev_name_to_number(name): """Take the given textual block-device name (e.g., '/dev/sda1', 'hda') and return the device number used by the OS. """ @@ -410,7 +402,11 @@ class XendDomainInfo: self.autorestart = 1 self.configure_backends() image = sxp.child_value(config, 'image') + if image is None: + raise VmError('missing image') image_name = sxp.name(image) + if image_name is None: + raise VmError('missing image name') image_handler = get_image_handler(image_name) if image_handler is None: raise VmError('unknown image type: ' + image_name) diff --git a/tools/python/xen/xend/XendError.py b/tools/python/xen/xend/XendError.py new file mode 100644 index 0000000000..0e6c75ebb7 --- /dev/null +++ b/tools/python/xen/xend/XendError.py @@ -0,0 +1,14 @@ + +class XendError(ValueError): + + def __init__(self, value): + self.value = value + + def __str__(self): + return self.value + +class VmError(XendError): + """Vm construction error.""" + + pass + diff --git a/tools/python/xen/xend/server/SrvBase.py b/tools/python/xen/xend/server/SrvBase.py index 6ea92ae6cc..048339e0b4 100644 --- a/tools/python/xen/xend/server/SrvBase.py +++ b/tools/python/xen/xend/server/SrvBase.py @@ -10,12 +10,15 @@ 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 xen.xend import sxp from xen.xend import PrettyPrint +from xen.xend.Args import ArgError +from xen.xend.XendError import XendError def uri_pathlist(p): """Split a path into a list. @@ -86,33 +89,45 @@ class SrvBase(resource.Resource): """ op = req.args.get('op') if op is None or len(op) != 1: - req.setResponseCode(404, "Invalid") + req.setResponseCode(http.NOT_ACCEPTABLE, "Invalid request") return '' op = op[0] op_method = self.get_op_method(op) if op_method is None: - req.setResponseCode(501, "Not implemented") + req.setResponseCode(http.NOT_IMPLEMENTED, "Operation not implemented: " + op) req.setHeader("Content-Type", "text/plain") - req.write("Not implemented: " + op) + req.write("Operation not implemented: " + op) return '' else: - val = op_method(op, req) - if isinstance(val, defer.Deferred): - val.addCallback(self._cb_perform, req, 1) - return server.NOT_DONE_YET - else: - self._cb_perform(val, req, 0) - return '' + return self._perform(op, op_method, req) - def _cb_perform(self, val, req, dfr): + def _perform(self, op, op_method, req): + try: + val = op_method(op, req) + except Exception, err: + return self._perform_err(err, req) + + if isinstance(val, defer.Deferred): + val.addCallback(self._perform_cb, req, dfr=1) + val.addErrback(self._perform_err, req, dfr=1) + return server.NOT_DONE_YET + else: + self._perform_cb(val, req, 0) + return '' + + def _perform_cb(self, val, req, dfr): """Callback to complete the request. May be called from a Deferred. + + @param err: the error + @param req: request causing the error + @param dfr: deferred flag """ if isinstance(val, error.ErrorPage): req.write(val.render(req)) elif self.use_sxp(req): req.setHeader("Content-Type", sxp.mime_type) - sxp.show(val, req) + sxp.show(val, out=req) else: req.write('
') self.print_path(req) @@ -126,6 +141,34 @@ class SrvBase(resource.Resource): if dfr: req.finish() + def _perform_err(self, err, req, dfr=0): + """Error callback to complete a request. + May be called from a Deferred. + + @param err: the error + @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 dfr: + return err + else: + raise + if self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + sxp.show(['xend.err', str(err)], out=req) + else: + req.setHeader("Content-Type", "text/plain") + req.write('Error in ') + req.write(op) + req.write(': ') + req.write(str(err)) + if dfr: + req.finish() + + def print_path(self, req): """Print the path with hyperlinks. """ diff --git a/tools/python/xen/xend/server/SrvConsole.py b/tools/python/xen/xend/server/SrvConsole.py index 59d0e5f11c..eb8994425b 100644 --- a/tools/python/xen/xend/server/SrvConsole.py +++ b/tools/python/xen/xend/server/SrvConsole.py @@ -21,19 +21,22 @@ class SrvConsole(SrvDir): return self.perform(req) def render_GET(self, req): - if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - sxp.show(self.info.sxpr(), out=req) - else: - req.write('') - self.print_path(req) - #self.ls() - req.write('%s
' % self.info) - req.write('' - % (self.info.uri(), self.info.dom2)) - self.form(req) - req.write('') - return '' + try: + if self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + sxp.show(self.info.sxpr(), out=req) + else: + req.write('') + self.print_path(req) + #self.ls() + req.write('%s
' % self.info) + req.write('' + % (self.info.uri(), self.info.dom2)) + self.form(req) + req.write('') + return '' + except Exception, ex: + self._perform_err(ex, req) def form(self, req): req.write('