etcdserver/server.go
func (s *EtcdServer) applyConfChange(cc raftpb.ConfChange, confState *raftpb.ConfState) (bool, error) {
	if err := s.cluster.ValidateConfigurationChange(cc); err != nil {
		cc.NodeID = raft.None
		s.r.ApplyConfChange(cc)
		return false, err
	}

	lg := s.getLogger()
	*confState = *s.r.ApplyConfChange(cc)
	switch cc.Type {
	case raftpb.ConfChangeAddNode:
		m := new(membership.Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if lg != nil {
				lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		if cc.NodeID != uint64(m.ID) {
			if lg != nil {
				lg.Panic(
					"got different member ID",
					zap.String("member-id-from-config-change-entry", types.ID(cc.NodeID).String()),
					zap.String("member-id-from-message", m.ID.String()),
				)
			} else {
				plog.Panicf("nodeID should always be equal to member ID")
			}
		}
		s.cluster.AddMember(m)
		if m.ID != s.id {
			s.r.transport.AddPeer(m.ID, m.PeerURLs)
		}

	case raftpb.ConfChangeRemoveNode:
		id := types.ID(cc.NodeID)
		s.cluster.RemoveMember(id)
		if id == s.id {
			return true, nil
		}
		s.r.transport.RemovePeer(id)

	case raftpb.ConfChangeUpdateNode:
		m := new(membership.Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if lg != nil {
				lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		if cc.NodeID != uint64(m.ID) {
			if lg != nil {
				lg.Panic(
					"got different member ID",
					zap.String("member-id-from-config-change-entry", types.ID(cc.NodeID).String()),
					zap.String("member-id-from-message", m.ID.String()),
				)
			} else {
				plog.Panicf("nodeID should always be equal to member ID")
			}
		}
		s.cluster.UpdateRaftAttributes(m.ID, m.RaftAttributes)
		if m.ID != s.id {
			s.r.transport.UpdatePeer(m.ID, m.PeerURLs)
		}
	}
	return false, nil
}
func (s *EtcdServer) applyConfChange(cc raftpb.ConfChange, confState *raftpb.ConfState) (bool, error) {
	if err := s.cluster.ValidateConfigurationChange(cc); err != nil {
		cc.NodeID = raft.None
		s.r.ApplyConfChange(cc)
		return false, err
	}

	lg := s.getLogger()
	*confState = *s.r.ApplyConfChange(cc)
	switch cc.Type {
	case raftpb.ConfChangeAddNode:
		m := new(membership.Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if lg != nil {
				lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		if cc.NodeID != uint64(m.ID) {
			if lg != nil {
				lg.Panic(
					"got different member ID",
					zap.String("member-id-from-config-change-entry", types.ID(cc.NodeID).String()),
					zap.String("member-id-from-message", m.ID.String()),
				)
			} else {
				plog.Panicf("nodeID should always be equal to member ID")
			}
		}
		s.cluster.AddMember(m)
		if m.ID != s.id {
			s.r.transport.AddPeer(m.ID, m.PeerURLs)
		}

	case raftpb.ConfChangeRemoveNode:
		id := types.ID(cc.NodeID)
		s.cluster.RemoveMember(id)
		if id == s.id {
			return true, nil
		}
		s.r.transport.RemovePeer(id)

	case raftpb.ConfChangeUpdateNode:
		m := new(membership.Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if lg != nil {
				lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		if cc.NodeID != uint64(m.ID) {
			if lg != nil {
				lg.Panic(
					"got different member ID",
					zap.String("member-id-from-config-change-entry", types.ID(cc.NodeID).String()),
					zap.String("member-id-from-message", m.ID.String()),
				)
			} else {
				plog.Panicf("nodeID should always be equal to member ID")
			}
		}
		s.cluster.UpdateRaftAttributes(m.ID, m.RaftAttributes)
		if m.ID != s.id {
			s.r.transport.UpdatePeer(m.ID, m.PeerURLs)
		}
	}
	return false, nil
}
// applyConfChange applies a ConfChange to the server. It is only
// invoked with a ConfChange that has already passed through Raft