Browse Source

Fix ExtendedInfo error handling for non-list item

Conflicts:
        sushy/exceptions.py

Change-Id: I2d082762fcf59d7b9bc8adc7c5159520ac628043
(cherry picked from commit 7ec04224b4)
(cherry picked from commit dfe6b33fa6)
changes/45/785045/1 2.0.5
Aija Jauntēva 4 months ago
committed by Steve Baker
parent
commit
40df70a4ea
4 changed files with 42 additions and 6 deletions
  1. +7
    -0
      releasenotes/notes/fix-extended-info-error-handling-73fecb6bf5c852ff.yaml
  2. +7
    -6
      sushy/exceptions.py
  3. +13
    -0
      sushy/tests/unit/json_samples/error_single_ext_info.json
  4. +15
    -0
      sushy/tests/unit/test_connector.py

+ 7
- 0
releasenotes/notes/fix-extended-info-error-handling-73fecb6bf5c852ff.yaml View File

@ -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.

+ 7
- 6
sushy/exceptions.py View File

@ -101,9 +101,9 @@ class HTTPError(SushyError):
self.code = self.body.get('code', 'Base.1.0.GeneralError')
self.detail = self.body.get('message')
ext_info = self.body.get('@Message.ExtendedInfo', [{}])
index = self._get_most_severe_msg_index(ext_info)
self.detail = ext_info[index].get('Message', self.detail)
error = '%s: %s' % (self.code, self.detail or 'unknown error')
message = self._get_most_severe_msg(ext_info)
self.detail = message or self.detail
error = '%s: %s' % (self.code, self.detail or 'unknown error.')
kwargs = {'method': method, 'url': url, 'code': self.status_code,
'error': error}
@ -112,13 +112,14 @@ class HTTPError(SushyError):
super(HTTPError, self).__init__(**kwargs)
@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:
for sev in ['Critical', 'Warning']:
for i, m in enumerate(extended_info):
if m.get('Severity') == sev:
return i
return 0
return m.get('Message')
class BadRequestError(HTTPError):


+ 13
- 0
sushy/tests/unit/json_samples/error_single_ext_info.json View File

@ -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"
}
}
}

+ 15
- 0
sushy/tests/unit/test_connector.py View File

@ -255,6 +255,21 @@ class ConnectorOpTestCase(base.TestCase):
self.assertIsNotNone(exc.body)
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):
self.request.return_value.status_code = http_client.NOT_FOUND
self.request.return_value.json.side_effect = ValueError('no json')


Loading…
Cancel
Save