diff --git a/nova/tests/unit/virt/libvirt/volume/test_scality.py b/nova/tests/unit/virt/libvirt/volume/test_scality.py index 329f5b01f630..8b490943f805 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_scality.py +++ b/nova/tests/unit/virt/libvirt/volume/test_scality.py @@ -12,8 +12,9 @@ import os -import fixtures +import mock +import nova.exception from nova.tests.unit.virt.libvirt.volume import test_volume from nova.virt.libvirt.volume import scality @@ -21,10 +22,19 @@ from nova.virt.libvirt.volume import scality class LibvirtScalityVolumeDriverTestCase( test_volume.LibvirtVolumeBaseTestCase): - def test_libvirt_scality_driver(self): - tempdir = self.useFixture(fixtures.TempDir()).path - TEST_MOUNT = os.path.join(tempdir, 'fake_mount') - TEST_CONFIG = os.path.join(tempdir, 'fake_config') + def setUp(self): + super(LibvirtScalityVolumeDriverTestCase, self).setUp() + + self.scality_sofs_config = 'fake.conf' + self.scality_sofs_mount_point = '/fake' + self.flags(scality_sofs_config=self.scality_sofs_config, + scality_sofs_mount_point=self.scality_sofs_mount_point, + group='libvirt') + + self.drv = scality.LibvirtScalityVolumeDriver(self.fake_conn) + + @mock.patch('six.moves.urllib.request.urlopen') + def test_connect_volume(self, mock_urlopen): TEST_VOLDIR = 'volumes' TEST_VOLNAME = 'volume_name' TEST_CONN_INFO = { @@ -32,11 +42,9 @@ class LibvirtScalityVolumeDriverTestCase( 'sofs_path': os.path.join(TEST_VOLDIR, TEST_VOLNAME) } } - TEST_VOLPATH = os.path.join(TEST_MOUNT, + TEST_VOLPATH = os.path.join(self.scality_sofs_mount_point, TEST_VOLDIR, TEST_VOLNAME) - open(TEST_CONFIG, "w+").close() - os.makedirs(os.path.join(TEST_MOUNT, 'sys')) def _access_wrapper(path, flags): if path == '/sbin/mount.sofs': @@ -45,16 +53,62 @@ class LibvirtScalityVolumeDriverTestCase( return os.access(path, flags) self.stubs.Set(os, 'access', _access_wrapper) - self.flags(scality_sofs_config=TEST_CONFIG, - scality_sofs_mount_point=TEST_MOUNT, - group='libvirt') - driver = scality.LibvirtScalityVolumeDriver(self.fake_conn) - driver.connect_volume(TEST_CONN_INFO, self.disk_info) - device_path = os.path.join(TEST_MOUNT, + with mock.patch.object(self.drv, '_mount_sofs'): + self.drv.connect_volume(TEST_CONN_INFO, self.disk_info) + + device_path = os.path.join(self.scality_sofs_mount_point, TEST_CONN_INFO['data']['sofs_path']) self.assertEqual(TEST_CONN_INFO['data']['device_path'], device_path) - conf = driver.get_config(TEST_CONN_INFO, self.disk_info) + conf = self.drv.get_config(TEST_CONN_INFO, self.disk_info) tree = conf.format_dom() self._assertFileTypeEquals(tree, TEST_VOLPATH) + + @mock.patch('nova.utils.execute') + def test_mount_sofs_when_sofs_already_mounted(self, mock_execute): + with mock.patch.object(self.drv, '_sofs_is_mounted') as m_is_mounted: + m_is_mounted.return_value = True + + self.drv._mount_sofs() + + mock_execute.assert_called_once_with('mkdir', '-p', + self.scality_sofs_mount_point) + self.assertEqual(1, m_is_mounted.call_count) + + @mock.patch('nova.utils.execute', mock.Mock()) + def test_mount_sofs_when_mount_fails(self): + with mock.patch.object(self.drv, '_sofs_is_mounted') as m_is_mounted: + m_is_mounted.side_effect = [False, False] + + self.assertRaises(nova.exception.NovaException, + self.drv._mount_sofs) + + self.assertEqual(2, m_is_mounted.call_count) + + @mock.patch('nova.utils.execute') + def test_mount_sofs_when_sofs_is_not_mounted(self, mock_execute): + with mock.patch.object(self.drv, '_sofs_is_mounted') as m_is_mounted: + m_is_mounted.side_effect = [False, True] + + self.drv._mount_sofs() + + self.assertEqual(2, m_is_mounted.call_count) + self.assertEqual(2, mock_execute.call_count) + expected_calls = [ + mock.call('mkdir', '-p', self.scality_sofs_mount_point), + mock.call('mount', '-t', 'sofs', self.scality_sofs_config, + self.scality_sofs_mount_point, run_as_root=True) + ] + mock_execute.assert_has_calls(expected_calls) + + def test_sofs_is_mounted_when_sofs_is_not_mounted(self): + mock_open = mock.mock_open(read_data='tmpfs /dev/shm\n') + with mock.patch('io.open', mock_open) as mock_open: + self.assertFalse(self.drv._sofs_is_mounted()) + + def test_sofs_is_mounted_when_sofs_is_mounted(self): + proc_mount = '/dev/fuse ' + self.scality_sofs_mount_point + '\n' + mock_open = mock.mock_open(read_data=proc_mount) + with mock.patch('io.open', mock_open) as mock_open: + self.assertTrue(self.drv._sofs_is_mounted()) diff --git a/nova/virt/libvirt/volume/scality.py b/nova/virt/libvirt/volume/scality.py index 10561e122d1d..2f042a1b180e 100644 --- a/nova/virt/libvirt/volume/scality.py +++ b/nova/virt/libvirt/volume/scality.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import io import os from oslo_config import cfg @@ -118,17 +119,27 @@ class LibvirtScalityVolumeDriver(fs.LibvirtBaseFileSystemVolumeDriver): LOG.warn(msg) raise exception.NovaException(msg) + def _sofs_is_mounted(self): + """Detects whether Scality SOFS is already mounted.""" + mount_path = CONF.libvirt.scality_sofs_mount_point.rstrip('/') + with io.open('/proc/mounts') as mounts: + for mount in mounts.readlines(): + parts = mount.split() + if (parts[0].endswith('fuse') and + parts[1].rstrip('/') == mount_path): + return True + return False + def _mount_sofs(self): config = CONF.libvirt.scality_sofs_config mount_path = CONF.libvirt.scality_sofs_mount_point - sysdir = os.path.join(mount_path, 'sys') if not os.path.isdir(mount_path): utils.execute('mkdir', '-p', mount_path) - if not os.path.isdir(sysdir): + if not self._sofs_is_mounted(): utils.execute('mount', '-t', 'sofs', config, mount_path, run_as_root=True) - if not os.path.isdir(sysdir): - msg = _("Cannot mount Scality SOFS, check syslog for errors") - LOG.warn(msg) - raise exception.NovaException(msg) + if not self._sofs_is_mounted(): + msg = _("Cannot mount Scality SOFS, check syslog for errors") + LOG.warn(msg) + raise exception.NovaException(msg)