Browse Source

Re-enable broken CG code in NetApp driver

Override the new create_share_group_snapshot() method in the driver class
and call the old CG snapshot code if the share group specifies CG
support, otherwise fall back on the new (existing) code.

This patch also removes dead code from the old CG feature from Newton and
earlier releases.

Change-Id: Ief71b9900c2c84e0df1d12d303517fa20ff7908b
Closes-bug: #1659023
changes/77/491877/12 5.0.0
Ben Swartzlander 4 years ago
parent
commit
80fe5f1fe4
  1. 47
      manila/share/drivers/netapp/dataontap/cluster_mode/drv_multi_svm.py
  2. 47
      manila/share/drivers/netapp/dataontap/cluster_mode/drv_single_svm.py
  3. 84
      manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py
  4. 179
      manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py
  5. 13
      manila/tests/share/drivers/netapp/dataontap/fakes.py
  6. 5
      releasenotes/notes/bug-1659023-netapp-cg-fix-56bb77b7bc61c3f5.yaml

47
manila/share/drivers/netapp/dataontap/cluster_mode/drv_multi_svm.py

@ -71,25 +71,6 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
def shrink_share(self, share, new_size, **kwargs):
self.library.shrink_share(share, new_size, **kwargs)
def create_consistency_group(self, context, cg_dict, **kwargs):
return self.library.create_consistency_group(context, cg_dict,
**kwargs)
def create_consistency_group_from_cgsnapshot(self, context, cg_dict,
cgsnapshot_dict, **kwargs):
return self.library.create_consistency_group_from_cgsnapshot(
context, cg_dict, cgsnapshot_dict, **kwargs)
def delete_consistency_group(self, context, cg_dict, **kwargs):
return self.library.delete_consistency_group(context, cg_dict,
**kwargs)
def create_cgsnapshot(self, context, snap_dict, **kwargs):
return self.library.create_cgsnapshot(context, snap_dict, **kwargs)
def delete_cgsnapshot(self, context, snap_dict, **kwargs):
return self.library.delete_cgsnapshot(context, snap_dict, **kwargs)
def ensure_share(self, context, share, **kwargs):
pass
@ -225,3 +206,31 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
context, source_share, destination_share,
source_snapshots, snapshot_mappings, share_server=share_server,
destination_share_server=destination_share_server)
def create_share_group_snapshot(self, context, snap_dict,
share_server=None):
fallback_create = super(NetAppCmodeMultiSvmShareDriver,
self).create_share_group_snapshot
return self.library.create_group_snapshot(context, snap_dict,
fallback_create,
share_server)
def delete_share_group_snapshot(self, context, snap_dict,
share_server=None):
fallback_delete = super(NetAppCmodeMultiSvmShareDriver,
self).delete_share_group_snapshot
return self.library.delete_group_snapshot(context, snap_dict,
fallback_delete,
share_server)
def create_share_group_from_share_group_snapshot(
self, context, share_group_dict, snapshot_dict,
share_server=None):
fallback_create = super(
NetAppCmodeMultiSvmShareDriver,
self).create_share_group_from_share_group_snapshot
return self.library.create_group_from_snapshot(context,
share_group_dict,
snapshot_dict,
fallback_create,
share_server)

47
manila/share/drivers/netapp/dataontap/cluster_mode/drv_single_svm.py

@ -71,25 +71,6 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
def shrink_share(self, share, new_size, **kwargs):
self.library.shrink_share(share, new_size, **kwargs)
def create_consistency_group(self, context, cg_dict, **kwargs):
return self.library.create_consistency_group(context, cg_dict,
**kwargs)
def create_consistency_group_from_cgsnapshot(self, context, cg_dict,
cgsnapshot_dict, **kwargs):
return self.library.create_consistency_group_from_cgsnapshot(
context, cg_dict, cgsnapshot_dict, **kwargs)
def delete_consistency_group(self, context, cg_dict, **kwargs):
return self.library.delete_consistency_group(context, cg_dict,
**kwargs)
def create_cgsnapshot(self, context, snap_dict, **kwargs):
return self.library.create_cgsnapshot(context, snap_dict, **kwargs)
def delete_cgsnapshot(self, context, snap_dict, **kwargs):
return self.library.delete_cgsnapshot(context, snap_dict, **kwargs)
def ensure_share(self, context, share, **kwargs):
pass
@ -241,3 +222,31 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
context, source_share, destination_share,
source_snapshots, snapshot_mappings, share_server=share_server,
destination_share_server=destination_share_server)
def create_share_group_snapshot(self, context, snap_dict,
share_server=None):
fallback_create = super(NetAppCmodeSingleSvmShareDriver,
self).create_share_group_snapshot
return self.library.create_group_snapshot(context, snap_dict,
fallback_create,
share_server)
def delete_share_group_snapshot(self, context, snap_dict,
share_server=None):
fallback_delete = super(NetAppCmodeSingleSvmShareDriver,
self).delete_share_group_snapshot
return self.library.delete_group_snapshot(context, snap_dict,
fallback_delete,
share_server)
def create_share_group_from_share_group_snapshot(
self, context, share_group_dict, snapshot_dict,
share_server=None):
fallback_create = super(
NetAppCmodeSingleSvmShareDriver,
self).create_share_group_from_share_group_snapshot
return self.library.create_group_from_snapshot(context,
share_group_dict,
snapshot_dict,
fallback_create,
share_server)

