Skip to content

Commit

Permalink
Support Cinder mount options for NFS/GlusterFS
Browse files Browse the repository at this point in the history
When connecting to an NFS or GlusterFS volume, use
mount options specified in the "options" field of
the connection_info structure to perform the mount.

This allows the Cinder volume service to specify mount
options rather than only being able to configure them
on the Nova compute node.

Fixes: bug 1185180
blueprint cinder-volume-options

Change-Id: I81a50a2ceb4da4d639f6471b2114a904e5d1a42e
  • Loading branch information
eharney committed May 29, 2013
1 parent dc48d3d commit a6306bd
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 11 deletions.
67 changes: 67 additions & 0 deletions nova/tests/virt/libvirt/test_libvirt_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,39 @@ def test_libvirt_nfs_driver(self):
('mount', '-t', 'nfs', export_string, 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)

libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)
export_string = '192.168.1.1:/nfs/share1'
name = 'volume-00001'
options = '-o intr,nfsvers=3'
export_mnt_base = os.path.join(mnt_base,
libvirt_driver.get_hash_str(export_string))
file_path = os.path.join(export_mnt_base, name)

connection_info = {'data': {'export': export_string,
'name': name,
'options': options}}
disk_info = {
"bus": "virtio",
"dev": "vde",
"type": "disk",
}
conf = libvirt_driver.connect_volume(connection_info, disk_info)
tree = conf.format_dom()
self.assertEqual(tree.get('type'), 'file')
self.assertEqual(tree.find('./source').get('file'), file_path)
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)
]
self.assertEqual(self.executes, expected_commands)

def aoe_connection(self, shelf, lun):
return {
'driver_volume_type': 'aoe',
Expand Down Expand Up @@ -504,6 +537,40 @@ def test_libvirt_glusterfs_driver(self):
('mount', '-t', 'glusterfs', export_string, export_mnt_base)]
self.assertEqual(self.executes, expected_commands)

def test_libvirt_glusterfs_driver_with_opts(self):
mnt_base = '/mnt'
self.flags(glusterfs_mount_point_base=mnt_base)

libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)
export_string = '192.168.1.1:/volume-00001'
options = '-o backupvolfile-server=192.168.1.2'
name = 'volume-00001'
export_mnt_base = os.path.join(mnt_base,
libvirt_driver.get_hash_str(export_string))
file_path = os.path.join(export_mnt_base, name)

connection_info = {'data': {'export': export_string,
'name': name,
'options': options}}
disk_info = {
"bus": "virtio",
"dev": "vde",
"type": "disk",
}

conf = libvirt_driver.connect_volume(connection_info, disk_info)
tree = conf.format_dom()
self.assertEqual(tree.get('type'), 'file')
self.assertEqual(tree.find('./source').get('file'), file_path)
libvirt_driver.disconnect_volume(connection_info, "vde")

expected_commands = [
('mkdir', '-p', export_mnt_base),
('mount', '-t', 'glusterfs',
'-o', 'backupvolfile-server=192.168.1.2',
export_string, export_mnt_base)]
self.assertEqual(self.executes, expected_commands)

def fibrechan_connection(self, volume, location, wwn):
return {
'driver_volume_type': 'fibrechan',
Expand Down
33 changes: 22 additions & 11 deletions nova/virt/libvirt/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,29 +474,33 @@ def connect_volume(self, connection_info, disk_info):
conf = super(LibvirtNFSVolumeDriver,
self).connect_volume(connection_info,
disk_info)
path = self._ensure_mounted(connection_info['data']['export'])
options = connection_info['data'].get('options')
path = self._ensure_mounted(connection_info['data']['export'], options)
path = os.path.join(path, connection_info['data']['name'])
conf.source_type = 'file'
conf.source_path = path
return conf

def _ensure_mounted(self, nfs_export):
def _ensure_mounted(self, nfs_export, options=None):
"""
@type nfs_export: string
@type options: string
"""
mount_path = os.path.join(CONF.nfs_mount_point_base,
self.get_hash_str(nfs_export))
self._mount_nfs(mount_path, nfs_export, ensure=True)
self._mount_nfs(mount_path, nfs_export, options, ensure=True)
return mount_path

def _mount_nfs(self, mount_path, nfs_share, ensure=False):
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.nfs_mount_options is not None:
nfs_cmd.extend(['-o', CONF.nfs_mount_options])
if options is not None:
nfs_cmd.extend(options.split(' '))
nfs_cmd.extend([nfs_share, mount_path])

try:
Expand Down Expand Up @@ -590,29 +594,36 @@ def connect_volume(self, connection_info, mount_device):
"""Connect the volume. Returns xml for libvirt."""
conf = super(LibvirtGlusterfsVolumeDriver,
self).connect_volume(connection_info, mount_device)
path = self._ensure_mounted(connection_info['data']['export'])
options = connection_info['data'].get('options')
path = self._ensure_mounted(connection_info['data']['export'], options)
path = os.path.join(path, connection_info['data']['name'])
conf.source_type = 'file'
conf.source_path = path
return conf

def _ensure_mounted(self, glusterfs_export):
def _ensure_mounted(self, glusterfs_export, options=None):
"""
@type glusterfs_export: string
@type options: string
"""
mount_path = os.path.join(CONF.glusterfs_mount_point_base,
self.get_hash_str(glusterfs_export))
self._mount_glusterfs(mount_path, glusterfs_export, ensure=True)
self._mount_glusterfs(mount_path, glusterfs_export,
options, ensure=True)
return mount_path

def _mount_glusterfs(self, mount_path, glusterfs_share, ensure=False):
def _mount_glusterfs(self, mount_path, glusterfs_share,
options=None, ensure=False):
"""Mount glusterfs export to mount path."""
utils.execute('mkdir', '-p', mount_path)

gluster_cmd = ['mount', '-t', 'glusterfs']
if options is not None:
gluster_cmd.extend(options.split(' '))
gluster_cmd.extend([glusterfs_share, mount_path])

try:
utils.execute('mount', '-t', 'glusterfs', glusterfs_share,
mount_path,
run_as_root=True)
utils.execute(*gluster_cmd, run_as_root=True)
except processutils.ProcessExecutionError as exc:
if ensure and 'already mounted' in exc.message:
LOG.warn(_("%s is already mounted"), glusterfs_share)
Expand Down

0 comments on commit a6306bd

Please sign in to comment.