etcdserver/server.go
func (s *EtcdServer) configure(ctx context.Context, cc raftpb.ConfChange) ([]*membership.Member, error) {
	cc.ID = s.reqIDGen.Next()
	ch := s.w.Register(cc.ID)

	start := time.Now()
	if err := s.r.ProposeConfChange(ctx, cc); err != nil {
		s.w.Trigger(cc.ID, nil)
		return nil, err
	}

	select {
	case x := <-ch:
		if x == nil {
			if lg := s.getLogger(); lg != nil {
				lg.Panic("failed to configure")
			} else {
				plog.Panicf("configure trigger value should never be nil")
			}
		}
		resp := x.(*confChangeResponse)
		if lg := s.getLogger(); lg != nil {
			lg.Info(
				"applied a configuration change through raft",
				zap.String("local-member-id", s.ID().String()),
				zap.String("raft-conf-change", cc.Type.String()),
				zap.String("raft-conf-change-node-id", types.ID(cc.NodeID).String()),
			)
		}
		return resp.membs, resp.err

	case <-ctx.Done():
		s.w.Trigger(cc.ID, nil) // GC wait
		return nil, s.parseProposeCtxErr(ctx.Err(), start)

	case <-s.stopping:
		return nil, ErrStopped
	}
}
func (s *EtcdServer) configure(ctx context.Context, cc raftpb.ConfChange) ([]*membership.Member, error) {
	cc.ID = s.reqIDGen.Next()
	ch := s.w.Register(cc.ID)

	start := time.Now()
	if err := s.r.ProposeConfChange(ctx, cc); err != nil {
		s.w.Trigger(cc.ID, nil)
		return nil, err
	}

	select {
	case x := <-ch:
		if x == nil {
			if lg := s.getLogger(); lg != nil {
				lg.Panic("failed to configure")
			} else {
				plog.Panicf("configure trigger value should never be nil")
			}
		}
		resp := x.(*confChangeResponse)
		if lg := s.getLogger(); lg != nil {
			lg.Info(
				"applied a configuration change through raft",
				zap.String("local-member-id", s.ID().String()),
				zap.String("raft-conf-change", cc.Type.String()),
				zap.String("raft-conf-change-node-id", types.ID(cc.NodeID).String()),
			)
		}
		return resp.membs, resp.err

	case <-ctx.Done():
		s.w.Trigger(cc.ID, nil) // GC wait
		return nil, s.parseProposeCtxErr(ctx.Err(), start)

	case <-s.stopping:
		return nil, ErrStopped
	}
}
// configure sends a configuration change through consensus and
// then waits for it to be applied to the server. It
// will block until the change is performed or there is an error.