2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-08-28 09:36:41 +00:00
Files
confluent/confluent_server/confluent/exceptions.py
T
Markus Hilger f6ba3802bc Report an error that carries no message of its own
nodereseat printed "Error: " and nothing else against a bmc that refused the
credentials. The redfish plugin reports it properly, but the message it emits
re-raises TargetEndpointBadCredentials with no arguments when a single node is
addressed, and the enclosure plugin renders that with str(e), which is empty.

Both hardwaremanagement plugins already had a helper for exactly this, one copy
each. Keep one in confluent.exceptions instead, teach it to fall back to the
description a confluent exception carries by class before falling back to the
exception name, and use it in the enclosure plugin too.

get_error_body had the mirror image of the same bug, joining the class
description and the message unconditionally and so answering "Bad Credentials -"
with a separator and nothing after it. The apierrorstr property beside it
already gets this right, so use it.
2026-08-14 21:26:28 +02:00

165 lines
5.2 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 IBM Corporation
# Copyright 2015-2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import base64
import json
import msgpack
def exc_text(theexc):
"""Render an exception for a user, even when it carries no message.
An error with no text at all tells the user nothing, so fall back to the
description a confluent exception carries by class, and then to the name of
the exception.
"""
text = str(theexc)
if text and text != 'None':
return text
return getattr(theexc, '_apierrorstr', None) or type(theexc).__name__
def deserialize_exc(msg):
excd = msgpack.unpackb(msg, raw=False)
if excd[0] == 'Exception':
return Exception(excd[1])
if excd[0] not in globals():
return Exception('Cannot deserialize: {0}'.format(repr(excd)))
classn = globals()[excd[0]]
if not issubclass(classn, ConfluentException):
return Exception('Cannot deserialize: {0}'.format(repr(excd)))
return classn(*excd[1])
class ConfluentException(Exception):
apierrorcode = 500
_apierrorstr = 'Unexpected Error'
def get_error_body(self):
return json.dumps({'error': self.apierrorstr})
def serialize(self):
return msgpack.packb([self.__class__.__name__, [str(self)]],
use_bin_type=False)
@property
def apierrorstr(self):
if str(self):
return self._apierrorstr + ' - ' + str(self)
return self._apierrorstr
class NotFoundException(ConfluentException):
# Something that could be construed as a name was not found
# basically, picture an http error code 404
apierrorcode = 404
_apierrorstr = 'Target not found'
class InvalidArgumentException(ConfluentException):
# Something from the remote client wasn't correct
# like http code 400
apierrorcode = 400
_apierrorstr = 'Bad Request'
class TargetEndpointUnreachable(ConfluentException):
# A target system was unavailable. For example, a BMC
# was unreachable. http code 504
apierrorcode = 504
_apierrorstr = 'Unreachable Target'
class TargetEndpointBadCredentials(ConfluentException):
# target was reachable, but authentication/authorization
# failed
apierrorcode = 502
_apierrorstr = 'Bad Credentials'
class LockedCredentials(ConfluentException):
# A request was performed that required a credential, but the credential
# store is locked
_apierrorstr = 'Credential store locked'
class DegradedCollective(ConfluentException):
# We are in a collective with at least half of the member nodes missing
_apierrorstr = 'Collective does not have quorum'
class ForbiddenRequest(ConfluentException):
# The client request is not allowed by authorization engine
apierrorcode = 403
_apierrorstr = 'Forbidden'
class NotImplementedException(ConfluentException):
# The current configuration/plugin is unable to perform
# the requested task. http code 501
apierrorcode = 501
_apierrorstr = '501 - Not Implemented'
class GlobalConfigError(ConfluentException):
# The configuration in the global config file is not right
_apierrorstr = 'Global configuration contains an error'
class TargetResourceUnavailable(ConfluentException):
# This is meant for scenarios like asking to read a sensor that is
# currently unavailable. This may be a persistent or transient state
apierrocode = 503
_apierrorstr = 'Target Resource Unavailable'
class PubkeyInvalid(ConfluentException):
apierrorcode = 502
_apierrorstr = '502 - Invalid certificate or key on target'
def __init__(self, text, certificate, fingerprint, attribname, event):
super(PubkeyInvalid, self).__init__(self, text)
self.myargs = (text, certificate, fingerprint, attribname, event)
self.fingerprint = fingerprint
self.attrname = attribname
self.message = text
certtxt = base64.b64encode(certificate)
if not isinstance(certtxt, str):
certtxt = certtxt.decode('utf8')
bodydata = {'message': text,
'event': event,
'fingerprint': fingerprint,
'fingerprintfield': attribname,
'certificate': certtxt}
self.errorbody = json.dumps(bodydata)
def serialize(self):
return msgpack.packb([self.__class__.__name__, self.myargs],
use_bin_type=False)
def get_error_body(self):
return self.errorbody
class LoggedOut(ConfluentException):
apierrorcode = 401
_apierrorstr = '401 - Logged out'
def get_error_body(self):
return '{"loggedout": 1}'
class Disconnect(ConfluentException):
apierrorcode = 503
_apierrorstr = 'Client disconnected'