privsep: Handle ENOENT when checking for direct IO support

We've seen a recent issue that suggest direct IO support checks can fail
in other valid ways than EINVAL, namely, failures with ENOENT or the
FileNotFoundError exception, which is a Python 3-only exception type,
can occur. While we can't test for this without breaking Python 2.7
support, we can mimic this by looking for checking for the errno
attribute of the OSError exception. Do this.

Change-Id: I8aab86bb62cbc8ad538c706af037a30437c7964d
Closes-Bug: #1788922
This commit is contained in:
Stephen Finucane 2018-08-27 16:28:32 +01:00
parent 8ee44744e6
commit ecfcf86538
2 changed files with 14 additions and 2 deletions

View File

@ -51,7 +51,7 @@ def supports_direct_io(dirpath):
LOG.debug("Path '%(path)s' supports direct I/O",
{'path': dirpath})
except OSError as e:
if e.errno == errno.EINVAL:
if e.errno in (errno.EINVAL, errno.ENOENT):
LOG.debug("Path '%(path)s' does not support direct I/O: "
"'%(ex)s'", {'path': dirpath, 'ex': e})
hasDirectIO = False

View File

@ -34,6 +34,8 @@ class SupportDirectIOTestCase(test.NoDBTestCase):
self.addCleanup(delattr, os, 'O_DIRECT')
self.einval = OSError()
self.einval.errno = errno.EINVAL
self.enoent = OSError()
self.enoent.errno = errno.ENOENT
self.test_path = os.path.join('.', '.directio.test')
self.io_flags = os.O_CREAT | os.O_WRONLY | os.O_DIRECT
@ -100,7 +102,7 @@ class SupportDirectIOTestCase(test.NoDBTestCase):
self.mock_close.assert_called_once_with(3)
self.mock_unlink.assert_called_once_with(self.test_path)
def test_supports_direct_io_with_oserror_in_open(self):
def test_supports_direct_io_with_oserror_in_open_einval(self):
self.mock_open.side_effect = self.einval
self.assertFalse(nova.privsep.utils.supports_direct_io('.'))
@ -109,3 +111,13 @@ class SupportDirectIOTestCase(test.NoDBTestCase):
self.mock_write.assert_not_called()
self.mock_close.assert_not_called()
self.mock_unlink.assert_called_once_with(self.test_path)
def test_supports_direct_io_with_oserror_in_open_enoent(self):
self.mock_open.side_effect = self.enoent
self.assertFalse(nova.privsep.utils.supports_direct_io('.'))
self.mock_open.assert_called_once_with(self.test_path, self.io_flags)
self.mock_write.assert_not_called()
self.mock_close.assert_not_called()
self.mock_unlink.assert_called_once_with(self.test_path)