glusterfs: add infrastructure to accommodate NAS helpers

- Refactor the main driver class, GlusterFSShareDriver, to make it
  pluggable with different NAS helpers.

   - Add GlusterNFS helper class to manage shares served by Gluster-NFS
     server. The management of these share was earlier done within the
     main driver class.

- Enhance the methods of the GlusterAddress class that would be used
  by the main driver class and the helper classes. Rename the
  GlusterAddress class to GlusterManager class. This class would
  contain the methods to interface with the backend GlusterFS volumes.

   - Retire GlusterAddress.make_gluster_args() in favor of
     GlusterManager.make_gluster_call(). The make_gluster_call() method
     implements a more correct approach to remote execution. It's
     remote execution is based on processutils.ssh_execute. The
     make_gluster_args() method that it replaces facilitated remote
     execution by prefixing arguments with 'ssh'.

   - Move the interface used to fetch the value of an option set on a
     GlusterFS volume, from the main driver class to the GlusterManager
     class.

Partially implements blueprint gateway-mediated-with-ganesha

Change-Id: I3cbeb49c26f5f24152b42b649ce3bc75451964ef
This commit is contained in:
Ramana Raja 2014-09-03 11:10:42 +00:00 committed by Csaba Henk
parent f16267d878
commit ca294a7449
4 changed files with 1059 additions and 801 deletions

View File

