a371f11835
Commit 26521718bd
imported
nova.utils into nova.privsep.utils which can cause
an ImportError due to an ArgsAlreadyParseError because of
nova.utils importing nova.conf which registers config options.
For some obscure reason, this is only being noticed when using
[libvirt]/image_type=lvm, so something in the libvirt lvm image
backend using privsep is tickling this import error, but regardless
the nova.privsep code should avoid importing stuff from the
rest of nova, so this change simply adds a simple
"generate_random_string" utility to nova.privsep.utils to
avoid the import.
Change-Id: I3799869fd4217d12b92d79e27484043ef5b8dc13
Closes-Bug: #1808247
128 lines
5.3 KiB
Python
128 lines
5.3 KiB
Python
# Copyright 2011 Justin Santa Barbara
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import errno
|
|
import mock
|
|
import os
|
|
|
|
import nova.privsep.utils
|
|
from nova import test
|
|
|
|
|
|
class SupportDirectIOTestCase(test.NoDBTestCase):
|
|
def setUp(self):
|
|
super(SupportDirectIOTestCase, self).setUp()
|
|
# O_DIRECT is not supported on all Python runtimes, so on platforms
|
|
# where it's not supported (e.g. Mac), we can still test the code-path
|
|
# by stubbing out the value.
|
|
if not hasattr(os, 'O_DIRECT'):
|
|
# `mock` seems to have trouble stubbing an attr that doesn't
|
|
# originally exist, so falling back to stubbing out the attribute
|
|
# directly.
|
|
os.O_DIRECT = 16384
|
|
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.123')
|
|
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.privsep.utils.generate_random_string', return_value='123')
|
|
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
|
|
|
|
self.assertTrue(nova.privsep.utils.supports_direct_io('.'))
|
|
|
|
self.mock_open.assert_called_once_with(self.test_path, self.io_flags)
|
|
self.mock_write.assert_called_once_with(3, mock.ANY)
|
|
# ensure unlink(filepath) will actually remove the file by deleting
|
|
# the remaining link to it in close(fd)
|
|
self.mock_close.assert_called_once_with(3)
|
|
self.mock_unlink.assert_called_once_with(self.test_path)
|
|
|
|
def test_supports_direct_io_with_exception_in_write(self):
|
|
self.mock_open.return_value = 3
|
|
self.mock_write.side_effect = ValueError()
|
|
|
|
self.assertRaises(ValueError, nova.privsep.utils.supports_direct_io,
|
|
'.')
|
|
|
|
self.mock_open.assert_called_once_with(self.test_path, self.io_flags)
|
|
self.mock_write.assert_called_once_with(3, mock.ANY)
|
|
# ensure unlink(filepath) will actually remove the file by deleting
|
|
# the remaining link to it in close(fd)
|
|
self.mock_close.assert_called_once_with(3)
|
|
self.mock_unlink.assert_called_once_with(self.test_path)
|
|
|
|
def test_supports_direct_io_with_exception_in_open(self):
|
|
self.mock_open.side_effect = ValueError()
|
|
|
|
self.assertRaises(ValueError, 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)
|
|
|
|
def test_supports_direct_io_with_oserror_in_write(self):
|
|
self.mock_open.return_value = 3
|
|
self.mock_write.side_effect = self.einval
|
|
|
|
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_called_once_with(3, mock.ANY)
|
|
# ensure unlink(filepath) will actually remove the file by deleting
|
|
# the remaining link to it in close(fd)
|
|
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_einval(self):
|
|
self.mock_open.side_effect = self.einval
|
|
|
|
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)
|
|
|
|
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)
|