diff --git a/releasenotes/notes/add-default-identity-10c5dd23bed0e915.yaml b/releasenotes/notes/add-default-identity-10c5dd23bed0e915.yaml new file mode 100644 index 00000000..6aa2a8b9 --- /dev/null +++ b/releasenotes/notes/add-default-identity-10c5dd23bed0e915.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + The ``get_system``, ``get_manager`` and ``get_chassis`` methods modified + not to require the ``identity`` parameter referring to a particular + resource instance. If ``identity`` is omited, sushy will default to the + only available resource for as long as it's single and therefore + deterministic. + The intent is to simplify user API by not requiring the consumer to + discover available resources prior to requesting one. diff --git a/sushy/exceptions.py b/sushy/exceptions.py index 9f1e01ae..3d6d18b7 100644 --- a/sushy/exceptions.py +++ b/sushy/exceptions.py @@ -60,6 +60,10 @@ class ArchiveParsingError(SushyError): message = 'Failed parsing archive "%(path)s": %(error)s' +class UnknownDefaultError(SushyError): + message = 'Failed at determining default for "%(entity)s": %(error)s' + + class ExtensionError(SushyError): message = ('Sushy Extension Error: %(error)s') diff --git a/sushy/main.py b/sushy/main.py index d397c32d..d378e127 100644 --- a/sushy/main.py +++ b/sushy/main.py @@ -182,12 +182,25 @@ class Sushy(base.ResourceBase): redfish_version=self.redfish_version, registries=self.registries) - def get_system(self, identity): + def get_system(self, identity=None): """Given the identity return a System object - :param identity: The identity of the System resource + :param identity: The identity of the System resource. If not given, + sushy will default to the single available System or fail + if there appear to be more or less then one System listed. + :raises: `UnknownDefaultError` if default system can't be determined. :returns: The System object """ + if identity is None: + systems_collection = self.get_system_collection() + listed_systems = systems_collection.get_members() + if len(listed_systems) != 1: + raise exceptions.UnknownDefaultError( + entity='ComputerSystem', + error='System count is not exactly one') + + identity = listed_systems[0].path + return system.System(self._conn, identity, redfish_version=self.redfish_version, registries=self.registries) @@ -207,12 +220,25 @@ class Sushy(base.ResourceBase): redfish_version=self.redfish_version, registries=self.registries) - def get_chassis(self, identity): + def get_chassis(self, identity=None): """Given the identity return a Chassis object - :param identity: The identity of the Chassis resource + :param identity: The identity of the Chassis resource. If not given, + sushy will default to the single available chassis or fail + if there appear to be more or less then one Chassis listed. + :raises: `UnknownDefaultError` if default system can't be determined. :returns: The Chassis object """ + if identity is None: + chassis_collection = self.get_chassis_collection() + listed_chassis = chassis_collection.get_members() + if len(listed_chassis) != 1: + raise exceptions.UnknownDefaultError( + entity='Chassis', + error='Chassis count is not exactly one') + + identity = listed_chassis[0].path + return chassis.Chassis(self._conn, identity, redfish_version=self.redfish_version, registries=self.registries) @@ -257,12 +283,24 @@ class Sushy(base.ResourceBase): redfish_version=self.redfish_version, registries=self.registries) - def get_manager(self, identity): + def get_manager(self, identity=None): """Given the identity return a Manager object - :param identity: The identity of the Manager resource + :param identity: The identity of the Manager resource. If not given, + sushy will default to the single available Manager or fail + if there appear to be more or less then one Manager listed. :returns: The Manager object """ + if identity is None: + managers_collection = self.get_manager_collection() + listed_managers = managers_collection.get_members() + if len(listed_managers) != 1: + raise exceptions.UnknownDefaultError( + entity='Manager', + error='Manager count is not exactly one') + + identity = listed_managers[0].path + return manager.Manager(self._conn, identity, redfish_version=self.redfish_version, registries=self.registries) diff --git a/sushy/tests/unit/test_main.py b/sushy/tests/unit/test_main.py index 92b9e3d6..9750b268 100644 --- a/sushy/tests/unit/test_main.py +++ b/sushy/tests/unit/test_main.py @@ -116,6 +116,41 @@ class MainTestCase(base.TestCase): redfish_version=self.root.redfish_version, registries=mock_registries) + @mock.patch.object(system, 'SystemCollection', autospec=True) + @mock.patch.object(system, 'System', autospec=True) + @mock.patch('sushy.Sushy.registries', autospec=True) + def test_get_system_default_ok( + self, mock_registries, mock_system, mock_system_collection): + self.root._standard_message_registries_path = None + mock_system.path = 'fake-system-id' + mock_members = mock_system_collection.return_value.get_members + mock_members.return_value = [mock_system] + self.root.get_system() + mock_system_collection.assert_called_once_with( + self.root._conn, '/redfish/v1/Systems', + redfish_version=self.root.redfish_version, + registries=mock_registries + ) + mock_system.assert_called_once_with( + self.root._conn, 'fake-system-id', + redfish_version=self.root.redfish_version, + registries=mock_registries) + + @mock.patch.object(system, 'SystemCollection', autospec=True) + @mock.patch.object(system, 'System', autospec=True) + @mock.patch('sushy.Sushy.registries', autospec=True) + def test_get_system_default_failure( + self, mock_registries, mock_system, mock_system_collection): + self.root._standard_message_registries_path = None + mock_members = mock_system_collection.return_value.get_members + mock_members.return_value = [] + self.assertRaises(exceptions.UnknownDefaultError, self.root.get_system) + mock_system_collection.assert_called_once_with( + self.root._conn, '/redfish/v1/Systems', + redfish_version=self.root.redfish_version, + registries=mock_registries + ) + @mock.patch.object(chassis, 'Chassis', autospec=True) def test_get_chassis(self, mock_chassis): self.root.get_chassis('fake-chassis-id') @@ -123,6 +158,43 @@ class MainTestCase(base.TestCase): self.root._conn, 'fake-chassis-id', self.root.redfish_version, self.root.registries) + @mock.patch.object(chassis, 'ChassisCollection', autospec=True) + @mock.patch.object(chassis, 'Chassis', autospec=True) + @mock.patch('sushy.Sushy.registries', autospec=True) + def test_get_chassis_default_ok( + self, mock_registries, mock_chassis, mock_chassis_collection): + self.root._standard_message_registries_path = None + mock_chassis.path = 'fake-chassis-id' + mock_members = mock_chassis_collection.return_value.get_members + mock_members.return_value = [mock_chassis] + self.root.get_chassis() + mock_chassis_collection.assert_called_once_with( + self.root._conn, '/redfish/v1/Chassis', + redfish_version=self.root.redfish_version, + registries=mock_registries + ) + mock_chassis.assert_called_once_with( + self.root._conn, 'fake-chassis-id', + redfish_version=self.root.redfish_version, + registries=mock_registries + ) + + @mock.patch.object(chassis, 'ChassisCollection', autospec=True) + @mock.patch.object(chassis, 'Chassis', autospec=True) + @mock.patch('sushy.Sushy.registries', autospec=True) + def test_get_chassis_default_failure( + self, mock_registries, mock_chassis, mock_chassis_collection): + self.root._standard_message_registries_path = None + mock_members = mock_chassis_collection.return_value.get_members + mock_members.return_value = [] + self.assertRaises( + exceptions.UnknownDefaultError, self.root.get_chassis) + mock_chassis_collection.assert_called_once_with( + self.root._conn, '/redfish/v1/Chassis', + redfish_version=self.root.redfish_version, + registries=mock_registries + ) + @mock.patch.object(chassis, 'ChassisCollection', autospec=True) def test_get_chassis_collection(self, chassis_collection_mock): self.root.get_chassis_collection() @@ -158,6 +230,42 @@ class MainTestCase(base.TestCase): self.root._conn, 'fake-manager-id', self.root.redfish_version, self.root.registries) + @mock.patch.object(manager, 'ManagerCollection', autospec=True) + @mock.patch.object(manager, 'Manager', autospec=True) + @mock.patch('sushy.Sushy.registries', autospec=True) + def test_get_manager_default_ok( + self, mock_registries, mock_manager, mock_manager_collection): + self.root._standard_message_registries_path = None + mock_manager.path = 'fake-manager-id' + mock_members = mock_manager_collection.return_value.get_members + mock_members.return_value = [mock_manager] + self.root.get_manager() + mock_manager_collection.assert_called_once_with( + self.root._conn, '/redfish/v1/Managers', + redfish_version=self.root.redfish_version, + registries=mock_registries + ) + mock_manager.assert_called_once_with( + self.root._conn, 'fake-manager-id', + redfish_version=self.root.redfish_version, + registries=mock_registries) + + @mock.patch.object(manager, 'ManagerCollection', autospec=True) + @mock.patch.object(manager, 'Manager', autospec=True) + @mock.patch('sushy.Sushy.registries', autospec=True) + def test_get_manager_default_failure( + self, mock_registries, mock_manager, mock_system_collection): + self.root._standard_message_registries_path = None + mock_members = mock_system_collection.return_value.get_members + mock_members.return_value = [] + self.assertRaises( + exceptions.UnknownDefaultError, self.root.get_manager) + mock_system_collection.assert_called_once_with( + self.root._conn, '/redfish/v1/Managers', + redfish_version=self.root.redfish_version, + registries=mock_registries + ) + @mock.patch.object(sessionservice, 'SessionService', autospec=True) def test_get_sessionservice(self, mock_sess_serv): self.root.get_session_service()