open-consul/agent/consul/server_oss.go
R.B. Boyer a97d20cf63
catalog: compare node names case insensitively in more places (#12444)
Many places in consul already treated node names case insensitively.
The state store indexes already do it, but there are a few places that
did a direct byte comparison which have now been corrected.

One place of particular consideration is ensureCheckIfNodeMatches
which is executed during snapshot restore (among other places). If a
node check used a slightly different casing than the casing of the node
during register then the snapshot restore here would deterministically
fail. This has been fixed.

Primary approach:

    git grep -i "node.*[!=]=.*node" -- ':!*_test.go' ':!docs'
    git grep -i '\[[^]]*member[^]]*\]
    git grep -i '\[[^]]*\(member\|name\|node\)[^]]*\]' -- ':!*_test.go' ':!website' ':!ui' ':!agent/proxycfg/testing.go:' ':!*.md'
2022-02-24 16:54:47 -06:00

161 lines
4.2 KiB
Go

//go:build !consulent
// +build !consulent
package consul
import (
"fmt"
"strings"
"time"
"github.com/armon/go-metrics"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/serf/coordinate"
"github.com/hashicorp/serf/serf"
"google.golang.org/grpc"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib"
)
func (s *Server) registerEnterpriseGRPCServices(deps Deps, srv *grpc.Server) {}
func (s *Server) enterpriseValidateJoinWAN() error {
return nil // no-op
}
// JoinLAN is used to have Consul join the inner-DC pool The target address
// should be another node inside the DC listening on the Serf LAN address
func (s *Server) JoinLAN(addrs []string, entMeta *structs.EnterpriseMeta) (int, error) {
return s.serfLAN.Join(addrs, true)
}
// removeFailedNode is used to remove a failed node from the cluster
//
// if node is empty, just remove wanNode from the WAN
func (s *Server) removeFailedNode(
removeFn func(*serf.Serf, string) error,
node, wanNode string,
entMeta *structs.EnterpriseMeta,
) error {
maybeRemove := func(s *serf.Serf, node string) (bool, error) {
if !isSerfMember(s, node) {
return false, nil
}
return true, removeFn(s, node)
}
foundAny := false
var merr error
if node != "" {
if found, err := maybeRemove(s.serfLAN, node); err != nil {
merr = multierror.Append(merr, fmt.Errorf("could not remove failed node from LAN: %w", err))
} else if found {
foundAny = true
}
}
if s.serfWAN != nil {
if found, err := maybeRemove(s.serfWAN, wanNode); err != nil {
merr = multierror.Append(merr, fmt.Errorf("could not remove failed node from WAN: %w", err))
} else if found {
foundAny = true
}
}
if merr != nil {
return merr
}
if !foundAny {
return fmt.Errorf("agent: No node found with name '%s'", node)
}
return nil
}
// lanPoolAllMembers only returns our own segment or partition's members, because
// OSS servers can't be in multiple segments or partitions.
func (s *Server) lanPoolAllMembers() ([]serf.Member, error) {
return s.LANMembersInAgentPartition(), nil
}
// LANMembers returns the LAN members for one of:
//
// - the requested partition
// - the requested segment
// - all segments
//
// This is limited to segments and partitions that the node is a member of.
func (s *Server) LANMembers(filter LANMemberFilter) ([]serf.Member, error) {
if err := filter.Validate(); err != nil {
return nil, err
}
if filter.Segment != "" {
return nil, structs.ErrSegmentsNotSupported
}
return s.LANMembersInAgentPartition(), nil
}
func (s *Server) GetMatchingLANCoordinate(_, _ string) (*coordinate.Coordinate, error) {
return s.serfLAN.GetCoordinate()
}
func (s *Server) addEnterpriseLANCoordinates(cs lib.CoordinateSet) error {
return nil
}
func (s *Server) LANSendUserEvent(name string, payload []byte, coalesce bool) error {
err := s.serfLAN.UserEvent(name, payload, coalesce)
if err != nil {
return fmt.Errorf("error broadcasting event: %w", err)
}
return nil
}
func (s *Server) DoWithLANSerfs(
fn func(name, poolKind string, pool *serf.Serf) error,
errorFn func(name, poolKind string, err error) error,
) error {
if errorFn == nil {
errorFn = func(_, _ string, err error) error { return err }
}
err := fn("", "", s.serfLAN)
if err != nil {
return errorFn("", "", err)
}
return nil
}
// reconcile is used to reconcile the differences between Serf membership and
// what is reflected in our strongly consistent store. Mainly we need to ensure
// all live nodes are registered, all failed nodes are marked as such, and all
// left nodes are deregistered.
func (s *Server) reconcile() (err error) {
defer metrics.MeasureSince([]string{"leader", "reconcile"}, time.Now())
members := s.serfLAN.Members()
knownMembers := make(map[string]struct{})
for _, member := range members {
memberName := strings.ToLower(member.Name)
if err := s.reconcileMember(member); err != nil {
return err
}
knownMembers[memberName] = struct{}{}
}
// Reconcile any members that have been reaped while we were not the
// leader.
return s.reconcileReaped(knownMembers, nil)
}
func (s *Server) addEnterpriseStats(stats map[string]map[string]string) {
// no-op
}
func getSerfMemberEnterpriseMeta(member serf.Member) *structs.EnterpriseMeta {
return structs.NodeEnterpriseMetaInDefaultPartition()
}