Make message parsing more resilient
Firmware from some vendors only includes the MessageKey in the MessageID. In this case, fall back to finding the MessageKey first in the Messages MessageRegistryFile and then in the BaseMessages MessageRegistryFile. If the message can't be found, then set the parsed message to 'unknown' instead of throwing an exception. If there are not enough arguments to populate the message, then populate the missing arguments with 'unknown'. Change-Id: I045f82167a415c92d6b67532222aef89ab1d68ef
This commit is contained in:
parent
b1bf433512
commit
bad68e1e60
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Makes message parsing more resilient by handling the case where the message
|
||||
ID only contains a message key and no registry name. In this case, fall
|
||||
back to the ``Messages`` message registry file and then to the
|
||||
``BaseMessages`` message registry file. If the message ID cannot be found,
|
||||
then set the message to ``unknown``. When parsing messages, if not enough
|
||||
arguments were supplied, then fill in the remaining arguments with
|
||||
``unknown``.
|
|
@ -459,9 +459,10 @@ class Sushy(base.ResourceBase):
|
|||
Fetches all registries if any provided by Redfish service
|
||||
and combines together with packaged standard registries.
|
||||
|
||||
:returns: dict of combined message registries where key is
|
||||
Registry_name.Major_version.Minor_version and value is registry
|
||||
itself.
|
||||
:returns: dict of combined message registries keyed by both the
|
||||
registry name (Registry_name.Major_version.Minor_version) and the
|
||||
message registry file identity, with the value being the actual
|
||||
registry itself.
|
||||
"""
|
||||
standard = self._get_standard_message_registry_collection()
|
||||
|
||||
|
@ -473,9 +474,13 @@ class Sushy(base.ResourceBase):
|
|||
|
||||
if registry_col:
|
||||
provided = registry_col.get_members()
|
||||
registries.update({r.registry: r.get_message_registry(
|
||||
self._language,
|
||||
self._public_connector) for r in provided})
|
||||
for r in provided:
|
||||
message_registry = r.get_message_registry(
|
||||
self._language,
|
||||
self._public_connector)
|
||||
registries[r.registry] = message_registry
|
||||
if r.identity not in registries:
|
||||
registries[r.identity] = message_registry
|
||||
|
||||
return registries
|
||||
|
||||
|
|
|
@ -13,11 +13,14 @@
|
|||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/v1/MessageRegistry.v1_1_1.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources import constants as res_cons
|
||||
from sushy.resources import mappings as res_maps
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MessageDictionaryField(base.DictionaryField):
|
||||
|
||||
|
@ -92,13 +95,44 @@ def parse_message(message_registries, message_field):
|
|||
:returns: parsed settings.MessageListField with missing attributes filled
|
||||
"""
|
||||
|
||||
registry, msg_key = message_field.message_id.rsplit('.', 1)
|
||||
reg_msg = None
|
||||
if '.' in message_field.message_id:
|
||||
registry, msg_key = message_field.message_id.rsplit('.', 1)
|
||||
|
||||
reg_msg = message_registries[registry].messages[msg_key]
|
||||
if (registry in message_registries and msg_key
|
||||
in message_registries[registry].messages):
|
||||
reg_msg = message_registries[registry].messages[msg_key]
|
||||
else:
|
||||
# Some firmware only reports the MessageKey and no RegistryName.
|
||||
# Fall back to the MessageRegistryFile with Id of Messages next, and
|
||||
# BaseMessages as a last resort
|
||||
registry = 'unknown'
|
||||
msg_key = message_field.message_id
|
||||
|
||||
mrf_ids = ['Messages', 'BaseMessages']
|
||||
for mrf_id in mrf_ids:
|
||||
if (mrf_id in message_registries and msg_key in
|
||||
message_registries[mrf_id].messages):
|
||||
reg_msg = message_registries[mrf_id].messages[msg_key]
|
||||
break
|
||||
|
||||
if not reg_msg:
|
||||
LOG.warning(
|
||||
'Unable to find message for registry %(registry), '
|
||||
'message ID %(msg_key)', {
|
||||
'registry': registry,
|
||||
'msg_key': msg_key})
|
||||
if message_field.message is None:
|
||||
message_field.message = 'unknown'
|
||||
return message_field
|
||||
|
||||
msg = reg_msg.message
|
||||
for i in range(1, reg_msg.number_of_args + 1):
|
||||
msg = msg.replace('%%%i' % i, str(message_field.message_args[i - 1]))
|
||||
if i <= len(message_field.message_args):
|
||||
msg = msg.replace('%%%i' % i,
|
||||
str(message_field.message_args[i - 1]))
|
||||
else:
|
||||
msg = msg.replace('%%%i' % i, 'unknown')
|
||||
|
||||
message_field.message = msg
|
||||
if not message_field.severity:
|
||||
|
|
|
@ -131,3 +131,130 @@ class MessageRegistryTestCase(base.TestCase):
|
|||
self.assertEqual(res_cons.SEVERITY_OK, parsed_msg.severity)
|
||||
self.assertEqual('Everything done successfully.',
|
||||
parsed_msg.message)
|
||||
|
||||
def test_parse_message_bad_registry(self):
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/message_registry.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
registry = message_registry.MessageRegistry(
|
||||
conn, '/redfish/v1/Registries/Test',
|
||||
redfish_version='1.0.2')
|
||||
registries = {'Test.1.0.0': registry}
|
||||
message_field = sushy_base.MessageListField('Foo')
|
||||
message_field.message_id = 'BadRegistry.TooBig'
|
||||
|
||||
parsed_msg = message_registry.parse_message(registries, message_field)
|
||||
|
||||
self.assertEqual(message_field, parsed_msg)
|
||||
|
||||
def test_parse_message_bad_message_key_existing_message(self):
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/message_registry.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
registry = message_registry.MessageRegistry(
|
||||
conn, '/redfish/v1/Registries/Test',
|
||||
redfish_version='1.0.2')
|
||||
registries = {'Test.1.0.0': registry}
|
||||
message_field = sushy_base.MessageListField('Foo')
|
||||
message_field.message_id = 'Test.1.0.0.BadMessageKey'
|
||||
message_field.message = 'Message'
|
||||
|
||||
parsed_msg = message_registry.parse_message(registries, message_field)
|
||||
|
||||
self.assertEqual(message_field.message, 'Message')
|
||||
self.assertEqual(message_field.message, parsed_msg.message)
|
||||
|
||||
def test_parse_message_bad_message_key_no_existing_message(self):
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/message_registry.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
registry = message_registry.MessageRegistry(
|
||||
conn, '/redfish/v1/Registries/Test',
|
||||
redfish_version='1.0.2')
|
||||
registries = {'Test.1.0.0': registry}
|
||||
message_field = sushy_base.MessageListField('Foo')
|
||||
message_field.message_id = 'Test.1.0.0.BadMessageKey'
|
||||
message_field.message = None
|
||||
|
||||
parsed_msg = message_registry.parse_message(registries, message_field)
|
||||
|
||||
self.assertEqual(message_field.message, 'unknown')
|
||||
self.assertEqual(message_field.message, parsed_msg.message)
|
||||
|
||||
def test_parse_message_fallback_to_messages(self):
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/message_registry.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
registry = message_registry.MessageRegistry(
|
||||
conn, '/redfish/v1/Registries/Test',
|
||||
redfish_version='1.0.2')
|
||||
registries = {'Messages': registry}
|
||||
message_field = sushy_base.MessageListField('Foo')
|
||||
message_field.message_id = 'Success'
|
||||
message_field.severity = res_cons.SEVERITY_OK
|
||||
message_field.resolution = 'Do nothing'
|
||||
|
||||
parsed_msg = message_registry.parse_message(registries, message_field)
|
||||
|
||||
self.assertEqual('Do nothing', parsed_msg.resolution)
|
||||
self.assertEqual(res_cons.SEVERITY_OK, parsed_msg.severity)
|
||||
self.assertEqual('Everything done successfully.',
|
||||
parsed_msg.message)
|
||||
|
||||
def test_parse_message_fallback_to_basemessages(self):
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/message_registry.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
registry = message_registry.MessageRegistry(
|
||||
conn, '/redfish/v1/Registries/Test',
|
||||
redfish_version='1.0.2')
|
||||
registries = {'BaseMessages': registry}
|
||||
message_field = sushy_base.MessageListField('Foo')
|
||||
message_field.message_id = 'Success'
|
||||
message_field.severity = res_cons.SEVERITY_OK
|
||||
message_field.resolution = 'Do nothing'
|
||||
|
||||
parsed_msg = message_registry.parse_message(registries, message_field)
|
||||
|
||||
self.assertEqual('Do nothing', parsed_msg.resolution)
|
||||
self.assertEqual(res_cons.SEVERITY_OK, parsed_msg.severity)
|
||||
self.assertEqual('Everything done successfully.',
|
||||
parsed_msg.message)
|
||||
|
||||
def test_parse_message_fallback_failed(self):
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/message_registry.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
registry = message_registry.MessageRegistry(
|
||||
conn, '/redfish/v1/Registries/Test',
|
||||
redfish_version='1.0.2')
|
||||
registries = {'Test.1.0.0': registry}
|
||||
message_field = sushy_base.MessageListField('Foo')
|
||||
message_field.message_id = 'BadMessageKey'
|
||||
message_field.message = None
|
||||
|
||||
parsed_msg = message_registry.parse_message(registries, message_field)
|
||||
|
||||
self.assertEqual(message_field.message, 'unknown')
|
||||
self.assertEqual(message_field.message, parsed_msg.message)
|
||||
|
||||
def test_parse_message_not_enough_args(self):
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/message_registry.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
registry = message_registry.MessageRegistry(
|
||||
conn, '/redfish/v1/Registries/Test',
|
||||
redfish_version='1.0.2')
|
||||
registries = {'Test.1.0.0': registry}
|
||||
message_field = sushy_base.MessageListField('Foo')
|
||||
message_field.message_id = 'Test.1.0.0.TooBig'
|
||||
message_field.message_args = ['arg1']
|
||||
message_field.severity = None
|
||||
message_field.resolution = None
|
||||
|
||||
parsed_msg = message_registry.parse_message(registries, message_field)
|
||||
|
||||
self.assertEqual('Try again', parsed_msg.resolution)
|
||||
self.assertEqual(res_cons.SEVERITY_WARNING, parsed_msg.severity)
|
||||
self.assertEqual('Property\'s arg1 value cannot be greater than '
|
||||
'unknown.', parsed_msg.message)
|
||||
|
|
|
@ -325,13 +325,15 @@ class MainTestCase(base.TestCase):
|
|||
mock_msg_reg2.registry_prefix = 'RegistryB'
|
||||
mock_msg_reg2.registry_version = '1.0.0'
|
||||
mock_msg_reg_file = mock.Mock()
|
||||
mock_msg_reg_file.identity = 'Messages'
|
||||
mock_msg_reg_file.registry = 'RegistryB.1.0'
|
||||
mock_msg_reg_file.get_message_registry.return_value = mock_msg_reg2
|
||||
mock_col.return_value.get_members.return_value = [mock_msg_reg_file]
|
||||
|
||||
registries = self.root.registries
|
||||
self.assertEqual({'RegistryA.2.0': mock_msg_reg1,
|
||||
'RegistryB.1.0': mock_msg_reg2}, registries)
|
||||
'RegistryB.1.0': mock_msg_reg2,
|
||||
'Messages': mock_msg_reg2}, registries)
|
||||
|
||||
@mock.patch('sushy.Sushy._get_standard_message_registry_collection',
|
||||
autospec=True)
|
||||
|
@ -347,6 +349,7 @@ class MainTestCase(base.TestCase):
|
|||
mock_msg_reg2.registry_prefix = 'RegistryB'
|
||||
mock_msg_reg2.registry_version = '1.0.0'
|
||||
mock_msg_reg_file = mock.Mock()
|
||||
mock_msg_reg_file.identity = 'Messages'
|
||||
mock_msg_reg_file.registry = 'RegistryB.1.0'
|
||||
mock_msg_reg_file.get_message_registry.return_value = mock_msg_reg2
|
||||
mock_col.return_value.get_members.return_value = [mock_msg_reg_file]
|
||||
|
@ -363,7 +366,8 @@ class MainTestCase(base.TestCase):
|
|||
|
||||
expected = {
|
||||
'RegistryA.2.0': mock_msg_reg1,
|
||||
'RegistryB.1.0': mock_msg_reg2
|
||||
'RegistryB.1.0': mock_msg_reg2,
|
||||
'Messages': mock_msg_reg2
|
||||
}
|
||||
|
||||
self.assertEqual(expected, registries)
|
||||
|
|
Loading…
Reference in New Issue