Merge "glusterfs_native: Add create share from snapshot"
This commit is contained in:
commit
acabb76ce2
|
@ -621,6 +621,102 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
|
||||
# TODO(deepakcs): Disable quota.
|
||||
|
||||
@staticmethod
|
||||
def _find_actual_backend_snapshot_name(gluster_mgr, snapshot):
|
||||
args = ('snapshot', 'list', gluster_mgr.volume, '--mode=script')
|
||||
try:
|
||||
out, err = gluster_mgr.gluster_call(*args)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_LE("Error retrieving snapshot list: %s"), exc.stderr)
|
||||
raise exception.GlusterfsException(_("gluster %s failed") %
|
||||
' '.join(args))
|
||||
snapgrep = list(filter(lambda x: snapshot['id'] in x, out.split("\n")))
|
||||
if len(snapgrep) != 1:
|
||||
msg = (_("Failed to identify backing GlusterFS object "
|
||||
"for snapshot %(snap_id)s of share %(share_id)s: "
|
||||
"a single candidate was expected, %(found)d was found.") %
|
||||
{'snap_id': snapshot['id'],
|
||||
'share_id': snapshot['share_id'],
|
||||
'found': len(snapgrep)})
|
||||
raise exception.GlusterfsException(msg)
|
||||
backend_snapshot_name = snapgrep[0]
|
||||
return backend_snapshot_name
|
||||
|
||||
def create_share_from_snapshot(self, context, share, snapshot,
|
||||
share_server=None):
|
||||
old_exportlocation = snapshot['share']['export_location']
|
||||
old_gmgr = self.gluster_used_vols_dict[old_exportlocation]
|
||||
|
||||
# Snapshot clone feature in GlusterFS server essential to support this
|
||||
# API is available in GlusterFS server versions 3.7 and higher. So do
|
||||
# a version check.
|
||||
vers = self.glusterfs_versions[old_gmgr.management_address]
|
||||
minvers = (3, 7)
|
||||
if glusterfs.GlusterManager.numreduct(vers) < minvers:
|
||||
minvers_str = '.'.join(six.text_type(c) for c in minvers)
|
||||
vers_str = '.'.join(vers)
|
||||
msg = (_("GlusterFS version %(version)s on server %(server)s does "
|
||||
"not support creation of shares from snapshot. "
|
||||
"minimum requirement: %(minversion)s") %
|
||||
{'version': vers_str, 'server': old_gmgr.host,
|
||||
'minversion': minvers_str})
|
||||
LOG.error(msg)
|
||||
raise exception.GlusterfsException(msg)
|
||||
|
||||
# Clone the snapshot. The snapshot clone, a new GlusterFS volume
|
||||
# would serve as a share.
|
||||
backend_snapshot_name = self._find_actual_backend_snapshot_name(
|
||||
old_gmgr, snapshot)
|
||||
volume = ''.join(['manila-', share['id']])
|
||||
args_tuple = (('snapshot', 'activate', backend_snapshot_name,
|
||||
'force', '--mode=script'),
|
||||
('snapshot', 'clone', volume, backend_snapshot_name))
|
||||
try:
|
||||
for args in args_tuple:
|
||||
out, err = old_gmgr.gluster_call(*args)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_LE("Error creating share from snapshot: %s"),
|
||||
exc.stderr)
|
||||
raise exception.GlusterfsException(_("gluster %s failed") %
|
||||
' '.join(args))
|
||||
|
||||
# Construct the volume address/export location of the new
|
||||
# volume/share.
|
||||
export_location = ':/'.join([old_gmgr.management_address, volume])
|
||||
|
||||
# Configure the GlusterFS volume to be used as share.
|
||||
# 1. The clone of the snapshot, the new volume, retains the authorized
|
||||
# access list of the snapshotted volume/share, which includes
|
||||
# identities of the backend servers and Manila clients. So only
|
||||
# retain the identities of the GlusterFS servers volume in the
|
||||
# authorized access list of the new volume. The identities of
|
||||
# GlusterFS are easy to figure as they're pre-fixed by
|
||||
# "glusterfs-server".
|
||||
# 2. Start the new volume.
|
||||
gmgr = self._glustermanager(export_location)
|
||||
old_access = gmgr.get_gluster_vol_option(AUTH_SSL_ALLOW)
|
||||
# wrt. GlusterFS' parsing of auth.ssl-allow, please see code from
|
||||
# https://github.com/gluster/glusterfs/blob/v3.6.2/
|
||||
# xlators/protocol/auth/login/src/login.c#L80
|
||||
# until end of gf_auth() function
|
||||
old_access_list = re.split('[ ,]', old_access)
|
||||
regex = re.compile('\Aglusterfs-server*')
|
||||
access_to = ','.join(filter(regex.match, old_access_list))
|
||||
args_tuple = (('volume', 'set', gmgr.volume, AUTH_SSL_ALLOW,
|
||||
access_to),
|
||||
('volume', 'start', gmgr.volume))
|
||||
try:
|
||||
for args in args_tuple:
|
||||
out, err = gmgr.gluster_call(*args)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_LE("Error creating share from snapshot: %s"),
|
||||
exc.stderr)
|
||||
raise exception.GlusterfsException(_("gluster %s failed") %
|
||||
' '.join(args))
|
||||
|
||||
self.gluster_used_vols_dict[export_location] = gmgr
|
||||
return export_location
|
||||
|
||||
def create_snapshot(self, context, snapshot, share_server=None):
|
||||
"""Creates a snapshot."""
|
||||
|
||||
|
@ -673,23 +769,10 @@ class GlusterfsNativeShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
|
||||
vol = snapshot['share']['export_location']
|
||||
gluster_mgr = self.gluster_used_vols_dict[vol]
|
||||
args = ('snapshot', 'list', gluster_mgr.volume, '--mode=script')
|
||||
try:
|
||||
out, err = gluster_mgr.gluster_call(*args)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
LOG.error(_LE("Error retrieving snapshot list: %s"), exc.stderr)
|
||||
raise exception.GlusterfsException(_("gluster %s failed") %
|
||||
' '.join(args))
|
||||
snapgrep = list(filter(lambda x: snapshot['id'] in x, out.split("\n")))
|
||||
if len(snapgrep) != 1:
|
||||
msg = (_("Failed to identify backing GlusterFS object "
|
||||
"for snapshot %(snap_id)s of share %(share_id)s: "
|
||||
"a single candidate was expected, %(found)d was found.") %
|
||||
{'snap_id': snapshot['id'],
|
||||
'share_id': snapshot['share_id'],
|
||||
'found': len(snapgrep)})
|
||||
raise exception.GlusterfsException(msg)
|
||||
args = ('--xml', 'snapshot', 'delete', snapgrep[0], '--mode=script')
|
||||
backend_snapshot_name = self._find_actual_backend_snapshot_name(
|
||||
gluster_mgr, snapshot)
|
||||
args = ('--xml', 'snapshot', 'delete', backend_snapshot_name,
|
||||
'--mode=script')
|
||||
try:
|
||||
out, err = gluster_mgr.gluster_call(*args)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
|
|
|
@ -869,6 +869,236 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
|||
self.assertRaises(exctype, self._driver.create_snapshot, self._context,
|
||||
snapshot)
|
||||
|
||||
def test_find_actual_backend_snapshot_name(self):
|
||||
gmgr = glusterfs.GlusterManager
|
||||
gmgr1 = gmgr(self.share1['export_location'], self._execute, None, None)
|
||||
self.mock_object(gmgr1, 'gluster_call',
|
||||
mock.Mock(return_value=('fake_snap_id_xyz', '')))
|
||||
args = ('snapshot', 'list', gmgr1.volume, '--mode=script')
|
||||
snapshot = {
|
||||
'id': 'fake_snap_id',
|
||||
'share_id': self.share1['id'],
|
||||
'share': self.share1
|
||||
}
|
||||
ret = self._driver._find_actual_backend_snapshot_name(gmgr1, snapshot)
|
||||
gmgr1.gluster_call.assert_called_once_with(*args)
|
||||
self.assertEqual('fake_snap_id_xyz', ret)
|
||||
|
||||
@ddt.data('this is too bad', 'fake_snap_id_xyx\nfake_snap_id_pqr')
|
||||
def test_find_actual_backend_snapshot_name_bad_snap_list(self, snaplist):
|
||||
gmgr = glusterfs.GlusterManager
|
||||
gmgr1 = gmgr(self.share1['export_location'], self._execute, None, None)
|
||||
self.mock_object(gmgr1, 'gluster_call',
|
||||
mock.Mock(return_value=(snaplist, '')))
|
||||
args = ('snapshot', 'list', gmgr1.volume, '--mode=script')
|
||||
snapshot = {
|
||||
'id': 'fake_snap_id',
|
||||
'share_id': self.share1['id'],
|
||||
'share': self.share1
|
||||
}
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver._find_actual_backend_snapshot_name,
|
||||
gmgr1, snapshot)
|
||||
gmgr1.gluster_call.assert_called_once_with(*args)
|
||||
|
||||
@ddt.data({'glusterfs_target': 'root@host1:/gv1',
|
||||
'glusterfs_server': 'root@host1'},
|
||||
{'glusterfs_target': 'host1:/gv1',
|
||||
'glusterfs_server': 'host1'})
|
||||
@ddt.unpack
|
||||
def test_create_share_from_snapshot(self, glusterfs_target,
|
||||
glusterfs_server):
|
||||
share = new_share()
|
||||
snapshot = {
|
||||
'id': 'fake_snap_id',
|
||||
'share': new_share(export_location=glusterfs_target)
|
||||
}
|
||||
volume = ''.join(['manila-', share['id']])
|
||||
new_export_location = ':/'.join([glusterfs_server, volume])
|
||||
gmgr = glusterfs.GlusterManager
|
||||
old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
|
||||
new_gmgr = gmgr(new_export_location, self._execute, None, None)
|
||||
self._driver.gluster_used_vols_dict = {glusterfs_target: old_gmgr}
|
||||
self._driver.glusterfs_versions = {glusterfs_server: ('3', '7')}
|
||||
|
||||
self.mock_object(old_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), ('', '')]))
|
||||
self.mock_object(new_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), ('', '')]))
|
||||
self.mock_object(new_gmgr, 'get_gluster_vol_option',
|
||||
mock.Mock())
|
||||
new_gmgr.get_gluster_vol_option.return_value = (
|
||||
'glusterfs-server-1,client')
|
||||
self.mock_object(self._driver, '_find_actual_backend_snapshot_name',
|
||||
mock.Mock(return_value='fake_snap_id_xyz'))
|
||||
self.mock_object(self._driver, '_glustermanager',
|
||||
mock.Mock(return_value=new_gmgr))
|
||||
|
||||
ret = self._driver.create_share_from_snapshot(
|
||||
self._context, share, snapshot, None)
|
||||
|
||||
(self._driver._find_actual_backend_snapshot_name.
|
||||
assert_called_once_with(old_gmgr, snapshot))
|
||||
args = (('snapshot', 'activate', 'fake_snap_id_xyz',
|
||||
'force', '--mode=script'),
|
||||
('snapshot', 'clone', volume, 'fake_snap_id_xyz'))
|
||||
old_gmgr.gluster_call.assert_has_calls([mock.call(*a) for a in args])
|
||||
self._driver._glustermanager.assert_called_once_with(
|
||||
new_export_location)
|
||||
new_gmgr.get_gluster_vol_option.assert_called_once_with(
|
||||
'auth.ssl-allow')
|
||||
args = (('volume', 'set', new_gmgr.volume, 'auth.ssl-allow',
|
||||
'glusterfs-server-1'),
|
||||
('volume', 'start', new_gmgr.volume), )
|
||||
new_gmgr.gluster_call.assert_has_calls([mock.call(*a) for a in args])
|
||||
self.assertEqual(
|
||||
new_gmgr,
|
||||
self._driver.gluster_used_vols_dict[new_export_location])
|
||||
self.assertEqual(new_export_location, ret)
|
||||
|
||||
def test_create_share_from_snapshot_error_old_gmr_gluster_calls(self):
|
||||
glusterfs_target = 'root@host1:/gv1'
|
||||
glusterfs_server = 'root@host1'
|
||||
share = new_share()
|
||||
snapshot = {
|
||||
'id': 'fake_snap_id',
|
||||
'share': new_share(export_location=glusterfs_target)
|
||||
}
|
||||
volume = ''.join(['manila-', share['id']])
|
||||
new_export_location = ':/'.join([glusterfs_server, volume])
|
||||
gmgr = glusterfs.GlusterManager
|
||||
old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
|
||||
new_gmgr = gmgr(new_export_location, self._execute, None, None)
|
||||
self._driver.gluster_used_vols_dict = {glusterfs_target: old_gmgr}
|
||||
self._driver.glusterfs_versions = {glusterfs_server: ('3', '7')}
|
||||
|
||||
self.mock_object(
|
||||
old_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), exception.ProcessExecutionError]))
|
||||
self.mock_object(new_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), ('', '')]))
|
||||
self.mock_object(new_gmgr, 'get_gluster_vol_option',
|
||||
mock.Mock())
|
||||
new_gmgr.get_gluster_vol_option.return_value = (
|
||||
'glusterfs-server-1,client')
|
||||
self.mock_object(self._driver, '_find_actual_backend_snapshot_name',
|
||||
mock.Mock(return_value='fake_snap_id_xyz'))
|
||||
self.mock_object(self._driver, '_glustermanager',
|
||||
mock.Mock(return_value=new_gmgr))
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver.create_share_from_snapshot,
|
||||
self._context, share, snapshot)
|
||||
|
||||
(self._driver._find_actual_backend_snapshot_name.
|
||||
assert_called_once_with(old_gmgr, snapshot))
|
||||
args = (('snapshot', 'activate', 'fake_snap_id_xyz',
|
||||
'force', '--mode=script'),
|
||||
('snapshot', 'clone', volume, 'fake_snap_id_xyz'))
|
||||
old_gmgr.gluster_call.assert_has_calls([mock.call(*a) for a in args])
|
||||
self.assertFalse(new_gmgr.get_gluster_vol_option.called)
|
||||
self.assertFalse(new_gmgr.gluster_call.called)
|
||||
self.assertNotIn(new_export_location,
|
||||
self._driver.glusterfs_versions.keys())
|
||||
|
||||
def test_create_share_from_snapshot_error_new_gmr_gluster_calls(self):
|
||||
glusterfs_target = 'root@host1:/gv1'
|
||||
glusterfs_server = 'root@host1'
|
||||
share = new_share()
|
||||
snapshot = {
|
||||
'id': 'fake_snap_id',
|
||||
'share': new_share(export_location=glusterfs_target)
|
||||
}
|
||||
volume = ''.join(['manila-', share['id']])
|
||||
new_export_location = ':/'.join([glusterfs_server, volume])
|
||||
gmgr = glusterfs.GlusterManager
|
||||
old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
|
||||
new_gmgr = gmgr(new_export_location, self._execute, None, None)
|
||||
self._driver.gluster_used_vols_dict = {glusterfs_target: old_gmgr}
|
||||
self._driver.glusterfs_versions = {glusterfs_server: ('3', '7')}
|
||||
|
||||
self.mock_object(
|
||||
old_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), ('', '')]))
|
||||
self.mock_object(
|
||||
new_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), exception.ProcessExecutionError]))
|
||||
self.mock_object(new_gmgr, 'get_gluster_vol_option',
|
||||
mock.Mock())
|
||||
new_gmgr.get_gluster_vol_option.return_value = (
|
||||
'glusterfs-server-1,client')
|
||||
self.mock_object(self._driver, '_find_actual_backend_snapshot_name',
|
||||
mock.Mock(return_value='fake_snap_id_xyz'))
|
||||
self.mock_object(self._driver, '_glustermanager',
|
||||
mock.Mock(return_value=new_gmgr))
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver.create_share_from_snapshot,
|
||||
self._context, share, snapshot)
|
||||
|
||||
(self._driver._find_actual_backend_snapshot_name.
|
||||
assert_called_once_with(old_gmgr, snapshot))
|
||||
args = (('snapshot', 'activate', 'fake_snap_id_xyz',
|
||||
'force', '--mode=script'),
|
||||
('snapshot', 'clone', volume, 'fake_snap_id_xyz'))
|
||||
old_gmgr.gluster_call.assert_has_calls([mock.call(*a) for a in args])
|
||||
self._driver._glustermanager.assert_called_once_with(
|
||||
new_export_location)
|
||||
new_gmgr.get_gluster_vol_option.assert_called_once_with(
|
||||
'auth.ssl-allow')
|
||||
args = (('volume', 'set', new_gmgr.volume, 'auth.ssl-allow',
|
||||
'glusterfs-server-1'),
|
||||
('volume', 'start', new_gmgr.volume), )
|
||||
new_gmgr.gluster_call.assert_has_calls([mock.call(*a) for a in args])
|
||||
self.assertNotIn(new_export_location,
|
||||
self._driver.glusterfs_versions.keys())
|
||||
|
||||
def test_create_share_from_snapshot_error_unsupported_gluster_version(
|
||||
self):
|
||||
|
||||
glusterfs_target = 'root@host1:/gv1'
|
||||
glusterfs_server = 'root@host1'
|
||||
share = new_share()
|
||||
snapshot = {
|
||||
'id': 'fake_snap_id',
|
||||
'share': new_share(export_location=glusterfs_target)
|
||||
}
|
||||
volume = ''.join(['manila-', share['id']])
|
||||
new_export_location = ':/'.join([glusterfs_server, volume])
|
||||
gmgr = glusterfs.GlusterManager
|
||||
old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
|
||||
new_gmgr = gmgr(new_export_location, self._execute, None, None)
|
||||
self._driver.gluster_used_vols_dict = {glusterfs_target: old_gmgr}
|
||||
self._driver.glusterfs_versions = {glusterfs_server: ('3', '6')}
|
||||
|
||||
self.mock_object(
|
||||
old_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), ('', '')]))
|
||||
self.mock_object(
|
||||
new_gmgr, 'gluster_call',
|
||||
mock.Mock(side_effect=[('', ''), exception.ProcessExecutionError]))
|
||||
self.mock_object(new_gmgr, 'get_gluster_vol_option',
|
||||
mock.Mock())
|
||||
new_gmgr.get_gluster_vol_option.return_value = (
|
||||
'glusterfs-server-1,client')
|
||||
self.mock_object(self._driver, '_find_actual_backend_snapshot_name',
|
||||
mock.Mock(return_value='fake_snap_id_xyz'))
|
||||
self.mock_object(self._driver, '_glustermanager',
|
||||
mock.Mock(return_value=new_gmgr))
|
||||
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver.create_share_from_snapshot,
|
||||
self._context, share, snapshot)
|
||||
|
||||
self.assertFalse(
|
||||
self._driver._find_actual_backend_snapshot_name.called)
|
||||
self.assertFalse(old_gmgr.gluster_call.called)
|
||||
self.assertFalse(self._driver._glustermanager.called)
|
||||
self.assertFalse(new_gmgr.get_gluster_vol_option.called)
|
||||
self.assertFalse(new_gmgr.gluster_call.called)
|
||||
self.assertNotIn(new_export_location,
|
||||
self._driver.glusterfs_versions.keys())
|
||||
|
||||
def test_delete_snapshot(self):
|
||||
self._driver.gluster_nosnap_vols_dict = {}
|
||||
|
||||
|
@ -881,19 +1111,21 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
|||
'share_id': self.share1['id'],
|
||||
'share': self.share1
|
||||
}
|
||||
|
||||
args = (('snapshot', 'list', gmgr1.volume, '--mode=script'),
|
||||
('--xml', 'snapshot', 'delete', 'fake_snap_id_xyz',
|
||||
'--mode=script'))
|
||||
self.mock_object(gmgr1, 'gluster_call',
|
||||
mock.Mock(side_effect=(('fake_snap_id_xyz', ''),
|
||||
GlusterXMLOut(ret=0, errno=0)())))
|
||||
self.mock_object(self._driver, '_find_actual_backend_snapshot_name',
|
||||
mock.Mock(return_value='fake_snap_id_xyz'))
|
||||
args = ('--xml', 'snapshot', 'delete', 'fake_snap_id_xyz',
|
||||
'--mode=script')
|
||||
self.mock_object(
|
||||
gmgr1, 'gluster_call',
|
||||
mock.Mock(return_value=GlusterXMLOut(ret=0, errno=0)()))
|
||||
ret = self._driver.delete_snapshot(self._context, snapshot)
|
||||
self.assertEqual(None, ret)
|
||||
gmgr1.gluster_call.assert_has_calls([mock.call(*a) for a in args])
|
||||
gmgr1.gluster_call.assert_called_once_with(*args)
|
||||
(self._driver._find_actual_backend_snapshot_name.
|
||||
assert_called_once_with(gmgr1, snapshot))
|
||||
|
||||
@ddt.data(GlusterXMLOut(ret=-1, errno=2)(), ('', ''))
|
||||
def test_delete_snapshot_error(self, badxmlout):
|
||||
def test_delete_snapshot_error(self, badxmloutput):
|
||||
self._driver.gluster_nosnap_vols_dict = {}
|
||||
|
||||
gmgr = glusterfs.GlusterManager
|
||||
|
@ -905,39 +1137,19 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
|||
'share_id': self.share1['id'],
|
||||
'share': self.share1
|
||||
}
|
||||
|
||||
args = (('snapshot', 'list', gmgr1.volume, '--mode=script'),
|
||||
('--xml', 'snapshot', 'delete', 'fake_snap_id_xyz',
|
||||
'--mode=script'))
|
||||
self.mock_object(gmgr1, 'gluster_call',
|
||||
mock.Mock(side_effect=(('fake_snap_id_xyz', ''),
|
||||
badxmlout)))
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver.delete_snapshot, self._context,
|
||||
snapshot)
|
||||
gmgr1.gluster_call.assert_has_calls([mock.call(*a) for a in args])
|
||||
|
||||
@ddt.data('this is too bad', 'fake_snap_id_xyx\nfake_snap_id_pqr')
|
||||
def test_delete_snapshot_bad_snap_list(self, snaplist):
|
||||
self._driver.gluster_nosnap_vols_dict = {}
|
||||
|
||||
gmgr = glusterfs.GlusterManager
|
||||
gmgr1 = gmgr(self.share1['export_location'], self._execute, None, None)
|
||||
|
||||
self._driver.gluster_used_vols_dict = {self.glusterfs_target1: gmgr1}
|
||||
snapshot = {
|
||||
'id': 'fake_snap_id',
|
||||
'share_id': self.share1['id'],
|
||||
'share': self.share1
|
||||
}
|
||||
|
||||
args = ('snapshot', 'list', gmgr1.volume, '--mode=script')
|
||||
self.mock_object(gmgr1, 'gluster_call',
|
||||
mock.Mock(side_effect=((snaplist, ''),)))
|
||||
self.mock_object(self._driver, '_find_actual_backend_snapshot_name',
|
||||
mock.Mock(return_value='fake_snap_id_xyz'))
|
||||
args = ('--xml', 'snapshot', 'delete', 'fake_snap_id_xyz',
|
||||
'--mode=script')
|
||||
self.mock_object(
|
||||
gmgr1, 'gluster_call',
|
||||
mock.Mock(return_value=badxmloutput))
|
||||
self.assertRaises(exception.GlusterfsException,
|
||||
self._driver.delete_snapshot, self._context,
|
||||
snapshot)
|
||||
gmgr1.gluster_call.assert_called_once_with(*args)
|
||||
(self._driver._find_actual_backend_snapshot_name.
|
||||
assert_called_once_with(gmgr1, snapshot))
|
||||
|
||||
def test_allow_access(self):
|
||||
self._driver._restart_gluster_vol = mock.Mock()
|
||||
|
@ -1104,7 +1316,7 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
|||
'total_capacity_gb': 'infinite',
|
||||
'free_capacity_gb': 'infinite',
|
||||
'pools': None,
|
||||
'snapshot_support': False,
|
||||
'snapshot_support': True,
|
||||
}
|
||||
|
||||
self._driver._update_share_stats()
|
||||
|
|
Loading…
Reference in New Issue