Esempio n. 1
0
    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
Esempio n. 2
0
 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)
Esempio n. 3
0
    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
Esempio n. 4
0
    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, []
Esempio n. 5
0
    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, []