diff --git a/os_brick/initiator/connectors/nvmeof.py b/os_brick/initiator/connectors/nvmeof.py index c9c89c1cd..88b00ec06 100644 --- a/os_brick/initiator/connectors/nvmeof.py +++ b/os_brick/initiator/connectors/nvmeof.py @@ -35,6 +35,7 @@ try: from os_brick.initiator.connectors import nvmeof_agent except ImportError: nvmeof_agent = None +from os_brick.privileged import nvmeof as priv_nvmeof from os_brick.privileged import rootwrap as priv_rootwrap from os_brick import utils @@ -768,7 +769,7 @@ class NVMeOFConnector(base.BaseLinuxConnector): nqn = None uuid = nvmf._get_host_uuid() - suuid = nvmf._get_system_uuid() + suuid = priv_nvmeof.get_system_uuid() if cls.nvme_present(): nqn = utils.get_host_nqn() if uuid: @@ -796,31 +797,6 @@ class NVMeOFConnector(base.BaseLinuxConnector): "Process execution error in _get_host_uuid: %s", e) return None - def _get_system_uuid(self) -> str: - """Get the system's UUID from DMI - - First try reading it from sysfs and if not possible use the dmidecode - tool. - """ - # RSD requires system_uuid to let Cinder RSD Driver identify - # Nova node for later RSD volume attachment. - try: - out, err = self._execute('cat', '/sys/class/dmi/id/product_uuid', - root_helper=self._root_helper, - run_as_root=True) - except putils.ProcessExecutionError: - try: - out, err = self._execute('dmidecode', '-ssystem-uuid', - root_helper=self._root_helper, - run_as_root=True) - if not out: - LOG.warning('dmidecode returned empty system-uuid') - except putils.ProcessExecutionError as e: - LOG.debug("Unable to locate dmidecode. For Cinder RSD Backend," - " please make sure it is installed: %s", e) - out = "" - return out.strip() - @classmethod def _set_native_multipath_supported(cls): if cls.native_multipath_supported is None: diff --git a/os_brick/privileged/nvmeof.py b/os_brick/privileged/nvmeof.py index 470385022..e4e1b6c26 100644 --- a/os_brick/privileged/nvmeof.py +++ b/os_brick/privileged/nvmeof.py @@ -71,3 +71,25 @@ def create_hostnqn() -> str: LOG.warning("Could not generate host nqn: %s", e) return host_nqn + + +@os_brick.privileged.default.entrypoint +def get_system_uuid() -> str: + # RSD requires system_uuid to let Cinder RSD Driver identify + # Nova node for later RSD volume attachment. + try: + with open('/sys/class/dmi/id/product_uuid', 'r') as f: + return f.read().strip() + except Exception: + LOG.debug("Could not read dmi's 'product_uuid' on sysfs") + + try: + out, err = rootwrap.custom_execute('dmidecode', '-ssystem-uuid') + if not out: + LOG.warning('dmidecode returned empty system-uuid') + except putils.ProcessExecutionError as e: + LOG.debug("Unable to locate dmidecode. For Cinder RSD Backend," + " please make sure it is installed: %s", e) + out = "" + + return out.strip() diff --git a/os_brick/tests/initiator/connectors/test_nvmeof.py b/os_brick/tests/initiator/connectors/test_nvmeof.py index 3b3fdacc9..e75f81152 100644 --- a/os_brick/tests/initiator/connectors/test_nvmeof.py +++ b/os_brick/tests/initiator/connectors/test_nvmeof.py @@ -21,6 +21,7 @@ from oslo_concurrency import processutils as putils from os_brick import exception from os_brick import executor from os_brick.initiator.connectors import nvmeof +from os_brick.privileged import nvmeof as priv_nvmeof from os_brick.privileged import rootwrap as priv_rootwrap from os_brick.tests import base as test_base from os_brick.tests.initiator import test_connector @@ -927,7 +928,7 @@ class NVMeOFConnectorTestCase(test_connector.ConnectorTestCase): return_value=True) @mock.patch.object(utils, 'get_host_nqn', return_value='fakenqn') - @mock.patch.object(nvmeof.NVMeOFConnector, '_get_system_uuid', + @mock.patch.object(priv_nvmeof, 'get_system_uuid', return_value=None) @mock.patch.object(nvmeof.NVMeOFConnector, '_get_host_uuid', return_value=None) @@ -944,7 +945,7 @@ class NVMeOFConnectorTestCase(test_connector.ConnectorTestCase): return_value=True) @mock.patch.object(nvmeof.NVMeOFConnector, 'nvme_present') @mock.patch.object(utils, 'get_host_nqn', autospec=True) - @mock.patch.object(nvmeof.NVMeOFConnector, '_get_system_uuid', + @mock.patch.object(priv_nvmeof, 'get_system_uuid', autospec=True) @mock.patch.object(nvmeof.NVMeOFConnector, '_get_host_uuid', autospec=True) def test_get_connector_properties_with_sysuuid(self, mock_host_uuid, diff --git a/os_brick/tests/initiator/test_connector.py b/os_brick/tests/initiator/test_connector.py index 2d7f7a433..e5a2f4940 100644 --- a/os_brick/tests/initiator/test_connector.py +++ b/os_brick/tests/initiator/test_connector.py @@ -26,6 +26,7 @@ from os_brick.initiator.connectors import fake from os_brick.initiator.connectors import iscsi from os_brick.initiator.connectors import nvmeof from os_brick.initiator import linuxfc +from os_brick.privileged import nvmeof as priv_nvmeof from os_brick.privileged import rootwrap as priv_rootwrap from os_brick.tests import base as test_base from os_brick import utils @@ -45,7 +46,7 @@ class ConnectorUtilsTestCase(test_base.TestCase): @mock.patch.object(nvmeof.NVMeOFConnector, '_is_native_multipath_supported', return_value=False) - @mock.patch.object(nvmeof.NVMeOFConnector, '_get_system_uuid', + @mock.patch.object(priv_nvmeof, 'get_system_uuid', return_value=None) @mock.patch.object(nvmeof.NVMeOFConnector, '_get_host_uuid', return_value=None) diff --git a/os_brick/tests/privileged/test_nvmeof.py b/os_brick/tests/privileged/test_nvmeof.py index 4261e0b3c..e150a8902 100644 --- a/os_brick/tests/privileged/test_nvmeof.py +++ b/os_brick/tests/privileged/test_nvmeof.py @@ -125,3 +125,44 @@ class PrivNVMeTestCase(base.TestCase): exist_ok=True) mock_exec.assert_called_once_with('nvme', 'show-hostnqn') self.assertEqual('', res) + + @mock.patch.object(builtins, 'open', new_callable=mock.mock_open) + def test_get_system_uuid_product_uuid(self, mock_open): + uuid = 'dbc6ba60-36ae-4b96-9310-628832bdfc3d' + mock_fd = mock_open.return_value.__enter__.return_value + mock_fd.read.return_value = uuid + res = privsep_nvme.get_system_uuid() + self.assertEqual(uuid, res) + mock_open.assert_called_once_with('/sys/class/dmi/id/product_uuid', + 'r') + mock_fd.read.assert_called_once_with() + + @mock.patch.object(builtins, 'open', side_effect=Exception) + @mock.patch.object(rootwrap, 'custom_execute') + def test_get_system_uuid_dmidecode(self, mock_exec, mock_open): + uuid = 'dbc6ba60-36ae-4b96-9310-628832bdfc3d' + mock_exec.return_value = (f' {uuid} ', '') + res = privsep_nvme.get_system_uuid() + self.assertEqual(uuid, res) + mock_open.assert_called_once_with('/sys/class/dmi/id/product_uuid', + 'r') + mock_exec.assert_called_once_with('dmidecode', '-ssystem-uuid') + + @mock.patch.object(builtins, 'open', side_effect=Exception) + @mock.patch.object(rootwrap, 'custom_execute', return_value=('', '')) + def test_get_system_uuid_dmidecode_empty(self, mock_exec, mock_open): + res = privsep_nvme.get_system_uuid() + self.assertEqual('', res) + mock_open.assert_called_once_with('/sys/class/dmi/id/product_uuid', + 'r') + mock_exec.assert_called_once_with('dmidecode', '-ssystem-uuid') + + @mock.patch.object(builtins, 'open', side_effect=Exception) + @mock.patch.object(rootwrap, 'custom_execute', + side_effect=putils.ProcessExecutionError) + def test_get_system_uuid_failure(self, mock_exec, mock_open): + res = privsep_nvme.get_system_uuid() + self.assertEqual('', res) + mock_open.assert_called_once_with('/sys/class/dmi/id/product_uuid', + 'r') + mock_exec.assert_called_once_with('dmidecode', '-ssystem-uuid')