Consistency groups in NetApp cDOT drivers
With the consistency groups feature in Manila core, we can support that in the NetApp cDOT drivers. Note that cDOT does not have a persistent CG concept, so some of the driver methods don't have much to do; the backend merely takes the synchronized snapshots across multiple shares as needed. DocImpact Implements bp: consistency-groups-in-netapp-cdot-drivers Depends-On: Id6e56426b212435366a36122dbeddc52910d9828 Change-Id: I27b707ea8ce34d899d300c9a2b207738effe069a
This commit is contained in:
parent
333474047c
commit
58c82eda2f
@ -1498,6 +1498,32 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||||||
api_args = {'volume': volume_name, 'snapshot': snapshot_name}
|
api_args = {'volume': volume_name, 'snapshot': snapshot_name}
|
||||||
self.send_request('snapshot-delete', api_args)
|
self.send_request('snapshot-delete', api_args)
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def create_cg_snapshot(self, volume_names, snapshot_name):
|
||||||
|
"""Creates a consistency group snapshot of one or more flexvols."""
|
||||||
|
cg_id = self._start_cg_snapshot(volume_names, snapshot_name)
|
||||||
|
if not cg_id:
|
||||||
|
msg = _('Could not start consistency group snapshot %s.')
|
||||||
|
raise exception.NetAppException(msg % snapshot_name)
|
||||||
|
self._commit_cg_snapshot(cg_id)
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def _start_cg_snapshot(self, volume_names, snapshot_name):
|
||||||
|
api_args = {
|
||||||
|
'snapshot': snapshot_name,
|
||||||
|
'timeout': 'relaxed',
|
||||||
|
'volumes': [
|
||||||
|
{'volume-name': volume_name} for volume_name in volume_names
|
||||||
|
],
|
||||||
|
}
|
||||||
|
result = self.send_request('cg-start', api_args)
|
||||||
|
return result.get_child_content('cg-id')
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def _commit_cg_snapshot(self, cg_id):
|
||||||
|
api_args = {'cg-id': cg_id}
|
||||||
|
self.send_request('cg-commit', api_args)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def create_cifs_share(self, share_name):
|
def create_cifs_share(self, share_name):
|
||||||
share_path = '/%s' % share_name
|
share_path = '/%s' % share_name
|
||||||
|
@ -67,6 +67,25 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
|
|||||||
def shrink_share(self, share, new_size, **kwargs):
|
def shrink_share(self, share, new_size, **kwargs):
|
||||||
self.library.shrink_share(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):
|
def ensure_share(self, context, share, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -67,6 +67,25 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
|||||||
def shrink_share(self, share, new_size, **kwargs):
|
def shrink_share(self, share, new_size, **kwargs):
|
||||||
self.library.shrink_share(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):
|
def ensure_share(self, context, share, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -171,17 +171,19 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
housekeeping_periodic_task.start(
|
housekeeping_periodic_task.start(
|
||||||
interval=self.HOUSEKEEPING_INTERVAL_SECONDS, initial_delay=0)
|
interval=self.HOUSEKEEPING_INTERVAL_SECONDS, initial_delay=0)
|
||||||
|
|
||||||
@na_utils.trace
|
|
||||||
def _get_valid_share_name(self, share_id):
|
def _get_valid_share_name(self, share_id):
|
||||||
"""Get share name according to share name template."""
|
"""Get share name according to share name template."""
|
||||||
return self.configuration.netapp_volume_name_template % {
|
return self.configuration.netapp_volume_name_template % {
|
||||||
'share_id': share_id.replace('-', '_')}
|
'share_id': share_id.replace('-', '_')}
|
||||||
|
|
||||||
@na_utils.trace
|
|
||||||
def _get_valid_snapshot_name(self, snapshot_id):
|
def _get_valid_snapshot_name(self, snapshot_id):
|
||||||
"""Get snapshot name according to snapshot name template."""
|
"""Get snapshot name according to snapshot name template."""
|
||||||
return 'share_snapshot_' + snapshot_id.replace('-', '_')
|
return 'share_snapshot_' + snapshot_id.replace('-', '_')
|
||||||
|
|
||||||
|
def _get_valid_cg_snapshot_name(self, snapshot_id):
|
||||||
|
"""Get snapshot name according to snapshot name template."""
|
||||||
|
return 'share_cg_snapshot_' + snapshot_id.replace('-', '_')
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def _get_aggregate_space(self):
|
def _get_aggregate_space(self):
|
||||||
aggregates = self._find_matching_aggregates()
|
aggregates = self._find_matching_aggregates()
|
||||||
@ -203,6 +205,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
'storage_protocol': 'NFS_CIFS',
|
'storage_protocol': 'NFS_CIFS',
|
||||||
'total_capacity_gb': 0.0,
|
'total_capacity_gb': 0.0,
|
||||||
'free_capacity_gb': 0.0,
|
'free_capacity_gb': 0.0,
|
||||||
|
'consistency_group_support': 'host',
|
||||||
'pools': self._get_pools(),
|
'pools': self._get_pools(),
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
@ -503,12 +506,13 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
raise exception.NetAppException(msg % msg_args)
|
raise exception.NetAppException(msg % msg_args)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def _allocate_container_from_snapshot(self, share, snapshot,
|
def _allocate_container_from_snapshot(
|
||||||
vserver_client):
|
self, share, snapshot, vserver_client,
|
||||||
|
snapshot_name_func=_get_valid_snapshot_name):
|
||||||
"""Clones existing share."""
|
"""Clones existing share."""
|
||||||
share_name = self._get_valid_share_name(share['id'])
|
share_name = self._get_valid_share_name(share['id'])
|
||||||
parent_share_name = self._get_valid_share_name(snapshot['share_id'])
|
parent_share_name = self._get_valid_share_name(snapshot['share_id'])
|
||||||
parent_snapshot_name = self._get_valid_snapshot_name(snapshot['id'])
|
parent_snapshot_name = snapshot_name_func(self, snapshot['id'])
|
||||||
|
|
||||||
LOG.debug('Creating share from snapshot %s', snapshot['id'])
|
LOG.debug('Creating share from snapshot %s', snapshot['id'])
|
||||||
vserver_client.create_volume_clone(share_name, parent_share_name,
|
vserver_client.create_volume_clone(share_name, parent_share_name,
|
||||||
@ -747,6 +751,148 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
msg_args = {'volume': volume['name']}
|
msg_args = {'volume': volume['name']}
|
||||||
raise exception.ManageInvalidShare(reason=msg % msg_args)
|
raise exception.ManageInvalidShare(reason=msg % msg_args)
|
||||||
|
|
||||||
|
@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):
|
||||||
|
"""Creates a consistency group from an existing CG snapshot."""
|
||||||
|
vserver, vserver_client = self._get_vserver(share_server=share_server)
|
||||||
|
|
||||||
|
# Ensure there is something to do
|
||||||
|
if not cgsnapshot_dict['cgsnapshot_members']:
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
clone_list = self._collate_cg_snapshot_info(cg_dict, cgsnapshot_dict)
|
||||||
|
share_update_list = []
|
||||||
|
|
||||||
|
LOG.debug('Creating consistency group from CG snapshot %s.',
|
||||||
|
cgsnapshot_dict['id'])
|
||||||
|
|
||||||
|
for clone in clone_list:
|
||||||
|
|
||||||
|
self._allocate_container_from_snapshot(
|
||||||
|
clone['share'], clone['snapshot'], vserver_client,
|
||||||
|
NetAppCmodeFileStorageLibrary._get_valid_cg_snapshot_name)
|
||||||
|
|
||||||
|
export_locations = self._create_export(clone['share'],
|
||||||
|
vserver,
|
||||||
|
vserver_client)
|
||||||
|
share_update_list.append({
|
||||||
|
'id': clone['share']['id'],
|
||||||
|
'export_locations': export_locations,
|
||||||
|
})
|
||||||
|
|
||||||
|
return None, share_update_list
|
||||||
|
|
||||||
|
def _collate_cg_snapshot_info(self, cg_dict, cgsnapshot_dict):
|
||||||
|
"""Collate the data for a clone of a CG snapshot.
|
||||||
|
|
||||||
|
Given two data structures, a CG snapshot (cgsnapshot_dict) and a new
|
||||||
|
CG to be cloned from the snapshot (cg_dict), match up both structures
|
||||||
|
into a list of dicts (share & snapshot) suitable for use by existing
|
||||||
|
driver methods that clone individual share snapshots.
|
||||||
|
"""
|
||||||
|
|
||||||
|
clone_list = list()
|
||||||
|
|
||||||
|
for share in cg_dict['shares']:
|
||||||
|
|
||||||
|
clone_info = {'share': share}
|
||||||
|
|
||||||
|
for cgsnapshot_member in cgsnapshot_dict['cgsnapshot_members']:
|
||||||
|
if (share['source_cgsnapshot_member_id'] ==
|
||||||
|
cgsnapshot_member['id']):
|
||||||
|
clone_info['snapshot'] = {
|
||||||
|
'share_id': cgsnapshot_member['share_id'],
|
||||||
|
'id': cgsnapshot_member['cgsnapshot_id']
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
msg = _("Invalid data supplied for creating consistency group "
|
||||||
|
"from CG snapshot %s.") % cgsnapshot_dict['id']
|
||||||
|
raise exception.InvalidConsistencyGroup(reason=msg)
|
||||||
|
|
||||||
|
clone_list.append(clone_info)
|
||||||
|
|
||||||
|
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(_LW("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_valid_share_name(member['share_id'])
|
||||||
|
for member in snap_dict.get('cgsnapshot_members', [])]
|
||||||
|
snapshot_name = self._get_valid_cg_snapshot_name(snap_dict['id'])
|
||||||
|
|
||||||
|
if share_names:
|
||||||
|
LOG.debug('Creating CG snapshot %s.', snapshot_name)
|
||||||
|
vserver_client.create_cg_snapshot(share_names, snapshot_name)
|
||||||
|
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def delete_cgsnapshot(self, context, snap_dict, share_server=None):
|
||||||
|
"""Deletes a consistency group snapshot."""
|
||||||
|
try:
|
||||||
|
vserver, vserver_client = self._get_vserver(
|
||||||
|
share_server=share_server)
|
||||||
|
except (exception.InvalidInput,
|
||||||
|
exception.VserverNotSpecified,
|
||||||
|
exception.VserverNotFound) as error:
|
||||||
|
LOG.warning(_LW("Could not determine share server for CG snapshot "
|
||||||
|
"being deleted: %(snap)s. Deletion of CG snapshot "
|
||||||
|
"record will proceed anyway. Error: %(error)s"),
|
||||||
|
{'snap': snap_dict['id'], 'error': error})
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
share_names = [self._get_valid_share_name(member['share_id'])
|
||||||
|
for member in snap_dict.get('cgsnapshot_members', [])]
|
||||||
|
snapshot_name = self._get_valid_cg_snapshot_name(snap_dict['id'])
|
||||||
|
|
||||||
|
for share_name in share_names:
|
||||||
|
try:
|
||||||
|
self._handle_busy_snapshot(vserver_client, share_name,
|
||||||
|
snapshot_name)
|
||||||
|
except exception.SnapshotNotFound:
|
||||||
|
LOG.info(_LI("Snapshot %(snap)s does not exist for share "
|
||||||
|
"%(share)s."),
|
||||||
|
{'snap': snapshot_name, 'share': share_name})
|
||||||
|
continue
|
||||||
|
|
||||||
|
LOG.debug("Deleting snapshot %(snap)s for share %(share)s.",
|
||||||
|
{'snap': snapshot_name, 'share': share_name})
|
||||||
|
vserver_client.delete_snapshot(share_name, snapshot_name)
|
||||||
|
|
||||||
|
return None, None
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def extend_share(self, share, new_size, share_server=None):
|
def extend_share(self, share, new_size, share_server=None):
|
||||||
"""Extends size of existing share."""
|
"""Extends size of existing share."""
|
||||||
|
@ -36,7 +36,9 @@ SHARE_AGGREGATE_RAID_TYPES = ('raid4', 'raid_dp')
|
|||||||
SHARE_AGGREGATE_DISK_TYPE = 'FCAL'
|
SHARE_AGGREGATE_DISK_TYPE = 'FCAL'
|
||||||
SHARE_NAME = 'fake_share'
|
SHARE_NAME = 'fake_share'
|
||||||
SHARE_SIZE = '1000000000'
|
SHARE_SIZE = '1000000000'
|
||||||
|
SHARE_NAME_2 = 'fake_share_2'
|
||||||
SNAPSHOT_NAME = 'fake_snapshot'
|
SNAPSHOT_NAME = 'fake_snapshot'
|
||||||
|
CG_SNAPSHOT_ID = 'fake_cg_id'
|
||||||
PARENT_SHARE_NAME = 'fake_parent_share'
|
PARENT_SHARE_NAME = 'fake_parent_share'
|
||||||
PARENT_SNAPSHOT_NAME = 'fake_parent_snapshot'
|
PARENT_SNAPSHOT_NAME = 'fake_parent_snapshot'
|
||||||
MAX_FILES = 5000
|
MAX_FILES = 5000
|
||||||
@ -84,6 +86,10 @@ NO_RECORDS_RESPONSE = etree.XML("""
|
|||||||
</results>
|
</results>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
PASSED_RESPONSE = etree.XML("""
|
||||||
|
<results status="passed" />
|
||||||
|
""")
|
||||||
|
|
||||||
VSERVER_GET_ITER_RESPONSE = etree.XML("""
|
VSERVER_GET_ITER_RESPONSE = etree.XML("""
|
||||||
<results status="passed">
|
<results status="passed">
|
||||||
<attributes-list>
|
<attributes-list>
|
||||||
@ -1170,6 +1176,18 @@ SNAPSHOT_GET_ITER_OTHER_ERROR_RESPONSE = etree.XML("""
|
|||||||
</results>
|
</results>
|
||||||
""" % {'volume': SHARE_NAME, 'vserver': VSERVER_NAME})
|
""" % {'volume': SHARE_NAME, 'vserver': VSERVER_NAME})
|
||||||
|
|
||||||
|
SNAPSHOT_MULTIDELETE_ERROR_RESPONSE = etree.XML("""
|
||||||
|
<results status="passed">
|
||||||
|
<volume-errors>
|
||||||
|
<volume-error>
|
||||||
|
<errno>13021</errno>
|
||||||
|
<name>%(volume)s</name>
|
||||||
|
<reason>No such snapshot.</reason>
|
||||||
|
</volume-error>
|
||||||
|
</volume-errors>
|
||||||
|
</results>
|
||||||
|
""" % {'volume': SHARE_NAME})
|
||||||
|
|
||||||
NFS_EXPORT_RULES = ('10.10.10.10', '10.10.10.20')
|
NFS_EXPORT_RULES = ('10.10.10.10', '10.10.10.20')
|
||||||
|
|
||||||
NFS_EXPORTFS_LIST_RULES_2_NO_RULES_RESPONSE = etree.XML("""
|
NFS_EXPORTFS_LIST_RULES_2_NO_RULES_RESPONSE = etree.XML("""
|
||||||
|
@ -2631,6 +2631,67 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
self.client.send_request.assert_has_calls([
|
self.client.send_request.assert_has_calls([
|
||||||
mock.call('snapshot-delete', snapshot_delete_args)])
|
mock.call('snapshot-delete', snapshot_delete_args)])
|
||||||
|
|
||||||
|
def test_create_cg_snapshot(self):
|
||||||
|
|
||||||
|
mock_start_cg_snapshot = self.mock_object(
|
||||||
|
self.client, '_start_cg_snapshot',
|
||||||
|
mock.Mock(return_value=fake.CG_SNAPSHOT_ID))
|
||||||
|
mock_commit_cg_snapshot = self.mock_object(
|
||||||
|
self.client, '_commit_cg_snapshot')
|
||||||
|
|
||||||
|
self.client.create_cg_snapshot([fake.SHARE_NAME, fake.SHARE_NAME_2],
|
||||||
|
fake.SNAPSHOT_NAME)
|
||||||
|
|
||||||
|
mock_start_cg_snapshot.assert_called_once_with(
|
||||||
|
[fake.SHARE_NAME, fake.SHARE_NAME_2], fake.SNAPSHOT_NAME)
|
||||||
|
mock_commit_cg_snapshot.assert_called_once_with(fake.CG_SNAPSHOT_ID)
|
||||||
|
|
||||||
|
def test_create_cg_snapshot_no_id(self):
|
||||||
|
|
||||||
|
mock_start_cg_snapshot = self.mock_object(
|
||||||
|
self.client, '_start_cg_snapshot', mock.Mock(return_value=None))
|
||||||
|
mock_commit_cg_snapshot = self.mock_object(
|
||||||
|
self.client, '_commit_cg_snapshot')
|
||||||
|
|
||||||
|
self.assertRaises(exception.NetAppException,
|
||||||
|
self.client.create_cg_snapshot,
|
||||||
|
[fake.SHARE_NAME, fake.SHARE_NAME_2],
|
||||||
|
fake.SNAPSHOT_NAME)
|
||||||
|
|
||||||
|
mock_start_cg_snapshot.assert_called_once_with(
|
||||||
|
[fake.SHARE_NAME, fake.SHARE_NAME_2], fake.SNAPSHOT_NAME)
|
||||||
|
self.assertFalse(mock_commit_cg_snapshot.called)
|
||||||
|
|
||||||
|
def test_start_cg_snapshot(self):
|
||||||
|
|
||||||
|
self.mock_object(self.client, 'send_request')
|
||||||
|
|
||||||
|
self.client._start_cg_snapshot([fake.SHARE_NAME, fake.SHARE_NAME_2],
|
||||||
|
fake.SNAPSHOT_NAME)
|
||||||
|
|
||||||
|
cg_start_args = {
|
||||||
|
'snapshot': fake.SNAPSHOT_NAME,
|
||||||
|
'timeout': 'relaxed',
|
||||||
|
'volumes': [
|
||||||
|
{'volume-name': fake.SHARE_NAME},
|
||||||
|
{'volume-name': fake.SHARE_NAME_2},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
self.client.send_request.assert_has_calls([
|
||||||
|
mock.call('cg-start', cg_start_args)])
|
||||||
|
|
||||||
|
def test_commit_cg_snapshot(self):
|
||||||
|
|
||||||
|
self.mock_object(self.client, 'send_request')
|
||||||
|
|
||||||
|
self.client._commit_cg_snapshot(fake.CG_SNAPSHOT_ID)
|
||||||
|
|
||||||
|
cg_commit_args = {'cg-id': fake.CG_SNAPSHOT_ID}
|
||||||
|
|
||||||
|
self.client.send_request.assert_has_calls([
|
||||||
|
mock.call('cg-commit', cg_commit_args)])
|
||||||
|
|
||||||
def test_create_cifs_share(self):
|
def test_create_cifs_share(self):
|
||||||
|
|
||||||
self.mock_object(self.client, 'send_request')
|
self.mock_object(self.client, 'send_request')
|
||||||
|
@ -301,6 +301,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
'storage_protocol': 'NFS_CIFS',
|
'storage_protocol': 'NFS_CIFS',
|
||||||
'total_capacity_gb': 0.0,
|
'total_capacity_gb': 0.0,
|
||||||
'free_capacity_gb': 0.0,
|
'free_capacity_gb': 0.0,
|
||||||
|
'consistency_group_support': 'host',
|
||||||
'pools': fake.POOLS,
|
'pools': fake.POOLS,
|
||||||
}
|
}
|
||||||
self.assertDictEqual(expected, result)
|
self.assertDictEqual(expected, result)
|
||||||
@ -1334,6 +1335,324 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
fake.FLEXVOL_TO_MANAGE,
|
fake.FLEXVOL_TO_MANAGE,
|
||||||
vserver_client)
|
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()
|
||||||
|
mock_get_vserver = self.mock_object(
|
||||||
|
self.library, '_get_vserver',
|
||||||
|
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
|
||||||
|
mock_allocate_container_from_snapshot = self.mock_object(
|
||||||
|
self.library, '_allocate_container_from_snapshot')
|
||||||
|
mock_create_export = self.mock_object(
|
||||||
|
self.library, '_create_export',
|
||||||
|
mock.Mock(side_effect=[['loc3'], ['loc4']]))
|
||||||
|
|
||||||
|
result = self.library.create_consistency_group_from_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake.CONSISTENCY_GROUP_DEST,
|
||||||
|
fake.CG_SNAPSHOT,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
share_update_list = [
|
||||||
|
{'id': fake.SHARE_ID3, 'export_locations': ['loc3']},
|
||||||
|
{'id': fake.SHARE_ID4, 'export_locations': ['loc4']}
|
||||||
|
]
|
||||||
|
expected = (None, share_update_list)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
mock_allocate_container_from_snapshot.assert_has_calls([
|
||||||
|
mock.call(fake.COLLATED_CGSNAPSHOT_INFO[0]['share'],
|
||||||
|
fake.COLLATED_CGSNAPSHOT_INFO[0]['snapshot'],
|
||||||
|
vserver_client,
|
||||||
|
mock.ANY),
|
||||||
|
mock.call(fake.COLLATED_CGSNAPSHOT_INFO[1]['share'],
|
||||||
|
fake.COLLATED_CGSNAPSHOT_INFO[1]['snapshot'],
|
||||||
|
vserver_client,
|
||||||
|
mock.ANY),
|
||||||
|
])
|
||||||
|
mock_create_export.assert_has_calls([
|
||||||
|
mock.call(fake.COLLATED_CGSNAPSHOT_INFO[0]['share'],
|
||||||
|
fake.VSERVER1,
|
||||||
|
vserver_client),
|
||||||
|
mock.call(fake.COLLATED_CGSNAPSHOT_INFO[1]['share'],
|
||||||
|
fake.VSERVER1,
|
||||||
|
vserver_client),
|
||||||
|
])
|
||||||
|
mock_get_vserver.assert_called_once_with(
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
def test_create_consistency_group_from_cgsnapshot_no_members(self):
|
||||||
|
|
||||||
|
vserver_client = mock.Mock()
|
||||||
|
mock_get_vserver = self.mock_object(
|
||||||
|
self.library, '_get_vserver',
|
||||||
|
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
|
||||||
|
mock_allocate_container_from_snapshot = self.mock_object(
|
||||||
|
self.library, '_allocate_container_from_snapshot')
|
||||||
|
mock_create_export = self.mock_object(
|
||||||
|
self.library, '_create_export',
|
||||||
|
mock.Mock(side_effect=[['loc3'], ['loc4']]))
|
||||||
|
|
||||||
|
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
|
||||||
|
fake_cg_snapshot['cgsnapshot_members'] = []
|
||||||
|
|
||||||
|
result = self.library.create_consistency_group_from_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake.CONSISTENCY_GROUP_DEST,
|
||||||
|
fake_cg_snapshot,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
self.assertEqual((None, None), result)
|
||||||
|
|
||||||
|
self.assertFalse(mock_allocate_container_from_snapshot.called)
|
||||||
|
self.assertFalse(mock_create_export.called)
|
||||||
|
mock_get_vserver.assert_called_once_with(
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
def test_collate_cg_snapshot_info(self):
|
||||||
|
|
||||||
|
result = self.library._collate_cg_snapshot_info(
|
||||||
|
fake.CONSISTENCY_GROUP_DEST, fake.CG_SNAPSHOT)
|
||||||
|
|
||||||
|
self.assertEqual(fake.COLLATED_CGSNAPSHOT_INFO, result)
|
||||||
|
|
||||||
|
def test_collate_cg_snapshot_info_invalid(self):
|
||||||
|
|
||||||
|
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
|
||||||
|
fake_cg_snapshot['cgsnapshot_members'] = []
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidConsistencyGroup,
|
||||||
|
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()
|
||||||
|
mock_get_vserver = self.mock_object(
|
||||||
|
self.library, '_get_vserver',
|
||||||
|
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
|
||||||
|
|
||||||
|
result = self.library.create_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake.CG_SNAPSHOT,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
share_names = [
|
||||||
|
self.library._get_valid_share_name(
|
||||||
|
fake.CG_SNAPSHOT_MEMBER_1['share_id']),
|
||||||
|
self.library._get_valid_share_name(
|
||||||
|
fake.CG_SNAPSHOT_MEMBER_2['share_id'])
|
||||||
|
]
|
||||||
|
snapshot_name = self.library._get_valid_cg_snapshot_name(
|
||||||
|
fake.CG_SNAPSHOT['id'])
|
||||||
|
vserver_client.create_cg_snapshot.assert_called_once_with(
|
||||||
|
share_names, snapshot_name)
|
||||||
|
self.assertEqual((None, None), result)
|
||||||
|
mock_get_vserver.assert_called_once_with(
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
def test_create_cgsnapshot_no_members(self):
|
||||||
|
|
||||||
|
vserver_client = mock.Mock()
|
||||||
|
mock_get_vserver = self.mock_object(
|
||||||
|
self.library, '_get_vserver',
|
||||||
|
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
|
||||||
|
|
||||||
|
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
|
||||||
|
fake_cg_snapshot['cgsnapshot_members'] = []
|
||||||
|
|
||||||
|
result = self.library.create_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake_cg_snapshot,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
self.assertFalse(vserver_client.create_cg_snapshot.called)
|
||||||
|
self.assertEqual((None, None), result)
|
||||||
|
mock_get_vserver.assert_called_once_with(
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
def test_delete_cgsnapshot(self):
|
||||||
|
|
||||||
|
vserver_client = mock.Mock()
|
||||||
|
mock_get_vserver = self.mock_object(
|
||||||
|
self.library, '_get_vserver',
|
||||||
|
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
|
||||||
|
mock_handle_busy_snapshot = self.mock_object(self.library,
|
||||||
|
'_handle_busy_snapshot')
|
||||||
|
|
||||||
|
result = self.library.delete_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake.CG_SNAPSHOT,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
share_names = [
|
||||||
|
self.library._get_valid_share_name(
|
||||||
|
fake.CG_SNAPSHOT_MEMBER_1['share_id']),
|
||||||
|
self.library._get_valid_share_name(
|
||||||
|
fake.CG_SNAPSHOT_MEMBER_2['share_id'])
|
||||||
|
]
|
||||||
|
snapshot_name = self.library._get_valid_cg_snapshot_name(
|
||||||
|
fake.CG_SNAPSHOT['id'])
|
||||||
|
|
||||||
|
mock_handle_busy_snapshot.assert_has_calls([
|
||||||
|
mock.call(vserver_client, share_names[0], snapshot_name),
|
||||||
|
mock.call(vserver_client, share_names[1], snapshot_name)
|
||||||
|
])
|
||||||
|
vserver_client.delete_snapshot.assert_has_calls([
|
||||||
|
mock.call(share_names[0], snapshot_name),
|
||||||
|
mock.call(share_names[1], snapshot_name)
|
||||||
|
])
|
||||||
|
self.assertEqual((None, None), result)
|
||||||
|
mock_get_vserver.assert_called_once_with(
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
def test_delete_cgsnapshot_no_members(self):
|
||||||
|
|
||||||
|
vserver_client = mock.Mock()
|
||||||
|
mock_get_vserver = self.mock_object(
|
||||||
|
self.library, '_get_vserver',
|
||||||
|
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
|
||||||
|
mock_handle_busy_snapshot = self.mock_object(self.library,
|
||||||
|
'_handle_busy_snapshot')
|
||||||
|
|
||||||
|
fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
|
||||||
|
fake_cg_snapshot['cgsnapshot_members'] = []
|
||||||
|
|
||||||
|
result = self.library.delete_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake_cg_snapshot,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
self.assertFalse(mock_handle_busy_snapshot.called)
|
||||||
|
self.assertFalse(vserver_client.delete_snapshot.called)
|
||||||
|
self.assertEqual((None, None), result)
|
||||||
|
mock_get_vserver.assert_called_once_with(
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
def test_delete_cgsnapshot_snapshots_not_found(self):
|
||||||
|
|
||||||
|
vserver_client = mock.Mock()
|
||||||
|
mock_get_vserver = self.mock_object(
|
||||||
|
self.library, '_get_vserver',
|
||||||
|
mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
|
||||||
|
mock_handle_busy_snapshot = self.mock_object(
|
||||||
|
self.library,
|
||||||
|
'_handle_busy_snapshot',
|
||||||
|
mock.Mock(side_effect=exception.SnapshotNotFound(name='fake')))
|
||||||
|
|
||||||
|
result = self.library.delete_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake.CG_SNAPSHOT,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
share_names = [
|
||||||
|
self.library._get_valid_share_name(
|
||||||
|
fake.CG_SNAPSHOT_MEMBER_1['share_id']),
|
||||||
|
self.library._get_valid_share_name(
|
||||||
|
fake.CG_SNAPSHOT_MEMBER_2['share_id'])
|
||||||
|
]
|
||||||
|
snapshot_name = self.library._get_valid_cg_snapshot_name(
|
||||||
|
fake.CG_SNAPSHOT['id'])
|
||||||
|
|
||||||
|
mock_handle_busy_snapshot.assert_has_calls([
|
||||||
|
mock.call(vserver_client, share_names[0], snapshot_name),
|
||||||
|
mock.call(vserver_client, share_names[1], snapshot_name)
|
||||||
|
])
|
||||||
|
self.assertFalse(vserver_client.delete_snapshot.called)
|
||||||
|
self.assertEqual((None, None), 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_cgsnapshot_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_cgsnapshot(
|
||||||
|
self.context,
|
||||||
|
fake.EMPTY_CONSISTENCY_GROUP,
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
|
self.assertEqual((None, None), result)
|
||||||
|
self.assertEqual(1, lib_base.LOG.warning.call_count)
|
||||||
|
mock_get_vserver.assert_called_once_with(
|
||||||
|
share_server=fake.SHARE_SERVER)
|
||||||
|
|
||||||
def test_extend_share(self):
|
def test_extend_share(self):
|
||||||
|
|
||||||
vserver_client = mock.Mock()
|
vserver_client = mock.Mock()
|
||||||
|
@ -35,11 +35,20 @@ FLEXVOL_NAME = 'fake_volume'
|
|||||||
JUNCTION_PATH = '/%s' % FLEXVOL_NAME
|
JUNCTION_PATH = '/%s' % FLEXVOL_NAME
|
||||||
EXPORT_LOCATION = '%s:%s' % (HOST_NAME, JUNCTION_PATH)
|
EXPORT_LOCATION = '%s:%s' % (HOST_NAME, JUNCTION_PATH)
|
||||||
SNAPSHOT_NAME = 'fake_snapshot'
|
SNAPSHOT_NAME = 'fake_snapshot'
|
||||||
|
CONSISTENCY_GROUP_NAME = 'fake_consistency_group'
|
||||||
SHARE_SIZE = 10
|
SHARE_SIZE = 10
|
||||||
TENANT_ID = '24cb2448-13d8-4f41-afd9-eff5c4fd2a57'
|
TENANT_ID = '24cb2448-13d8-4f41-afd9-eff5c4fd2a57'
|
||||||
SHARE_ID = '7cf7c200-d3af-4e05-b87e-9167c95dfcad'
|
SHARE_ID = '7cf7c200-d3af-4e05-b87e-9167c95dfcad'
|
||||||
|
SHARE_ID2 = 'b51c5a31-aa5b-4254-9ee8-7d39fa4c8c38'
|
||||||
|
SHARE_ID3 = '1379991d-037b-4897-bf3a-81b4aac72eff'
|
||||||
|
SHARE_ID4 = '1cb41aad-fd9b-4964-8059-646f69de925e'
|
||||||
PARENT_SHARE_ID = '585c3935-2aa9-437c-8bad-5abae1076555'
|
PARENT_SHARE_ID = '585c3935-2aa9-437c-8bad-5abae1076555'
|
||||||
SNAPSHOT_ID = 'de4c9050-e2f9-4ce1-ade4-5ed0c9f26451'
|
SNAPSHOT_ID = 'de4c9050-e2f9-4ce1-ade4-5ed0c9f26451'
|
||||||
|
CONSISTENCY_GROUP_ID = '65bfa2c9-dc6c-4513-951a-b8d15b453ad8'
|
||||||
|
CONSISTENCY_GROUP_ID2 = '35f5c1ea-45fb-40c4-98ae-2a2a17554159'
|
||||||
|
CG_SNAPSHOT_ID = '6ddd8a6b-5df7-417b-a2ae-3f6e449f4eea'
|
||||||
|
CG_SNAPSHOT_MEMBER_ID1 = '629f79ef-b27e-4596-9737-30f084e5ba29'
|
||||||
|
CG_SNAPSHOT_MEMBER_ID2 = 'e876aa9c-a322-4391-bd88-9266178262be'
|
||||||
FREE_CAPACITY = 10000000000
|
FREE_CAPACITY = 10000000000
|
||||||
TOTAL_CAPACITY = 20000000000
|
TOTAL_CAPACITY = 20000000000
|
||||||
AGGREGATES = ('manila_aggr_1', 'manila_aggr_2')
|
AGGREGATES = ('manila_aggr_1', 'manila_aggr_2')
|
||||||
@ -224,6 +233,113 @@ CDOT_SNAPSHOT_BUSY_VOLUME_CLONE = {
|
|||||||
'owners': {'volume clone'},
|
'owners': {'volume clone'},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHARE_FOR_CG1 = {
|
||||||
|
'id': SHARE_ID,
|
||||||
|
'host': '%(host)s@%(backend)s#%(pool)s' % {
|
||||||
|
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
|
||||||
|
'name': 'share1',
|
||||||
|
'share_proto': 'NFS',
|
||||||
|
'source_cgsnapshot_member_id': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
SHARE_FOR_CG2 = {
|
||||||
|
'id': SHARE_ID2,
|
||||||
|
'host': '%(host)s@%(backend)s#%(pool)s' % {
|
||||||
|
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
|
||||||
|
'name': 'share2',
|
||||||
|
'share_proto': 'NFS',
|
||||||
|
'source_cgsnapshot_member_id': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clone dest of SHARE_FOR_CG1
|
||||||
|
SHARE_FOR_CG3 = {
|
||||||
|
'id': SHARE_ID3,
|
||||||
|
'host': '%(host)s@%(backend)s#%(pool)s' % {
|
||||||
|
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
|
||||||
|
'name': 'share3',
|
||||||
|
'share_proto': 'NFS',
|
||||||
|
'source_cgsnapshot_member_id': CG_SNAPSHOT_MEMBER_ID1,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clone dest of SHARE_FOR_CG2
|
||||||
|
SHARE_FOR_CG4 = {
|
||||||
|
'id': SHARE_ID4,
|
||||||
|
'host': '%(host)s@%(backend)s#%(pool)s' % {
|
||||||
|
'host': HOST_NAME, 'backend': BACKEND_NAME, 'pool': POOL_NAME},
|
||||||
|
'name': 'share4',
|
||||||
|
'share_proto': 'NFS',
|
||||||
|
'source_cgsnapshot_member_id': CG_SNAPSHOT_MEMBER_ID2,
|
||||||
|
}
|
||||||
|
|
||||||
|
EMPTY_CONSISTENCY_GROUP = {
|
||||||
|
'cgsnapshots': [],
|
||||||
|
'description': 'fake description',
|
||||||
|
'host': '%(host)s@%(backend)s' % {
|
||||||
|
'host': HOST_NAME, 'backend': BACKEND_NAME},
|
||||||
|
'id': CONSISTENCY_GROUP_ID,
|
||||||
|
'name': CONSISTENCY_GROUP_NAME,
|
||||||
|
'shares': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSISTENCY_GROUP = {
|
||||||
|
'cgsnapshots': [],
|
||||||
|
'description': 'fake description',
|
||||||
|
'host': '%(host)s@%(backend)s' % {
|
||||||
|
'host': HOST_NAME, 'backend': BACKEND_NAME},
|
||||||
|
'id': CONSISTENCY_GROUP_ID,
|
||||||
|
'name': CONSISTENCY_GROUP_NAME,
|
||||||
|
'shares': [SHARE_FOR_CG1, SHARE_FOR_CG2],
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSISTENCY_GROUP_DEST = {
|
||||||
|
'cgsnapshots': [],
|
||||||
|
'description': 'fake description',
|
||||||
|
'host': '%(host)s@%(backend)s' % {
|
||||||
|
'host': HOST_NAME, 'backend': BACKEND_NAME},
|
||||||
|
'id': CONSISTENCY_GROUP_ID,
|
||||||
|
'name': CONSISTENCY_GROUP_NAME,
|
||||||
|
'shares': [SHARE_FOR_CG3, SHARE_FOR_CG4],
|
||||||
|
}
|
||||||
|
|
||||||
|
CG_SNAPSHOT_MEMBER_1 = {
|
||||||
|
'cgsnapshot_id': CG_SNAPSHOT_ID,
|
||||||
|
'id': CG_SNAPSHOT_MEMBER_ID1,
|
||||||
|
'share_id': SHARE_ID,
|
||||||
|
'share_proto': 'NFS',
|
||||||
|
}
|
||||||
|
|
||||||
|
CG_SNAPSHOT_MEMBER_2 = {
|
||||||
|
'cgsnapshot_id': CG_SNAPSHOT_ID,
|
||||||
|
'id': CG_SNAPSHOT_MEMBER_ID2,
|
||||||
|
'share_id': SHARE_ID2,
|
||||||
|
'share_proto': 'NFS',
|
||||||
|
}
|
||||||
|
|
||||||
|
CG_SNAPSHOT = {
|
||||||
|
'cgsnapshot_members': [CG_SNAPSHOT_MEMBER_1, CG_SNAPSHOT_MEMBER_2],
|
||||||
|
'consistency_group': CONSISTENCY_GROUP,
|
||||||
|
'consistency_group_id': CONSISTENCY_GROUP_ID,
|
||||||
|
'id': CG_SNAPSHOT_ID,
|
||||||
|
'project_id': TENANT_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
COLLATED_CGSNAPSHOT_INFO = [
|
||||||
|
{
|
||||||
|
'share': SHARE_FOR_CG3,
|
||||||
|
'snapshot': {
|
||||||
|
'share_id': SHARE_ID,
|
||||||
|
'id': CG_SNAPSHOT_ID
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'share': SHARE_FOR_CG4,
|
||||||
|
'snapshot': {
|
||||||
|
'share_id': SHARE_ID2,
|
||||||
|
'id': CG_SNAPSHOT_ID
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
LIF_NAMES = []
|
LIF_NAMES = []
|
||||||
LIF_ADDRESSES = ['10.10.10.10', '10.10.10.20']
|
LIF_ADDRESSES = ['10.10.10.10', '10.10.10.20']
|
||||||
LIFS = (
|
LIFS = (
|
||||||
|
Loading…
Reference in New Issue
Block a user