@ -25,8 +25,8 @@ TODO(rraja): support SMB protocol.
import errno
import os
import pipes
import re
import sys
import xml.etree.cElementTree as etree
from oslo.config import cfg
@ -38,6 +38,8 @@ from manila.i18n import _LE
from manila.i18n import _LW
from manila.openstack.common import log as logging
from manila.share import driver
from manila.share.drivers import ganesha
from manila.share.drivers.ganesha import utils as ganesha_utils
LOG = logging.getLogger(__name__)
@ -51,6 +53,19 @@ GlusterfsManilaShare_opts = [
default='$state_path/mnt',
help='Base directory containing mount points for Gluster '
'volumes.'),
cfg.StrOpt('glusterfs_nfs_server_type',
default='Gluster',
help='Type of NFS server that mediate access to the Gluster '
'volumes (for now: only Gluster).'),
cfg.StrOpt('glusterfs_server_password',
default=None,
secret=True,
help="Remote GlusterFS server node's login password. "
"This is not required if 'glusterfs_path_to_private_key'"
' is configured.'),
cfg.StrOpt('glusterfs_path_to_private_key',
default=None,
help='Path of Manila host\'s private SSH key file.'),
]
CONF = cfg.CONF
@ -60,13 +75,22 @@ NFS_EXPORT_DIR = 'nfs.export-dir'
NFS_EXPORT_VOL = 'nfs.export-volumes'
class GlusterAddress(object):
class GlusterManager(object):
"""Interface with a GlusterFS volume."""
scheme = re.compile('\A(?:(?P<user>[^:@/]+)@)?'
'(?P<host>[^:@/]+):'
'/(?P<vol>.+)')
def __init__(self, address):
def __init__(self, address, execf, path_to_private_key=None,
remote_server_password=None):
"""Initialize a GaneshaManager instance.
:param address: the Gluster URI (in [<user>@]<host>:/<vol> format).
:param execf: executor function for management commands.
:param path_to_private_key: path to private ssh key of remote server.
:param remote_server_password: ssh password for remote server.
"""
m = self.scheme.search(address)
if not m:
raise exception.GlusterfsException('invalid gluster address ' +
@ -76,68 +100,36 @@ class GlusterAddress(object):
self.volume = m.group('vol')
self.qualified = address
self.export = ':/'.join([self.host, self.volume])
self.path_to_private_key = path_to_private_key
self.remote_server_password = remote_server_password
self.gluster_call = self.make_gluster_call(execf)
def make_gluster_args(self, *args):
args = ('gluster',) + args
kw = {}
def make_gluster_call(self, execf):
"""Execute a Gluster command locally or remotely."""
if self.remote_user:
args = ('ssh', '@'.join([self.remote_user, self.host]),
' '.join(pipes.quote(a) for a in args))
gluster_execf = ganesha_utils.SSHExecutor(
self.host, 22, None, self.remote_user,
password=self.remote_server_password,
privatekey=self.path_to_private_key)
else:
kw['run_as_root'] = True
return args, kw
gluster_execf = ganesha_utils.RootExecutor(execf)
return lambda *args, **kwargs: gluster_execf(*(('gluster',) + args),
**kwargs)
class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
"""Execute commands relating to Shares."""
def __init__(self, db, *args, **kwargs):
super(GlusterfsShareDriver, self).__init__(False, *args, **kwargs)
self.db = db
self._helpers = None
self.gluster_address = None
self.configuration.append_config_values(GlusterfsManilaShare_opts)
self.backend_name = self.configuration.safe_get(
'share_backend_name') or 'GlusterFS'
def do_setup(self, context):
"""Native mount the GlusterFS volume and tune it."""
super(GlusterfsShareDriver, self).do_setup(context)
if not self.configuration.glusterfs_target:
raise exception.GlusterfsException(
_('glusterfs_target configuration that specifies the GlusterFS'
' volume to be mounted on the Manila host is not set.'))
self.gluster_address = GlusterAddress(
self.configuration.glusterfs_target
)
def get_gluster_vol_option(self, option):
"""Get the value of an option set on a GlusterFS volume."""
args = ('--xml', 'volume', 'info', self.volume)
try:
self._execute('mount.glusterfs', check_exit_code=False)
except OSError as exc:
if exc.errno == errno.ENOENT:
raise exception.GlusterfsException(
_('mount.glusterfs is not installed'))
else:
raise
self._ensure_gluster_vol_mounted()
self._setup_gluster_vol()
def _get_gluster_vol_option(self, option):
try:
args, kw = self.gluster_address.make_gluster_args(
'--xml',
'volume',
'info',
self.gluster_address.volume
)
out, err = self._execute(*args, **kw)
out, err = self.gluster_call(*args)
except exception.ProcessExecutionError as exc:
LOG.error(_LE("Error retrieving volume info: %s"), exc.stderr)
raise exception.GlusterfsException(exc)
raise exception.GlusterfsException("gluster %s failed" %
' '.join(args))
if not out:
raise exception.GlusterfsException(
'Empty answer from gluster command'
'gluster volume info %s: no data received' %
self.volume
)
vix = etree.fromstring(out)
@ -148,37 +140,77 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
if o == option:
return v
def _setup_gluster_vol(self):
# exporting the whole volume must be prohibited
# to not to defeat access control
args, kw = self.gluster_address.make_gluster_args(
'volume', 'set', self.gluster_address.volume,
NFS_EXPORT_VOL, 'off')
class GlusterfsShareDriver(driver.ExecuteMixin, driver.GaneshaMixin,
driver.ShareDriver,):
"""Execute commands relating to Shares."""
def __init__(self, db, *args, **kwargs):
super(GlusterfsShareDriver, self).__init__(False, *args, **kwargs)
self.db = db
self._helpers = {}
self.gluster_manager = None
self.configuration.append_config_values(GlusterfsManilaShare_opts)
self.backend_name = self.configuration.safe_get(
'share_backend_name') or 'GlusterFS'
def do_setup(self, context):
"""Prepares the backend and appropriate NAS helpers."""
super(GlusterfsShareDriver, self).do_setup(context)
if not self.configuration.glusterfs_target:
raise exception.GlusterfsException(
_('glusterfs_target configuration that specifies the GlusterFS'
' volume to be mounted on the Manila host is not set.'))
self.gluster_manager = GlusterManager(
self.configuration.glusterfs_target,
self._execute,
self.configuration.glusterfs_path_to_private_key,
self.configuration.glusterfs_server_password,
)
try:
self._execute(*args, **kw)
except exception.ProcessExecutionError as exc:
LOG.error(_LE("Error in disabling access to the entire GlusterFS "
"volume: %s"), exc.stderr)
raise
self._execute('mount.glusterfs', check_exit_code=False)
except OSError as exc:
if exc.errno == errno.ENOENT:
raise exception.GlusterfsException(
_('mount.glusterfs is not installed'))
else:
raise
# enable quota options of a GlusteFS volume to allow
# creation of shares of specific size
args, kw = self.gluster_address.make_gluster_args(
'volume', 'quota', self.gluster_address.volume, 'enable')
args = ('volume', 'quota', self.gluster_manager.volume, 'enable')
try:
self._execute(*args, **kw)
self.gluster_manager.gluster_call(*args)
except exception.ProcessExecutionError as exc:
if self._get_gluster_vol_option('features.quota') != 'on':
LOG.error(_LE("Error in enabling creation of shares of "
"specific size: %s"), exc.stderr)
if (self.gluster_manager.
get_gluster_vol_option('features.quota')) != 'on':
LOG.error(_LE("Error in tuning GlusterFS volume to enable "
"creation of shares of specific size: %s"),
exc.stderr)
raise exception.GlusterfsException(exc)
self._setup_helpers()
self._ensure_gluster_vol_mounted()
def _setup_helpers(self):
"""Initializes protocol-specific NAS drivers."""
# TODO(rraja): The below seems crude. Accommodate CIFS helper as well?
nfs_helper = getattr(
sys.modules[__name__],
self.configuration.glusterfs_nfs_server_type + 'NFSHelper')
self._helpers['NFS'] = nfs_helper(self._execute,
self.configuration,
gluster_manager=self.gluster_manager)
for helper in self._helpers.values():
helper.init_helper()
def check_for_setup_error(self):
pass
def _get_mount_point_for_gluster_vol(self):
"""Return mount point for the GlusterFS volume."""
return os.path.join(self.configuration.glusterfs_mount_point_base,
self.gluster_address.volume)
self.gluster_manager.volume)
def _do_mount(self, cmd, ensure):
"""Execute the mount command based on 'ensure' parameter.
@ -191,7 +223,7 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
except exception.ProcessExecutionError as exc:
if ensure and 'already mounted' in exc.stderr:
LOG.warn(_LW("%s is already mounted"),
self.gluster_address.export)
self.gluster_manager.export)
else:
raise exception.GlusterfsException(
'Unable to mount Gluster volume'
@ -200,28 +232,10 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
def _mount_gluster_vol(self, mount_path, ensure=False):
"""Mount GlusterFS volume at the specified mount path."""
self._execute('mkdir', '-p', mount_path)
command = ['mount', '-t', 'glusterfs', self.gluster_address.export,
command = ['mount', '-t', 'glusterfs', self.gluster_manager.export,
mount_path]
self._do_mount(command, ensure)
def _get_export_dir_dict(self):
"""Get the export entries of shares in the GlusterFS volume."""
export_dir = self._get_gluster_vol_option(NFS_EXPORT_DIR)
edh = {}
if export_dir:
# see
# https://github.com/gluster/glusterfs
# /blob/aa19909/xlators/nfs/server/src/nfs.c#L1582
# regarding the format of nfs.export-dir
edl = export_dir.split(',')
# parsing export_dir into a dict of {dir: [hostpec,..]..}
# format
r = re.compile('\A/(.*)\((.*)\)\Z')
for ed in edl:
d, e = r.match(ed).groups()
edh[d] = e.split('|')
return edh
def _ensure_gluster_vol_mounted(self):
"""Ensure GlusterFS volume is native-mounted on Manila host."""
mount_path = self._get_mount_point_for_gluster_vol()
@ -229,7 +243,7 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
self._mount_gluster_vol(mount_path, ensure=True)
except exception.GlusterfsException:
LOG.error(_LE('Could not mount the Gluster volume %s'),
self.gluster_address.volume)
self.gluster_manager.volume)
raise
def _get_local_share_path(self, share):
@ -266,23 +280,25 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
def create_share(self, ctx, share, share_server=None):
"""Create a sub-directory/share in the GlusterFS volume."""
# probe into getting a NAS protocol helper for the share in order
# to facilitate early detection of unsupported protocol type
self._get_helper(share)
sizestr = six.text_type(share['size']) + 'GB'
share_dir = '/' + share['name']
local_share_path = self._get_local_share_path(share)
cmd = ['mkdir', local_share_path]
# set hard limit quota on the sub-directory/share
args, kw = self.gluster_address.make_gluster_args(
'volume', 'quota', self.gluster_address.volume, 'limit-usage',
share_dir, sizestr)
args = ('volume', 'quota', self.gluster_manager.volume,
'limit-usage', share_dir, sizestr)
try:
self._execute(*cmd, run_as_root=True)
self._execute(*args, **kw)
self.gluster_manager.gluster_call(*args)
except exception.ProcessExecutionError as exc:
self._cleanup_create_share(local_share_path, share['name'])
LOG.error(_LE('Unable to create share %s'), share['name'])
raise exception.GlusterfsException(exc)
export_location = os.path.join(self.gluster_address.qualified,
export_location = os.path.join(self.gluster_manager.qualified,
share['name'])
return export_location
@ -325,13 +341,75 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
"""Might not be needed?"""
pass
def _manage_access(self, context, share, access, cbk):
def _get_helper(self, share):
"""Choose a protocol specific helper class."""
if share['share_proto'] == 'NFS':
return self._helpers['NFS']
else:
raise exception.InvalidShare(
reason=(_('Unsupported share type, %s.')
% share['share_proto']))
def allow_access(self, context, share, access, share_server=None):
"""Allow access to the share."""
self._get_helper(share).allow_access('/', share, access)
def deny_access(self, context, share, access, share_server=None):
"""Deny access to the share."""
self._get_helper(share).deny_access('/', share, access)
class GlusterNFSHelper(ganesha.NASHelperBase):
"""Manage shares with Gluster-NFS server."""
def __init__(self, execute, config_object, **kwargs):
self.gluster_manager = kwargs.pop('gluster_manager')
super(GlusterNFSHelper, self).__init__(execute, config_object,
**kwargs)
def init_helper(self):
# exporting the whole volume must be prohibited
# to not to defeat access control
args = ('volume', 'set', self.gluster_manager.volume, NFS_EXPORT_VOL,
'off')
try:
self.gluster_manager.gluster_call(*args)
except exception.ProcessExecutionError as exc:
LOG.error(_LE("Error in tuning GlusterFS volume to prevent "
"exporting the entire volume: %s"), exc.stderr)
raise exception.GlusterfsException("gluster %s failed" %
' '.join(args))
def _get_export_dir_dict(self):
"""Get the export entries of shares in the GlusterFS volume."""
export_dir = self.gluster_manager.get_gluster_vol_option(
NFS_EXPORT_DIR)
edh = {}
if export_dir:
# see
# https://github.com/gluster/glusterfs
# /blob/aa19909/xlators/nfs/server/src/nfs.c#L1582
# regarding the format of nfs.export-dir
edl = export_dir.split(',')
# parsing export_dir into a dict of {dir: [hostpec,..]..}
# format
r = re.compile('\A/(.*)\((.*)\)\Z')
for ed in edl:
d, e = r.match(ed).groups()
edh[d] = e.split('|')
return edh
def _manage_access(self, share_name, access_type, access_to, cbk):
"""Manage share access with cbk.
Adjust the exports of the Gluster-NFS server using cbk.
:param share: share object
:param access: access object
:param share_name: name of the share
:type share_name: string
:param access_type: type of access allowed in Manila
:type access_type: string
:param access_to: ip of the guest whose share access is managed
:type access_to: string
:param cbk: callback to adjust the exports of NFS server
Following is the description of cbk(ddict, edir, host).
@ -345,29 +423,27 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
:returns: bool (cbk leaves ddict intact) or None (cbk modifies ddict)
"""
if access['access_type'] != 'ip':
if access_type != 'ip':
raise exception.InvalidShareAccess('only ip access type allowed')
export_dir_dict = self._get_export_dir_dict()
if cbk(export_dir_dict, share['name'], access['access_to']):
if cbk(export_dir_dict, share_name, access_to):
return
if export_dir_dict:
export_dir_new = (",".join("/%s(%s)" % (d, "|".join(v))
for d, v in sorted(export_dir_dict.items())))
args, kw = self.gluster_address.make_gluster_args(
'volume', 'set', self.gluster_address.volume,
NFS_EXPORT_DIR, export_dir_new)
args = ('volume', 'set', self.gluster_manager.volume,
NFS_EXPORT_DIR, export_dir_new)
else:
args, kw = self.gluster_address.make_gluster_args(
'volume', 'reset', self.gluster_address.volume,
NFS_EXPORT_DIR)
args = ('volume', 'reset', self.gluster_manager.volume,
NFS_EXPORT_DIR)
try:
self._execute(*args, **kw)
self.gluster_manager.gluster_call(*args)
except exception.ProcessExecutionError as exc:
LOG.error(_LE("Error in gluster volume set: %s"), exc.stderr)
raise
def allow_access(self, context, share, access, share_server=None):
def allow_access(self, base, share, access):
"""Allow access to a share."""
def cbk(ddict, edir, host):
if edir not in ddict:
@ -375,9 +451,10 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
if host in ddict[edir]:
return True
ddict[edir].append(host)
self._manage_access(context, share, access, cbk)
self._manage_access(share['name'], access['access_type'],
access['access_to'], cbk)
def deny_access(self, context, share, access, share_server=None):
def deny_access(self, base, share, access):
"""Deny access to a share."""
def cbk(ddict, edir, host):
if edir not in ddict or host not in ddict[edir]:
@ -385,4 +462,5 @@ class GlusterfsShareDriver(driver.ExecuteMixin, driver.ShareDriver):
ddict[edir].remove(host)
if not ddict[edir]:
ddict.pop(edir)
self._manage_access(context, share, access, cbk)
self._manage_access(share['name'], access['access_type'],
access['access_to'], cbk)

View File

@ -50,6 +50,16 @@ glusterfs_native_manila_share_opts = [
help='List of GlusterFS volumes that can be used to create '
'shares. Each GlusterFS volume should be of the form '
'[remoteuser@]<volserver>:/<volid>'),
cfg.StrOpt('glusterfs_native_server_password',
default=None,
secret=True,
help='Remote GlusterFS server node\'s login password. '
'This is not required if '
'\'glusterfs_native_path_to_private_key\' is '
'configured.'),
cfg.StrOpt('glusterfs_native_path_to_private_key',
default=None,
help='Path of Manila host\'s private SSH key file.'),
]
CONF = cfg.CONF
@ -143,24 +153,27 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
shares = self.db.share_get_all(context)
# Store the gluster volumes in dict thats helpful to track
# (push and pop) in future. {gluster_export: gluster_addr, ...}
# (push and pop) in future. {gluster_export: gluster_mgr, ...}
# gluster_export is of form hostname:/volname which is unique
# enough to be used as a key.
self.gluster_unused_vols_dict = {}
self.gluster_used_vols_dict = {}
for gv in self.configuration.glusterfs_targets:
gaddr = glusterfs.GlusterAddress(gv)
exp_locn_gv = gaddr.export
gmgr = glusterfs.GlusterManager(
gv, self._execute,
self.configuration.glusterfs_native_path_to_private_key,
self.configuration.glusterfs_native_server_password)
exp_locn_gv = gmgr.export
# Assume its unused to begin with.
self.gluster_unused_vols_dict.update({exp_locn_gv: gaddr})
self.gluster_unused_vols_dict.update({exp_locn_gv: gmgr})
for s in shares:
exp_locn_share = s.get('export_location', None)
if exp_locn_share == exp_locn_gv:
# gluster volume is in use, move it to used list.
self.gluster_used_vols_dict.update({exp_locn_gv: gaddr})
self.gluster_used_vols_dict.update({exp_locn_gv: gmgr})
self.gluster_unused_vols_dict.pop(exp_locn_gv)
break
@ -168,99 +181,94 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
def _setup_gluster_vols(self):
# Enable gluster volumes for SSL access only.
for gluster_addr in six.itervalues(self.gluster_unused_vols_dict):
for gluster_mgr in six.itervalues(self.gluster_unused_vols_dict):
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
NFS_EXPORT_VOL, 'off')
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
NFS_EXPORT_VOL, 'off')
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during volume setup. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
"rror: %(error)s"),
{'volname': gluster_mgr.volume,
'option': NFS_EXPORT_VOL, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
CLIENT_SSL, 'on')
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
CLIENT_SSL, 'on')
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during volume setup. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': CLIENT_SSL, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
SERVER_SSL, 'on')
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
SERVER_SSL, 'on')
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during volume setup. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': SERVER_SSL, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
# TODO(deepakcs) Remove this once ssl options can be
# set dynamically.
self._restart_gluster_vol(gluster_addr)
self._restart_gluster_vol(gluster_mgr)
def _restart_gluster_vol(self, gluster_addr):
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'stop', gluster_addr.volume, '--mode=script')
def _restart_gluster_vol(self, gluster_mgr):
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'stop', gluster_mgr.volume, '--mode=script')
except exception.ProcessExecutionError as exc:
msg = (_("Error stopping gluster volume. "
"Volume: %(volname)s, Error: %(error)s"),
{'volname': gluster_addr.volume, 'error': exc.stderr})
{'volname': gluster_mgr.volume, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'start', gluster_addr.volume)
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'start', gluster_mgr.volume)
except exception.ProcessExecutionError as exc:
msg = (_("Error starting gluster volume. "
"Volume: %(volname)s, Error: %(error)s"),
{'volname': gluster_addr.volume, 'error': exc.stderr})
{'volname': gluster_mgr.volume, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
@utils.synchronized("glusterfs_native", external=False)
def _pop_gluster_vol(self):
try:
exp_locn, gaddr = self.gluster_unused_vols_dict.popitem()
exp_locn, gmgr = self.gluster_unused_vols_dict.popitem()
except KeyError:
msg = (_("Couldn't find a free gluster volume to use."))
LOG.error(msg)
raise exception.GlusterfsException(msg)
self.gluster_used_vols_dict.update({exp_locn: gaddr})
self.gluster_used_vols_dict.update({exp_locn: gmgr})
return exp_locn
@utils.synchronized("glusterfs_native", external=False)
def _push_gluster_vol(self, exp_locn):
try:
gaddr = self.gluster_used_vols_dict.pop(exp_locn)
gmgr = self.gluster_used_vols_dict.pop(exp_locn)
except KeyError:
msg = (_("Couldn't find the share in used list."))
LOG.error(msg)
raise exception.GlusterfsException(msg)
self.gluster_unused_vols_dict.update({exp_locn: gaddr})
self.gluster_unused_vols_dict.update({exp_locn: gmgr})
def _do_mount(self, gluster_export, mntdir):
@ -286,41 +294,39 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
LOG.error(msg)
raise exception.GlusterfsException(msg)
def _wipe_gluster_vol(self, gluster_addr):
def _wipe_gluster_vol(self, gluster_mgr):
# Reset the SSL options.
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
CLIENT_SSL, 'off')
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
CLIENT_SSL, 'off')
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during _wipe_gluster_vol. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': CLIENT_SSL, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
SERVER_SSL, 'off')
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
SERVER_SSL, 'off')
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during _wipe_gluster_vol. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': SERVER_SSL, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
self._restart_gluster_vol(gluster_addr)
self._restart_gluster_vol(gluster_mgr)
# Create a temporary mount.
gluster_export = gluster_addr.export
gluster_export = gluster_mgr.export
tmpdir = tempfile.mkdtemp()
try:
self._do_mount(gluster_export, tmpdir)
@ -344,35 +350,33 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
shutil.rmtree(tmpdir, ignore_errors=True)
# Set the SSL options.
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
CLIENT_SSL, 'on')
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
CLIENT_SSL, 'on')
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during _wipe_gluster_vol. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': CLIENT_SSL, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
SERVER_SSL, 'on')
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
SERVER_SSL, 'on')
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during _wipe_gluster_vol. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': SERVER_SSL, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
self._restart_gluster_vol(gluster_addr)
self._restart_gluster_vol(gluster_mgr)
def get_network_allocations_number(self):
return 0
@ -408,7 +412,7 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
exp_locn = share.get('export_location', None)
try:
# Get the gluster address associated with the export.
gaddr = self.gluster_used_vols_dict[exp_locn]
gmgr = self.gluster_used_vols_dict[exp_locn]
except KeyError:
msg = (_("Invalid request. Ignoring delete_share request for "
"share %(share_id)s"), {'share_id': share['id']},)
@ -416,7 +420,7 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
return
try:
self._wipe_gluster_vol(gaddr)
self._wipe_gluster_vol(gmgr)
self._push_gluster_vol(exp_locn)
except exception.GlusterfsException:
msg = (_("Error during delete_share request for "
@ -436,18 +440,17 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
raise exception.InvalidShareAccess(_("Only 'cert' access type "
"allowed"))
exp_locn = share.get('export_location', None)
gluster_addr = self.gluster_used_vols_dict.get(exp_locn)
gluster_mgr = self.gluster_used_vols_dict.get(exp_locn)
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'set', gluster_addr.volume,
AUTH_SSL_ALLOW, access['access_to'])
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'set', gluster_mgr.volume,
AUTH_SSL_ALLOW, access['access_to'])
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume set during allow access. "
"Volume: %(volname)s, Option: %(option)s, "
"access_to: %(access_to)s, Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': AUTH_SSL_ALLOW,
'access_to': access['access_to'], 'error': exc.stderr})
LOG.error(msg)
@ -455,7 +458,7 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
# TODO(deepakcs) Remove this once ssl options can be
# set dynamically.
self._restart_gluster_vol(gluster_addr)
self._restart_gluster_vol(gluster_mgr)
def deny_access(self, context, share, access, share_server=None):
"""Deny access to a share that's using cert based auth.
@ -468,25 +471,24 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
"allowed for access "
"removal."))
exp_locn = share.get('export_location', None)
gluster_addr = self.gluster_used_vols_dict.get(exp_locn)
gluster_mgr = self.gluster_used_vols_dict.get(exp_locn)
gargs, gkw = gluster_addr.make_gluster_args(
'volume', 'reset', gluster_addr.volume,
AUTH_SSL_ALLOW)
try:
self._execute(*gargs, **gkw)
gluster_mgr.gluster_call(
'volume', 'reset', gluster_mgr.volume,
AUTH_SSL_ALLOW)
except exception.ProcessExecutionError as exc:
msg = (_("Error in gluster volume reset during deny access. "
"Volume: %(volname)s, Option: %(option)s, "
"Error: %(error)s"),
{'volname': gluster_addr.volume,
{'volname': gluster_mgr.volume,
'option': AUTH_SSL_ALLOW, 'error': exc.stderr})
LOG.error(msg)
raise exception.GlusterfsException(msg)
# TODO(deepakcs) Remove this once ssl options can be
# set dynamically.
self._restart_gluster_vol(gluster_addr)
self._restart_gluster_vol(gluster_mgr)
def _update_share_stats(self):
"""Send stats info for the GlusterFS volume."""

File diff suppressed because it is too large Load Diff

View File

@ -85,6 +85,10 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self.gluster_target2 = 'root@host2:/gv2'
CONF.set_default('glusterfs_targets',
[self.gluster_target1, self.gluster_target2])
CONF.set_default('glusterfs_server_password',
'fake_password')
CONF.set_default('glusterfs_path_to_private_key',
'/fakepath/to/privatekey')
CONF.set_default('driver_handles_share_servers', False)
self.fake_conf = config.Configuration(None)
@ -94,7 +98,8 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
configuration=self.fake_conf)
self.stubs.Set(tempfile, 'mkdtemp',
mock.Mock(return_value='/tmp/tmpKGHKJ'))
self.stubs.Set(glusterfs.GlusterManager, 'make_gluster_call',
mock.Mock())
self.addCleanup(fake_utils.fake_execute_set_repliers, [])
self.addCleanup(fake_utils.fake_execute_clear_log)
@ -102,15 +107,17 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._setup_gluster_vols = mock.Mock()
self._db.share_get_all = mock.Mock(return_value=[])
expected_exec = ['mount.glusterfs']
gaddr = glusterfs.GlusterAddress
gmgr = glusterfs.GlusterManager
self._driver.do_setup(self._context)
self.assertEqual(2, len(self._driver.gluster_unused_vols_dict))
self.assertTrue(gaddr(self.gluster_target1).export in
self._driver.gluster_unused_vols_dict)
self.assertTrue(gaddr(self.gluster_target2).export in
self._driver.gluster_unused_vols_dict)
self.assertTrue(
gmgr(self.gluster_target1, self._execute, None, None).export in
self._driver.gluster_unused_vols_dict)
self.assertTrue(
gmgr(self.gluster_target2, self._execute, None, None).export in
self._driver.gluster_unused_vols_dict)
self.assertTrue(self._driver._setup_gluster_vols.called)
self.assertTrue(self._db.share_get_all.called)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
@ -146,193 +153,220 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver.gluster_unused_vols_dict)
def test_setup_gluster_vols(self):
test_args = [
('volume', 'set', 'gv2', 'nfs.export-volumes', 'off'),
('volume', 'set', 'gv2', 'client.ssl', 'on'),
('volume', 'set', 'gv2', 'server.ssl', 'on')]
self._driver._restart_gluster_vol = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
expected_exec = [
'ssh root@host2 gluster volume set gv2 nfs.export-volumes off',
'ssh root@host2 gluster volume set gv2 client.ssl on',
'ssh root@host2 gluster volume set gv2 server.ssl on']
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
self._driver._setup_gluster_vols()
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
gmgr2.gluster_call.has_calls(
mock.call(*test_args[0]),
mock.call(*test_args[1]),
mock.call(*test_args[2]))
self.assertTrue(self._driver._restart_gluster_vol.called)
def test_setup_gluster_vols_excp1(self):
test_args = ('volume', 'set', 'gv2', 'nfs.export-volumes', 'off')
def raise_exception(*args, **kwargs):
if(args == test_args):
raise exception.ProcessExecutionError()
self._driver._restart_gluster_vol = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
expected_exec = [
'ssh root@host2 gluster volume set gv2 nfs.export-volumes off']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
self.stubs.Set(gmgr2, 'gluster_call',
mock.Mock(side_effect=raise_exception))
self.assertRaises(exception.GlusterfsException,
self._driver._setup_gluster_vols)
gmgr2.gluster_call.assert_called_once_with(*test_args)
self.assertFalse(self._driver._restart_gluster_vol.called)
def test_setup_gluster_vols_excp2(self):
test_args = [
('volume', 'set', 'gv2', 'nfs.export-volumes', 'off'),
('volume', 'set', 'gv2', 'client.ssl', 'on'),
('volume', 'set', 'gv2', 'server.ssl', 'off')]
def raise_exception(*args, **kwargs):
if(args == test_args[1]):
raise exception.ProcessExecutionError()
self._driver._restart_gluster_vol = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
expected_exec = [
'ssh root@host2 gluster volume set gv2 client.ssl on']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
self.stubs.Set(gmgr2, 'gluster_call',
mock.Mock(side_effect=raise_exception))
self.assertRaises(exception.GlusterfsException,
self._driver._setup_gluster_vols)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1])],
gmgr2.gluster_call.call_args_list)
self.assertFalse(self._driver._restart_gluster_vol.called)
def test_setup_gluster_vols_excp3(self):
test_args = [
('volume', 'set', 'gv2', 'nfs.export-volumes', 'off'),
('volume', 'set', 'gv2', 'client.ssl', 'on'),
('volume', 'set', 'gv2', 'server.ssl', 'on')]
def raise_exception(*args, **kwargs):
if(args == test_args[2]):
raise exception.ProcessExecutionError()
self._driver._restart_gluster_vol = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
expected_exec = [
'ssh root@host2 gluster volume set gv2 server.ssl on']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
self.stubs.Set(gmgr2, 'gluster_call',
mock.Mock(side_effect=raise_exception))
self.assertRaises(exception.GlusterfsException,
self._driver._setup_gluster_vols)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1]),
mock.call(*test_args[2])],
gmgr2.gluster_call.call_args_list)
self.assertFalse(self._driver._restart_gluster_vol.called)
def test_restart_gluster_vol(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
test_args = [('volume', 'stop', 'gv1', '--mode=script'),
('volume', 'start', 'gv1')]
expected_exec = [
'ssh root@host1 gluster volume stop gv1 --mode=script',
'ssh root@host1 gluster volume start gv1']
self._driver._restart_gluster_vol(gaddr1)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
self._driver._restart_gluster_vol(gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1])],
gmgr1.gluster_call.call_args_list)
def test_restart_gluster_vol_excp1(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
test_args = ('volume', 'stop', 'gv1', '--mode=script')
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
def raise_exception(*args, **kwargs):
if(args == test_args):
raise exception.ProcessExecutionError()
expected_exec = [
'ssh root@host1 gluster volume stop gv1 --mode=script']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
self.assertRaises(exception.GlusterfsException,
self._driver._restart_gluster_vol, gaddr1)
self._driver._restart_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args)],
gmgr1.gluster_call.call_args_list)
def test_restart_gluster_vol_excp2(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
test_args = [('volume', 'stop', 'gv1', '--mode=script'),
('volume', 'start', 'gv1')]
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
def raise_exception(*args, **kwargs):
if(args == test_args[1]):
raise exception.ProcessExecutionError()
expected_exec = [
'ssh root@host1 gluster volume start gv1']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
self.assertRaises(exception.GlusterfsException,
self._driver._restart_gluster_vol, gaddr1)
self._driver._restart_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1])],
gmgr1.gluster_call.call_args_list)
def test_pop_gluster_vol(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
exp_locn = self._driver._pop_gluster_vol()
self.assertEqual(0, len(self._driver.gluster_unused_vols_dict))
self.assertFalse(
gaddr2.export in self._driver.gluster_unused_vols_dict)
gmgr2.export in self._driver.gluster_unused_vols_dict)
self.assertEqual(2, len(self._driver.gluster_used_vols_dict))
self.assertTrue(
gaddr2.export in self._driver.gluster_used_vols_dict)
self.assertEqual(exp_locn, gaddr2.export)
gmgr2.export in self._driver.gluster_used_vols_dict)
self.assertEqual(exp_locn, gmgr2.export)
def test_pop_gluster_vol_excp(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
gmgr2.export: gmgr2, gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {}
self.assertRaises(exception.GlusterfsException,
self._driver._pop_gluster_vol)
def test_push_gluster_vol(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {
gaddr1.export: gaddr1, gaddr2.export: gaddr2}
gmgr1.export: gmgr1, gmgr2.export: gmgr2}
self._driver.gluster_unused_vols_dict = {}
self._driver._push_gluster_vol(gaddr2.export)
self._driver._push_gluster_vol(gmgr2.export)
self.assertEqual(1, len(self._driver.gluster_unused_vols_dict))
self.assertTrue(
gaddr2.export in self._driver.gluster_unused_vols_dict)
gmgr2.export in self._driver.gluster_unused_vols_dict)
self.assertEqual(1, len(self._driver.gluster_used_vols_dict))
self.assertFalse(
gaddr2.export in self._driver.gluster_used_vols_dict)
gmgr2.export in self._driver.gluster_used_vols_dict)
def test_push_gluster_vol_excp(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {}
self.assertRaises(exception.GlusterfsException,
self._driver._push_gluster_vol, gaddr2.export)
self._driver._push_gluster_vol, gmgr2.export)
def test_do_mount(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
tmpdir = '/tmp/tmpKGHKJ'
expected_exec = ['mount -t glusterfs host1:/gv1 /tmp/tmpKGHKJ']
self._driver._do_mount(gaddr1.export, tmpdir)
self._driver._do_mount(gmgr1.export, tmpdir)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
@ -340,15 +374,15 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
tmpdir = '/tmp/tmpKGHKJ'
expected_exec = ['mount -t glusterfs host1:/gv1 /tmp/tmpKGHKJ']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self.assertRaises(exception.GlusterfsException,
self._driver._do_mount, gaddr1.export, tmpdir)
self._driver._do_mount, gmgr1.export, tmpdir)
def test_do_umount(self):
tmpdir = '/tmp/tmpKGHKJ'
@ -375,20 +409,24 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_mount = mock.Mock()
self._driver._do_umount = mock.Mock()
shutil.rmtree = mock.Mock()
test_args = [
('volume', 'set', 'gv1', 'client.ssl', 'off'),
('volume', 'set', 'gv1', 'server.ssl', 'off'),
('volume', 'set', 'gv1', 'client.ssl', 'on'),
('volume', 'set', 'gv1', 'server.ssl', 'on')]
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
expected_exec = [
'ssh root@host1 gluster volume set gv1 client.ssl off',
'ssh root@host1 gluster volume set gv1 server.ssl off',
'find /tmp/tmpKGHKJ -mindepth 1 -delete',
'ssh root@host1 gluster volume set gv1 client.ssl on',
'ssh root@host1 gluster volume set gv1 server.ssl on']
expected_exec = ['find /tmp/tmpKGHKJ -mindepth 1 -delete']
self._driver._wipe_gluster_vol(gaddr1)
self._driver._wipe_gluster_vol(gmgr1)
self.assertEqual(2, self._driver._restart_gluster_vol.call_count)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1]),
mock.call(*test_args[2]), mock.call(*test_args[3])],
gmgr1.gluster_call.call_args_list)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
self.assertTrue(tempfile.mkdtemp.called)
self.assertTrue(self._driver._do_mount.called)
@ -400,21 +438,21 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_mount = mock.Mock()
self._driver._do_umount = mock.Mock()
shutil.rmtree = mock.Mock()
test_args = ('volume', 'set', 'gv1', 'client.ssl', 'off')
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
def raise_exception(*args, **kwargs):
if(args == test_args):
raise exception.ProcessExecutionError()
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
expected_exec = [
'ssh root@host1 gluster volume set gv1 client.ssl off']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
self.assertRaises(exception.GlusterfsException,
self._driver._wipe_gluster_vol, gaddr1)
self._driver._wipe_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args)], gmgr1.gluster_call.call_args_list)
self.assertFalse(self._driver._restart_gluster_vol.called)
self.assertFalse(tempfile.mkdtemp.called)
self.assertFalse(self._driver._do_mount.called)
@ -426,21 +464,24 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_mount = mock.Mock()
self._driver._do_umount = mock.Mock()
shutil.rmtree = mock.Mock()
test_args = [
('volume', 'set', 'gv1', 'client.ssl', 'off'),
('volume', 'set', 'gv1', 'server.ssl', 'off')]
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
def raise_exception(*args, **kwargs):
if(args == test_args[1]):
raise exception.ProcessExecutionError()
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
expected_exec = [
'ssh root@host1 gluster volume set gv1 server.ssl off']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
self.assertRaises(exception.GlusterfsException,
self._driver._wipe_gluster_vol, gaddr1)
self._driver._wipe_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1])],
gmgr1.gluster_call.call_args_list)
self.assertFalse(self._driver._restart_gluster_vol.called)
self.assertFalse(tempfile.mkdtemp.called)
self.assertFalse(self._driver._do_mount.called)
@ -452,21 +493,29 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_mount = mock.Mock()
self._driver._do_umount = mock.Mock()
shutil.rmtree = mock.Mock()
test_args = [
('volume', 'set', 'gv1', 'client.ssl', 'off'),
('volume', 'set', 'gv1', 'server.ssl', 'off'),
('volume', 'set', 'gv1', 'client.ssl', 'on')]
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
def raise_exception(*args, **kwargs):
if(args == test_args[2]):
raise exception.ProcessExecutionError()
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
expected_exec = [
'ssh root@host1 gluster volume set gv1 client.ssl on']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
expected_exec = ['find /tmp/tmpKGHKJ -mindepth 1 -delete']
self.assertRaises(exception.GlusterfsException,
self._driver._wipe_gluster_vol, gaddr1)
self._driver._wipe_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1]),
mock.call(*test_args[2])],
gmgr1.gluster_call.call_args_list)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
self.assertTrue(self._driver._restart_gluster_vol.called)
self.assertTrue(tempfile.mkdtemp.called)
self.assertTrue(self._driver._do_mount.called)
@ -478,21 +527,30 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_mount = mock.Mock()
self._driver._do_umount = mock.Mock()
shutil.rmtree = mock.Mock()
test_args = [
('volume', 'set', 'gv1', 'client.ssl', 'off'),
('volume', 'set', 'gv1', 'server.ssl', 'off'),
('volume', 'set', 'gv1', 'client.ssl', 'on'),
('volume', 'set', 'gv1', 'server.ssl', 'on')]
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
def raise_exception(*args, **kwargs):
if(args == test_args[3]):
raise exception.ProcessExecutionError()
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
expected_exec = [
'ssh root@host1 gluster volume set gv1 server.ssl on']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
expected_exec = ['find /tmp/tmpKGHKJ -mindepth 1 -delete']
self.assertRaises(exception.GlusterfsException,
self._driver._wipe_gluster_vol, gaddr1)
self._driver._wipe_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1]),
mock.call(*test_args[2]), mock.call(*test_args[3])],
gmgr1.gluster_call.call_args_list)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
self.assertTrue(self._driver._restart_gluster_vol.called)
self.assertTrue(tempfile.mkdtemp.called)
self.assertTrue(self._driver._do_mount.called)
@ -505,8 +563,12 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_umount = mock.Mock()
shutil.rmtree = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
test_args = [
('volume', 'set', 'gv1', 'client.ssl', 'off'),
('volume', 'set', 'gv1', 'server.ssl', 'off')]
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
@ -517,8 +579,10 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self.assertRaises(exception.GlusterfsException,
self._driver._wipe_gluster_vol, gaddr1)
self._driver._wipe_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1])],
gmgr1.gluster_call.call_args_list)
self.assertTrue(self._driver._restart_gluster_vol.called)
self.assertTrue(tempfile.mkdtemp.called)
self.assertTrue(self._driver._do_mount.called)
@ -532,17 +596,18 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_umount = mock.Mock()
shutil.rmtree = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
expected_exec = [
'ssh root@host1 gluster volume set gv1 client.ssl off',
'ssh root@host1 gluster volume set gv1 server.ssl off']
test_args = [
('volume', 'set', 'gv1', 'client.ssl', 'off'),
('volume', 'set', 'gv1', 'server.ssl', 'off')]
self.assertRaises(exception.GlusterfsException,
self._driver._wipe_gluster_vol, gaddr1)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
self._driver._wipe_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1])],
gmgr1.gluster_call.call_args_list)
self.assertTrue(self._driver._restart_gluster_vol.called)
self.assertTrue(tempfile.mkdtemp.called)
self.assertTrue(self._driver._do_mount.called)
@ -556,17 +621,20 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._do_umount.side_effect = exception.GlusterfsException
shutil.rmtree = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
expected_exec = [
'ssh root@host1 gluster volume set gv1 client.ssl off',
'ssh root@host1 gluster volume set gv1 server.ssl off',
'find /tmp/tmpKGHKJ -mindepth 1 -delete']
test_args = [
('volume', 'set', 'gv1', 'client.ssl', 'off'),
('volume', 'set', 'gv1', 'server.ssl', 'off')]
expected_exec = ['find /tmp/tmpKGHKJ -mindepth 1 -delete']
self.assertRaises(exception.GlusterfsException,
self._driver._wipe_gluster_vol, gaddr1)
self._driver._wipe_gluster_vol, gmgr1)
self.assertEqual(
[mock.call(*test_args[0]), mock.call(*test_args[1])],
gmgr1.gluster_call.call_args_list)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
self.assertTrue(self._driver._restart_gluster_vol.called)
self.assertTrue(tempfile.mkdtemp.called)
@ -575,26 +643,26 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self.assertFalse(shutil.rmtree.called)
def test_create_share(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
share = new_share()
exp_locn = self._driver.create_share(self._context, share)
self.assertEqual(exp_locn, gaddr2.export)
self.assertEqual(exp_locn, gmgr2.export)
def test_create_share_excp(self):
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
gmgr2.export: gmgr2, gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {}
share = new_share()
@ -605,12 +673,12 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
def test_delete_share(self):
self._driver._wipe_gluster_vol = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
gmgr2.export: gmgr2, gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {}
share = fake_db_share2()[0]
@ -626,13 +694,13 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self._driver._wipe_gluster_vol = mock.Mock()
self._driver._push_gluster_vol = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {}
self._driver.gluster_unused_vols_dict = {
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
gmgr2.export: gmgr2, gmgr1.export: gmgr1}
share = fake_db_share2()[0]
@ -648,12 +716,12 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
exception.GlusterfsException)
self._driver._push_gluster_vol = mock.Mock()
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
gmgr2.export: gmgr2, gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {}
share = fake_db_share2()[0]
@ -667,21 +735,19 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
def test_allow_access(self):
self._driver._restart_gluster_vol = mock.Mock()
access = {'access_type': 'cert', 'access_to': 'client.example.com'}
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
test_args = ('volume', 'set', 'gv1', 'auth.ssl-allow',
access['access_to'])
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
share = fake_db_share1()[0]
expected_exec = [
'ssh root@host1 gluster volume set gv1 '
'auth.ssl-allow client.example.com']
self._driver.allow_access(self._context, share, access)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
gmgr1.gluster_call.assert_called_once_with(*test_args)
self.assertTrue(self._driver._restart_gluster_vol.called)
def test_allow_access_invalid_access_type(self):
@ -697,48 +763,47 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
def test_allow_access_excp(self):
self._driver._restart_gluster_vol = mock.Mock()
access = {'access_type': 'cert', 'access_to': 'client.example.com'}
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
test_args = ('volume', 'set', 'gv1', 'auth.ssl-allow',
access['access_to'])
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
def raise_exception(*args, **kwargs):
if (args == test_args):
raise exception.ProcessExecutionError()
self._driver._restart_gluster_vol = mock.Mock()
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
share = fake_db_share1()[0]
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
expected_exec = [
'ssh root@host1 gluster volume set gv1 '
'auth.ssl-allow client.example.com']
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self.assertRaises(exception.GlusterfsException,
self._driver.allow_access,
self._context, share, access)
gmgr1.gluster_call.assert_called_once_with(*test_args)
self.assertFalse(self._driver._restart_gluster_vol.called)
def test_deny_access(self):
self._driver._restart_gluster_vol = mock.Mock()
access = {'access_type': 'cert', 'access_to': 'NotApplicable'}
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
test_args = ('volume', 'reset', 'gv1', 'auth.ssl-allow')
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
share = fake_db_share1()[0]
expected_exec = [
'ssh root@host1 gluster volume reset gv1 auth.ssl-allow']
self._driver.deny_access(self._context, share, access)
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
gmgr1.gluster_call.assert_called_once_with(*test_args)
self.assertTrue(self._driver._restart_gluster_vol.called)
def test_deny_access_invalid_access_type(self):
@ -754,28 +819,30 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
def test_deny_access_excp(self):
self._driver._restart_gluster_vol = mock.Mock()
access = {'access_type': 'cert', 'access_to': 'NotApplicable'}
gaddr = glusterfs.GlusterAddress
gaddr1 = gaddr(self.gluster_target1)
gaddr2 = gaddr(self.gluster_target2)
test_args = ('volume', 'reset', 'gv1', 'auth.ssl-allow')
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
def raise_exception(*args, **kwargs):
if (args == test_args):
raise exception.ProcessExecutionError()
self._driver._restart_gluster_vol = mock.Mock()
gmgr = glusterfs.GlusterManager
gmgr1 = gmgr(self.gluster_target1, self._execute, None, None)
gmgr2 = gmgr(self.gluster_target2, self._execute, None, None)
self._driver.gluster_used_vols_dict = {gmgr1.export: gmgr1}
self._driver.gluster_unused_vols_dict = {gmgr2.export: gmgr2}
self.stubs.Set(gmgr1, 'gluster_call',
mock.Mock(side_effect=raise_exception))
share = fake_db_share1()[0]
expected_exec = [
'ssh root@host1 gluster volume reset gv1 auth.ssl-allow']
def exec_runner(*ignore_args, **ignore_kwargs):
raise exception.ProcessExecutionError
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
self.assertRaises(exception.GlusterfsException,
self._driver.deny_access,
self._context, share, access)
gmgr1.gluster_call.assert_called_once_with(*test_args)
self.assertFalse(self._driver._restart_gluster_vol.called)
def test_get_share_stats_refresh_false(self):