84
manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py

@ -258,6 +258,9 @@ class NetAppCmodeFileStorageLibrary(object):
'storage_protocol': 'NFS_CIFS',
'pools': self._get_pools(filter_function=filter_function,
goodness_function=goodness_function),
'share_group_stats': {
'consistent_snapshot_support': 'host',
},
}
if (self.configuration.replication_domain and
@ -1096,15 +1099,6 @@ class NetAppCmodeFileStorageLibrary(object):
def unmanage_snapshot(self, snapshot):
"""Removes the specified snapshot from Manila management."""
@na_utils.trace
def create_consistency_group(self, context, cg_dict, share_server=None):
"""Creates a consistency group.
cDOT has no persistent CG object, so apart from validating the
share_server info is passed correctly, this method has nothing to do.
"""
vserver, vserver_client = self._get_vserver(share_server=share_server)
@na_utils.trace
def create_consistency_group_from_cgsnapshot(
self, context, cg_dict, cgsnapshot_dict, share_server=None):
@ -1112,7 +1106,7 @@ class NetAppCmodeFileStorageLibrary(object):
vserver, vserver_client = self._get_vserver(share_server=share_server)
# Ensure there is something to do
if not cgsnapshot_dict['cgsnapshot_members']:
if not cgsnapshot_dict['share_group_snapshot_members']:
return None, None
clone_list = self._collate_cg_snapshot_info(cg_dict, cgsnapshot_dict)
@ -1153,12 +1147,13 @@ class NetAppCmodeFileStorageLibrary(object):
clone_info = {'share': share}
for cgsnapshot_member in cgsnapshot_dict['cgsnapshot_members']:
if (share['source_cgsnapshot_member_id'] ==
for cgsnapshot_member in (
cgsnapshot_dict['share_group_snapshot_members']):
if (share['source_share_group_snapshot_member_id'] ==
cgsnapshot_member['id']):
clone_info['snapshot'] = {
'share_id': cgsnapshot_member['share_id'],
'id': cgsnapshot_member['cgsnapshot_id']
'id': cgsnapshot_dict['id']
}
break
@ -1171,31 +1166,14 @@ class NetAppCmodeFileStorageLibrary(object):
return clone_list
@na_utils.trace
def delete_consistency_group(self, context, cg_dict, share_server=None):
"""Deletes a consistency group.
cDOT has no persistent CG object, so apart from validating the
share_server info is passed correctly, this method has nothing to do.
"""
try:
vserver, vserver_client = self._get_vserver(
share_server=share_server)
except (exception.InvalidInput,
exception.VserverNotSpecified,
exception.VserverNotFound) as error:
LOG.warning("Could not determine share server for consistency "
"group being deleted: %(cg)s. Deletion of CG "
"record will proceed anyway. Error: %(error)s",
{'cg': cg_dict['id'], 'error': error})
@na_utils.trace
def create_cgsnapshot(self, context, snap_dict, share_server=None):
"""Creates a consistency group snapshot."""
vserver, vserver_client = self._get_vserver(share_server=share_server)
share_names = [self._get_backend_share_name(member['share_id'])
for member in snap_dict.get('cgsnapshot_members', [])]
for member in
snap_dict.get('share_group_snapshot_members', [])]
snapshot_name = self._get_backend_cg_snapshot_name(snap_dict['id'])
if share_names:
@ -1220,7 +1198,8 @@ class NetAppCmodeFileStorageLibrary(object):
return None, None
share_names = [self._get_backend_share_name(member['share_id'])
for member in snap_dict.get('cgsnapshot_members', [])]
for member in (
snap_dict.get('share_group_snapshot_members', []))]
snapshot_name = self._get_backend_cg_snapshot_name(snap_dict['id'])
for share_name in share_names:
@ -1236,6 +1215,45 @@ class NetAppCmodeFileStorageLibrary(object):
return None, None
@staticmethod
def _is_group_cg(context, share_group):
return 'host' == share_group.consistent_snapshot_support
@na_utils.trace
def create_group_snapshot(self, context, snap_dict, fallback_create,
share_server=None):
share_group = snap_dict['share_group']
if self._is_group_cg(context, share_group):
return self.create_cgsnapshot(context, snap_dict,
share_server=share_server)
else:
return fallback_create(context, snap_dict,
share_server=share_server)
@na_utils.trace
def delete_group_snapshot(self, context, snap_dict, fallback_delete,
share_server=None):
share_group = snap_dict['share_group']
if self._is_group_cg(context, share_group):
return self.delete_cgsnapshot(context, snap_dict,
share_server=share_server)
else:
return fallback_delete(context, snap_dict,
share_server=share_server)
@na_utils.trace
def create_group_from_snapshot(self, context, share_group,
snapshot_dict, fallback_create,
share_server=None):
share_group2 = snapshot_dict['share_group']
if self._is_group_cg(context, share_group2):
return self.create_consistency_group_from_cgsnapshot(
context, share_group, snapshot_dict,
share_server=share_server)
else:
return fallback_create(context, share_group, snapshot_dict,
share_server=share_server)
@na_utils.trace
def _adjust_qos_policy_with_volume_resize(self, share, new_size,
vserver_client):

