Fix ExtendedInfo error handling for non-list item
Conflicts: sushy/exceptions.py Change-Id: I2d082762fcf59d7b9bc8adc7c5159520ac628043 (cherry picked from commit7ec04224b4
) (cherry picked from commitdfe6b33fa6
)
This commit is contained in:
parent
74efff4083
commit
40df70a4ea
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixes ``AttributeError: 'str' object has no attribute 'get'`` during error
|
||||||
|
handling. This occurs when BMC does not return a list of messages inside
|
||||||
|
``@Message.ExtendedInfo``, but a single item. This has been observed with
|
||||||
|
iDRAC.
|
|
@ -101,9 +101,9 @@ class HTTPError(SushyError):
|
||||||
self.code = self.body.get('code', 'Base.1.0.GeneralError')
|
self.code = self.body.get('code', 'Base.1.0.GeneralError')
|
||||||
self.detail = self.body.get('message')
|
self.detail = self.body.get('message')
|
||||||
ext_info = self.body.get('@Message.ExtendedInfo', [{}])
|
ext_info = self.body.get('@Message.ExtendedInfo', [{}])
|
||||||
index = self._get_most_severe_msg_index(ext_info)
|
message = self._get_most_severe_msg(ext_info)
|
||||||
self.detail = ext_info[index].get('Message', self.detail)
|
self.detail = message or self.detail
|
||||||
error = '%s: %s' % (self.code, self.detail or 'unknown error')
|
error = '%s: %s' % (self.code, self.detail or 'unknown error.')
|
||||||
|
|
||||||
kwargs = {'method': method, 'url': url, 'code': self.status_code,
|
kwargs = {'method': method, 'url': url, 'code': self.status_code,
|
||||||
'error': error}
|
'error': error}
|
||||||
|
@ -112,13 +112,14 @@ class HTTPError(SushyError):
|
||||||
super(HTTPError, self).__init__(**kwargs)
|
super(HTTPError, self).__init__(**kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_most_severe_msg_index(extended_info):
|
def _get_most_severe_msg(extended_info):
|
||||||
|
if not isinstance(extended_info, list):
|
||||||
|
return extended_info.get('Message', None)
|
||||||
if len(extended_info) > 0:
|
if len(extended_info) > 0:
|
||||||
for sev in ['Critical', 'Warning']:
|
for sev in ['Critical', 'Warning']:
|
||||||
for i, m in enumerate(extended_info):
|
for i, m in enumerate(extended_info):
|
||||||
if m.get('Severity') == sev:
|
if m.get('Severity') == sev:
|
||||||
return i
|
return m.get('Message')
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
class BadRequestError(HTTPError):
|
class BadRequestError(HTTPError):
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"error": {
|
||||||
|
"code": "Base.1.5.GeneralError",
|
||||||
|
"message": "A general error has occurred. See ExtendedInfo for more information.",
|
||||||
|
"@Message.ExtendedInfo": {
|
||||||
|
"@odata.type": "#Message.v1_0_0.Message",
|
||||||
|
"MessageId": "Base.1.5.GeneralError",
|
||||||
|
"Message": "A general error has occurred. See Resolution for information on how to resolve the error.",
|
||||||
|
"Resolution": "Redfish request contains unsupported media type. Correct the request body and resubmit.",
|
||||||
|
"Severity": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -255,6 +255,21 @@ class ConnectorOpTestCase(base.TestCase):
|
||||||
self.assertIsNotNone(exc.body)
|
self.assertIsNotNone(exc.body)
|
||||||
self.assertIn('body submitted was malformed JSON', exc.detail)
|
self.assertIn('body submitted was malformed JSON', exc.detail)
|
||||||
|
|
||||||
|
def test_known_http_error_nonlist_ext_info(self):
|
||||||
|
self.request.return_value.status_code =\
|
||||||
|
http_client.UNSUPPORTED_MEDIA_TYPE
|
||||||
|
with open('sushy/tests/unit/json_samples/'
|
||||||
|
'error_single_ext_info.json') as f:
|
||||||
|
self.request.return_value.json.return_value = json.load(f)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(exceptions.HTTPError,
|
||||||
|
'See Resolution for information') as cm:
|
||||||
|
self.conn._op('POST', 'http://foo.bar')
|
||||||
|
exc = cm.exception
|
||||||
|
self.assertEqual(http_client.UNSUPPORTED_MEDIA_TYPE, exc.status_code)
|
||||||
|
self.assertIsNotNone(exc.body)
|
||||||
|
self.assertIn('See Resolution for information', exc.detail)
|
||||||
|
|
||||||
def test_not_found_error(self):
|
def test_not_found_error(self):
|
||||||
self.request.return_value.status_code = http_client.NOT_FOUND
|
self.request.return_value.status_code = http_client.NOT_FOUND
|
||||||
self.request.return_value.json.side_effect = ValueError('no json')
|
self.request.return_value.json.side_effect = ValueError('no json')
|
||||||
|
|
Loading…
Reference in New Issue