From 26521718bdba3bccbf6270e26b76754c26304658 Mon Sep 17 00:00:00 2001 From: Pavel Glushchak Date: Wed, 25 Oct 2017 15:58:01 +0300 Subject: [PATCH] Fixed concurrent access to direct io test file When instances are deployed concurrently on multiple compute nodes, nova-compute may fail on checking direct io capabilities when instance_path is shared across nodes. This fails on shared storage, that doesn't support concurrent write access to the same file, i.e. Virtuozzo Storage. To fix that we add random string at the end of test file name. Closes-Bug: #1727369 Change-Id: I085ade355fba0e9727a38d2dcbc9cffa735a62d1 Signed-off-by: Pavel Glushchak --- nova/privsep/utils.py | 5 ++++- nova/tests/functional/test_servers.py | 2 ++ nova/tests/unit/privsep/test_utils.py | 6 +++++- nova/tests/unit/virt/libvirt/test_driver.py | 4 ++++ nova/utils.py | 8 ++++++-- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/nova/privsep/utils.py b/nova/privsep/utils.py index 926599d5c923..460aab945957 100644 --- a/nova/privsep/utils.py +++ b/nova/privsep/utils.py @@ -27,6 +27,7 @@ import os from oslo_log import log as logging from oslo_utils import excutils +from nova import utils as nova_utils LOG = logging.getLogger(__name__) @@ -37,7 +38,9 @@ def supports_direct_io(dirpath): LOG.debug("This python runtime does not support direct I/O") return False - testfile = os.path.join(dirpath, ".directio.test") + file_name = "%s.%s" % (".directio.test", + nova_utils.generate_random_string()) + testfile = os.path.join(dirpath, file_name) hasDirectIO = True fd = None diff --git a/nova/tests/functional/test_servers.py b/nova/tests/functional/test_servers.py index 4a66aefc4e12..65f309205ddc 100644 --- a/nova/tests/functional/test_servers.py +++ b/nova/tests/functional/test_servers.py @@ -633,6 +633,8 @@ class ServersTest(ServersTestBase): self.assertIn('reservation_id', response) reservation_id = response['reservation_id'] self.assertNotIn(reservation_id, ['', None]) + # Assert that the reservation_id itself has the expected format + self.assertRegex(reservation_id, 'r-[0-9a-zA-Z]{8}') # Create 1 more server, which should not return a reservation_id server = self._build_minimal_create_server_request() diff --git a/nova/tests/unit/privsep/test_utils.py b/nova/tests/unit/privsep/test_utils.py index 6d87a643641c..cdb64331fa31 100644 --- a/nova/tests/unit/privsep/test_utils.py +++ b/nova/tests/unit/privsep/test_utils.py @@ -36,21 +36,25 @@ class SupportDirectIOTestCase(test.NoDBTestCase): self.einval.errno = errno.EINVAL self.enoent = OSError() self.enoent.errno = errno.ENOENT - self.test_path = os.path.join('.', '.directio.test') + self.test_path = os.path.join('.', '.directio.test.abc123') self.io_flags = os.O_CREAT | os.O_WRONLY | os.O_DIRECT open_patcher = mock.patch('os.open') write_patcher = mock.patch('os.write') close_patcher = mock.patch('os.close') unlink_patcher = mock.patch('os.unlink') + random_string_patcher = mock.patch('nova.utils.generate_random_string', + return_value='abc123') self.addCleanup(open_patcher.stop) self.addCleanup(write_patcher.stop) self.addCleanup(close_patcher.stop) self.addCleanup(unlink_patcher.stop) + self.addCleanup(random_string_patcher.stop) self.mock_open = open_patcher.start() self.mock_write = write_patcher.start() self.mock_close = close_patcher.start() self.mock_unlink = unlink_patcher.start() + random_string_patcher.start() def test_supports_direct_io(self): self.mock_open.return_value = 3 diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 4e7b0e43b13f..088bf7ac499e 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -2435,6 +2435,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(0, len(cfg.cputune.vcpupin)) self.assertIsNone(cfg.cpu.numa) + @mock.patch('nova.privsep.utils.supports_direct_io', + new=mock.Mock(return_value=True)) @mock.patch.object( host.Host, "is_cpu_control_policy_capable", return_value=True) def test_get_guest_config_numa_host_instance_no_fit(self, is_able): @@ -2686,6 +2688,8 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(0, len(cfg.cputune.vcpupin)) self.assertIsNone(cfg.cpu.numa) + @mock.patch('nova.privsep.utils.supports_direct_io', + new=mock.Mock(return_value=True)) @mock.patch.object( host.Host, "is_cpu_control_policy_capable", return_value=True) def test_get_guest_config_numa_host_instance_2pci_no_fit(self, is_able): diff --git a/nova/utils.py b/nova/utils.py index f3eb78570204..8d7bc1efd227 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -244,9 +244,13 @@ def ssh_execute(dest, *cmd, **kwargs): def generate_uid(topic, size=8): + random_string = generate_random_string(size) + return '%s-%s' % (topic, random_string) + + +def generate_random_string(size=8): characters = '01234567890abcdefghijklmnopqrstuvwxyz' - choices = [random.choice(characters) for _x in range(size)] - return '%s-%s' % (topic, ''.join(choices)) + return ''.join([random.choice(characters) for _x in range(size)]) # Default symbols to use for passwords. Avoids visually confusing characters.