179
manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py

@ -367,6 +367,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
'netapp_storage_family': 'ontap_cluster',
'storage_protocol': 'NFS_CIFS',
'pools': fake.POOLS,
'share_group_stats': {'consistent_snapshot_support': 'host'},
}
self.assertDictEqual(expected, result)
mock_get_pools.assert_called_once_with(filter_function='filter',
@ -392,6 +393,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
'replication_type': 'dr',
'replication_domain': 'fake_domain',
'pools': fake.POOLS,
'share_group_stats': {'consistent_snapshot_support': 'host'},
}
self.assertDictEqual(expected, result)
mock_get_pools.assert_called_once_with(filter_function='filter',
@ -1839,40 +1841,6 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.FLEXVOL_TO_MANAGE,
vserver_client)
def test_create_consistency_group(self):
vserver_client = mock.Mock()
mock_get_vserver = self.mock_object(
self.library, '_get_vserver',
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
result = self.library.create_consistency_group(
self.context, fake.EMPTY_CONSISTENCY_GROUP,
share_server=fake.SHARE_SERVER)
self.assertIsNone(result)
mock_get_vserver.assert_called_once_with(
share_server=fake.SHARE_SERVER)
@ddt.data(exception.InvalidInput(reason='fake_reason'),
exception.VserverNotSpecified(),
exception.VserverNotFound(vserver='fake_vserver'))
def test_create_consistency_group_no_share_server(self,
get_vserver_exception):
mock_get_vserver = self.mock_object(
self.library, '_get_vserver',
mock.Mock(side_effect=get_vserver_exception))
self.assertRaises(type(get_vserver_exception),
self.library.create_consistency_group,
self.context,
fake.EMPTY_CONSISTENCY_GROUP,
share_server=fake.SHARE_SERVER)
mock_get_vserver.assert_called_once_with(
share_server=fake.SHARE_SERVER)
def test_create_consistency_group_from_cgsnapshot(self):
vserver_client = mock.Mock()
@ -1936,7 +1904,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
mock.Mock(side_effect=[['loc3'], ['loc4']]))
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
fake_cg_snapshot['cgsnapshot_members'] = []
fake_cg_snapshot['share_group_snapshot_members'] = []
result = self.library.create_consistency_group_from_cgsnapshot(
self.context,
@ -1961,48 +1929,12 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
def test_collate_cg_snapshot_info_invalid(self):
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
fake_cg_snapshot['cgsnapshot_members'] = []
fake_cg_snapshot['share_group_snapshot_members'] = []
self.assertRaises(exception.InvalidShareGroup,
self.library._collate_cg_snapshot_info,
fake.CONSISTENCY_GROUP_DEST, fake_cg_snapshot)
def test_delete_consistency_group(self):
vserver_client = mock.Mock()
mock_get_vserver = self.mock_object(
self.library, '_get_vserver',
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
result = self.library.delete_consistency_group(
self.context,
fake.EMPTY_CONSISTENCY_GROUP,
share_server=fake.SHARE_SERVER)
self.assertIsNone(result)
mock_get_vserver.assert_called_once_with(
share_server=fake.SHARE_SERVER)
@ddt.data(exception.InvalidInput(reason='fake_reason'),
exception.VserverNotSpecified(),
exception.VserverNotFound(vserver='fake_vserver'))
def test_delete_consistency_group_no_share_server(self,
get_vserver_exception):
mock_get_vserver = self.mock_object(
self.library, '_get_vserver',
mock.Mock(side_effect=get_vserver_exception))
result = self.library.delete_consistency_group(
self.context,
fake.EMPTY_CONSISTENCY_GROUP,
share_server=fake.SHARE_SERVER)
self.assertIsNone(result)
self.assertEqual(1, lib_base.LOG.warning.call_count)
mock_get_vserver.assert_called_once_with(
share_server=fake.SHARE_SERVER)
def test_create_cgsnapshot(self):
vserver_client = mock.Mock()
@ -2037,7 +1969,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
fake_cg_snapshot['cgsnapshot_members'] = []
fake_cg_snapshot['share_group_snapshot_members'] = []
result = self.library.create_cgsnapshot(
self.context,
@ -2090,7 +2022,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
'_delete_snapshot')
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
fake_cg_snapshot['cgsnapshot_members'] = []
fake_cg_snapshot['share_group_snapshot_members'] = []
result = self.library.delete_cgsnapshot(
self.context,
@ -4779,3 +4711,102 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
share_obj, fake.VSERVER1, {'maxiops': '3000'})
self.library._client.qos_policy_group_modify.assert_not_called()
self.library._client.qos_policy_group_rename.assert_not_called()
@ddt.data(('host', True), ('pool', False), (None, False), ('fake', False))
@ddt.unpack
def test__is_group_cg(self, css, is_cg):
share_group = mock.Mock()
share_group.consistent_snapshot_support = css
self.assertEqual(is_cg,
self.library._is_group_cg(self.context, share_group))
def test_create_group_snapshot_cg(self):
share_group = mock.Mock()
share_group.consistent_snapshot_support = 'host'
snap_dict = {'share_group': share_group}
fallback_create = mock.Mock()
mock_create_cgsnapshot = self.mock_object(self.library,
'create_cgsnapshot')
self.library.create_group_snapshot(self.context, snap_dict,
fallback_create,
share_server=fake.SHARE_SERVER)
mock_create_cgsnapshot.assert_called_once_with(
self.context, snap_dict, share_server=fake.SHARE_SERVER)
fallback_create.assert_not_called()
@ddt.data('pool', None, 'fake')
def test_create_group_snapshot_fallback(self, css):
share_group = mock.Mock()
share_group.consistent_snapshot_support = css
snap_dict = {'share_group': share_group}
fallback_create = mock.Mock()
mock_create_cgsnapshot = self.mock_object(self.library,
'create_cgsnapshot')
self.library.create_group_snapshot(self.context, snap_dict,
fallback_create,
share_server=fake.SHARE_SERVER)
mock_create_cgsnapshot.assert_not_called()
fallback_create.assert_called_once_with(self.context,
snap_dict,
share_server=fake.SHARE_SERVER)
def test_delete_group_snapshot_cg(self):
share_group = mock.Mock()
share_group.consistent_snapshot_support = 'host'
snap_dict = {'share_group': share_group}
fallback_delete = mock.Mock()
mock_delete_cgsnapshot = self.mock_object(self.library,
'delete_cgsnapshot')
self.library.delete_group_snapshot(self.context, snap_dict,
fallback_delete,
share_server=fake.SHARE_SERVER)
mock_delete_cgsnapshot.assert_called_once_with(
self.context, snap_dict, share_server=fake.SHARE_SERVER)
fallback_delete.assert_not_called()
@ddt.data('pool', None, 'fake')
def test_delete_group_snapshot_fallback(self, css):
share_group = mock.Mock()
share_group.consistent_snapshot_support = css
snap_dict = {'share_group': share_group}
fallback_delete = mock.Mock()
mock_delete_cgsnapshot = self.mock_object(self.library,
'delete_cgsnapshot')
self.library.delete_group_snapshot(self.context, snap_dict,
fallback_delete,
share_server=fake.SHARE_SERVER)
mock_delete_cgsnapshot.assert_not_called()
fallback_delete.assert_called_once_with(self.context,
snap_dict,
share_server=fake.SHARE_SERVER)
def test_create_group_from_snapshot_cg(self):
share_group = mock.Mock()
share_group.consistent_snapshot_support = 'host'
snap_dict = {'share_group': share_group}
fallback_create = mock.Mock()
mock_create_cg_from_snapshot = self.mock_object(
self.library, 'create_consistency_group_from_cgsnapshot')
self.library.create_group_from_snapshot(self.context, share_group,
snap_dict, fallback_create,
share_server=fake.SHARE_SERVER)
mock_create_cg_from_snapshot.assert_called_once_with(
self.context, share_group, snap_dict,
share_server=fake.SHARE_SERVER)
fallback_create.assert_not_called()
@ddt.data('pool', None, 'fake')
def test_create_group_from_snapshot_fallback(self, css):
share_group = mock.Mock()
share_group.consistent_snapshot_support = css
snap_dict = {'share_group': share_group}
fallback_create = mock.Mock()
mock_create_cg_from_snapshot = self.mock_object(
self.library, 'create_consistency_group_from_cgsnapshot')
self.library.create_group_from_snapshot(self.context, share_group,
snap_dict, fallback_create,
share_server=fake.SHARE_SERVER)
mock_create_cg_from_snapshot.assert_not_called()
fallback_create.assert_called_once_with(self.context, share_group,
snap_dict,
share_server=fake.SHARE_SERVER)

13
manila/tests/share/drivers/netapp/dataontap/fakes.py

@ -385,7 +385,7 @@ SHARE_FOR_CG1 = {
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
'name': 'share_1',
'share_proto': 'NFS',
'source_cgsnapshot_member_id': None,
'source_share_group_snapshot_member_id': None,
}
SHARE_FOR_CG2 = {
@ -394,7 +394,7 @@ SHARE_FOR_CG2 = {
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
'name': 'share_2',
'share_proto': 'NFS',
'source_cgsnapshot_member_id': None,
'source_share_group_snapshot_member_id': None,
}
# Clone dest of SHARE_FOR_CG1
@ -404,7 +404,7 @@ SHARE_FOR_CG3 = {
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
'name': 'share3',
'share_proto': 'NFS',
'source_cgsnapshot_member_id': CG_SNAPSHOT_MEMBER_ID1,
'source_share_group_snapshot_member_id': CG_SNAPSHOT_MEMBER_ID1,
}
# Clone dest of SHARE_FOR_CG2
@ -414,7 +414,7 @@ SHARE_FOR_CG4 = {
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
'name': 'share4',
'share_proto': 'NFS',
'source_cgsnapshot_member_id': CG_SNAPSHOT_MEMBER_ID2,
'source_share_group_snapshot_member_id': CG_SNAPSHOT_MEMBER_ID2,
}
EMPTY_CONSISTENCY_GROUP = {
@ -462,9 +462,10 @@ CG_SNAPSHOT_MEMBER_2 = {
}
CG_SNAPSHOT = {
'cgsnapshot_members': [CG_SNAPSHOT_MEMBER_1, CG_SNAPSHOT_MEMBER_2],
'share_group_snapshot_members': [CG_SNAPSHOT_MEMBER_1,
CG_SNAPSHOT_MEMBER_2],
'share_group': CONSISTENCY_GROUP,
'consistency_group_id': CONSISTENCY_GROUP_ID,
'share_group_id': CONSISTENCY_GROUP_ID,
'id': CG_SNAPSHOT_ID,
'project_id': TENANT_ID,
}

5
releasenotes/notes/bug-1659023-netapp-cg-fix-56bb77b7bc61c3f5.yaml

@ -0,0 +1,5 @@
---
fixes:
- Re-enabled the consistent snapshot code in the NetApp driver, now
compatible with the Manila Share Groups API instead of the deprecated
and removed Manila Consistency Groups API.
Loading…
Cancel
Save