NetApp cDOT: Handle replicated snapshots
This patch implements the following driver methods required for replicated snapshots to be handled correctly. create_replicated_snapshot delete_replicated_snapshot update_replicated_snapshot Closes-Bug: #1557071 Related-Bug: #1546303 Change-Id: Ia4cd2a36e31418e7a3d1c218080caa632755fe16
This commit is contained in:
parent
94e04c8de2
commit
430a18b50c
|
@ -1769,6 +1769,56 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||
api_args = {'volume': volume_name, 'snapshot': snapshot_name}
|
||||
self.send_request('snapshot-create', api_args)
|
||||
|
||||
@na_utils.trace
|
||||
def snapshot_exists(self, snapshot_name, volume_name):
|
||||
"""Checks if Snapshot exists for a specified volume."""
|
||||
LOG.debug('Checking if snapshot %(snapshot)s exists for '
|
||||
'volume %(volume)s',
|
||||
{'snapshot': snapshot_name, 'volume': volume_name})
|
||||
|
||||
"""Gets a single snapshot."""
|
||||
api_args = {
|
||||
'query': {
|
||||
'snapshot-info': {
|
||||
'name': snapshot_name,
|
||||
'volume': volume_name,
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'snapshot-info': {
|
||||
'name': None,
|
||||
'volume': None,
|
||||
'busy': None,
|
||||
'snapshot-owners-list': {
|
||||
'snapshot-owner': None,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
result = self.send_request('snapshot-get-iter', api_args)
|
||||
|
||||
error_record_list = result.get_child_by_name(
|
||||
'volume-errors') or netapp_api.NaElement('none')
|
||||
errors = error_record_list.get_children()
|
||||
|
||||
if errors:
|
||||
error = errors[0]
|
||||
error_code = error.get_child_content('errno')
|
||||
error_reason = error.get_child_content('reason')
|
||||
msg = _('Could not read information for snapshot %(name)s. '
|
||||
'Code: %(code)s. Reason: %(reason)s')
|
||||
msg_args = {
|
||||
'name': snapshot_name,
|
||||
'code': error_code,
|
||||
'reason': error_reason
|
||||
}
|
||||
if error_code == netapp_api.ESNAPSHOTNOTALLOWED:
|
||||
raise exception.SnapshotUnavailable(msg % msg_args)
|
||||
else:
|
||||
raise exception.NetAppException(msg % msg_args)
|
||||
|
||||
return self._has_records(result)
|
||||
|
||||
@na_utils.trace
|
||||
def get_snapshot(self, volume_name, snapshot_name):
|
||||
"""Gets a single snapshot."""
|
||||
|
|
|
@ -137,3 +137,16 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
|
|||
access_rules, replica_snapshots,
|
||||
share_server=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_replicated_snapshot(self, context, replica_list,
|
||||
replica_snapshots, share_server=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete_replicated_snapshot(self, context, replica_list,
|
||||
replica_snapshots, share_server=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def update_replicated_snapshot(self, context, replica_list,
|
||||
share_replica, replica_snapshots,
|
||||
replica_snapshot, share_server=None):
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -53,7 +53,7 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
|||
snapshot, **kwargs)
|
||||
|
||||
def create_snapshot(self, context, snapshot, **kwargs):
|
||||
self.library.create_snapshot(context, snapshot, **kwargs)
|
||||
return self.library.create_snapshot(context, snapshot, **kwargs)
|
||||
|
||||
def delete_share(self, context, share, **kwargs):
|
||||
self.library.delete_share(context, share, **kwargs)
|
||||
|
@ -123,11 +123,13 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
|||
def create_replica(self, context, replica_list, replica, access_rules,
|
||||
replica_snapshots, **kwargs):
|
||||
return self.library.create_replica(context, replica_list, replica,
|
||||
access_rules, **kwargs)
|
||||
access_rules, replica_snapshots,
|
||||
**kwargs)
|
||||
|
||||
def delete_replica(self, context, replica_list, replica_snapshots, replica,
|
||||
**kwargs):
|
||||
self.library.delete_replica(context, replica_list, replica, **kwargs)
|
||||
self.library.delete_replica(context, replica_list, replica,
|
||||
replica_snapshots, **kwargs)
|
||||
|
||||
def promote_replica(self, context, replica_list, replica, access_rules,
|
||||
share_server=None):
|
||||
|
@ -142,4 +144,24 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
|||
replica_list,
|
||||
replica,
|
||||
access_rules,
|
||||
replica_snapshots,
|
||||
share_server=share_server)
|
||||
|
||||
def create_replicated_snapshot(self, context, replica_list,
|
||||
replica_snapshots, share_server=None):
|
||||
return self.library.create_replicated_snapshot(
|
||||
context, replica_list, replica_snapshots,
|
||||
share_server=share_server)
|
||||
|
||||
def delete_replicated_snapshot(self, context, replica_list,
|
||||
replica_snapshots, share_server=None):
|
||||
return self.library.delete_replicated_snapshot(
|
||||
context, replica_list, replica_snapshots,
|
||||
share_server=share_server)
|
||||
|
||||
def update_replicated_snapshot(self, context, replica_list,
|
||||
share_replica, replica_snapshots,
|
||||
replica_snapshot, share_server=None):
|
||||
return self.library.update_replicated_snapshot(
|
||||
replica_list, share_replica, replica_snapshots, replica_snapshot,
|
||||
share_server=share_server)
|
||||
|
|
|
@ -562,8 +562,10 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
"""Clones existing share."""
|
||||
share_name = self._get_backend_share_name(share['id'])
|
||||
parent_share_name = self._get_backend_share_name(snapshot['share_id'])
|
||||
parent_snapshot_name = snapshot_name_func(self, snapshot['id'])
|
||||
|
||||
if snapshot.get('provider_location') is None:
|
||||
parent_snapshot_name = snapshot_name_func(self, snapshot['id'])
|
||||
else:
|
||||
parent_snapshot_name = snapshot['provider_location']
|
||||
LOG.debug('Creating share from snapshot %s', snapshot['id'])
|
||||
vserver_client.create_volume_clone(share_name, parent_share_name,
|
||||
parent_snapshot_name)
|
||||
|
@ -713,9 +715,11 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
snapshot_name = self._get_backend_snapshot_name(snapshot['id'])
|
||||
LOG.debug('Creating snapshot %s', snapshot_name)
|
||||
vserver_client.create_snapshot(share_name, snapshot_name)
|
||||
return {'provider_location': snapshot_name}
|
||||
|
||||
@na_utils.trace
|
||||
def delete_snapshot(self, context, snapshot, share_server=None):
|
||||
def delete_snapshot(self, context, snapshot, share_server=None,
|
||||
snapshot_name=None):
|
||||
"""Deletes a snapshot of a share."""
|
||||
try:
|
||||
vserver, vserver_client = self._get_vserver(
|
||||
|
@ -730,7 +734,8 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
return
|
||||
|
||||
share_name = self._get_backend_share_name(snapshot['share_id'])
|
||||
snapshot_name = self._get_backend_snapshot_name(snapshot['id'])
|
||||
snapshot_name = (snapshot.get('provider_location') or snapshot_name or
|
||||
self._get_backend_snapshot_name(snapshot['id']))
|
||||
|
||||
try:
|
||||
self._delete_snapshot(vserver_client, share_name, snapshot_name)
|
||||
|
@ -1111,7 +1116,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
return r
|
||||
|
||||
def create_replica(self, context, replica_list, new_replica,
|
||||
access_rules=None, share_server=None):
|
||||
access_rules, share_snapshots, share_server=None):
|
||||
"""Creates the new replica on this backend and sets up SnapMirror."""
|
||||
active_replica = self._find_active_replica(replica_list)
|
||||
dm_session = data_motion.DataMotionSession()
|
||||
|
@ -1139,7 +1144,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
|
||||
return model_update
|
||||
|
||||
def delete_replica(self, context, replica_list, replica,
|
||||
def delete_replica(self, context, replica_list, replica, share_snapshots,
|
||||
share_server=None):
|
||||
"""Removes the replica on this backend and destroys SnapMirror."""
|
||||
dm_session = data_motion.DataMotionSession()
|
||||
|
@ -1163,7 +1168,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
self._deallocate_container(share_name, vserver_client)
|
||||
|
||||
def update_replica_state(self, context, replica_list, replica,
|
||||
access_rules, share_server=None):
|
||||
access_rules, share_snapshots, share_server=None):
|
||||
"""Returns the status of the given replica on this backend."""
|
||||
active_replica = self._find_active_replica(replica_list)
|
||||
|
||||
|
@ -1225,6 +1230,14 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
3600))):
|
||||
return constants.REPLICA_STATE_OUT_OF_SYNC
|
||||
|
||||
# Check all snapshots exist
|
||||
snapshots = [snap['share_replica_snapshot']
|
||||
for snap in share_snapshots]
|
||||
for snap in snapshots:
|
||||
snapshot_name = snap.get('provider_location')
|
||||
if not vserver_client.snapshot_exists(snapshot_name, share_name):
|
||||
return constants.REPLICA_STATE_OUT_OF_SYNC
|
||||
|
||||
return constants.REPLICA_STATE_IN_SYNC
|
||||
|
||||
def promote_replica(self, context, replica_list, replica, access_rules,
|
||||
|
@ -1364,3 +1377,105 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||
replica['export_locations'] = []
|
||||
|
||||
return replica
|
||||
|
||||
def create_replicated_snapshot(self, context, replica_list,
|
||||
snapshot_instances, share_server=None):
|
||||
active_replica = self._find_active_replica(replica_list)
|
||||
active_snapshot = [x for x in snapshot_instances
|
||||
if x['share_id'] == active_replica['id']][0]
|
||||
snapshot_name = self._get_backend_snapshot_name(active_snapshot['id'])
|
||||
|
||||
self.create_snapshot(context, active_snapshot,
|
||||
share_server=share_server)
|
||||
|
||||
active_snapshot['status'] = constants.STATUS_AVAILABLE
|
||||
active_snapshot['provider_location'] = snapshot_name
|
||||
snapshots = [active_snapshot]
|
||||
instances = zip(sorted(replica_list,
|
||||
key=lambda x: x['id']),
|
||||
sorted(snapshot_instances,
|
||||
key=lambda x: x['share_id']))
|
||||
|
||||
for replica, snapshot in instances:
|
||||
if snapshot['id'] != active_snapshot['id']:
|
||||
snapshot['provider_location'] = snapshot_name
|
||||
snapshots.append(snapshot)
|
||||
dm_session = data_motion.DataMotionSession()
|
||||
if replica.get('host'):
|
||||
try:
|
||||
dm_session.update_snapmirror(active_replica,
|
||||
replica)
|
||||
except netapp_api.NaApiError as e:
|
||||
if e.code != netapp_api.EOBJECTNOTFOUND:
|
||||
raise
|
||||
return snapshots
|
||||
|
||||
def delete_replicated_snapshot(self, context, replica_list,
|
||||
snapshot_instances, share_server=None):
|
||||
active_replica = self._find_active_replica(replica_list)
|
||||
active_snapshot = [x for x in snapshot_instances
|
||||
if x['share_id'] == active_replica['id']][0]
|
||||
|
||||
self.delete_snapshot(context, active_snapshot,
|
||||
share_server=share_server,
|
||||
snapshot_name=active_snapshot['provider_location']
|
||||
)
|
||||
active_snapshot['status'] = constants.STATUS_DELETED
|
||||
instances = zip(sorted(replica_list,
|
||||
key=lambda x: x['id']),
|
||||
sorted(snapshot_instances,
|
||||
key=lambda x: x['share_id']))
|
||||
|
||||
for replica, snapshot in instances:
|
||||
if snapshot['id'] != active_snapshot['id']:
|
||||
dm_session = data_motion.DataMotionSession()
|
||||
if replica.get('host'):
|
||||
try:
|
||||
dm_session.update_snapmirror(active_replica, replica)
|
||||
except netapp_api.NaApiError as e:
|
||||
if e.code != netapp_api.EOBJECTNOTFOUND:
|
||||
raise
|
||||
|
||||
return [active_snapshot]
|
||||
|
||||
def update_replicated_snapshot(self, replica_list, share_replica,
|
||||
snapshot_instances, snapshot_instance,
|
||||
share_server=None):
|
||||
active_replica = self._find_active_replica(replica_list)
|
||||
vserver, vserver_client = self._get_vserver(share_server=share_server)
|
||||
share_name = self._get_backend_share_name(
|
||||
snapshot_instance['share_id'])
|
||||
snapshot_name = snapshot_instance.get('provider_location')
|
||||
# NOTE(ameade): If there is no provider location,
|
||||
# then grab from active snapshot instance
|
||||
if snapshot_name is None:
|
||||
active_snapshot = [x for x in snapshot_instances
|
||||
if x['share_id'] == active_replica['id']][0]
|
||||
snapshot_name = active_snapshot.get('provider_location')
|
||||
if not snapshot_name:
|
||||
return
|
||||
|
||||
try:
|
||||
snapshot_exists = vserver_client.snapshot_exists(snapshot_name,
|
||||
share_name)
|
||||
except exception.SnapshotUnavailable:
|
||||
# The volume must still be offline
|
||||
return
|
||||
|
||||
if (snapshot_exists and
|
||||
snapshot_instance['status'] == constants.STATUS_CREATING):
|
||||
return {
|
||||
'status': constants.STATUS_AVAILABLE,
|
||||
'provider_location': snapshot_name,
|
||||
}
|
||||
elif (not snapshot_exists and
|
||||
snapshot_instance['status'] == constants.STATUS_DELETING):
|
||||
raise exception.SnapshotResourceNotFound(
|
||||
name=snapshot_instance.get('provider_location'))
|
||||
|
||||
dm_session = data_motion.DataMotionSession()
|
||||
try:
|
||||
dm_session.update_snapmirror(active_replica, share_replica)
|
||||
except netapp_api.NaApiError as e:
|
||||
if e.code != netapp_api.EOBJECTNOTFOUND:
|
||||
raise
|
||||
|
|
|
@ -2545,6 +2545,68 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||
|
||||
self.assertFalse(self.client.volume_exists(fake.SHARE_NAME))
|
||||
|
||||
def test_snapshot_exists(self):
|
||||
|
||||
api_response = netapp_api.NaElement(fake.VOLUME_GET_NAME_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
result = self.client.snapshot_exists(fake.SNAPSHOT_NAME,
|
||||
fake.SHARE_NAME)
|
||||
|
||||
snapshot_get_iter_args = {
|
||||
'query': {
|
||||
'snapshot-info': {
|
||||
'name': fake.SNAPSHOT_NAME,
|
||||
'volume': fake.SHARE_NAME,
|
||||
}
|
||||
},
|
||||
'desired-attributes': {
|
||||
'snapshot-info': {
|
||||
'name': None,
|
||||
'volume': None,
|
||||
'busy': None,
|
||||
'snapshot-owners-list': {
|
||||
'snapshot-owner': None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('snapshot-get-iter', snapshot_get_iter_args)])
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_snapshot_exists_not_found(self):
|
||||
api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
self.assertFalse(self.client.snapshot_exists(fake.SNAPSHOT_NAME,
|
||||
fake.SHARE_NAME))
|
||||
|
||||
@ddt.data({
|
||||
'api_response_xml': fake.SNAPSHOT_GET_ITER_UNAVAILABLE_RESPONSE,
|
||||
'raised_exception': exception.SnapshotUnavailable,
|
||||
}, {
|
||||
'api_response_xml': fake.SNAPSHOT_GET_ITER_OTHER_ERROR_RESPONSE,
|
||||
'raised_exception': exception.NetAppException,
|
||||
})
|
||||
@ddt.unpack
|
||||
def test_snapshot_exists_error(self, api_response_xml, raised_exception):
|
||||
|
||||
api_response = netapp_api.NaElement(api_response_xml)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
self.assertRaises(raised_exception,
|
||||
self.client.snapshot_exists,
|
||||
fake.SNAPSHOT_NAME,
|
||||
fake.SHARE_NAME)
|
||||
|
||||
def test_get_aggregate_for_volume(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
|
|
|
@ -20,6 +20,7 @@ import copy
|
|||
import math
|
||||
import socket
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
|
@ -1112,9 +1113,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
self.library.create_snapshot(self.context,
|
||||
fake.SNAPSHOT,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
model_update = self.library.create_snapshot(
|
||||
self.context, fake.SNAPSHOT, share_server=fake.SHARE_SERVER)
|
||||
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake.SNAPSHOT['share_id'])
|
||||
|
@ -1122,6 +1122,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
fake.SNAPSHOT['id'])
|
||||
vserver_client.create_snapshot.assert_called_once_with(share_name,
|
||||
snapshot_name)
|
||||
self.assertEqual(snapshot_name, model_update['provider_location'])
|
||||
|
||||
def test_delete_snapshot(self):
|
||||
|
||||
|
@ -1144,6 +1145,25 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
mock_delete_snapshot.assert_called_once_with(
|
||||
vserver_client, share_name, snapshot_name)
|
||||
|
||||
def test_delete_snapshot_with_provider_location(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['provider_location'] = 'fake_provider_location'
|
||||
|
||||
self.library.delete_snapshot(self.context,
|
||||
fake_snapshot,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake_snapshot['share_id'])
|
||||
vserver_client.delete_snapshot.assert_called_once_with(
|
||||
share_name, fake_snapshot['provider_location'])
|
||||
|
||||
@ddt.data(exception.InvalidInput(reason='fake_reason'),
|
||||
exception.VserverNotSpecified(),
|
||||
exception.VserverNotFound(vserver='fake_vserver'))
|
||||
|
@ -2066,7 +2086,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
}
|
||||
|
||||
model_update = self.library.create_replica(
|
||||
None, [fake.SHARE], fake.SHARE, share_server=None)
|
||||
None, [fake.SHARE], fake.SHARE, [], [],
|
||||
share_server=None)
|
||||
|
||||
self.assertDictMatch(expected_model_update, model_update)
|
||||
mock_dm_session.create_snapmirror.assert_called_once_with(fake.SHARE,
|
||||
|
@ -2092,7 +2113,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
}
|
||||
|
||||
model_update = self.library.create_replica(
|
||||
None, [fake.SHARE], fake.SHARE, share_server=fake.SHARE_SERVER)
|
||||
None, [fake.SHARE], fake.SHARE, [], [],
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
self.assertDictMatch(expected_model_update, model_update)
|
||||
mock_dm_session.create_snapmirror.assert_called_once_with(fake.SHARE,
|
||||
|
@ -2117,6 +2139,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
result = self.library.delete_replica(None,
|
||||
[fake.SHARE],
|
||||
fake.SHARE,
|
||||
[],
|
||||
share_server=None)
|
||||
self.assertEqual(None, result)
|
||||
mock_dm_session.delete_snapmirror.assert_called_with(fake.SHARE,
|
||||
|
@ -2143,6 +2166,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
result = self.library.delete_replica(None,
|
||||
[fake.SHARE],
|
||||
fake.SHARE,
|
||||
[],
|
||||
share_server=fake.SHARE_SERVER)
|
||||
self.assertEqual(None, result)
|
||||
mock_dm_session.delete_snapmirror.assert_called_with(fake.SHARE,
|
||||
|
@ -2170,6 +2194,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
result = self.library.delete_replica(None,
|
||||
[fake.SHARE],
|
||||
fake.SHARE,
|
||||
[],
|
||||
share_server=None)
|
||||
|
||||
self.assertEqual(None, result)
|
||||
|
@ -2195,7 +2220,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
replica['status'] = constants.STATUS_CREATING
|
||||
|
||||
result = self.library.update_replica_state(
|
||||
None, [replica], replica, None, share_server=None)
|
||||
None, [replica], replica, None, [], share_server=None)
|
||||
|
||||
self.assertFalse(self.mock_dm_session.create_snapmirror.called)
|
||||
self.assertEqual(constants.STATUS_OUT_OF_SYNC, result)
|
||||
|
@ -2216,7 +2241,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
replica['status'] = constants.REPLICA_STATE_OUT_OF_SYNC
|
||||
|
||||
result = self.library.update_replica_state(
|
||||
None, [replica], replica, None, share_server=None)
|
||||
None, [replica], replica, None, [], share_server=None)
|
||||
|
||||
self.assertTrue(self.mock_dm_session.create_snapmirror.called)
|
||||
self.assertEqual(constants.STATUS_ERROR, result)
|
||||
|
@ -2236,7 +2261,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
replica['status'] = status
|
||||
|
||||
result = self.library.update_replica_state(
|
||||
None, [replica], replica, None, share_server=None)
|
||||
None, [replica], replica, None, [], share_server=None)
|
||||
|
||||
self.assertEqual(1, self.mock_dm_session.create_snapmirror.call_count)
|
||||
self.assertEqual(constants.STATUS_OUT_OF_SYNC, result)
|
||||
|
@ -2260,7 +2285,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
return_value=[fake_snapmirror])
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None,
|
||||
fake.SHARE, None, [],
|
||||
share_server=None)
|
||||
|
||||
vserver_client.resync_snapmirror.assert_called_once_with(
|
||||
|
@ -2288,7 +2313,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
return_value=[fake_snapmirror])
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None,
|
||||
fake.SHARE, None, [],
|
||||
share_server=None)
|
||||
|
||||
self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, result)
|
||||
|
@ -2305,7 +2330,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
netapp_api.NaApiError(code=0))
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None,
|
||||
fake.SHARE, None, [],
|
||||
share_server=None)
|
||||
self.assertTrue(self.mock_dm_session.get_snapmirrors.called)
|
||||
self.assertEqual(constants.STATUS_ERROR, result)
|
||||
|
@ -2330,7 +2355,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
vserver_client.resync_snapmirror.side_effect = netapp_api.NaApiError
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None,
|
||||
fake.SHARE, None, [],
|
||||
share_server=None)
|
||||
|
||||
vserver_client.resync_snapmirror.assert_called_once_with(
|
||||
|
@ -2356,7 +2381,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
return_value=[fake_snapmirror])
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None,
|
||||
fake.SHARE, None, [],
|
||||
share_server=None)
|
||||
|
||||
self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, result)
|
||||
|
@ -2378,7 +2403,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
return_value=[fake_snapmirror])
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None,
|
||||
fake.SHARE, None, [],
|
||||
share_server=None)
|
||||
|
||||
self.assertEqual(constants.REPLICA_STATE_IN_SYNC, result)
|
||||
|
@ -2394,9 +2419,59 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
|
||||
self.assertRaises(exception.ShareResourceNotFound,
|
||||
self.library.update_replica_state,
|
||||
None, [fake.SHARE], fake.SHARE, None,
|
||||
None, [fake.SHARE], fake.SHARE, None, [],
|
||||
share_server=None)
|
||||
|
||||
def test_update_replica_state_in_sync_with_snapshots(self):
|
||||
fake_snapmirror = {
|
||||
'mirror-state': 'snapmirrored',
|
||||
'relationship-status': 'idle',
|
||||
'last-transfer-end-timestamp': '%s' % float(time.time())
|
||||
}
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = fake.SHARE['id']
|
||||
snapshots = [{'share_replica_snapshot': fake_snapshot}]
|
||||
vserver_client = mock.Mock()
|
||||
self.mock_object(vserver_client, 'snapshot_exists', mock.Mock(
|
||||
return_value=True))
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
self.mock_dm_session.get_snapmirrors = mock.Mock(
|
||||
return_value=[fake_snapmirror])
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None, snapshots,
|
||||
share_server=None)
|
||||
|
||||
self.assertEqual(constants.REPLICA_STATE_IN_SYNC, result)
|
||||
|
||||
def test_update_replica_state_missing_snapshot(self):
|
||||
fake_snapmirror = {
|
||||
'mirror-state': 'snapmirrored',
|
||||
'relationship-status': 'idle',
|
||||
'last-transfer-end-timestamp': '%s' % float(time.time())
|
||||
}
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = fake.SHARE['id']
|
||||
snapshots = [{'share_replica_snapshot': fake_snapshot}]
|
||||
vserver_client = mock.Mock()
|
||||
self.mock_object(vserver_client, 'snapshot_exists', mock.Mock(
|
||||
return_value=False))
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
self.mock_dm_session.get_snapmirrors = mock.Mock(
|
||||
return_value=[fake_snapmirror])
|
||||
|
||||
result = self.library.update_replica_state(None, [fake.SHARE],
|
||||
fake.SHARE, None, snapshots,
|
||||
share_server=None)
|
||||
|
||||
self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, result)
|
||||
|
||||
def test_promote_replica(self):
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
|
@ -2744,3 +2819,549 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||
self.assertEqual([], replica['export_locations'])
|
||||
self.assertEqual(constants.STATUS_ERROR,
|
||||
replica['replica_state'])
|
||||
|
||||
def test_create_replicated_snapshot(self):
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
model_list = self.library.create_replicated_snapshot(
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake_snapshot['share_id'])
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
vserver_client.create_snapshot.assert_called_once_with(share_name,
|
||||
snapshot_name)
|
||||
self.assertEqual(3, len(model_list))
|
||||
for snapshot in model_list:
|
||||
self.assertEqual(snapshot['provider_location'], snapshot_name)
|
||||
actual_active_snapshot = list(filter(
|
||||
lambda x: x['id'] == fake_snapshot['id'], model_list))[0]
|
||||
self.assertEqual(constants.STATUS_AVAILABLE,
|
||||
actual_active_snapshot['status'])
|
||||
actual_non_active_snapshot_list = list(filter(
|
||||
lambda x: x['id'] != fake_snapshot['id'], model_list))
|
||||
for snapshot in actual_non_active_snapshot_list:
|
||||
self.assertEqual(constants.STATUS_CREATING, snapshot['status'])
|
||||
self.mock_dm_session.update_snapmirror.assert_has_calls(
|
||||
[mock.call(self.fake_replica, self.fake_replica_2),
|
||||
mock.call(self.fake_replica, fake_replica_3)],
|
||||
any_order=True
|
||||
)
|
||||
|
||||
def test_create_replicated_snapshot_with_creating_replica(self):
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
fake_replica_3['host'] = None
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
model_list = self.library.create_replicated_snapshot(
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake_snapshot['share_id'])
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
vserver_client.create_snapshot.assert_called_once_with(share_name,
|
||||
snapshot_name)
|
||||
self.assertEqual(3, len(model_list))
|
||||
for snapshot in model_list:
|
||||
self.assertEqual(snapshot['provider_location'], snapshot_name)
|
||||
actual_active_snapshot = list(filter(
|
||||
lambda x: x['id'] == fake_snapshot['id'], model_list))[0]
|
||||
self.assertEqual(constants.STATUS_AVAILABLE,
|
||||
actual_active_snapshot['status'])
|
||||
actual_non_active_snapshot_list = list(filter(
|
||||
lambda x: x['id'] != fake_snapshot['id'], model_list))
|
||||
for snapshot in actual_non_active_snapshot_list:
|
||||
self.assertEqual(constants.STATUS_CREATING, snapshot['status'])
|
||||
self.mock_dm_session.update_snapmirror.assert_has_calls(
|
||||
[mock.call(self.fake_replica, self.fake_replica_2)],
|
||||
any_order=True
|
||||
)
|
||||
|
||||
def test_create_replicated_snapshot_no_snapmirror(self):
|
||||
self.mock_dm_session.update_snapmirror.side_effect = [
|
||||
None,
|
||||
netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND)
|
||||
]
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
model_list = self.library.create_replicated_snapshot(
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake_snapshot['share_id'])
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
vserver_client.create_snapshot.assert_called_once_with(share_name,
|
||||
snapshot_name)
|
||||
self.assertEqual(3, len(model_list))
|
||||
for snapshot in model_list:
|
||||
self.assertEqual(snapshot['provider_location'], snapshot_name)
|
||||
actual_active_snapshot = list(filter(
|
||||
lambda x: x['id'] == fake_snapshot['id'], model_list))[0]
|
||||
self.assertEqual(constants.STATUS_AVAILABLE,
|
||||
actual_active_snapshot['status'])
|
||||
actual_non_active_snapshot_list = list(filter(
|
||||
lambda x: x['id'] != fake_snapshot['id'], model_list))
|
||||
for snapshot in actual_non_active_snapshot_list:
|
||||
self.assertEqual(constants.STATUS_CREATING, snapshot['status'])
|
||||
self.mock_dm_session.update_snapmirror.assert_has_calls(
|
||||
[mock.call(self.fake_replica, self.fake_replica_2),
|
||||
mock.call(self.fake_replica, fake_replica_3)],
|
||||
any_order=True
|
||||
)
|
||||
|
||||
def test_create_replicated_snapshot_update_error(self):
|
||||
self.mock_dm_session.update_snapmirror.side_effect = [
|
||||
None,
|
||||
netapp_api.NaApiError()
|
||||
]
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
self.assertRaises(netapp_api.NaApiError,
|
||||
self.library.create_replicated_snapshot,
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
def test_delete_replicated_snapshot(self):
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake_snapshot['share_id'])
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_2['provider_location'] = snapshot_name
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
fake_snapshot_3['provider_location'] = snapshot_name
|
||||
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
self.library.delete_replicated_snapshot(
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
vserver_client.delete_snapshot.assert_called_once_with(share_name,
|
||||
snapshot_name)
|
||||
|
||||
self.mock_dm_session.update_snapmirror.assert_has_calls(
|
||||
[mock.call(self.fake_replica, self.fake_replica_2),
|
||||
mock.call(self.fake_replica, fake_replica_3)],
|
||||
any_order=True
|
||||
)
|
||||
|
||||
def test_delete_replicated_snapshot_replica_still_creating(self):
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
fake_replica_3['host'] = None
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake_snapshot['share_id'])
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_2['provider_location'] = snapshot_name
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
fake_snapshot_3['provider_location'] = snapshot_name
|
||||
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
self.library.delete_replicated_snapshot(
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
vserver_client.delete_snapshot.assert_called_once_with(share_name,
|
||||
snapshot_name)
|
||||
|
||||
self.mock_dm_session.update_snapmirror.assert_has_calls(
|
||||
[mock.call(self.fake_replica, self.fake_replica_2)],
|
||||
any_order=True
|
||||
)
|
||||
|
||||
def test_delete_replicated_snapshot_missing_snapmirror(self):
|
||||
self.mock_dm_session.update_snapmirror.side_effect = [
|
||||
None,
|
||||
netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND)
|
||||
]
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
share_name = self.library._get_backend_share_name(
|
||||
fake_snapshot['share_id'])
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
fake_snapshot['busy'] = False
|
||||
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_2['provider_location'] = snapshot_name
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
fake_snapshot_3['provider_location'] = snapshot_name
|
||||
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.get_snapshot.return_value = fake_snapshot
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
self.library.delete_replicated_snapshot(
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
vserver_client.delete_snapshot.assert_called_once_with(share_name,
|
||||
snapshot_name)
|
||||
|
||||
self.mock_dm_session.update_snapmirror.assert_has_calls(
|
||||
[mock.call(self.fake_replica, self.fake_replica_2),
|
||||
mock.call(self.fake_replica, fake_replica_3)],
|
||||
any_order=True
|
||||
)
|
||||
|
||||
def test_delete_replicated_snapshot_update_error(self):
|
||||
self.mock_dm_session.update_snapmirror.side_effect = [
|
||||
None,
|
||||
netapp_api.NaApiError()
|
||||
]
|
||||
fake_replica_3 = copy.deepcopy(self.fake_replica_2)
|
||||
fake_replica_3['id'] = fake.SHARE_ID3
|
||||
replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
fake_snapshot['busy'] = False
|
||||
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
fake_snapshot_2['provider_location'] = snapshot_name
|
||||
fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_3['id'] = str(uuid.uuid4())
|
||||
fake_snapshot_3['share_id'] = fake_replica_3['id']
|
||||
fake_snapshot_3['provider_location'] = snapshot_name
|
||||
|
||||
snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
|
||||
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.get_snapshot.return_value = fake_snapshot
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
self.assertRaises(netapp_api.NaApiError,
|
||||
self.library.delete_replicated_snapshot,
|
||||
self.context, replica_list, snapshot_list,
|
||||
share_server=fake.SHARE_SERVER)
|
||||
|
||||
def test_update_replicated_snapshot_still_creating(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = False
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica, self.fake_replica_2]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_CREATING
|
||||
fake_snapshot['share_id'] = self.fake_replica_2['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
|
||||
model_update = self.library.update_replicated_snapshot(
|
||||
replica_list, self.fake_replica_2, [fake_snapshot], fake_snapshot)
|
||||
|
||||
self.assertEqual(None, model_update)
|
||||
self.mock_dm_session.update_snapmirror.assert_called_once_with(
|
||||
self.fake_replica, self.fake_replica_2
|
||||
)
|
||||
|
||||
def test_update_replicated_snapshot_still_creating_no_host(self):
|
||||
self.fake_replica_2['host'] = None
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = False
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica, self.fake_replica_2]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_CREATING
|
||||
fake_snapshot['share_id'] = self.fake_replica_2['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
|
||||
model_update = self.library.update_replicated_snapshot(
|
||||
replica_list, self.fake_replica_2, [fake_snapshot], fake_snapshot)
|
||||
|
||||
self.assertEqual(None, model_update)
|
||||
self.mock_dm_session.update_snapmirror.assert_called_once_with(
|
||||
self.fake_replica, self.fake_replica_2
|
||||
)
|
||||
|
||||
def test_update_replicated_snapshot_no_snapmirror(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = False
|
||||
self.mock_dm_session.update_snapmirror.side_effect = (
|
||||
netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND)
|
||||
)
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica, self.fake_replica_2]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_CREATING
|
||||
fake_snapshot['share_id'] = self.fake_replica_2['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
|
||||
model_update = self.library.update_replicated_snapshot(
|
||||
replica_list, self.fake_replica_2, [fake_snapshot], fake_snapshot)
|
||||
|
||||
self.assertEqual(None, model_update)
|
||||
self.mock_dm_session.update_snapmirror.assert_called_once_with(
|
||||
self.fake_replica, self.fake_replica_2
|
||||
)
|
||||
|
||||
def test_update_replicated_snapshot_update_error(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = False
|
||||
self.mock_dm_session.update_snapmirror.side_effect = (
|
||||
netapp_api.NaApiError()
|
||||
)
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica, self.fake_replica_2]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_CREATING
|
||||
fake_snapshot['share_id'] = self.fake_replica_2['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
|
||||
self.assertRaises(netapp_api.NaApiError,
|
||||
self.library.update_replicated_snapshot,
|
||||
replica_list, self.fake_replica_2,
|
||||
[fake_snapshot], fake_snapshot)
|
||||
|
||||
def test_update_replicated_snapshot_still_deleting(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = True
|
||||
vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
|
||||
replica_list = [self.fake_replica]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_DELETING
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
|
||||
model_update = self.library.update_replicated_snapshot(
|
||||
replica_list, self.fake_replica, [fake_snapshot], fake_snapshot)
|
||||
|
||||
self.assertEqual(None, model_update)
|
||||
|
||||
def test_update_replicated_snapshot_created(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = True
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_CREATING
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
|
||||
model_update = self.library.update_replicated_snapshot(
|
||||
replica_list, self.fake_replica, [fake_snapshot], fake_snapshot)
|
||||
|
||||
self.assertEqual(constants.STATUS_AVAILABLE, model_update['status'])
|
||||
self.assertEqual(snapshot_name, model_update['provider_location'])
|
||||
|
||||
def test_update_replicated_snapshot_created_no_provider_location(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = True
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica, self.fake_replica_2]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_ACTIVE
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot_2['status'] = constants.STATUS_CREATING
|
||||
fake_snapshot_2['share_id'] = self.fake_replica_2['id']
|
||||
|
||||
model_update = self.library.update_replicated_snapshot(
|
||||
replica_list, self.fake_replica_2,
|
||||
[fake_snapshot, fake_snapshot_2], fake_snapshot_2)
|
||||
|
||||
self.assertEqual(constants.STATUS_AVAILABLE, model_update['status'])
|
||||
self.assertEqual(snapshot_name, model_update['provider_location'])
|
||||
|
||||
def test_update_replicated_snapshot_deleted(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = False
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_DELETING
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
snapshot_name = self.library._get_backend_snapshot_name(
|
||||
fake_snapshot['id'])
|
||||
fake_snapshot['provider_location'] = snapshot_name
|
||||
|
||||
self.assertRaises(exception.SnapshotResourceNotFound,
|
||||
self.library.update_replicated_snapshot,
|
||||
replica_list, self.fake_replica, [fake_snapshot],
|
||||
fake_snapshot)
|
||||
|
||||
def test_update_replicated_snapshot_no_provider_locations(self):
|
||||
vserver_client = mock.Mock()
|
||||
vserver_client.snapshot_exists.return_value = True
|
||||
self.mock_object(self.library,
|
||||
'_get_vserver',
|
||||
mock.Mock(return_value=(fake.VSERVER1,
|
||||
vserver_client)))
|
||||
replica_list = [self.fake_replica]
|
||||
fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
|
||||
fake_snapshot['status'] = constants.STATUS_CREATING
|
||||
fake_snapshot['share_id'] = self.fake_replica['id']
|
||||
fake_snapshot['provider_location'] = None
|
||||
|
||||
model_update = self.library.update_replicated_snapshot(
|
||||
replica_list, self.fake_replica, [fake_snapshot], fake_snapshot)
|
||||
|
||||
self.assertEqual(None, model_update)
|
||||
|
|
|
@ -262,7 +262,9 @@ SHARE_SERVER = {
|
|||
SNAPSHOT = {
|
||||
'id': SNAPSHOT_ID,
|
||||
'project_id': TENANT_ID,
|
||||
'share_id': PARENT_SHARE_ID
|
||||
'share_id': PARENT_SHARE_ID,
|
||||
'status': constants.STATUS_CREATING,
|
||||
'provider_location': None,
|
||||
}
|
||||
|
||||
CDOT_SNAPSHOT = {
|
||||
|
|
Loading…
Reference in New Issue