Make NFS exports in generic driver permanent
Generic driver uses 'exportfs' utility for exports handling, but it stores exports in temporary file /var/lib/nfs/etab and server loses all exports after reboot. This change copies temp exports file to permanent exports file located in /etc/exports after each action with exports and makes reexport of all shares. After restart of server all exports will be restored from permanent file. Change-Id: I6a1e7074f18c70df5785d236c6f70c40731cda77 Closes-Bug: #1358688
This commit is contained in:
parent
1b6b37c5c6
commit
20b810bfb6
|
@ -25,6 +25,9 @@ STATUS_DEACTIVATING = 'DEACTIVATING'
|
|||
|
||||
SECURITY_SERVICES_ALLOWED_TYPES = ['active_directory', 'ldap', 'kerberos']
|
||||
|
||||
NFS_EXPORTS_FILE = '/etc/exports'
|
||||
NFS_EXPORTS_FILE_TEMP = '/var/lib/nfs/etab'
|
||||
|
||||
# Below represented ports are ranges (from, to)
|
||||
CIFS_PORTS = (
|
||||
("tcp", (445, 445)),
|
||||
|
|
|
@ -22,6 +22,7 @@ import time
|
|||
from oslo.config import cfg
|
||||
import six
|
||||
|
||||
from manila.common import constants as const
|
||||
from manila import compute
|
||||
from manila import context
|
||||
from manila import exception
|
||||
|
@ -614,6 +615,20 @@ class NASHelperBase(object):
|
|||
raise NotImplementedError()
|
||||
|
||||
|
||||
def nfs_synchronized(f):
|
||||
|
||||
def wrapped_func(self, *args, **kwargs):
|
||||
key = "nfs-%s" % args[0]["instance_id"]
|
||||
|
||||
@utils.synchronized(key)
|
||||
def source_func(self, *args, **kwargs):
|
||||
return f(self, *args, **kwargs)
|
||||
|
||||
return source_func(self, *args, **kwargs)
|
||||
|
||||
return wrapped_func
|
||||
|
||||
|
||||
class NFSHelper(NASHelperBase):
|
||||
"""Interface to work with share."""
|
||||
|
||||
|
@ -637,6 +652,7 @@ class NFSHelper(NASHelperBase):
|
|||
"""Remove export."""
|
||||
pass
|
||||
|
||||
@nfs_synchronized
|
||||
def allow_access(self, server, share_name, access_type, access):
|
||||
"""Allow access to the host."""
|
||||
local_path = os.path.join(self.configuration.share_mount_path,
|
||||
|
@ -654,7 +670,9 @@ class NFSHelper(NASHelperBase):
|
|||
self._ssh_exec(server,
|
||||
['sudo', 'exportfs', '-o', 'rw,no_subtree_check',
|
||||
':'.join([access, local_path])])
|
||||
self._sync_nfs_temp_and_perm_files(server)
|
||||
|
||||
@nfs_synchronized
|
||||
def deny_access(self, server, share_name, access_type, access,
|
||||
force=False):
|
||||
"""Deny access to the host."""
|
||||
|
@ -662,6 +680,20 @@ class NFSHelper(NASHelperBase):
|
|||
share_name)
|
||||
self._ssh_exec(server, ['sudo', 'exportfs', '-u',
|
||||
':'.join([access, local_path])])
|
||||
self._sync_nfs_temp_and_perm_files(server)
|
||||
|
||||
def _sync_nfs_temp_and_perm_files(self, server):
|
||||
"""Sync changes of exports with permanent NFS config file.
|
||||
|
||||
This is required to ensure, that after share server reboot, exports
|
||||
still exist.
|
||||
"""
|
||||
sync_cmd = [
|
||||
'sudo', 'cp ', const.NFS_EXPORTS_FILE_TEMP, const.NFS_EXPORTS_FILE,
|
||||
'&&',
|
||||
'sudo', 'exportfs', '-a',
|
||||
]
|
||||
self._ssh_exec(server, sync_cmd)
|
||||
|
||||
|
||||
class CIFSHelper(NASHelperBase):
|
||||
|
|
|
@ -706,39 +706,53 @@ class NFSHelperTestCase(test.TestCase):
|
|||
self._execute = mock.Mock(return_value=('', ''))
|
||||
self._helper = generic.NFSHelper(self._execute, self._ssh_exec,
|
||||
self.fake_conf)
|
||||
ip = '10.254.0.3'
|
||||
self.server = fake_compute.FakeServer(
|
||||
ip=ip, public_address=ip, instance_id='fake_instance_id')
|
||||
|
||||
def test_create_export(self):
|
||||
fake_server = fake_compute.FakeServer(public_address='10.254.0.3')
|
||||
ret = self._helper.create_export(fake_server, 'volume-00001')
|
||||
expected_location = ':'.join([fake_server['public_address'],
|
||||
ret = self._helper.create_export(self.server, 'fake_share')
|
||||
expected_location = ':'.join([self.server['public_address'],
|
||||
os.path.join(CONF.share_mount_path,
|
||||
'volume-00001')])
|
||||
'fake_share')])
|
||||
self.assertEqual(ret, expected_location)
|
||||
|
||||
def test_allow_access(self):
|
||||
fake_server = fake_compute.FakeServer(ip='10.254.0.3')
|
||||
self._helper.allow_access(fake_server, 'volume-00001',
|
||||
self.stubs.Set(self._helper, '_sync_nfs_temp_and_perm_files',
|
||||
mock.Mock())
|
||||
self._helper.allow_access(self.server, 'fake_share',
|
||||
'ip', '10.0.0.2')
|
||||
local_path = os.path.join(CONF.share_mount_path, 'volume-00001')
|
||||
local_path = os.path.join(CONF.share_mount_path, 'fake_share')
|
||||
self._ssh_exec.assert_has_calls([
|
||||
mock.call(fake_server, ['sudo', 'exportfs']),
|
||||
mock.call(fake_server, ['sudo', 'exportfs', '-o',
|
||||
mock.call(self.server, ['sudo', 'exportfs']),
|
||||
mock.call(self.server, ['sudo', 'exportfs', '-o',
|
||||
'rw,no_subtree_check',
|
||||
':'.join(['10.0.0.2', local_path])])
|
||||
])
|
||||
self._helper._sync_nfs_temp_and_perm_files.assert_called_once_with(
|
||||
self.server)
|
||||
|
||||
def test_allow_access_no_ip(self):
|
||||
self.assertRaises(exception.InvalidShareAccess,
|
||||
self._helper.allow_access, 'fake_server', 'share0',
|
||||
'fake', 'fakerule')
|
||||
self.assertRaises(
|
||||
exception.InvalidShareAccess,
|
||||
self._helper.allow_access,
|
||||
self.server, 'fake_share', 'fake', 'fakerule',
|
||||
)
|
||||
|
||||
def test_deny_access(self):
|
||||
fake_server = fake_compute.FakeServer(ip='10.254.0.3')
|
||||
local_path = os.path.join(CONF.share_mount_path, 'volume-00001')
|
||||
self._helper.deny_access(fake_server, 'volume-00001', 'ip', '10.0.0.2')
|
||||
self.stubs.Set(self._helper, '_sync_nfs_temp_and_perm_files',
|
||||
mock.Mock())
|
||||
local_path = os.path.join(CONF.share_mount_path, 'fake_share')
|
||||
self._helper.deny_access(self.server, 'fake_share', 'ip', '10.0.0.2')
|
||||
export_string = ':'.join(['10.0.0.2', local_path])
|
||||
expected_exec = ['sudo', 'exportfs', '-u', export_string]
|
||||
self._ssh_exec.assert_called_once_with(fake_server, expected_exec)
|
||||
self._ssh_exec.assert_called_once_with(self.server, expected_exec)
|
||||
self._helper._sync_nfs_temp_and_perm_files.assert_called_once_with(
|
||||
self.server)
|
||||
|
||||
def test_sync_nfs_temp_and_perm_files(self):
|
||||
self._helper._sync_nfs_temp_and_perm_files(self.server)
|
||||
self._helper._ssh_exec.assert_called_once_with(self.server, mock.ANY)
|
||||
|
||||
|
||||
class CIFSHelperTestCase(test.TestCase):
|
||||
|
|
Loading…
Reference in New Issue