def failover_host(self, context, volumes, secondary_id=None): """Failover to replication target.""" volume_updates = [] if secondary_id and secondary_id != self.replica.backend_id: LOG.error( _LE("Kaminario driver received failover_host " "request, But backend is non replicated device")) raise exception.UnableToFailOver(reason=_("Failover requested " "on non replicated " "backend.")) for v in volumes: vol_name = self.get_volume_name(v['id']) rv = self.get_rep_name(vol_name) if self.target.search("volumes", name=rv).total: self._failover_volume(v) volume_updates.append({ 'volume_id': v['id'], 'updates': { 'replication_status': fields.ReplicationStatus.FAILED_OVER } }) else: volume_updates.append({ 'volume_id': v['id'], 'updates': { 'status': 'error', } }) return self.replica.backend_id, volume_updates
def start_host_pprc_failback(self, luns, backend_id): # check whether primary client is alive or not. if not self._mm_manager.is_target_alive(): try: self._target_helper.update_client() except restclient.APIException: msg = _("Can not connect to the primary backend, " "please make sure it is back.") LOG.error(msg) raise exception.UnableToFailOver(reason=msg) LOG.debug("Failback host starts, backend id is %s.", backend_id) sample_luns = self._get_sample_luns(luns) for lun in sample_luns: self._mm_manager.create_pprc_path(lun) self._mm_manager.do_pprc_failback(luns) # revert the relationship of source volume and target volume self.start_host_pprc_failover(luns, backend_id) self._mm_manager.do_pprc_failback(luns) LOG.debug("Failback host ends, backend id is %s.", backend_id)
def _failover_host(self, volumes, secondary_id=None): if secondary_id == self.backend_name: msg = _("Cannot failover to the same host as the primary.") raise exception.InvalidReplicationTarget(reason=msg) replication_targets = self.get_replication_backend_names( self.configuration) if not replication_targets: msg = _("No replication targets configured for backend " "%s. Cannot failover.") raise exception.InvalidReplicationTarget(reason=msg % self.host) elif secondary_id and secondary_id not in replication_targets: msg = _("%(target)s is not among replication targets configured " "for back end %(host)s. Cannot failover.") payload = { 'target': secondary_id, 'host': self.host, } raise exception.InvalidReplicationTarget(reason=msg % payload) flexvols = self.ssc_library.get_ssc_flexvol_names() try: active_backend_name, volume_updates = self._complete_failover( self.backend_name, replication_targets, flexvols, volumes, failover_target=secondary_id) except exception.NetAppDriverException as e: msg = _("Could not complete failover: %s") % e raise exception.UnableToFailOver(reason=msg) # Update the ZAPI client to the backend we failed over to self._update_zapi_client(active_backend_name) self.failed_over = True self.failed_over_backend_name = active_backend_name return active_backend_name, volume_updates
def failover_host(self, context, volumes, secondary_id=None, groups=None): """Failover to replication target.""" volume_updates = [] back_end_ip = None svc_host = vol_utils.extract_host(self.host, 'backend') service = objects.Service.get_by_args(context, svc_host, 'cinder-volume') if secondary_id and secondary_id != self.replica.backend_id: LOG.error("Kaminario driver received failover_host " "request, But backend is non replicated device") raise exception.UnableToFailOver(reason=_("Failover requested " "on non replicated " "backend.")) if (service.active_backend_id and service.active_backend_id != self.configuration.san_ip): self.snap_updates = [] rep_volumes = [] # update status for non-replicated primary volumes for v in volumes: vol_name = self.get_volume_name(v['id']) vol = self.client.search("volumes", name=vol_name) if v.replication_status != K2_REP_FAILED_OVER and vol.total: status = 'available' if v.volume_attachment: map_rs = self.client.search("mappings", volume=vol.hits[0]) status = 'in-use' if map_rs.total: map_rs.hits[0].delete() volume_updates.append({'volume_id': v['id'], 'updates': {'status': status}}) else: rep_volumes.append(v) # In-sync from secondaray array to primary array for v in rep_volumes: vol_name = self.get_volume_name(v['id']) vol = self.client.search("volumes", name=vol_name) rvol_name = self.get_rep_name(vol_name) rvol = self.target.search("volumes", name=rvol_name) session_name = self.get_session_name(v['id']) rsession_name = self.get_rep_name(session_name) ssn = self.target.search("replication/sessions", name=rsession_name) if ssn.total: tgt_ssn = ssn.hits[0] ssn = self.client.search("replication/sessions", name=session_name) if ssn.total: src_ssn = ssn.hits[0] if (tgt_ssn.state == 'failed_over' and tgt_ssn.current_role == 'target' and vol.total and src_ssn): map_rs = self.client.search("mappings", volume=vol.hits[0]) if map_rs.total: map_rs.hits[0].delete() tgt_ssn.state = 'in_sync' tgt_ssn.save() self._check_for_status(src_ssn, 'in_sync') if (rvol.total and src_ssn.state == 'in_sync' and src_ssn.current_role == 'target'): gen_no = self._create_volume_replica_user_snap(self.target, tgt_ssn) self.snap_updates.append({'tgt_ssn': tgt_ssn, 'gno': gen_no, 'stime': time.time()}) LOG.debug("The target session: %s state is " "changed to in sync", rsession_name) self._is_user_snap_sync_finished() # Delete secondary volume mappings and create snapshot for v in rep_volumes: vol_name = self.get_volume_name(v['id']) vol = self.client.search("volumes", name=vol_name) rvol_name = self.get_rep_name(vol_name) rvol = self.target.search("volumes", name=rvol_name) session_name = self.get_session_name(v['id']) rsession_name = self.get_rep_name(session_name) ssn = self.target.search("replication/sessions", name=rsession_name) if ssn.total: tgt_ssn = ssn.hits[0] ssn = self.client.search("replication/sessions", name=session_name) if ssn.total: src_ssn = ssn.hits[0] if (rvol.total and src_ssn.state == 'in_sync' and src_ssn.current_role == 'target'): map_rs = self.target.search("mappings", volume=rvol.hits[0]) if map_rs.total: map_rs.hits[0].delete() gen_no = self._create_volume_replica_user_snap(self.target, tgt_ssn) self.snap_updates.append({'tgt_ssn': tgt_ssn, 'gno': gen_no, 'stime': time.time()}) self._is_user_snap_sync_finished() # changing source sessions to failed-over for v in rep_volumes: vol_name = self.get_volume_name(v['id']) vol = self.client.search("volumes", name=vol_name) rvol_name = self.get_rep_name(vol_name) rvol = self.target.search("volumes", name=rvol_name) session_name = self.get_session_name(v['id']) rsession_name = self.get_rep_name(session_name) ssn = self.target.search("replication/sessions", name=rsession_name) if ssn.total: tgt_ssn = ssn.hits[0] ssn = self.client.search("replication/sessions", name=session_name) if ssn.total: src_ssn = ssn.hits[0] if (rvol.total and src_ssn.state == 'in_sync' and src_ssn.current_role == 'target'): src_ssn.state = 'failed_over' src_ssn.save() self._check_for_status(tgt_ssn, 'suspended') LOG.debug("The target session: %s state is " "changed to failed over", session_name) src_ssn.state = 'in_sync' src_ssn.save() LOG.debug("The target session: %s state is " "changed to in sync", session_name) rep_status = fields.ReplicationStatus.DISABLED volume_updates.append({'volume_id': v['id'], 'updates': {'replication_status': rep_status}}) back_end_ip = self.configuration.san_ip else: """Failover to replication target.""" for v in volumes: vol_name = self.get_volume_name(v['id']) rv = self.get_rep_name(vol_name) if self.target.search("volumes", name=rv).total: self._failover_volume(v) volume_updates.append( {'volume_id': v['id'], 'updates': {'replication_status': K2_REP_FAILED_OVER}}) else: volume_updates.append({'volume_id': v['id'], 'updates': {'status': 'error', }}) back_end_ip = self.replica.backend_id return back_end_ip, volume_updates, []
def failover_host(self, ctxt, volumes, secondary_id, groups=None): """Fail over the volume back and forth. if secondary_id is 'default', volumes will be failed back, otherwize failed over. """ volume_update_list = [] if secondary_id == strings.PRIMARY_BACKEND_ID: if not self._active_backend_id: LOG.info("Host has been failed back. doesn't need " "to fail back again.") return self._active_backend_id, volume_update_list, [] else: if self._active_backend_id: LOG.info("Host has been failed over to %s.", self._active_backend_id) return self._active_backend_id, volume_update_list, [] backend_id = self._replication._target_helper.backend['id'] if secondary_id is None: secondary_id = backend_id elif secondary_id != backend_id: raise exception.InvalidReplicationTarget( message=(_('Invalid secondary_backend_id specified. ' 'Valid backend id is %s.') % backend_id)) LOG.debug("Starting failover to %s.", secondary_id) replicated_luns = [] for volume in volumes: lun = Lun(volume) if lun.type_replication and lun.status == "available": replicated_luns.append(lun) else: volume_update = ( self._replication.failover_unreplicated_volume(lun)) volume_update_list.append(volume_update) if replicated_luns: try: if secondary_id != strings.PRIMARY_BACKEND_ID: self._replication.do_pprc_failover(replicated_luns, secondary_id) self._active_backend_id = secondary_id replicated_luns = self._switch_backend_connection( secondary_id, replicated_luns) else: self._replication.start_pprc_failback( replicated_luns, self._active_backend_id) self._active_backend_id = "" self._helper = self._replication._source_helper except restclient.APIException as e: raise exception.UnableToFailOver( reason=(_("Unable to failover host to %(id)s. " "Exception= %(ex)s") % {'id': secondary_id, 'ex': six.text_type(e)})) for lun in replicated_luns: volume_update = lun.get_volume_update() volume_update['replication_status'] = ( 'failed-over' if self._active_backend_id else 'enabled') model_update = {'volume_id': lun.os_id, 'updates': volume_update} volume_update_list.append(model_update) else: LOG.info("No volume has replication capability.") if secondary_id != strings.PRIMARY_BACKEND_ID: LOG.info("Switch to the target %s", secondary_id) self._switch_backend_connection(secondary_id) self._active_backend_id = secondary_id else: LOG.info("Switch to the primary %s", secondary_id) self._switch_backend_connection(self._active_backend_id) self._active_backend_id = "" return secondary_id, volume_update_list, []