Fix OEM extension loading for different servers

Remove caching and re-using loaded extension objects
as it loaded the same instance for different servers
making it impossible to use it for more than 1
server.

The caching of extension managers is still in place,
consumer of loaded extension object can manage and
reuse the instance as needed.

Change-Id: I7834b49455258f4c3e5690708b23c67d6a361158
Story: 2007669
Task: 39767
(cherry picked from commit 359f2ec2c1)
This commit is contained in:
Aija Jaunteva 2020-05-13 14:52:09 +03:00
parent c1a7d06f63
commit 0241cd9a43
3 changed files with 36 additions and 50 deletions

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Fixes Sushy OEM extension loading when using multiple servers that
caused loaded extensions to point to server for which the extension
was loaded first.

View File

@ -85,26 +85,6 @@ def _get_extension_manager_of_resource(resource_name):
return _global_extn_mgrs_by_resource[resource_name]
@utils.synchronized
def _get_resource_vendor_extension_obj(extension, resource, vendor):
"""Get the object returned by extension's plugin() method.
:param extension: stevedore Extension
:param resource: The Sushy resource instance
:param vendor: This is the OEM vendor string which is the vendor-specific
extensibility identifier. Examples are: 'Contoso', 'Hpe'. As a matter
of fact the lowercase of this string will be the plugin entry point
name.
:returns: The object returned by ``plugin(*args, **kwds)`` of extension.
"""
if extension.obj is None:
oem_resource = extension.plugin()
extension.obj = resource.clone_resource(
oem_resource).set_parent_resource(resource, vendor)
return extension.obj
def get_resource_extension_by_vendor(
resource_name, vendor, resource):
"""Helper method to get Resource specific OEM extension object for vendor
@ -131,7 +111,6 @@ def get_resource_extension_by_vendor(
raise exceptions.OEMExtensionNotFoundError(
resource=resource_name, name=vendor.lower())
if resource_vendor_extn.obj is None:
return _get_resource_vendor_extension_obj(
resource_vendor_extn, resource, vendor)
return resource_vendor_extn.obj
oem_resource = resource_vendor_extn.plugin()
return resource.clone_resource(
oem_resource).set_parent_resource(resource, vendor)

View File

@ -114,32 +114,6 @@ class ResourceOEMCommonMethodsTestCase(base.TestCase):
self.assertTrue(extension in (self.contoso_extn,
self.faux_extn))
def test__get_resource_vendor_extension_obj_lazy_plugin_invoke(self):
resource_instance_mock = mock.Mock()
extension_mock = mock.MagicMock()
extension_mock.obj = None
mock_oem_resource = extension_mock.plugin.return_value
result = oem_common._get_resource_vendor_extension_obj(
extension_mock, resource_instance_mock, 'fish-n-chips')
mock_clone_resource = resource_instance_mock.clone_resource
mock_clone_resource.assert_called_once_with(mock_oem_resource)
mock_ext = mock_clone_resource.return_value
mock_ext.set_parent_resource.assert_called_once_with(
resource_instance_mock, 'fish-n-chips')
mock_ext = mock_ext.set_parent_resource.return_value
self.assertEqual(result, mock_ext)
extension_mock.reset_mock()
# extension_mock.obj is not None anymore
oem_common._get_resource_vendor_extension_obj(
extension_mock, resource_instance_mock, 'fish-n-chips')
self.assertFalse(extension_mock.plugin.called)
@mock.patch.object(stevedore, 'ExtensionManager', autospec=True)
def test_get_resource_extension_by_vendor(self, ExtensionManager_mock):
oem_resource_mock = mock.Mock()
@ -192,3 +166,30 @@ class ResourceOEMCommonMethodsTestCase(base.TestCase):
'by name "faux"',
oem_common.get_resource_extension_by_vendor,
'sushy.resources.system.oems', 'Faux', resource_instance_mock)
@mock.patch.object(stevedore, 'ExtensionManager', autospec=True)
def test_get_resource_extension_by_vendor_different_resources(
self, ExtensionManager_mock):
oem_resource_mock = mock.Mock()
oem_resource_mock.set_parent_resource = lambda *x: oem_resource_mock
resource_instance_mock = mock.Mock()
resource_instance_mock.clone_resource = lambda *x: oem_resource_mock
oem_resource_mock2 = mock.Mock()
oem_resource_mock2.set_parent_resource = lambda *x: oem_resource_mock2
resource_instance_mock2 = mock.Mock()
resource_instance_mock2.clone_resource = lambda *x: oem_resource_mock2
ExtensionManager_mock.side_effect = [self.fake_ext_mgr]
result = oem_common.get_resource_extension_by_vendor(
'system', 'Faux', resource_instance_mock)
self.assertEqual(result, oem_resource_mock)
ExtensionManager_mock.assert_called_once_with(
'sushy.resources.system.oems', propagate_map_exceptions=True,
on_load_failure_callback=oem_common._raise)
ExtensionManager_mock.reset_mock()
result2 = oem_common.get_resource_extension_by_vendor(
'system', 'Faux', resource_instance_mock2)
self.assertEqual(result2, oem_resource_mock2)
ExtensionManager_mock.assert_not_called()
ExtensionManager_mock.reset_mock()