diff --git a/nova/tests/unit/virt/libvirt/test_utils.py b/nova/tests/unit/virt/libvirt/test_utils.py index 9fb350e95be8..a4adb535eaf6 100644 --- a/nova/tests/unit/virt/libvirt/test_utils.py +++ b/nova/tests/unit/virt/libvirt/test_utils.py @@ -768,3 +768,61 @@ disk size: 4.4M with mock.patch.object(libvirt_utils.LOG, 'warning') as mock_log: libvirt_utils.update_mtime(mock.sentinel.path) self.assertTrue(mock_log.called) + + def test_is_mounted(self): + mount_path = "/var/lib/nova/mnt" + source = "192.168.0.1:/nova" + proc_with_mnt = """/dev/sda3 / xfs rw,seclabel,attr2,inode64 0 0 +tmpfs /tmp tmpfs rw,seclabel 0 0 +hugetlbfs /dev/hugepages hugetlbfs rw,seclabel,relatime 0 0 +mqueue /dev/mqueue mqueue rw,seclabel,relatime 0 0 +debugfs /sys/kernel/debug debugfs rw,seclabel,relatime 0 0 +nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 +/dev/sda1 /boot ext4 rw,seclabel,relatime,data=ordered 0 0 +sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0 +192.168.0.1:/nova /var/lib/nova/mnt nfs4 rw,relatime,vers=4.1 +""" + proc_wrong_mnt = """/dev/sda3 / xfs rw,seclabel,attr2,inode64 0 0 +tmpfs /tmp tmpfs rw,seclabel 0 0 +hugetlbfs /dev/hugepages hugetlbfs rw,seclabel,relatime 0 0 +mqueue /dev/mqueue mqueue rw,seclabel,relatime 0 0 +debugfs /sys/kernel/debug debugfs rw,seclabel,relatime 0 0 +nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 +/dev/sda1 /boot ext4 rw,seclabel,relatime,data=ordered 0 0 +sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0 +192.168.0.2:/nova /var/lib/nova/mnt nfs4 rw,relatime,vers=4.1 +""" + proc_without_mnt = """/dev/sda3 / xfs rw,seclabel,,attr2,inode64 0 0 +tmpfs /tmp tmpfs rw,seclabel 0 0 +hugetlbfs /dev/hugepages hugetlbfs rw,seclabel,relatime 0 0 +mqueue /dev/mqueue mqueue rw,seclabel,relatime 0 0 +debugfs /sys/kernel/debug debugfs rw,seclabel,relatime 0 0 +nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 +/dev/sda1 /boot ext4 rw,seclabel,relatime,data=ordered 0 0 +sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0 +""" + with mock.patch.object(os.path, 'ismount') as mock_ismount: + # is_mounted(mount_path) with no source is equivalent to + # os.path.ismount(mount_path) + mock_ismount.return_value = False + self.assertFalse(libvirt_utils.is_mounted(mount_path)) + + mock_ismount.return_value = True + self.assertTrue(libvirt_utils.is_mounted(mount_path)) + + # Source is given, and matches source in /proc/mounts + proc_mnt = mock.mock_open(read_data=proc_with_mnt) + with mock.patch.object(six.moves.builtins, "open", proc_mnt): + self.assertTrue(libvirt_utils.is_mounted(mount_path, source)) + + # Source is given, and doesn't match source in /proc/mounts + proc_mnt = mock.mock_open(read_data=proc_wrong_mnt) + with mock.patch.object(six.moves.builtins, "open", proc_mnt): + self.assertFalse(libvirt_utils.is_mounted(mount_path, source)) + + # Source is given, and mountpoint isn't present in /proc/mounts + # Note that this shouldn't occur, as os.path.ismount should have + # previously returned False in this case. + proc_umnt = mock.mock_open(read_data=proc_without_mnt) + with mock.patch.object(six.moves.builtins, "open", proc_umnt): + self.assertFalse(libvirt_utils.is_mounted(mount_path, source)) diff --git a/nova/tests/unit/virt/libvirt/volume/test_glusterfs.py b/nova/tests/unit/virt/libvirt/volume/test_glusterfs.py index cb08fa198cf5..b48655f15a59 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_glusterfs.py +++ b/nova/tests/unit/virt/libvirt/volume/test_glusterfs.py @@ -78,7 +78,8 @@ class LibvirtGlusterfsVolumeDriverTestCase( self._assertFileTypeEquals(tree, file_path) self.assertEqual('qcow2', tree.find('./driver').get('type')) - def test_libvirt_glusterfs_driver_already_mounted(self): + @mock.patch.object(libvirt_utils, 'is_mounted', return_value=True) + def test_libvirt_glusterfs_driver_already_mounted(self, mock_is_mounted): mnt_base = '/mnt' self.flags(glusterfs_mount_point_base=mnt_base, group='libvirt') @@ -93,8 +94,6 @@ class LibvirtGlusterfsVolumeDriverTestCase( libvirt_driver.disconnect_volume(connection_info, "vde") expected_commands = [ - ('findmnt', '--target', export_mnt_base, - '--source', export_string), ('umount', export_mnt_base)] self.assertEqual(expected_commands, self.executes) diff --git a/nova/tests/unit/virt/libvirt/volume/test_nfs.py b/nova/tests/unit/virt/libvirt/volume/test_nfs.py index cdd0b2499fd1..c46fa698cb32 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_nfs.py +++ b/nova/tests/unit/virt/libvirt/volume/test_nfs.py @@ -94,7 +94,8 @@ class LibvirtNFSVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase): self.assertEqual('raw', tree.find('./driver').get('type')) self.assertEqual('native', tree.find('./driver').get('io')) - def test_libvirt_nfs_driver_already_mounted(self): + @mock.patch.object(libvirt_utils, 'is_mounted', return_value=True) + def test_libvirt_nfs_driver_already_mounted(self, mock_is_mounted): libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_host) export_string = '192.168.1.1:/nfs/share1' @@ -107,8 +108,6 @@ class LibvirtNFSVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase): libvirt_driver.disconnect_volume(connection_info, "vde") expected_commands = [ - ('findmnt', '--target', export_mnt_base, '--source', - export_string), ('umount', export_mnt_base)] self.assertEqual(expected_commands, self.executes) diff --git a/nova/tests/unit/virt/libvirt/volume/test_quobyte.py b/nova/tests/unit/virt/libvirt/volume/test_quobyte.py index 64afee55644f..a43a79a8ad35 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_quobyte.py +++ b/nova/tests/unit/virt/libvirt/volume/test_quobyte.py @@ -253,7 +253,9 @@ class LibvirtQuobyteVolumeDriverTestCase( @mock.patch.object(quobyte, 'validate_volume') @mock.patch.object(quobyte, 'umount_volume') + @mock.patch.object(libvirt_utils, 'is_mounted', return_value=True) def test_libvirt_quobyte_driver_already_mounted(self, + mock_is_mounted, mock_umount_volume, mock_validate_volume ): @@ -277,14 +279,6 @@ class LibvirtQuobyteVolumeDriverTestCase( self._assertFileTypeEquals(tree, file_path) libvirt_driver.disconnect_volume(connection_info, "vde") - expected_commands = [ - ('findmnt', '--target', export_mnt_base, - '--source', "quobyte@" + quobyte_volume), - ('findmnt', '--target', export_mnt_base, - '--source', "quobyte@" + quobyte_volume), - ] - self.assertEqual(expected_commands, self.executes) - mock_umount_volume.assert_called_once_with(export_mnt_base) mock_validate_volume.assert_called_once_with(export_mnt_base) @@ -324,7 +318,9 @@ class LibvirtQuobyteVolumeDriverTestCase( libvirt_driver.disconnect_volume(connection_info, "vde") - def test_libvirt_quobyte_driver_mount_non_quobyte_volume(self): + @mock.patch.object(libvirt_utils, 'is_mounted', return_value=True) + def test_libvirt_quobyte_driver_mount_non_quobyte_volume(self, + mock_is_mounted): mnt_base = '/mnt' self.flags(quobyte_mount_point_base=mnt_base, group='libvirt') diff --git a/nova/tests/unit/virt/libvirt/volume/test_smbfs.py b/nova/tests/unit/virt/libvirt/volume/test_smbfs.py index 9e9250cc6a03..4c12d050b99d 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_smbfs.py +++ b/nova/tests/unit/virt/libvirt/volume/test_smbfs.py @@ -49,7 +49,8 @@ class LibvirtSMBFSVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase): ('umount', export_mnt_base)] self.assertEqual(expected_commands, self.executes) - def test_libvirt_smbfs_driver_already_mounted(self): + @mock.patch.object(libvirt_utils, 'is_mounted', return_value=True) + def test_libvirt_smbfs_driver_already_mounted(self, mock_is_mounted): libvirt_driver = smbfs.LibvirtSMBFSVolumeDriver(self.fake_host) export_string = '//192.168.1.1/volumes' export_mnt_base = os.path.join(self.mnt_base, @@ -61,8 +62,6 @@ class LibvirtSMBFSVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase): libvirt_driver.disconnect_volume(connection_info, "vde") expected_commands = [ - ('findmnt', '--target', export_mnt_base, - '--source', export_string), ('umount', export_mnt_base)] self.assertEqual(expected_commands, self.executes) diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py index 0392e2120235..94d93d7c1b7b 100644 --- a/nova/virt/libvirt/utils.py +++ b/nova/virt/libvirt/utils.py @@ -531,20 +531,15 @@ def get_arch(image_meta): def is_mounted(mount_path, source=None): """Check if the given source is mounted at given destination point.""" - try: - check_cmd = ['findmnt', '--target', mount_path] - if source: - check_cmd.extend(['--source', source]) + if not os.path.ismount(mount_path): + return False - utils.execute(*check_cmd) + if source is None: return True - except processutils.ProcessExecutionError: - return False - except OSError as exc: - # info since it's not required to have this tool. - if exc.errno == errno.ENOENT: - LOG.info(_LI("findmnt tool is not installed")) - return False + + with open('/proc/mounts', 'r') as proc_mounts: + mounts = [mount.split() for mount in proc_mounts.readlines()] + return any(mnt[0] == source and mnt[1] == mount_path for mnt in mounts) def is_valid_hostname(hostname):