Skip to content

Commit

Permalink
[WIP] Update replica state before promote.
Browse files Browse the repository at this point in the history
During promote of replica, retrieve replica state from backend before
promotion. In case DB state is in-sync, but backend reports out-sync,
halt promotion.
  • Loading branch information
kpawar-sap committed Sep 8, 2022
1 parent 2ab75f0 commit 3ebf07c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 1 deletion.
3 changes: 3 additions & 0 deletions manila/share/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,9 @@ def delete_share_replica(self, context, share_replica, force=False):

def promote_share_replica(self, context, share_replica):

self.share_rpcapi.update_share_replica(context, share_replica)
share_replica = self.db.share_replica_get(context,
share_replica['id'])
if share_replica.get('status') != constants.STATUS_AVAILABLE:
msg = _("Replica %(replica_id)s must be in %(status)s state to be "
"promoted.")
Expand Down
32 changes: 31 additions & 1 deletion manila/share/drivers/netapp/dataontap/cluster_mode/lib_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,6 @@ def _get_logical_space_options(self, vserver_client, share_name):
src_volume.get('is-space-reporting-logical')
}


def _get_efficiency_options(self, vserver_client, share_name):
status = vserver_client.get_volume_efficiency_status(share_name)
provisioning_opts = {
Expand Down Expand Up @@ -2954,6 +2953,37 @@ def update_replica_state(self, context, replica_list, replica,
.isoformat(), 3600))):
return constants.REPLICA_STATE_OUT_OF_SYNC

for k, v in snapmirror.items():
LOG.error("===== snapmirror Key %(k)s Value %(v)s ", {'k': k, 'v': v})

'''
replica_backend = share_utils.extract_host(replica['host'],
level='backend_name')
config = data_motion.get_backend_configuration(replica_backend)
config_size = (int(config.safe_get(
'netapp_snapmirror_last_transfer_size_limit')) * units.Ki)
last_transfer_size = snapmirror.get('last-transfer-size', 0)
for unit in ['B', 'KB', 'MB', 'GB']:
last_transfer_size = last_transfer_size.split(unit)[0]
try:
last_transfer_size = float(last_transfer_size)
if unit == 'KB':
last_transfer_size = last_transfer_size * 1024 ** 1
if unit == 'MB':
last_transfer_size = last_transfer_size * 1024 ** 2
if unit == 'GB':
last_transfer_size = last_transfer_size * 1024 ** 3
break
except ValueError:
continue
if last_transfer_size > config_size:
return constants.REPLICA_STATE_OUT_OF_SYNC
last_transfer_error = snapmirror.get('last-transfer-error', None)
if last_transfer_error:
return constants.REPLICA_STATE_OUT_OF_SYNC
'''

# Check all snapshots exist
snapshots = [snap['share_replica_snapshot']
for snap in share_snapshots]
Expand Down
6 changes: 6 additions & 0 deletions manila/share/drivers/netapp/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@
default=3600, # One Hour
help='The maximum time in seconds to wait for a snapmirror '
'release when breaking snapmirror relationships.'),
cfg.IntOpt('netapp_snapmirror_last_transfer_size_limit',
min=512,
default=1024, # One MB
help='This option set the last transfer size limit (in KB) '
'of snapmirror to decide whether replica is in sync or '
'out of sync.'),
cfg.IntOpt('netapp_volume_move_cutover_timeout',
min=0,
default=3600, # One Hour,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4371,6 +4371,9 @@ def test_update_replica_state_in_sync(self):
self.mock_object(self.library,
'_is_readable_replica',
mock.Mock(return_value=False))
mock_backend_config = fake.get_config_cmode()
self.mock_object(data_motion, 'get_backend_configuration',
mock.Mock(return_value=mock_backend_config))

result = self.library.update_replica_state(None, [fake.SHARE],
fake.SHARE, None, [],
Expand Down Expand Up @@ -4414,6 +4417,9 @@ def test_update_replica_state_in_sync_with_snapshots(self):
self.mock_object(self.library,
'_is_readable_replica',
mock.Mock(return_value=False))
mock_backend_config = fake.get_config_cmode()
self.mock_object(data_motion, 'get_backend_configuration',
mock.Mock(return_value=mock_backend_config))

result = self.library.update_replica_state(None, [fake.SHARE],
fake.SHARE, None, snapshots,
Expand Down Expand Up @@ -4442,6 +4448,9 @@ def test_update_replica_state_missing_snapshot(self):
self.mock_object(self.library,
'_is_readable_replica',
mock.Mock(return_value=False))
mock_backend_config = fake.get_config_cmode()
self.mock_object(data_motion, 'get_backend_configuration',
mock.Mock(return_value=mock_backend_config))

result = self.library.update_replica_state(None, [fake.SHARE],
fake.SHARE, None, snapshots,
Expand Down
10 changes: 10 additions & 0 deletions manila/tests/share/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4033,13 +4033,18 @@ def test_delete_share_replica(self, force):
def test_promote_share_replica_non_available_status(self, status):
replica = fakes.fake_replica(
status=status, replica_state=constants.REPLICA_STATE_IN_SYNC)
mock_rpcapi_update_share_replica_call = self.mock_object(
self.share_rpcapi, 'update_share_replica')
self.mock_object(db_api, 'share_replica_get',
mock.Mock(return_value=replica))
mock_rpcapi_promote_share_replica_call = self.mock_object(
self.share_rpcapi, 'promote_share_replica')

self.assertRaises(exception.ReplicationException,
self.api.promote_share_replica,
self.context,
replica)
self.assertTrue(mock_rpcapi_update_share_replica_call.called)
self.assertFalse(mock_rpcapi_promote_share_replica_call.called)

@ddt.data(constants.REPLICA_STATE_OUT_OF_SYNC, constants.STATUS_ERROR)
Expand All @@ -4050,13 +4055,18 @@ def test_promote_share_replica_out_of_sync_non_admin(self, replica_state):
replica = fakes.fake_replica(
status=constants.STATUS_AVAILABLE,
replica_state=replica_state)
mock_rpcapi_update_share_replica_call = self.mock_object(
self.share_rpcapi, 'update_share_replica')
self.mock_object(db_api, 'share_replica_get',
mock.Mock(return_value=replica))
mock_rpcapi_promote_share_replica_call = self.mock_object(
self.share_rpcapi, 'promote_share_replica')

self.assertRaises(exception.AdminRequired,
self.api.promote_share_replica,
fake_user_context,
replica)
self.assertTrue(mock_rpcapi_update_share_replica_call.called)
self.assertFalse(mock_rpcapi_promote_share_replica_call.called)

@ddt.data(constants.REPLICA_STATE_OUT_OF_SYNC, constants.STATUS_ERROR)
Expand Down

0 comments on commit 3ebf07c

Please sign in to comment.