From 23aac5dab76200fa74b262f5ce536b086b1ba69b Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 5 May 2014 19:53:57 -0400 Subject: [PATCH] Rework error reporting for errors. For now, the only live path is the one that gets struck by exception. However, the exception only happens on 'strip_node', meaning for multi-node resources, things should be sane when the time comes. --- TODO | 8 +++---- confluent/httpapi.py | 31 ++++++++++++++----------- confluent/messages.py | 36 ++++++++++++++++++++++++++++++ confluent/sockapi.py | 8 +++++++ plugins/hardwaremanagement/ipmi.py | 4 ++-- 5 files changed, 68 insertions(+), 19 deletions(-) diff --git a/TODO b/TODO index 22042929..9b8ca6ce 100644 --- a/TODO +++ b/TODO @@ -10,9 +10,6 @@ 'flexdiscover' command, if possible bring an ipmi device under management by way of ipv6 to eliminate requirement for ip to be specified. Requires the polling event support (which is required for security anyway) --Change the remote timeout behavior to yield a response, then have pluginapi - decides whether to error the response or a message indicating error in case of - multi-node request -this stack trace (happened with method was set to ""): Traceback (most recent call last): @@ -32,4 +29,7 @@ KeyError: '' -confetty to do right thing with respect to status updates when run right on a console. It currently clutters up the screen with data that would land in a titlebar --audit log did not show confetty activity for starting console \ No newline at end of file +-audit log did not show confetty activity for starting console +-ipmi plugin needs to watch for connection attribute changes. test case is to + connect to a bmc and then misconfigure. Currently, it keeps working, it should + break. watchattribs is the key \ No newline at end of file diff --git a/confluent/httpapi.py b/confluent/httpapi.py index 0a0eb992..1d485608 100644 --- a/confluent/httpapi.py +++ b/confluent/httpapi.py @@ -351,25 +351,30 @@ def resourcehandler_backend(env, start_response): try: hdlr = pluginapi.handle_path(url, operation, cfgmgr, querydict) + + pagecontent = "" + if mimetype == 'text/html': + for datum in _assemble_html(hdlr, resource, lquerydict, url, + extension): + pagecontent += datum + else: + for datum in _assemble_json(hdlr, resource, url, extension): + pagecontent += datum + start_response('200 OK', headers) + yield pagecontent except exc.NotFoundException: start_response('404 Not found', headers) yield "404 - Request path not recognized" - return except exc.InvalidArgumentException: - traceback.print_exc() start_response('400 Bad Request', headers) yield '400 - Bad Request' - return - pagecontent = "" - if mimetype == 'text/html': - for datum in _assemble_html(hdlr, resource, lquerydict, url, - extension): - pagecontent += datum - else: - for datum in _assemble_json(hdlr, resource, url, extension): - pagecontent += datum - start_response('200 OK', headers) - yield pagecontent + except exc.TargetEndpointUnreachable: + start_response('504 Unreachable Target', headers) + yield '504 - Unreachable Target' + except exc.TargetEndpointBadCredentials: + start_response('502 Bad Credentials', headers) + yield '502 - Bad Credentials' + def _assemble_html(responses, resource, querydict, url, extension): diff --git a/confluent/messages.py b/confluent/messages.py index 929f2440..15fd9d6b 100644 --- a/confluent/messages.py +++ b/confluent/messages.py @@ -126,6 +126,42 @@ class ConfluentMessage(object): return snippet +class ConfluentNodeError(object): + def __init__(self, node): + self.node = node + self.error = None + raise NotImplementedError # this is an abstract base class + + def raw(self): + return {self.node: {'error': self.error}} + + def html(self): + return self.node + ":" + self.error + + def strip_node(self, node): + #NOTE(jbjohnso): For single node errors, raise exception to + #trigger what a developer of that medium would expect + raise NotImplementedError + + +class ConfluentTargetTimeout(ConfluentNodeError): + def __init__(self, node): + self.node = node + self.error = 'timeout' + + def strip_node(self, node): + raise exc.TargetEndpointUnreachable + + +class ConfluentTargetInvalidCredentials(ConfluentNodeError): + def __init__(self, node): + self.node = node + self.error = 'bad credentials' + + def strip_node(self, node): + raise exc.TargetEndpointBadCredentials + + class DeletedResource(ConfluentMessage): def __init__(self, resource): self.kvpairs = {} diff --git a/confluent/sockapi.py b/confluent/sockapi.py index 15c4a03a..6e5150f3 100644 --- a/confluent/sockapi.py +++ b/confluent/sockapi.py @@ -102,6 +102,14 @@ def sessionhdl(connection, authname, skipauth=False): tlvdata.send(connection, {'errorcode': 403, 'error': 'Forbidden'}) tlvdata.send(connection, {'_requestdone': 1}) + except exc.TargetEndpointBadCredentials: + tlvdata.send(connection, {'errorcode': 502, + 'error': 'Bad Credentials'}) + tlvdata.send(connection, {'_requestdone': 1}) + except exc.TargetEndpointUnreachable: + tlvdata.send(connection, {'errorcode': 504, + 'error': 'Unreachable Target'}) + tlvdata.send(connection, {'_requestdone': 1}) except: tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event, event=log.Events.stacktrace) diff --git a/plugins/hardwaremanagement/ipmi.py b/plugins/hardwaremanagement/ipmi.py index f04d3ea3..3492e297 100644 --- a/plugins/hardwaremanagement/ipmi.py +++ b/plugins/hardwaremanagement/ipmi.py @@ -217,7 +217,7 @@ class IpmiHandler(object): tenant = cfg.tenant self._logevt = None if ((node, tenant) not in persistent_ipmicmds or - not persistent_ipmicmds[(node, tenant)].logged): + not persistent_ipmicmds[(node, tenant)].ipmi_session.logged): self._logevt = threading.Event() persistent_ipmicmds[(node, tenant)] = ipmicommand.Command( bmc=connparams['bmc'], userid=connparams['username'], @@ -243,7 +243,7 @@ class IpmiHandler(object): self._logevt = None if self.broken: if self.error == 'timeout': - raise exc.TargetEndpointUnreachable('Target timed out') + return iter([msg.ConfluentTargetTimeout(self.node)]) else: raise Exception(self.error) if self.element == ['power', 'state']: