From a118c155f47711a2d4ba8aee7a6b8849a62de4bb Mon Sep 17 00:00:00 2001 From: Andrea Rosa Date: Thu, 16 Jul 2015 16:12:14 +0100 Subject: [PATCH] Raise NovaException for missing/empty machine-id When the sysinfo_serial config parameter is set to 'os', Nova tries to get the UUID for the host operating system from the /etc/machine-id file. Currently if the file is missing, Nova return an IOError exception. If the file is present but empty, Nova will return an IndexError exception. We want to have the same behaviour in both cases and return an error with clearer and more useful information. This patch makes Nova return a NovaException when the machine-id file is either missing or empty. Closes-Bug: 1475353 Change-Id: I2b163d6a42f66ab660c3728b1e29b4b64efbceba --- nova/tests/unit/virt/libvirt/test_driver.py | 49 ++++++++++++++------- nova/virt/libvirt/driver.py | 11 ++++- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 05c08ed2d9..fde806bb06 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -3470,27 +3470,44 @@ class LibvirtConnTestCase(test.NoDBTestCase): self._test_get_guest_config_sysinfo_serial(theuuid) + @contextlib.contextmanager + def patch_exists(self, result): + real_exists = os.path.exists + + def fake_exists(filename): + if filename == "/etc/machine-id": + return result + return real_exists(filename) + + with mock.patch.object(os.path, "exists") as mock_exists: + mock_exists.side_effect = fake_exists + yield mock_exists + def test_get_guest_config_sysinfo_serial_os(self): self.flags(sysinfo_serial="os", group="libvirt") - - real_open = builtins.open + theuuid = "56b40135-a973-4eb3-87bb-a2382a3e6dbc" with contextlib.nested( - mock.patch.object(builtins, "open"), - ) as (mock_open, ): - theuuid = "56b40135-a973-4eb3-87bb-a2382a3e6dbc" - - def fake_open(filename, *args, **kwargs): - if filename == "/etc/machine-id": - h = mock.MagicMock() - h.read.return_value = theuuid - h.__enter__.return_value = h - return h - return real_open(filename, *args, **kwargs) - - mock_open.side_effect = fake_open - + mock.patch('__builtin__.open', + mock.mock_open(read_data=theuuid)), + self.patch_exists(True)): self._test_get_guest_config_sysinfo_serial(theuuid) + def test_get_guest_config_sysinfo_serial_os_empty_machine_id(self): + self.flags(sysinfo_serial="os", group="libvirt") + with contextlib.nested( + mock.patch('__builtin__.open', mock.mock_open(read_data="")), + self.patch_exists(True)): + self.assertRaises(exception.NovaException, + self._test_get_guest_config_sysinfo_serial, + None) + + def test_get_guest_config_sysinfo_serial_os_no_machine_id_file(self): + self.flags(sysinfo_serial="os", group="libvirt") + with self.patch_exists(False): + self.assertRaises(exception.NovaException, + self._test_get_guest_config_sysinfo_serial, + None) + def test_get_guest_config_sysinfo_serial_auto_hardware(self): self.flags(sysinfo_serial="auto", group="libvirt") diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index b89e25d647..25e05cb982 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -3257,10 +3257,19 @@ class LibvirtDriver(driver.ComputeDriver): systemd based containers and can be provided by other init systems too, since it is just a plain text file. """ + if not os.path.exists("/etc/machine-id"): + msg = _("Unable to get host UUID: /etc/machine-id does not exist") + raise exception.NovaException(msg) + with open("/etc/machine-id") as f: # We want to have '-' in the right place # so we parse & reformat the value - return str(uuid.UUID(f.read().split()[0])) + lines = f.read().split() + if not lines: + msg = _("Unable to get host UUID: /etc/machine-id is empty") + raise exception.NovaException(msg) + + return str(uuid.UUID(lines[0])) def _get_host_sysinfo_serial_auto(self): if os.path.exists("/etc/machine-id"):