etcdserver/api/membership/cluster.go
func (c *RaftCluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
	members, removed := membersFromStore(c.lg, c.v2store)
	id := types.ID(cc.NodeID)
	if removed[id] {
		return ErrIDRemoved
	}
	switch cc.Type {
	case raftpb.ConfChangeAddNode:
		if members[id] != nil {
			return ErrIDExists
		}
		urls := make(map[string]bool)
		for _, m := range members {
			for _, u := range m.PeerURLs {
				urls[u] = true
			}
		}
		m := new(Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if c.lg != nil {
				c.lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		for _, u := range m.PeerURLs {
			if urls[u] {
				return ErrPeerURLexists
			}
		}

	case raftpb.ConfChangeRemoveNode:
		if members[id] == nil {
			return ErrIDNotFound
		}

	case raftpb.ConfChangeUpdateNode:
		if members[id] == nil {
			return ErrIDNotFound
		}
		urls := make(map[string]bool)
		for _, m := range members {
			if m.ID == id {
				continue
			}
			for _, u := range m.PeerURLs {
				urls[u] = true
			}
		}
		m := new(Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if c.lg != nil {
				c.lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		for _, u := range m.PeerURLs {
			if urls[u] {
				return ErrPeerURLexists
			}
		}

	default:
		if c.lg != nil {
			c.lg.Panic("unknown ConfChange type", zap.String("type", cc.Type.String()))
		} else {
			plog.Panicf("ConfChange type should be either AddNode, RemoveNode or UpdateNode")
		}
	}
	return nil
}
func (c *RaftCluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
	members, removed := membersFromStore(c.lg, c.v2store)
	id := types.ID(cc.NodeID)
	if removed[id] {
		return ErrIDRemoved
	}
	switch cc.Type {
	case raftpb.ConfChangeAddNode:
		if members[id] != nil {
			return ErrIDExists
		}
		urls := make(map[string]bool)
		for _, m := range members {
			for _, u := range m.PeerURLs {
				urls[u] = true
			}
		}
		m := new(Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if c.lg != nil {
				c.lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		for _, u := range m.PeerURLs {
			if urls[u] {
				return ErrPeerURLexists
			}
		}

	case raftpb.ConfChangeRemoveNode:
		if members[id] == nil {
			return ErrIDNotFound
		}

	case raftpb.ConfChangeUpdateNode:
		if members[id] == nil {
			return ErrIDNotFound
		}
		urls := make(map[string]bool)
		for _, m := range members {
			if m.ID == id {
				continue
			}
			for _, u := range m.PeerURLs {
				urls[u] = true
			}
		}
		m := new(Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if c.lg != nil {
				c.lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		for _, u := range m.PeerURLs {
			if urls[u] {
				return ErrPeerURLexists
			}
		}

	default:
		if c.lg != nil {
			c.lg.Panic("unknown ConfChange type", zap.String("type", cc.Type.String()))
		} else {
			plog.Panicf("ConfChange type should be either AddNode, RemoveNode or UpdateNode")
		}
	}
	return nil
}
func ( c * RaftCluster ) ValidateConfigurationChange ( cc raftpb . ConfChange ) error { members , removed := membersFromStore ( c . lg , c . v2store ) id := types . ID ( cc . NodeID ) if removed [ id ] { return ErrIDRemoved } switch cc . Type { case raftpb . ConfChangeAddNode : if members [ id ] != nil { return ErrIDExists } urls := make ( map [ string ] bool ) for _ , m := range members { for _ , u := range m . PeerURLs { urls [ u ] = true } } m := new ( Member ) if err := json . Unmarshal ( cc . Context , m ) ; err != nil { if c . lg != nil { c . lg . Panic ( " " , zap . Error ( err ) ) } else { plog . Panicf ( " " , err ) } } for _ , u := range m . PeerURLs { if urls [ u ] { return ErrPeerURLexists } } case raftpb . ConfChangeRemoveNode : if members [ id ] == nil { return ErrIDNotFound } case raftpb . ConfChangeUpdateNode : if members [ id ] == nil { return ErrIDNotFound } urls := make ( map [ string ] bool ) for _ , m := range members { if m . ID == id { continue } for _ , u := range m . PeerURLs { urls [ u ] = true } } m := new ( Member ) if err := json . Unmarshal ( cc . Context , m ) ; err != nil { if c . lg != nil { c . lg . Panic ( " " , zap . Error ( err ) ) } else { plog . Panicf ( " " , err ) } } for _ , u := range m . PeerURLs { if urls [ u ] { return ErrPeerURLexists } } default : if c . lg != nil { c . lg . Panic ( " " , zap . String ( " " , cc . Type . String ( ) ) ) } else { plog . Panicf ( " " ) } } return nil }
// ValidateConfigurationChange takes a proposed ConfChange and
// ensures that it is still valid.
ValidateConfigurationChange takes a proposed ConfChange and ensures that it is still valid .