Merge "Add support for working with multiple glusterfs volumes"
This commit is contained in:
commit
81d82d19af
|
@ -17,3 +17,9 @@ ip: CommandFilter, /sbin/ip, root
|
|||
|
||||
# manila/network/linux/interface.py: 'ovs-vsctl', 'add-port', '%s', '%s'
|
||||
ovs-vsctl: CommandFilter, /usr/bin/ovs-vsctl, root
|
||||
|
||||
# manila/share/drivers/glusterfs_native.py: 'find', '%s', '-mindepth', '1', '-delete'
|
||||
find_del: RegExpFilter, /bin/find, root, find, .*, -mindepth, 1, -delete
|
||||
|
||||
# manila/share/drivers/glusterfs_native.py: 'umount', '%s'
|
||||
umount: CommandFilter, umount, root
|
||||
|
|
|
@ -19,81 +19,376 @@ Manila share is a GlusterFS volume. Unlike the generic driver, this
|
|||
does not use service VM approach. Instances directly talk with the
|
||||
GlusterFS backend storage pool. Instance use the 'glusterfs' protocol
|
||||
to mount the GlusterFS share. Access to the share is allowed via
|
||||
SSL Certificates. Only the share which has the SSL trust established
|
||||
SSL Certificates. Only the instance which has the SSL trust established
|
||||
with the GlusterFS backend can mount and hence use the share.
|
||||
|
||||
Supports working with multiple glusterfs volumes.
|
||||
"""
|
||||
|
||||
import errno
|
||||
import pipes
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
from oslo.config import cfg
|
||||
import six
|
||||
|
||||
from manila import exception
|
||||
from manila.openstack.common import log as logging
|
||||
from manila.share import driver
|
||||
from manila.share.drivers import glusterfs
|
||||
from manila import utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
CLIENT_SSL = 'client.ssl'
|
||||
SERVER_SSL = 'server.ssl'
|
||||
AUTH_SSL_ALLOW = 'auth.ssl-allow'
|
||||
glusterfs_native_manila_share_opts = [
|
||||
cfg.ListOpt('glusterfs_targets',
|
||||
default=[],
|
||||
help='List of GlusterFS volumes that can be used to create '
|
||||
'shares. Each GlusterFS volume should be of the form '
|
||||
'[remoteuser@]<volserver>:/<volid>'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(glusterfs_native_manila_share_opts)
|
||||
|
||||
ACCESS_TYPE_CERT = 'cert'
|
||||
AUTH_SSL_ALLOW = 'auth.ssl-allow'
|
||||
CLIENT_SSL = 'client.ssl'
|
||||
NFS_EXPORT_VOL = 'nfs.export-volumes'
|
||||
SERVER_SSL = 'server.ssl'
|
||||
|
||||
|
||||
class GlusterfsNativeShareDriver(glusterfs.GlusterfsShareDriver):
|
||||
class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
"""GlusterFS native protocol (glusterfs) share driver.
|
||||
|
||||
def _setup_gluster_vol(self):
|
||||
super(GlusterfsNativeShareDriver, self)._setup_gluster_vol()
|
||||
Executes commands relating to Shares.
|
||||
Supports working with multiple glusterfs volumes.
|
||||
|
||||
# Enable gluster volume for SSL access.
|
||||
# This applies for both service mount and instance mount(s).
|
||||
API version history:
|
||||
|
||||
# TODO(deepakcs): Once gluster support dual-access, we can limit
|
||||
# service mount to non-ssl access.
|
||||
gargs, gkw = self.gluster_address.make_gluster_args(
|
||||
'volume', 'set', self.gluster_address.volume,
|
||||
1.0 - Initial version.
|
||||
1.1 - Support for working with multiple gluster volumes.
|
||||
"""
|
||||
|
||||
def __init__(self, db, *args, **kwargs):
|
||||
super(GlusterfsNativeShareDriver, self).__init__(*args, **kwargs)
|
||||
self.db = db
|
||||
self._helpers = None
|
||||
self.gluster_unused_vols_dict = {}
|
||||
self.gluster_used_vols_dict = {}
|
||||
self.configuration.append_config_values(
|
||||
glusterfs_native_manila_share_opts)
|
||||
self.backend_name = self.configuration.safe_get(
|
||||
'share_backend_name') or 'GlusterFS-Native'
|
||||
|
||||
def do_setup(self, context):
|
||||
"""Setup the GlusterFS volumes."""
|
||||
super(GlusterfsNativeShareDriver, self).do_setup(context)
|
||||
|
||||
# We don't use a service mount as its not necessary for us.
|
||||
# Do some sanity checks.
|
||||
if len(self.configuration.glusterfs_targets) == 0:
|
||||
# No volumes specified in the config file. Raise exception.
|
||||
msg = (_("glusterfs_targets list seems to be empty! "
|
||||
"Add one or more gluster volumes to work "
|
||||
"with in the glusterfs_targets configuration "
|
||||
"parameter."))
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
|
||||
LOG.info(_("Number of gluster volumes read from config: "
|
||||
"%(numvols)s"),
|
||||
{'numvols': len(self.configuration.glusterfs_targets)})
|
||||
|
||||
try:
|
||||
self._execute('mount.glusterfs', check_exit_code=False)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.ENOENT:
|
||||
msg = (_("mount.glusterfs is not installed."))
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
else:
|
||||
msg = (_("Error running mount.glusterfs."))
|
||||
LOG.error(msg)
|
||||
raise
|
||||
|
||||
# Update gluster_unused_vols_dict, gluster_used_vols_dict by walking
|
||||
# through the DB.
|
||||
self._update_gluster_vols_dict(context)
|
||||
if len(self.gluster_unused_vols_dict) == 0:
|
||||
# No volumes available for use as share. Warn user.
|
||||
msg = (_("No unused gluster volumes available for use as share! "
|
||||
"Create share won't be supported unless existing shares "
|
||||
"are deleted or add one or more gluster volumes to work "
|
||||
"with in the glusterfs_targets configuration parameter."))
|
||||
LOG.warn(msg)
|
||||
else:
|
||||
LOG.info(_("Number of gluster volumes in use: %(inuse-numvols)s. "
|
||||
"Number of gluster volumes available for use as share: "
|
||||
"%(unused-numvols)s"),
|
||||
{'inuse-numvols': len(self.gluster_used_vols_dict),
|
||||
'unused-numvols': len(self.gluster_unused_vols_dict)})
|
||||
|
||||
self._setup_gluster_vols()
|
||||
|
||||
@utils.synchronized("glusterfs_native", external=False)
|
||||
def _update_gluster_vols_dict(self, context):
|
||||
"""Update dict of gluster vols that are used/unused."""
|
||||
|
||||
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, ...}
|
||||
# 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
|
||||
|
||||
# Assume its unused to begin with.
|
||||
self.gluster_unused_vols_dict.update({exp_locn_gv: gaddr})
|
||||
|
||||
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_unused_vols_dict.pop(exp_locn_gv)
|
||||
break
|
||||
|
||||
@utils.synchronized("glusterfs_native", external=False)
|
||||
def _setup_gluster_vols(self):
|
||||
# Enable gluster volumes for SSL access only.
|
||||
|
||||
for gluster_addr 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)
|
||||
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,
|
||||
'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)
|
||||
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,
|
||||
'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)
|
||||
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,
|
||||
'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)
|
||||
|
||||
def _restart_gluster_vol(self, gluster_addr):
|
||||
gargs, gkw = gluster_addr.make_gluster_args(
|
||||
'volume', 'stop', gluster_addr.volume, '--mode=script')
|
||||
try:
|
||||
self._execute(*gargs, **gkw)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
msg = (_("Error stopping gluster volume. "
|
||||
"Volume: %(volname)s, Error: %(error)s"),
|
||||
{'volname': gluster_addr.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)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
msg = (_("Error starting gluster volume. "
|
||||
"Volume: %(volname)s, Error: %(error)s"),
|
||||
{'volname': gluster_addr.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()
|
||||
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})
|
||||
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)
|
||||
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})
|
||||
|
||||
def _do_mount(self, gluster_export, mntdir):
|
||||
|
||||
cmd = ['mount', '-t', 'glusterfs', gluster_export, mntdir]
|
||||
try:
|
||||
self._execute(*cmd, run_as_root=True)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
msg = (_("Unable to mount gluster volume. "
|
||||
"gluster_export: %(export)s, Error: %(error)s"),
|
||||
{'export': gluster_export, 'error': exc.stderr})
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
|
||||
def _do_umount(self, mntdir):
|
||||
|
||||
cmd = ['umount', mntdir]
|
||||
try:
|
||||
self._execute(*cmd, run_as_root=True)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
msg = (_("Unable to unmount gluster volume. "
|
||||
"mount_dir: %(mntdir)s, Error: %(error)s"),
|
||||
{'mntdir': mntdir, 'error': exc.stderr})
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
|
||||
def _wipe_gluster_vol(self, gluster_addr):
|
||||
|
||||
# Reset the SSL options.
|
||||
gargs, gkw = gluster_addr.make_gluster_args(
|
||||
'volume', 'set', gluster_addr.volume,
|
||||
CLIENT_SSL, 'off')
|
||||
try:
|
||||
self._execute(*gargs, **gkw)
|
||||
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,
|
||||
'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)
|
||||
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,
|
||||
'option': SERVER_SSL, 'error': exc.stderr})
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
|
||||
self._restart_gluster_vol(gluster_addr)
|
||||
|
||||
# Create a temporary mount.
|
||||
gluster_export = gluster_addr.export
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
self._do_mount(gluster_export, tmpdir)
|
||||
except exception.GlusterfsException:
|
||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||
raise
|
||||
|
||||
# Delete only the contents, not the directory.
|
||||
cmd = ['find', pipes.quote(tmpdir), '-mindepth', '1', '-delete']
|
||||
try:
|
||||
self._execute(*cmd, run_as_root=True)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
msg = (_("Error trying to wipe gluster volume. "
|
||||
"gluster_export: %(export)s, Error: %(error)s"),
|
||||
{'export': gluster_export, 'error': exc.stderr})
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
finally:
|
||||
# Unmount.
|
||||
self._do_umount(tmpdir)
|
||||
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)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_("Error in gluster volume set during volume setup."
|
||||
"Volume: %(volname)s, Option: %(option)s, "
|
||||
"Error: %(error)s"),
|
||||
{'volname': self.gluster_address.volume,
|
||||
'option': CLIENT_SSL, 'error': exc.stderr})
|
||||
raise
|
||||
gargs, gkw = self.gluster_address.make_gluster_args(
|
||||
'volume', 'set', self.gluster_address.volume,
|
||||
msg = (_("Error in gluster volume set during _wipe_gluster_vol. "
|
||||
"Volume: %(volname)s, Option: %(option)s, "
|
||||
"Error: %(error)s"),
|
||||
{'volname': gluster_addr.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)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_("Error in gluster volume set during volume setup."
|
||||
"Volume: %(volname)s, Option: %(option)s, "
|
||||
"Error: %(error)s"),
|
||||
{'volname': self.gluster_address.volume,
|
||||
'option': SERVER_SSL, 'error': exc.stderr})
|
||||
raise
|
||||
msg = (_("Error in gluster volume set during _wipe_gluster_vol. "
|
||||
"Volume: %(volname)s, Option: %(option)s, "
|
||||
"Error: %(error)s"),
|
||||
{'volname': gluster_addr.volume,
|
||||
'option': SERVER_SSL, 'error': exc.stderr})
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
|
||||
def create_share(self, ctx, share, share_server=None):
|
||||
self._restart_gluster_vol(gluster_addr)
|
||||
|
||||
def create_share(self, context, share, share_server=None):
|
||||
"""Create a share using GlusterFS volume.
|
||||
|
||||
1 Manila share = 1 GlusterFS volume. Ensure that the
|
||||
GlusterFS volume is properly setup to be consumed as
|
||||
a share.
|
||||
1 Manila share = 1 GlusterFS volume. Pick an unused
|
||||
GlusterFS volume for use as a share.
|
||||
"""
|
||||
|
||||
# Handle the case where create is called after delete share
|
||||
try:
|
||||
self._setup_gluster_vol()
|
||||
except exception.ProcessExecutionError:
|
||||
LOG.error(_("Unable to create share %s"), (share['name'],))
|
||||
export_location = self._pop_gluster_vol()
|
||||
except exception.GlusterfsException:
|
||||
msg = (_("Error creating share %(share_id)s"),
|
||||
{'share_id': share['id']})
|
||||
LOG.error(msg)
|
||||
raise
|
||||
|
||||
# TODO(deepakcs): Add validation for gluster mount being present
|
||||
# (decorator maybe)
|
||||
# TODO(deepakcs): Enable quota and set it to the share size.
|
||||
|
||||
# For native protocol, the export_location should be of the form:
|
||||
# server:/volname
|
||||
export_location = self.gluster_address.export
|
||||
|
||||
LOG.info(_("export_location sent back from create_share: %s"),
|
||||
(export_location,))
|
||||
return export_location
|
||||
|
@ -101,22 +396,30 @@ class GlusterfsNativeShareDriver(glusterfs.GlusterfsShareDriver):
|
|||
def delete_share(self, context, share, share_server=None):
|
||||
"""Delete a share on the GlusterFS volume.
|
||||
|
||||
1 Manila share = 1 GlusterFS volume. Ensure that the
|
||||
GlusterFS volume is reset back to its original state.
|
||||
1 Manila share = 1 GlusterFS volume. Put the gluster
|
||||
volume back in the available list.
|
||||
"""
|
||||
# Get the gluster volume back to its original state
|
||||
|
||||
gargs, gkw = self.gluster_address.make_gluster_args(
|
||||
'volume', 'reset', self.gluster_address.volume)
|
||||
exp_locn = share.get('export_location', None)
|
||||
try:
|
||||
self._execute(*gargs, **gkw)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_("Error in gluster volume reset during delete share."
|
||||
"Volume: %(volname)s, Error: %(error)s"),
|
||||
{'volname': self.gluster_address.volume,
|
||||
'error': exc.stderr})
|
||||
# Get the gluster address associated with the export.
|
||||
gaddr = 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']},)
|
||||
LOG.warn(msg)
|
||||
return
|
||||
|
||||
try:
|
||||
self._wipe_gluster_vol(gaddr)
|
||||
self._push_gluster_vol(exp_locn)
|
||||
except exception.GlusterfsException:
|
||||
msg = (_("Error during delete_share request for "
|
||||
"share %(share_id)s"), {'share_id': share['id']},)
|
||||
LOG.error(msg)
|
||||
raise
|
||||
|
||||
# TODO(deepakcs): Disable quota.
|
||||
|
||||
def allow_access(self, context, share, access, share_server=None):
|
||||
"""Allow access to a share using certs.
|
||||
|
||||
|
@ -126,20 +429,27 @@ class GlusterfsNativeShareDriver(glusterfs.GlusterfsShareDriver):
|
|||
if access['access_type'] != ACCESS_TYPE_CERT:
|
||||
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)
|
||||
|
||||
gargs, gkw = self.gluster_address.make_gluster_args(
|
||||
'volume', 'set', self.gluster_address.volume,
|
||||
gargs, gkw = gluster_addr.make_gluster_args(
|
||||
'volume', 'set', gluster_addr.volume,
|
||||
AUTH_SSL_ALLOW, access['access_to'])
|
||||
try:
|
||||
self._execute(*gargs, **gkw)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_("Error in gluster volume set during allow access."
|
||||
"Volume: %(volname)s, Option: %(option)s, "
|
||||
"access_to: %(access_to)s, Error: %(error)s"),
|
||||
{'volname': self.gluster_address.volume,
|
||||
'option': AUTH_SSL_ALLOW,
|
||||
'access_to': access['access_to'], 'error': exc.stderr})
|
||||
raise
|
||||
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,
|
||||
'option': AUTH_SSL_ALLOW,
|
||||
'access_to': access['access_to'], '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)
|
||||
|
||||
def deny_access(self, context, share, access, share_server=None):
|
||||
"""Deny access to a share that's using cert based auth.
|
||||
|
@ -151,16 +461,63 @@ class GlusterfsNativeShareDriver(glusterfs.GlusterfsShareDriver):
|
|||
raise exception.InvalidShareAccess(_("Only 'cert' access type "
|
||||
"allowed for access "
|
||||
"removal."))
|
||||
exp_locn = share.get('export_location', None)
|
||||
gluster_addr = self.gluster_used_vols_dict.get(exp_locn)
|
||||
|
||||
gargs, gkw = self.gluster_address.make_gluster_args(
|
||||
'volume', 'reset', self.gluster_address.volume,
|
||||
gargs, gkw = gluster_addr.make_gluster_args(
|
||||
'volume', 'reset', gluster_addr.volume,
|
||||
AUTH_SSL_ALLOW)
|
||||
try:
|
||||
self._execute(*gargs, **gkw)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_("Error in gluster volume reset during deny access."
|
||||
"Volume: %(volname)s, Option: %(option)s, "
|
||||
"Error: %(error)s"),
|
||||
{'volname': self.gluster_address.volume,
|
||||
'option': AUTH_SSL_ALLOW, 'error': exc.stderr})
|
||||
raise
|
||||
msg = (_("Error in gluster volume reset during deny access. "
|
||||
"Volume: %(volname)s, Option: %(option)s, "
|
||||
"Error: %(error)s"),
|
||||
{'volname': gluster_addr.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)
|
||||
|
||||
def get_share_stats(self, refresh=False):
|
||||
"""Get share stats.
|
||||
|
||||
If 'refresh' is True, update the stats first.
|
||||
"""
|
||||
if refresh:
|
||||
self._update_share_stats()
|
||||
|
||||
return self._stats
|
||||
|
||||
def _update_share_stats(self):
|
||||
"""Send stats info for the GlusterFS volume."""
|
||||
|
||||
LOG.debug("Updating share stats")
|
||||
|
||||
data = {}
|
||||
|
||||
data["share_backend_name"] = self.backend_name
|
||||
data["vendor_name"] = 'Red Hat'
|
||||
data["driver_version"] = '1.1'
|
||||
data["storage_protocol"] = 'glusterfs'
|
||||
|
||||
data['reserved_percentage'] = (
|
||||
self.configuration.reserved_share_percentage)
|
||||
data['QoS_support'] = False
|
||||
|
||||
# We don't use a service mount to get stats data.
|
||||
# Instead we use glusterfs quota feature and use that to limit
|
||||
# the share to its expected share['size'].
|
||||
|
||||
# TODO(deepakcs): Change below once glusterfs supports volume
|
||||
# specific stats via the gluster cli.
|
||||
data['total_capacity_gb'] = 'infinite'
|
||||
data['free_capacity_gb'] = 'infinite'
|
||||
self._stats = data
|
||||
|
||||
def ensure_share(self, context, share, share_server=None):
|
||||
"""Invoked to ensure that share is exported."""
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,806 @@
|
|||
# Copyright (c) 2014 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
""" GlusterFS native protocol (glusterfs) driver for shares.
|
||||
|
||||
Test cases for GlusterFS native protocol driver.
|
||||
"""
|
||||
|
||||
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.share import configuration as config
|
||||
from manila.share.drivers import glusterfs
|
||||
from manila.share.drivers import glusterfs_native
|
||||
from manila import test
|
||||
from manila.tests import fake_utils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def fake_db_share1(**kwargs):
|
||||
share = {
|
||||
'id': 'fakeid',
|
||||
'name': 'fakename',
|
||||
'size': 1,
|
||||
'share_proto': 'glusterfs',
|
||||
'export_location': 'host1:/gv1',
|
||||
}
|
||||
share.update(kwargs)
|
||||
return [share]
|
||||
|
||||
|
||||
def fake_db_share2(**kwargs):
|
||||
share = {
|
||||
'id': 'fakeid',
|
||||
'name': 'fakename',
|
||||
'size': 1,
|
||||
'share_proto': 'glusterfs',
|
||||
'export_location': 'host2:/gv2',
|
||||
}
|
||||
share.update(kwargs)
|
||||
return [share]
|
||||
|
||||
|
||||
def new_share(**kwargs):
|
||||
share = {
|
||||
'id': 'fakeid',
|
||||
'name': 'fakename',
|
||||
'size': 1,
|
||||
'share_proto': 'glusterfs',
|
||||
}
|
||||
share.update(kwargs)
|
||||
return share
|
||||
|
||||
|
||||
class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
||||
"""Tests GlusterfsNativeShareDriver."""
|
||||
|
||||
def setUp(self):
|
||||
super(GlusterfsNativeShareDriverTestCase, self).setUp()
|
||||
fake_utils.stub_out_utils_execute(self.stubs)
|
||||
self._execute = fake_utils.fake_execute
|
||||
self._context = context.get_admin_context()
|
||||
|
||||
self.gluster_target1 = 'root@host1:/gv1'
|
||||
self.gluster_target2 = 'root@host2:/gv2'
|
||||
CONF.set_default('glusterfs_targets',
|
||||
[self.gluster_target1, self.gluster_target2])
|
||||
|
||||
self.fake_conf = config.Configuration(None)
|
||||
self._db = mock.Mock()
|
||||
self._driver = glusterfs_native.GlusterfsNativeShareDriver(
|
||||
self._db, execute=self._execute,
|
||||
configuration=self.fake_conf)
|
||||
self.stubs.Set(tempfile, 'mkdtemp',
|
||||
mock.Mock(return_value='/tmp/tmpKGHKJ'))
|
||||
|
||||
self.addCleanup(fake_utils.fake_execute_set_repliers, [])
|
||||
self.addCleanup(fake_utils.fake_execute_clear_log)
|
||||
|
||||
def test_do_setup(self):
|
||||
self._driver._setup_gluster_vols = mock.Mock()
|
||||
self._db.share_get_all = mock.Mock(return_value=[])
|
||||
expected_exec = ['mount.glusterfs']
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
|
||||
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(self._driver._setup_gluster_vols.called)
|
||||
self.assertTrue(self._db.share_get_all.called)
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
|
||||
def test_do_setup_glusterfs_targets_empty(self):
|
||||
self._driver.configuration.glusterfs_targets = []
|
||||
self.assertRaises(exception.GlusterfsException, self._driver.do_setup,
|
||||
self._context)
|
||||
|
||||
def test_update_gluster_vols_dict(self):
|
||||
self._db.share_get_all = mock.Mock(return_value=fake_db_share1())
|
||||
|
||||
self._driver._update_gluster_vols_dict(self._context)
|
||||
|
||||
self.assertEqual(1, len(self._driver.gluster_used_vols_dict))
|
||||
self.assertEqual(1, len(self._driver.gluster_unused_vols_dict))
|
||||
self.assertTrue(self._db.share_get_all.called)
|
||||
|
||||
share_in_use = fake_db_share1()[0]
|
||||
share_not_in_use = fake_db_share2()[0]
|
||||
|
||||
self.assertTrue(
|
||||
share_in_use['export_location'] in
|
||||
self._driver.gluster_used_vols_dict)
|
||||
self.assertFalse(
|
||||
share_not_in_use['export_location'] in
|
||||
self._driver.gluster_used_vols_dict)
|
||||
self.assertTrue(
|
||||
share_not_in_use['export_location'] in
|
||||
self._driver.gluster_unused_vols_dict)
|
||||
self.assertFalse(
|
||||
share_in_use['export_location'] in
|
||||
self._driver.gluster_unused_vols_dict)
|
||||
|
||||
def test_setup_gluster_vols(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
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._setup_gluster_vols()
|
||||
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
self.assertTrue(self._driver._restart_gluster_vol.called)
|
||||
|
||||
def test_setup_gluster_vols_excp1(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
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.assertRaises(exception.GlusterfsException,
|
||||
self._driver._setup_gluster_vols)
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
|
||||
def test_setup_gluster_vols_excp2(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
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.assertRaises(exception.GlusterfsException,
|
||||
self._driver._setup_gluster_vols)
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
|
||||
def test_setup_gluster_vols_excp3(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
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.assertRaises(exception.GlusterfsException,
|
||||
self._driver._setup_gluster_vols)
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
|
||||
def test_restart_gluster_vol(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
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())
|
||||
|
||||
def test_restart_gluster_vol_excp1(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
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.assertRaises(exception.GlusterfsException,
|
||||
self._driver._restart_gluster_vol, gaddr1)
|
||||
|
||||
def test_restart_gluster_vol_excp2(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
expected_exec = [
|
||||
'ssh root@host1 gluster volume start gv1']
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._restart_gluster_vol, gaddr1)
|
||||
|
||||
def test_pop_gluster_vol(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
def test_pop_gluster_vol_excp(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {
|
||||
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
|
||||
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)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {
|
||||
gaddr1.export: gaddr1, gaddr2.export: gaddr2}
|
||||
self._driver.gluster_unused_vols_dict = {}
|
||||
|
||||
self._driver._push_gluster_vol(gaddr2.export)
|
||||
|
||||
self.assertEqual(1, len(self._driver.gluster_unused_vols_dict))
|
||||
self.assertTrue(
|
||||
gaddr2.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)
|
||||
|
||||
def test_push_gluster_vol_excp(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {}
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._push_gluster_vol, gaddr2.export)
|
||||
|
||||
def test_do_mount(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
tmpdir = '/tmp/tmpKGHKJ'
|
||||
expected_exec = ['mount -t glusterfs host1:/gv1 /tmp/tmpKGHKJ']
|
||||
|
||||
self._driver._do_mount(gaddr1.export, tmpdir)
|
||||
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
|
||||
def test_do_mount_excp(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
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)
|
||||
|
||||
def test_do_umount(self):
|
||||
tmpdir = '/tmp/tmpKGHKJ'
|
||||
expected_exec = ['umount /tmp/tmpKGHKJ']
|
||||
|
||||
self._driver._do_umount(tmpdir)
|
||||
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
|
||||
def test_do_umount_excp(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
tmpdir = '/tmp/tmpKGHKJ'
|
||||
expected_exec = ['umount /tmp/tmpKGHKJ']
|
||||
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._do_umount, tmpdir)
|
||||
|
||||
def test_wipe_gluster_vol(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_umount = mock.Mock()
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
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']
|
||||
|
||||
self._driver._wipe_gluster_vol(gaddr1)
|
||||
|
||||
self.assertEqual(2, self._driver._restart_gluster_vol.call_count)
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
self.assertTrue(tempfile.mkdtemp.called)
|
||||
self.assertTrue(self._driver._do_mount.called)
|
||||
self.assertTrue(self._driver._do_umount.called)
|
||||
self.assertTrue(shutil.rmtree.called)
|
||||
|
||||
def test_wipe_gluster_vol_excp1(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_umount = mock.Mock()
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
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)])
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._wipe_gluster_vol, gaddr1)
|
||||
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
self.assertFalse(tempfile.mkdtemp.called)
|
||||
self.assertFalse(self._driver._do_mount.called)
|
||||
self.assertFalse(self._driver._do_umount.called)
|
||||
self.assertFalse(shutil.rmtree.called)
|
||||
|
||||
def test_wipe_gluster_vol_excp2(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_umount = mock.Mock()
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
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)])
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._wipe_gluster_vol, gaddr1)
|
||||
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
self.assertFalse(tempfile.mkdtemp.called)
|
||||
self.assertFalse(self._driver._do_mount.called)
|
||||
self.assertFalse(self._driver._do_umount.called)
|
||||
self.assertFalse(shutil.rmtree.called)
|
||||
|
||||
def test_wipe_gluster_vol_excp3(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_umount = mock.Mock()
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
expected_exec = [
|
||||
'ssh root@host1 gluster volume set gv1 client.ssl on']
|
||||
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._wipe_gluster_vol, gaddr1)
|
||||
|
||||
self.assertTrue(self._driver._restart_gluster_vol.called)
|
||||
self.assertTrue(tempfile.mkdtemp.called)
|
||||
self.assertTrue(self._driver._do_mount.called)
|
||||
self.assertTrue(self._driver._do_umount.called)
|
||||
self.assertTrue(shutil.rmtree.called)
|
||||
|
||||
def test_wipe_gluster_vol_excp4(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_umount = mock.Mock()
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
expected_exec = [
|
||||
'ssh root@host1 gluster volume set gv1 server.ssl on']
|
||||
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._wipe_gluster_vol, gaddr1)
|
||||
|
||||
self.assertTrue(self._driver._restart_gluster_vol.called)
|
||||
self.assertTrue(tempfile.mkdtemp.called)
|
||||
self.assertTrue(self._driver._do_mount.called)
|
||||
self.assertTrue(self._driver._do_umount.called)
|
||||
self.assertTrue(shutil.rmtree.called)
|
||||
|
||||
def test_wipe_gluster_vol_excp5(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_umount = mock.Mock()
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
expected_exec = [
|
||||
'find /tmp/tmpKGHKJ -mindepth 1 -delete']
|
||||
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._wipe_gluster_vol, gaddr1)
|
||||
|
||||
self.assertTrue(self._driver._restart_gluster_vol.called)
|
||||
self.assertTrue(tempfile.mkdtemp.called)
|
||||
self.assertTrue(self._driver._do_mount.called)
|
||||
self.assertTrue(self._driver._do_umount.called)
|
||||
self.assertTrue(shutil.rmtree.called)
|
||||
|
||||
def test_wipe_gluster_vol_mount_fail(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_mount.side_effect = exception.GlusterfsException
|
||||
self._driver._do_umount = mock.Mock()
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
expected_exec = [
|
||||
'ssh root@host1 gluster volume set gv1 client.ssl off',
|
||||
'ssh root@host1 gluster 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.assertTrue(self._driver._restart_gluster_vol.called)
|
||||
self.assertTrue(tempfile.mkdtemp.called)
|
||||
self.assertTrue(self._driver._do_mount.called)
|
||||
self.assertFalse(self._driver._do_umount.called)
|
||||
self.assertTrue(shutil.rmtree.called)
|
||||
|
||||
def test_wipe_gluster_vol_umount_fail(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
self._driver._do_mount = mock.Mock()
|
||||
self._driver._do_umount = mock.Mock()
|
||||
self._driver._do_umount.side_effect = exception.GlusterfsException
|
||||
shutil.rmtree = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
|
||||
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']
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._wipe_gluster_vol, gaddr1)
|
||||
|
||||
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)
|
||||
self.assertTrue(self._driver._do_umount.called)
|
||||
self.assertFalse(shutil.rmtree.called)
|
||||
|
||||
def test_create_share(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
|
||||
|
||||
share = new_share()
|
||||
|
||||
exp_locn = self._driver.create_share(self._context, share)
|
||||
|
||||
self.assertEqual(exp_locn, gaddr2.export)
|
||||
|
||||
def test_create_share_excp(self):
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {
|
||||
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {}
|
||||
|
||||
share = new_share()
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver.create_share, self._context, share)
|
||||
|
||||
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)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {
|
||||
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {}
|
||||
|
||||
share = fake_db_share2()[0]
|
||||
|
||||
self._driver.delete_share(self._context, share)
|
||||
|
||||
self.assertEqual(1, len(self._driver.gluster_used_vols_dict))
|
||||
self.assertEqual(1, len(self._driver.gluster_unused_vols_dict))
|
||||
self.assertTrue(self._driver._wipe_gluster_vol.called)
|
||||
|
||||
def test_delete_share_warn(self):
|
||||
glusterfs_native.LOG.warn = mock.Mock()
|
||||
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)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {}
|
||||
self._driver.gluster_unused_vols_dict = {
|
||||
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
|
||||
|
||||
share = fake_db_share2()[0]
|
||||
|
||||
self._driver.delete_share(self._context, share)
|
||||
|
||||
self.assertTrue(glusterfs_native.LOG.warn.called)
|
||||
self.assertFalse(self._driver._wipe_gluster_vol.called)
|
||||
self.assertFalse(self._driver._push_gluster_vol.called)
|
||||
|
||||
def test_delete_share_excp1(self):
|
||||
self._driver._wipe_gluster_vol = mock.Mock()
|
||||
self._driver._wipe_gluster_vol.side_effect = (
|
||||
exception.GlusterfsException)
|
||||
self._driver._push_gluster_vol = mock.Mock()
|
||||
|
||||
gaddr = glusterfs.GlusterAddress
|
||||
gaddr1 = gaddr(self.gluster_target1)
|
||||
gaddr2 = gaddr(self.gluster_target2)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {
|
||||
gaddr2.export: gaddr2, gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {}
|
||||
|
||||
share = fake_db_share2()[0]
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver.delete_share, self._context, share)
|
||||
|
||||
self.assertTrue(self._driver._wipe_gluster_vol.called)
|
||||
self.assertFalse(self._driver._push_gluster_vol.called)
|
||||
|
||||
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)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
|
||||
|
||||
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())
|
||||
self.assertTrue(self._driver._restart_gluster_vol.called)
|
||||
|
||||
def test_allow_access_invalid_access_type(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
access = {'access_type': 'invalid', 'access_to': 'client.example.com'}
|
||||
share = fake_db_share1()[0]
|
||||
expected_exec = []
|
||||
|
||||
self.assertRaises(exception.InvalidShareAccess,
|
||||
self._driver.allow_access,
|
||||
self._context, share, access)
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
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)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
|
||||
|
||||
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())
|
||||
self.assertTrue(self._driver._restart_gluster_vol.called)
|
||||
|
||||
def test_deny_access_invalid_access_type(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
access = {'access_type': 'invalid', 'access_to': 'NotApplicable'}
|
||||
share = fake_db_share1()[0]
|
||||
expected_exec = []
|
||||
|
||||
self.assertRaises(exception.InvalidShareAccess,
|
||||
self._driver.deny_access,
|
||||
self._context, share, access)
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
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)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {gaddr1.export: gaddr1}
|
||||
self._driver.gluster_unused_vols_dict = {gaddr2.export: gaddr2}
|
||||
|
||||
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)
|
||||
self.assertFalse(self._driver._restart_gluster_vol.called)
|
||||
|
||||
def test_get_share_stats_refresh_false(self):
|
||||
self._driver._stats = mock.Mock()
|
||||
ret = self._driver.get_share_stats()
|
||||
self.assertEqual(ret, self._driver._stats)
|
||||
|
||||
def test_get_share_stats_refresh_true(self):
|
||||
def foo():
|
||||
self._driver._stats = {'key': 'value'}
|
||||
self._driver._update_share_stats = mock.Mock(side_effect=foo)
|
||||
ret = self._driver.get_share_stats(refresh=True)
|
||||
self.assertEqual(ret, {'key': 'value'})
|
||||
|
||||
def test_update_share_stats(self):
|
||||
test_data = {
|
||||
'share_backend_name': 'GlusterFS-Native',
|
||||
'vendor_name': 'Red Hat',
|
||||
'driver_version': '1.1',
|
||||
'storage_protocol': 'glusterfs',
|
||||
'reserved_percentage': 0,
|
||||
'QoS_support': False,
|
||||
'total_capacity_gb': 'infinite',
|
||||
'free_capacity_gb': 'infinite',
|
||||
}
|
||||
|
||||
self._driver._update_share_stats()
|
||||
|
||||
self.assertEqual(self._driver._stats, test_data)
|
|
@ -1,199 +0,0 @@
|
|||
# Copyright (c) 2014 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
""" GlusterFS native protocol (glusterfs) driver for shares.
|
||||
|
||||
Test cases for GlusterFS native protocol driver.
|
||||
"""
|
||||
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.share import configuration as config
|
||||
from manila.share.drivers import glusterfs_native
|
||||
from manila import test
|
||||
from manila.tests.db import fakes as db_fakes
|
||||
from manila.tests import fake_utils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
gluster_address_attrs = {
|
||||
'export': '127.0.0.1:/testvol',
|
||||
'host': '127.0.0.1',
|
||||
'qualified': 'testuser@127.0.0.1:/testvol',
|
||||
'remote_user': 'testuser',
|
||||
'volume': 'testvol',
|
||||
}
|
||||
|
||||
|
||||
def fake_share(**kwargs):
|
||||
share = {
|
||||
'id': 'fakeid',
|
||||
'name': 'fakename',
|
||||
'size': 1,
|
||||
'share_proto': 'glusterfs',
|
||||
'export_location': '127.0.0.1:/mnt/glusterfs/testvol',
|
||||
}
|
||||
share.update(kwargs)
|
||||
return db_fakes.FakeModel(share)
|
||||
|
||||
|
||||
class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
||||
"""Tests GlusterfsNativeShareDriver."""
|
||||
|
||||
def setUp(self):
|
||||
super(GlusterfsNativeShareDriverTestCase, self).setUp()
|
||||
fake_utils.stub_out_utils_execute(self.stubs)
|
||||
self._execute = fake_utils.fake_execute
|
||||
self._context = context.get_admin_context()
|
||||
|
||||
CONF.set_default('glusterfs_mount_point_base', '/mnt/glusterfs')
|
||||
CONF.set_default('reserved_share_percentage', 50)
|
||||
|
||||
self.fake_conf = config.Configuration(None)
|
||||
self._db = mock.Mock()
|
||||
self._driver = glusterfs_native.GlusterfsNativeShareDriver(
|
||||
self._db, execute=self._execute,
|
||||
configuration=self.fake_conf)
|
||||
self._driver.gluster_address = mock.Mock(**gluster_address_attrs)
|
||||
self.share = fake_share()
|
||||
|
||||
self.addCleanup(fake_utils.fake_execute_set_repliers, [])
|
||||
self.addCleanup(fake_utils.fake_execute_clear_log)
|
||||
|
||||
def test_create_share(self):
|
||||
self._driver._setup_gluster_vol = mock.Mock()
|
||||
|
||||
expected = gluster_address_attrs['export']
|
||||
actual = self._driver.create_share(self._context, self.share)
|
||||
|
||||
self.assertTrue(self._driver._setup_gluster_vol.called)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_create_share_error(self):
|
||||
self._driver._setup_gluster_vol = mock.Mock()
|
||||
self._driver._setup_gluster_vol.side_effect = (
|
||||
exception.ProcessExecutionError)
|
||||
|
||||
self.assertRaises(exception.ProcessExecutionError,
|
||||
self._driver.create_share, self._context, self.share)
|
||||
|
||||
def test_delete_share(self):
|
||||
self._driver.gluster_address = mock.Mock(
|
||||
make_gluster_args=mock.Mock(return_value=(('true',), {})))
|
||||
|
||||
self._driver.delete_share(self._context, self.share)
|
||||
|
||||
self.assertTrue(self._driver.gluster_address.make_gluster_args.called)
|
||||
self.assertEqual(
|
||||
self._driver.gluster_address.make_gluster_args.call_args[0][1],
|
||||
'reset')
|
||||
|
||||
def test_delete_share_error(self):
|
||||
self._driver.gluster_address = mock.Mock(
|
||||
make_gluster_args=mock.Mock(return_value=(('true',), {})))
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kw):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
expected_exec = ['true']
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.ProcessExecutionError,
|
||||
self._driver.delete_share, self._context, self.share)
|
||||
|
||||
def test_allow_access(self):
|
||||
self._driver.gluster_address = mock.Mock(
|
||||
make_gluster_args=mock.Mock(return_value=(('true',), {})))
|
||||
access = {'access_type': 'cert', 'access_to': 'client.example.com'}
|
||||
|
||||
self._driver.allow_access(self._context, self.share, access)
|
||||
|
||||
self.assertTrue(self._driver.gluster_address.make_gluster_args.called)
|
||||
self.assertEqual(
|
||||
self._driver.gluster_address.make_gluster_args.call_args[0][1],
|
||||
'set')
|
||||
self.assertEqual(
|
||||
self._driver.gluster_address.make_gluster_args.call_args[0][-2],
|
||||
'auth.ssl-allow')
|
||||
self.assertEqual(
|
||||
self._driver.gluster_address.make_gluster_args.call_args[0][-1],
|
||||
access['access_to'])
|
||||
|
||||
def test_allow_access_error(self):
|
||||
# Invalid access type
|
||||
access = {'access_type': 'invalid', 'access_to': 'client.example.com'}
|
||||
|
||||
self.assertRaises(exception.InvalidShareAccess,
|
||||
self._driver.allow_access, self._context, self.share,
|
||||
access)
|
||||
|
||||
# ProcessExecutionError
|
||||
self._driver.gluster_address = mock.Mock(
|
||||
make_gluster_args=mock.Mock(return_value=(('true',), {})))
|
||||
access = {'access_type': 'cert', 'access_to': 'client.example.com'}
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kw):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
expected_exec = ['true']
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.ProcessExecutionError,
|
||||
self._driver.allow_access, self._context, self.share,
|
||||
access)
|
||||
|
||||
def test_deny_access(self):
|
||||
self._driver.gluster_address = mock.Mock(
|
||||
make_gluster_args=mock.Mock(return_value=(('true',), {})))
|
||||
access = {'access_type': 'cert', 'access_to': 'client.example.com'}
|
||||
|
||||
self._driver.deny_access(self._context, self.share, access)
|
||||
|
||||
self.assertTrue(self._driver.gluster_address.make_gluster_args.called)
|
||||
self.assertEqual(
|
||||
self._driver.gluster_address.make_gluster_args.call_args[0][1],
|
||||
'reset')
|
||||
self.assertEqual(
|
||||
self._driver.gluster_address.make_gluster_args.call_args[0][-1],
|
||||
'auth.ssl-allow')
|
||||
|
||||
def test_deny_access_error(self):
|
||||
# Invalid access type
|
||||
access = {'access_type': 'invalid', 'access_to': 'client.example.com'}
|
||||
|
||||
self.assertRaises(exception.InvalidShareAccess,
|
||||
self._driver.deny_access, self._context, self.share,
|
||||
access)
|
||||
|
||||
# ProcessExecutionError
|
||||
self._driver.gluster_address = mock.Mock(
|
||||
make_gluster_args=mock.Mock(return_value=(('true',), {})))
|
||||
access = {'access_type': 'cert', 'access_to': 'client.example.com'}
|
||||
|
||||
def exec_runner(*ignore_args, **ignore_kw):
|
||||
raise exception.ProcessExecutionError
|
||||
|
||||
expected_exec = ['true']
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.ProcessExecutionError,
|
||||
self._driver.deny_access, self._context, self.share,
|
||||
access)
|
Loading…
Reference in New Issue