libvirt: move LibvirtNFSVolumeDriver into it's own module
Part of blueprint consolidate-libvirt-fs-volume-drivers Change-Id: Ia2b867be06400e02c3a6668102fd79ac75a228c5
This commit is contained in:
129
nova/tests/unit/virt/libvirt/volume/test_nfs.py
Normal file
129
nova/tests/unit/virt/libvirt/volume/test_nfs.py
Normal file
@@ -0,0 +1,129 @@
|
||||
# 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 os
|
||||
|
||||
import mock
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from nova.tests.unit.virt.libvirt.volume import test_volume
|
||||
from nova import utils
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
from nova.virt.libvirt.volume import nfs
|
||||
|
||||
|
||||
class LibvirtNFSVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase):
|
||||
"""Tests the libvirt NFS volume driver."""
|
||||
|
||||
def setUp(self):
|
||||
super(LibvirtNFSVolumeDriverTestCase, self).setUp()
|
||||
self.mnt_base = '/mnt'
|
||||
self.flags(nfs_mount_point_base=self.mnt_base, group='libvirt')
|
||||
|
||||
def test_libvirt_nfs_driver(self):
|
||||
libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)
|
||||
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
export_mnt_base = os.path.join(self.mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name}}
|
||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
device_path = os.path.join(export_mnt_base,
|
||||
connection_info['data']['name'])
|
||||
self.assertEqual(device_path, connection_info['data']['device_path'])
|
||||
expected_commands = [
|
||||
('mkdir', '-p', export_mnt_base),
|
||||
('mount', '-t', 'nfs', export_string, export_mnt_base),
|
||||
('umount', export_mnt_base)]
|
||||
self.assertEqual(expected_commands, self.executes)
|
||||
|
||||
@mock.patch.object(nfs.utils, 'execute')
|
||||
@mock.patch.object(nfs.LOG, 'debug')
|
||||
@mock.patch.object(nfs.LOG, 'exception')
|
||||
def test_libvirt_nfs_driver_umount_error(self, mock_LOG_exception,
|
||||
mock_LOG_debug, mock_utils_exe):
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name}}
|
||||
libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
mock_utils_exe.side_effect = processutils.ProcessExecutionError(
|
||||
None, None, None, 'umount', 'umount: device is busy.')
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
self.assertTrue(mock_LOG_debug.called)
|
||||
mock_utils_exe.side_effect = processutils.ProcessExecutionError(
|
||||
None, None, None, 'umount', 'umount: target is busy.')
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
self.assertTrue(mock_LOG_debug.called)
|
||||
mock_utils_exe.side_effect = processutils.ProcessExecutionError(
|
||||
None, None, None, 'umount', 'umount: Other error.')
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
self.assertTrue(mock_LOG_exception.called)
|
||||
|
||||
def test_libvirt_nfs_driver_get_config(self):
|
||||
libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
export_mnt_base = os.path.join(self.mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
file_path = os.path.join(export_mnt_base, self.name)
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name,
|
||||
'device_path': file_path}}
|
||||
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
||||
tree = conf.format_dom()
|
||||
self._assertFileTypeEquals(tree, file_path)
|
||||
self.assertEqual('raw', tree.find('./driver').get('type'))
|
||||
|
||||
def test_libvirt_nfs_driver_already_mounted(self):
|
||||
libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
export_mnt_base = os.path.join(self.mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name}}
|
||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
expected_commands = [
|
||||
('findmnt', '--target', export_mnt_base, '--source',
|
||||
export_string),
|
||||
('umount', export_mnt_base)]
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
def test_libvirt_nfs_driver_with_opts(self):
|
||||
libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
options = '-o intr,nfsvers=3'
|
||||
export_mnt_base = os.path.join(self.mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name,
|
||||
'options': options}}
|
||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
expected_commands = [
|
||||
('mkdir', '-p', export_mnt_base),
|
||||
('mount', '-t', 'nfs', '-o', 'intr,nfsvers=3',
|
||||
export_string, export_mnt_base),
|
||||
('umount', export_mnt_base),
|
||||
]
|
||||
self.assertEqual(expected_commands, self.executes)
|
||||
@@ -13,11 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
import mock
|
||||
from os_brick.initiator import connector
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
|
||||
from nova import exception
|
||||
@@ -25,7 +22,6 @@ from nova import test
|
||||
from nova.tests.unit.virt.libvirt import fakelibvirt
|
||||
from nova import utils
|
||||
from nova.virt.libvirt import host
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
from nova.virt.libvirt.volume import volume
|
||||
|
||||
CONF = cfg.CONF
|
||||
@@ -532,115 +528,3 @@ Setting up iSCSI targets: unused
|
||||
self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)
|
||||
self.assertEqual(tree.find('./auth/secret').get('uuid'), SECRET_UUID)
|
||||
libvirt_driver.disconnect_volume(connection_info, 'vde')
|
||||
|
||||
def test_libvirt_nfs_driver(self):
|
||||
# NOTE(vish) exists is to make driver assume connecting worked
|
||||
mnt_base = '/mnt'
|
||||
self.flags(nfs_mount_point_base=mnt_base, group='libvirt')
|
||||
|
||||
libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)
|
||||
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
export_mnt_base = os.path.join(mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name}}
|
||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
device_path = os.path.join(export_mnt_base,
|
||||
connection_info['data']['name'])
|
||||
self.assertEqual(device_path, connection_info['data']['device_path'])
|
||||
expected_commands = [
|
||||
('mkdir', '-p', export_mnt_base),
|
||||
('mount', '-t', 'nfs', export_string, export_mnt_base),
|
||||
('umount', export_mnt_base)]
|
||||
self.assertEqual(expected_commands, self.executes)
|
||||
|
||||
@mock.patch.object(volume.utils, 'execute')
|
||||
@mock.patch.object(volume.LOG, 'debug')
|
||||
@mock.patch.object(volume.LOG, 'exception')
|
||||
def test_libvirt_nfs_driver_umount_error(self, mock_LOG_exception,
|
||||
mock_LOG_debug, mock_utils_exe):
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name}}
|
||||
libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
mock_utils_exe.side_effect = processutils.ProcessExecutionError(
|
||||
None, None, None, 'umount', 'umount: device is busy.')
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
self.assertTrue(mock_LOG_debug.called)
|
||||
mock_utils_exe.side_effect = processutils.ProcessExecutionError(
|
||||
None, None, None, 'umount', 'umount: target is busy.')
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
self.assertTrue(mock_LOG_debug.called)
|
||||
mock_utils_exe.side_effect = processutils.ProcessExecutionError(
|
||||
None, None, None, 'umount', 'umount: Other error.')
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
self.assertTrue(mock_LOG_exception.called)
|
||||
|
||||
def test_libvirt_nfs_driver_get_config(self):
|
||||
libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
mnt_base = '/mnt'
|
||||
self.flags(nfs_mount_point_base=mnt_base, group='libvirt')
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
export_mnt_base = os.path.join(mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
file_path = os.path.join(export_mnt_base, self.name)
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name,
|
||||
'device_path': file_path}}
|
||||
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
||||
tree = conf.format_dom()
|
||||
self._assertFileTypeEquals(tree, file_path)
|
||||
self.assertEqual('raw', tree.find('./driver').get('type'))
|
||||
|
||||
def test_libvirt_nfs_driver_already_mounted(self):
|
||||
# NOTE(vish) exists is to make driver assume connecting worked
|
||||
mnt_base = '/mnt'
|
||||
self.flags(nfs_mount_point_base=mnt_base, group='libvirt')
|
||||
|
||||
libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
export_mnt_base = os.path.join(mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name}}
|
||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
expected_commands = [
|
||||
('findmnt', '--target', export_mnt_base, '--source',
|
||||
export_string),
|
||||
('umount', export_mnt_base)]
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
def test_libvirt_nfs_driver_with_opts(self):
|
||||
mnt_base = '/mnt'
|
||||
self.flags(nfs_mount_point_base=mnt_base, group='libvirt')
|
||||
|
||||
libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
options = '-o intr,nfsvers=3'
|
||||
export_mnt_base = os.path.join(mnt_base,
|
||||
utils.get_hash_str(export_string))
|
||||
|
||||
connection_info = {'data': {'export': export_string,
|
||||
'name': self.name,
|
||||
'options': options}}
|
||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
expected_commands = [
|
||||
('mkdir', '-p', export_mnt_base),
|
||||
('mount', '-t', 'nfs', '-o', 'intr,nfsvers=3',
|
||||
export_string, export_mnt_base),
|
||||
('umount', export_mnt_base),
|
||||
]
|
||||
self.assertEqual(expected_commands, self.executes)
|
||||
|
||||
@@ -279,7 +279,7 @@ libvirt_volume_drivers = [
|
||||
'fake=nova.virt.libvirt.volume.volume.LibvirtFakeVolumeDriver',
|
||||
'rbd=nova.virt.libvirt.volume.volume.LibvirtNetVolumeDriver',
|
||||
'sheepdog=nova.virt.libvirt.volume.volume.LibvirtNetVolumeDriver',
|
||||
'nfs=nova.virt.libvirt.volume.volume.LibvirtNFSVolumeDriver',
|
||||
'nfs=nova.virt.libvirt.volume.nfs.LibvirtNFSVolumeDriver',
|
||||
'smbfs=nova.virt.libvirt.volume.smbfs.LibvirtSMBFSVolumeDriver',
|
||||
'aoe=nova.virt.libvirt.volume.aoe.LibvirtAOEVolumeDriver',
|
||||
'glusterfs='
|
||||
|
||||
117
nova/virt/libvirt/volume/nfs.py
Normal file
117
nova/virt/libvirt/volume/nfs.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# 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 os
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.i18n import _LE, _LW
|
||||
from nova import paths
|
||||
from nova import utils
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
from nova.virt.libvirt.volume import volume as libvirt_volume
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
volume_opts = [
|
||||
cfg.StrOpt('nfs_mount_point_base',
|
||||
default=paths.state_path_def('mnt'),
|
||||
help='Directory where the NFS volume is mounted on the'
|
||||
' compute node'),
|
||||
cfg.StrOpt('nfs_mount_options',
|
||||
help='Mount options passed to the NFS client. See section '
|
||||
'of the nfs man page for details'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(volume_opts, 'libvirt')
|
||||
|
||||
|
||||
class LibvirtNFSVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver):
|
||||
"""Class implements libvirt part of volume driver for NFS."""
|
||||
|
||||
def __init__(self, connection):
|
||||
"""Create back-end to nfs."""
|
||||
super(LibvirtNFSVolumeDriver,
|
||||
self).__init__(connection, is_block_dev=False)
|
||||
|
||||
def _get_device_path(self, connection_info):
|
||||
path = os.path.join(CONF.libvirt.nfs_mount_point_base,
|
||||
utils.get_hash_str(connection_info['data']['export']))
|
||||
path = os.path.join(path, connection_info['data']['name'])
|
||||
return path
|
||||
|
||||
def get_config(self, connection_info, disk_info):
|
||||
"""Returns xml for libvirt."""
|
||||
conf = super(LibvirtNFSVolumeDriver,
|
||||
self).get_config(connection_info, disk_info)
|
||||
|
||||
conf.source_type = 'file'
|
||||
conf.source_path = connection_info['data']['device_path']
|
||||
conf.driver_format = connection_info['data'].get('format', 'raw')
|
||||
return conf
|
||||
|
||||
def connect_volume(self, connection_info, disk_info):
|
||||
"""Connect the volume. Returns xml for libvirt."""
|
||||
options = connection_info['data'].get('options')
|
||||
self._ensure_mounted(connection_info['data']['export'], options)
|
||||
|
||||
connection_info['data']['device_path'] = \
|
||||
self._get_device_path(connection_info)
|
||||
|
||||
def disconnect_volume(self, connection_info, disk_dev):
|
||||
"""Disconnect the volume."""
|
||||
|
||||
export = connection_info['data']['export']
|
||||
mount_path = os.path.join(CONF.libvirt.nfs_mount_point_base,
|
||||
utils.get_hash_str(export))
|
||||
|
||||
try:
|
||||
utils.execute('umount', mount_path, run_as_root=True)
|
||||
except processutils.ProcessExecutionError as exc:
|
||||
if ('device is busy' in exc.message or
|
||||
'target is busy' in exc.message):
|
||||
LOG.debug("The NFS share %s is still in use.", export)
|
||||
else:
|
||||
LOG.exception(_LE("Couldn't unmount the NFS share %s"), export)
|
||||
|
||||
def _ensure_mounted(self, nfs_export, options=None):
|
||||
"""@type nfs_export: string
|
||||
@type options: string
|
||||
"""
|
||||
mount_path = os.path.join(CONF.libvirt.nfs_mount_point_base,
|
||||
utils.get_hash_str(nfs_export))
|
||||
if not libvirt_utils.is_mounted(mount_path, nfs_export):
|
||||
self._mount_nfs(mount_path, nfs_export, options, ensure=True)
|
||||
return mount_path
|
||||
|
||||
def _mount_nfs(self, mount_path, nfs_share, options=None, ensure=False):
|
||||
"""Mount nfs export to mount path."""
|
||||
utils.execute('mkdir', '-p', mount_path)
|
||||
|
||||
# Construct the NFS mount command.
|
||||
nfs_cmd = ['mount', '-t', 'nfs']
|
||||
if CONF.libvirt.nfs_mount_options is not None:
|
||||
nfs_cmd.extend(['-o', CONF.libvirt.nfs_mount_options])
|
||||
if options:
|
||||
nfs_cmd.extend(options.split(' '))
|
||||
nfs_cmd.extend([nfs_share, mount_path])
|
||||
|
||||
try:
|
||||
utils.execute(*nfs_cmd, run_as_root=True)
|
||||
except processutils.ProcessExecutionError as exc:
|
||||
if ensure and 'already mounted' in exc.message:
|
||||
LOG.warn(_LW("%s is already mounted"), nfs_share)
|
||||
else:
|
||||
raise
|
||||
@@ -16,10 +16,7 @@
|
||||
|
||||
"""Volume drivers for libvirt."""
|
||||
|
||||
import os
|
||||
|
||||
from os_brick.initiator import connector
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
@@ -28,7 +25,6 @@ from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova.i18n import _LE
|
||||
from nova.i18n import _LW
|
||||
from nova import paths
|
||||
from nova import utils
|
||||
from nova.virt.libvirt import config as vconfig
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
@@ -47,13 +43,6 @@ volume_opts = [
|
||||
cfg.StrOpt('rbd_secret_uuid',
|
||||
help='The libvirt UUID of the secret for the rbd_user'
|
||||
'volumes'),
|
||||
cfg.StrOpt('nfs_mount_point_base',
|
||||
default=paths.state_path_def('mnt'),
|
||||
help='Directory where the NFS volume is mounted on the'
|
||||
' compute node'),
|
||||
cfg.StrOpt('nfs_mount_options',
|
||||
help='Mount options passed to the NFS client. See section '
|
||||
'of the nfs man page for details'),
|
||||
cfg.BoolOpt('iscsi_use_multipath',
|
||||
default=False,
|
||||
help='Use multipath connection of the iSCSI volume'),
|
||||
@@ -327,82 +316,3 @@ class LibvirtISERVolumeDriver(LibvirtISCSIVolumeDriver):
|
||||
|
||||
def _get_transport(self):
|
||||
return 'iser'
|
||||
|
||||
|
||||
class LibvirtNFSVolumeDriver(LibvirtBaseVolumeDriver):
|
||||
"""Class implements libvirt part of volume driver for NFS."""
|
||||
|
||||
def __init__(self, connection):
|
||||
"""Create back-end to nfs."""
|
||||
super(LibvirtNFSVolumeDriver,
|
||||
self).__init__(connection, is_block_dev=False)
|
||||
|
||||
def _get_device_path(self, connection_info):
|
||||
path = os.path.join(CONF.libvirt.nfs_mount_point_base,
|
||||
utils.get_hash_str(connection_info['data']['export']))
|
||||
path = os.path.join(path, connection_info['data']['name'])
|
||||
return path
|
||||
|
||||
def get_config(self, connection_info, disk_info):
|
||||
"""Returns xml for libvirt."""
|
||||
conf = super(LibvirtNFSVolumeDriver,
|
||||
self).get_config(connection_info, disk_info)
|
||||
|
||||
conf.source_type = 'file'
|
||||
conf.source_path = connection_info['data']['device_path']
|
||||
conf.driver_format = connection_info['data'].get('format', 'raw')
|
||||
return conf
|
||||
|
||||
def connect_volume(self, connection_info, disk_info):
|
||||
"""Connect the volume. Returns xml for libvirt."""
|
||||
options = connection_info['data'].get('options')
|
||||
self._ensure_mounted(connection_info['data']['export'], options)
|
||||
|
||||
connection_info['data']['device_path'] = \
|
||||
self._get_device_path(connection_info)
|
||||
|
||||
def disconnect_volume(self, connection_info, disk_dev):
|
||||
"""Disconnect the volume."""
|
||||
|
||||
export = connection_info['data']['export']
|
||||
mount_path = os.path.join(CONF.libvirt.nfs_mount_point_base,
|
||||
utils.get_hash_str(export))
|
||||
|
||||
try:
|
||||
utils.execute('umount', mount_path, run_as_root=True)
|
||||
except processutils.ProcessExecutionError as exc:
|
||||
if ('device is busy' in exc.message or
|
||||
'target is busy' in exc.message):
|
||||
LOG.debug("The NFS share %s is still in use.", export)
|
||||
else:
|
||||
LOG.exception(_LE("Couldn't unmount the NFS share %s"), export)
|
||||
|
||||
def _ensure_mounted(self, nfs_export, options=None):
|
||||
"""@type nfs_export: string
|
||||
@type options: string
|
||||
"""
|
||||
mount_path = os.path.join(CONF.libvirt.nfs_mount_point_base,
|
||||
utils.get_hash_str(nfs_export))
|
||||
if not libvirt_utils.is_mounted(mount_path, nfs_export):
|
||||
self._mount_nfs(mount_path, nfs_export, options, ensure=True)
|
||||
return mount_path
|
||||
|
||||
def _mount_nfs(self, mount_path, nfs_share, options=None, ensure=False):
|
||||
"""Mount nfs export to mount path."""
|
||||
utils.execute('mkdir', '-p', mount_path)
|
||||
|
||||
# Construct the NFS mount command.
|
||||
nfs_cmd = ['mount', '-t', 'nfs']
|
||||
if CONF.libvirt.nfs_mount_options is not None:
|
||||
nfs_cmd.extend(['-o', CONF.libvirt.nfs_mount_options])
|
||||
if options:
|
||||
nfs_cmd.extend(options.split(' '))
|
||||
nfs_cmd.extend([nfs_share, mount_path])
|
||||
|
||||
try:
|
||||
utils.execute(*nfs_cmd, run_as_root=True)
|
||||
except processutils.ProcessExecutionError as exc:
|
||||
if ensure and 'already mounted' in exc.message:
|
||||
LOG.warn(_LW("%s is already mounted"), nfs_share)
|
||||
else:
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user