def switch_over(self, replica_pair_id): pair_info = self._get_replication_pair_info(replica_pair_id) if strutils.bool_from_string(pair_info['ISPRIMARY']): LOG.warning('The replica to promote is already primary, ' 'no need to switch over.') return replica_state = self._check_replica_state(pair_info) if replica_state != common_constants.REPLICA_STATE_IN_SYNC: # replica is not in SYNC state, can't be promoted msg = _('Data of replica %s is not sync, cannot promote.' ) % replica_pair_id raise exception.ReplicationException(reason=msg) try: self.helper.split_replication_pair(replica_pair_id) except Exception as err: # split failed # means replication pair is in an abnormal status, # ignore this exception, continue to cancel secondary write lock, # let secondary share accessible for disaster recovery. LOG.exception( 'Failed to split replication pair %(pair)s while ' 'switching over. Reason: %(err)s', { "pair": replica_pair_id, "err": err }) try: self.helper.cancel_pair_secondary_write_lock(replica_pair_id) except Exception: LOG.exception( 'Failed to cancel replication pair %s ' 'secondary write lock.', replica_pair_id) raise def _rollback_done(): _pair_info = self._get_replication_pair_info(replica_pair_id) return _pair_info.get('ISROLLBACK', 'false') != 'true' huawei_utils.wait_for_condition(_rollback_done, 3, 3600 * 24) try: self.helper.switch_replication_pair(replica_pair_id) self.helper.set_pair_secondary_write_lock(replica_pair_id) self.helper.sync_replication_pair(replica_pair_id) except Exception as err: LOG.exception( 'Failed to completely switch over replication pair' ' %(pair)s. Reason: %(err)s', { "pair": replica_pair_id, "err": err }) # for all the rest steps, # because secondary share is accessible now, # the upper business may access the secondary share, # return success to tell replica is primary. return
def create(self, local_share_info, remote_device_wwn, remote_fs_id): local_share_name = local_share_info.get('name') try: local_fs_id = self.helper.get_fsid_by_name(local_share_name) if not local_fs_id: msg = _("Local fs was not found by name %s.") LOG.error(msg, local_share_name) raise exception.ReplicationException(reason=msg % local_share_name) remote_device = self.helper.get_remote_device_by_wwn( remote_device_wwn) pair_params = { "LOCALRESID": local_fs_id, "LOCALRESTYPE": constants.FILE_SYSTEM_TYPE, "REMOTEDEVICEID": remote_device.get('ID'), "REMOTEDEVICENAME": remote_device.get('NAME'), "REMOTERESID": remote_fs_id, "REPLICATIONMODEL": constants.REPLICA_ASYNC_MODEL, "RECOVERYPOLICY": '2', "SYNCHRONIZETYPE": '1', "SPEED": constants.REPLICA_SPEED_MEDIUM, } pair_info = self.helper.create_replication_pair(pair_params) except Exception: msg = _LE("Failed to create replication pair for share %s.") LOG.exception(msg, local_share_name) raise self._sync_replication_pair(pair_info['ID']) return pair_info['ID']
def wait_for_quiesced(): snapmirror = dest_client.get_snapmirrors_svm( source_vserver=source_vserver, dest_vserver=dest_vserver, desired_attributes=['relationship-status', 'mirror-state'])[0] if snapmirror.get('relationship-status') != 'quiesced': raise exception.ReplicationException( reason="Snapmirror relationship is not quiesced.")
def create(self, local_share_info, remote_device_wwn, remote_fs_id, local_replication): local_share_name = local_share_info.get('name') try: local_fs_info = self.helper.get_fs_info_by_name(local_share_name) if not local_fs_info: msg = _("Local fs was not found by name %s." % local_share_name) LOG.error(msg) raise exception.ReplicationException(reason=msg) local_fs_id = local_fs_info['ID'] pair_params = { "LOCALRESID": local_fs_id, "LOCALRESTYPE": constants.FILE_SYSTEM_TYPE, "REMOTERESID": remote_fs_id, "REPLICATIONMODEL": constants.REPLICA_ASYNC_MODEL, "RECOVERYPOLICY": '2', "SYNCHRONIZETYPE": '1', "SPEED": constants.REPLICA_SPEED_HIGHEST, } if local_replication: pair_params["PAIRTYPE"] = constants.LOCAL_REPLICATION else: remote_device = self.helper.get_remote_device_by_wwn( remote_device_wwn) pair_params["REMOTEDEVICEID"] = remote_device.get('ID') support_sync_snapshot = huawei_utils.is_dorado_v6(self.helper) if support_sync_snapshot: pair_params["syncSnapPolicy"] = "1" pair_info = self.helper.create_replication_pair(pair_params) local_pair_id = pair_info['ID'] if local_replication: remote_fs = self.helper.get_fs_info_by_id(remote_fs_id) if not remote_fs: msg = _('Remote filesystem %s is not exist.' % remote_fs_id) LOG.error(msg) raise exception.StorageResourceNotFound(name=remote_fs_id) replication_ids = json.loads(remote_fs['REMOTEREPLICATIONIDS']) # Here must have a replication id. remote_pair_id = replication_ids[0] else: remote_pair_id = local_pair_id except Exception: LOG.exception("Failed to create replication pair for share %s.", local_share_name) raise self._sync_replication_pair(local_pair_id, need_sync=False) return local_pair_id, remote_pair_id
def wait_for_quiesced(): snapmirror = dest_client.get_snapmirrors( src_vserver, src_volume_name, dest_vserver, dest_volume_name, desired_attributes=['relationship-status', 'mirror-state'] )[0] if snapmirror.get('relationship-status') != 'quiesced': raise exception.ReplicationException( reason=_LE("Snapmirror relationship is not quiesced."))
def switch_over(self, replica_pair_id): pair_info = self._get_replication_pair_info(replica_pair_id) if strutils.bool_from_string(pair_info['ISPRIMARY']): LOG.warning( _LW('The replica to promote is already primary, ' 'no need to switch over.')) return replica_state = self._check_replica_state(pair_info) if replica_state != common_constants.REPLICA_STATE_IN_SYNC: # replica is not in SYNC state, can't be promoted msg = _('Data of replica %s is not synchronized, ' 'can not promote.') raise exception.ReplicationException(reason=msg % replica_pair_id) try: self.helper.split_replication_pair(replica_pair_id) except Exception: # split failed # means replication pair is in an abnormal status, # ignore this exception, continue to cancel secondary write lock, # let secondary share accessible for disaster recovery. LOG.exception( _LE('Failed to split replication pair %s while ' 'switching over.'), replica_pair_id) try: self.helper.cancel_pair_secondary_write_lock(replica_pair_id) except Exception: LOG.exception( _LE('Failed to cancel replication pair %s ' 'secondary write lock.'), replica_pair_id) raise try: self.helper.switch_replication_pair(replica_pair_id) self.helper.set_pair_secondary_write_lock(replica_pair_id) self.helper.sync_replication_pair(replica_pair_id) except Exception: LOG.exception( _LE('Failed to completely switch over ' 'replication pair %s.'), replica_pair_id) # for all the rest steps, # because secondary share is accessible now, # the upper business may access the secondary share, # return success to tell replica is primary. return
def create(self, local_share_info, remote_device_wwn, remote_fs_id, local_replication): local_share_name = local_share_info.get('name') try: local_fs_id = self.helper.get_fsid_by_name(local_share_name) if not local_fs_id: msg = _("Local fs was not found by name %s.") LOG.error(msg, local_share_name) raise exception.ReplicationException( reason=msg % local_share_name) pair_params = { "LOCALRESID": local_fs_id, "LOCALRESTYPE": constants.FILE_SYSTEM_TYPE, "REMOTERESID": remote_fs_id, "REPLICATIONMODEL": constants.REPLICA_ASYNC_MODEL, "RECOVERYPOLICY": '2', "SYNCHRONIZETYPE": '1', "SPEED": constants.REPLICA_SPEED_MEDIUM, } if local_replication: pair_params["PAIRTYPE"] = constants.LOCAL_REPLICATION else: remote_device = self.helper.get_remote_device_by_wwn( remote_device_wwn) pair_params["REMOTEDEVICEID"] = remote_device.get('ID') pair_info = self.helper.create_replication_pair(pair_params) local_pair_id = pair_info['ID'] if local_replication: remote_fs = self.helper._get_fs_info_by_id(remote_fs_id) replication_ids = json.loads(remote_fs['REMOTEREPLICATIONIDS']) # Here must have a replication id. remote_pair_id = replication_ids[0] else: remote_pair_id = local_pair_id except Exception: LOG.exception("Failed to create replication pair for share %s.", local_share_name) raise self._sync_replication_pair(local_pair_id) return local_pair_id, remote_pair_id
def test_promote_replication_exception(self): body = {'promote': None} replica, expected_replica = self._get_fake_replica( replica_state=constants.REPLICA_STATE_IN_SYNC) exception_type = exception.ReplicationException(reason='xyz') self.mock_object(share_replicas.db, 'share_replica_get', mock.Mock(return_value=replica)) mock_api_promote_replica_call = self.mock_object( share.API, 'promote_share_replica', mock.Mock(side_effect=exception_type)) self.assertRaises(exc.HTTPBadRequest, self.controller.promote, self.replicas_req, replica['id'], body) self.assertTrue(mock_api_promote_replica_call.called) self.mock_policy_check.assert_called_once_with(self.member_context, self.resource_name, 'promote')
def test_delete_exception(self): fake_replica_1 = self._get_fake_replica( share_id='FAKE_SHARE_ID', replica_state=constants.REPLICA_STATE_ACTIVE)[0] fake_replica_2 = self._get_fake_replica( share_id='FAKE_SHARE_ID', replica_state=constants.REPLICA_STATE_ACTIVE)[0] exception_type = exception.ReplicationException(reason='xyz') self.mock_object(share_replicas.db, 'share_replica_get', mock.Mock(return_value=fake_replica_1)) self.mock_object( share_replicas.db, 'share_replicas_get_all_by_share', mock.Mock(return_value=[fake_replica_1, fake_replica_2])) self.mock_object(share.API, 'delete_share_replica', mock.Mock(side_effect=exception_type)) self.assertRaises(exc.HTTPBadRequest, self.controller.delete, self.replicas_req, 'FAKE_REPLICA_ID') self.mock_policy_check.assert_called_once_with( self.member_context, self.resource_name, 'delete')
def test_replication_exception(self): # Verify response code for exception.ReplicationException reason = "Something bad happened." e = exception.ReplicationException(reason=reason) self.assertEqual(500, e.code) self.assertIn(reason, e.msg)