'Failover a backend to a secondary replication target.
Instructs a replication capable/configured backend to failover
to one of it\'s secondary replication targets. host=None is
an acceetable input, and leaves it to the driver to failover
to the only configured target, or to choose a target on it\'s
own. All of the hosts volumes will be passed on to the driver
in order for it to determine the replicated volumes on the host,
if needed.
:param context: security context
:param secondary_backend_id: Specifies backend_id to fail over to'

def failover(self, context, secondary_backend_id=None):

    updates = {}
    repl_status = fields.ReplicationStatus
    svc_host = vol_utils.extract_host(self.host, 'backend')
    service = objects.Service.get_by_args(context, svc_host, constants.VOLUME_BINARY)
    volumes = self._get_my_volumes(context)
    replicated_vols = []
    for volume in volumes:
        if (volume.replication_status not in (repl_status.DISABLED, repl_status.NOT_CAPABLE)):
            replicated_vols.append(volume)
        elif (secondary_backend_id != self.FAILBACK_SENTINEL):
            volume.previous_status = volume.status
            volume.status = 'error'
            volume.replication_status = repl_status.NOT_CAPABLE
            volume.save()
            for snapshot in volume.snapshots:
                snapshot.status = fields.SnapshotStatus.ERROR
                snapshot.save()
    volume_update_list = None
    group_update_list = None
    try:
        failover = getattr(self.driver, ('failover' if service.is_clustered else 'failover_host'))
        filters = self._get_cluster_or_host_filters()
        groups = objects.GroupList.get_all_replicated(context, filters=filters)
        (active_backend_id, volume_update_list, group_update_list) = failover(context, replicated_vols, secondary_id=secondary_backend_id, groups=groups)
        try:
            update_data = {u['volume_id']: u['updates'] for u in volume_update_list}
        except KeyError:
            msg = "Update    list,    doesn't    include    volume_id"
            raise exception.ProgrammingError(reason=msg)
        try:
            update_group_data = {g['group_id']: g['updates'] for g in group_update_list}
        except KeyError:
            msg = "Update    list,    doesn't    include    group_id"
            raise exception.ProgrammingError(reason=msg)
    except Exception as exc:
        if isinstance(exc, exception.InvalidReplicationTarget):
            log_method = LOG.error
            if service.active_backend_id:
                updates['replication_status'] = repl_status.FAILED_OVER
            else:
                updates['replication_status'] = repl_status.ENABLED
        else:
            log_method = LOG.exception
            updates.update(disabled=True, replication_status=repl_status.FAILOVER_ERROR)
        log_method('Error    encountered    during    failover    on    host:    %(host)s    to    %(backend_id)s:    %(error)s', {'host': self.host, 'backend_id': secondary_backend_id, 'error': exc})
        LOG.error('Failed    update_list    is:    %s', volume_update_list)
        self.finish_failover(context, service, updates)
        return
    if (secondary_backend_id == 'default'):
        updates['replication_status'] = repl_status.ENABLED
        updates['active_backend_id'] = ''
        updates['disabled'] = service.frozen
        updates['disabled_reason'] = ('frozen' if service.frozen else '')
    else:
        updates['replication_status'] = repl_status.FAILED_OVER
        updates['active_backend_id'] = active_backend_id
        updates['disabled'] = True
        updates['disabled_reason'] = 'failed-over'
    self.finish_failover(context, service, updates)
    for volume in replicated_vols:
        update = update_data.get(volume.id, {})
        if (update.get('status', '') == 'error'):
            update['replication_status'] = repl_status.FAILOVER_ERROR
        elif (update.get('replication_status') in (None, repl_status.FAILED_OVER)):
            update['replication_status'] = updates['replication_status']
        if (update['replication_status'] == repl_status.FAILOVER_ERROR):
            update.setdefault('status', 'error')
            for snapshot in volume.snapshots:
                snapshot.status = fields.SnapshotStatus.ERROR
                snapshot.save()
        if ('status' in update):
            update['previous_status'] = volume.status
        volume.update(update)
        volume.save()
    for grp in groups:
        update = update_group_data.get(grp.id, {})
        if (update.get('status', '') == 'error'):
            update['replication_status'] = repl_status.FAILOVER_ERROR
        elif (update.get('replication_status') in (None, repl_status.FAILED_OVER)):
            update['replication_status'] = updates['replication_status']
        if (update['replication_status'] == repl_status.FAILOVER_ERROR):
            update.setdefault('status', 'error')
        grp.update(update)
        grp.save()
    LOG.info('Failed    over    to    replication    target    successfully.')
