mirror of
https://github.com/status-im/consul.git
synced 2025-01-11 06:16:08 +00:00
Fixes an issue where servers would delete catalog information set by
the node when they were trying to reconcile a member.
This commit is contained in:
parent
d428bc63c1
commit
3f1c4a6f44
@ -450,11 +450,11 @@ func (s *Server) handleAliveMember(member serf.Member) error {
|
|||||||
AFTER_CHECK:
|
AFTER_CHECK:
|
||||||
s.logger.Printf("[INFO] consul: member '%s' joined, marking health alive", member.Name)
|
s.logger.Printf("[INFO] consul: member '%s' joined, marking health alive", member.Name)
|
||||||
|
|
||||||
// Register with the catalog
|
// Register with the catalog.
|
||||||
req := structs.RegisterRequest{
|
req := structs.RegisterRequest{
|
||||||
Datacenter: s.config.Datacenter,
|
Datacenter: s.config.Datacenter,
|
||||||
ID: types.NodeID(member.Tags["id"]),
|
|
||||||
Node: member.Name,
|
Node: member.Name,
|
||||||
|
ID: types.NodeID(member.Tags["id"]),
|
||||||
Address: member.Addr.String(),
|
Address: member.Addr.String(),
|
||||||
Service: service,
|
Service: service,
|
||||||
Check: &structs.HealthCheck{
|
Check: &structs.HealthCheck{
|
||||||
@ -464,6 +464,10 @@ AFTER_CHECK:
|
|||||||
Status: structs.HealthPassing,
|
Status: structs.HealthPassing,
|
||||||
Output: SerfCheckAliveOutput,
|
Output: SerfCheckAliveOutput,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// If there's existing information about the node, do not
|
||||||
|
// clobber it.
|
||||||
|
SkipNodeUpdate: true,
|
||||||
}
|
}
|
||||||
_, err = s.raftApply(structs.RegisterRequestType, &req)
|
_, err = s.raftApply(structs.RegisterRequestType, &req)
|
||||||
return err
|
return err
|
||||||
@ -496,6 +500,7 @@ func (s *Server) handleFailedMember(member serf.Member) error {
|
|||||||
req := structs.RegisterRequest{
|
req := structs.RegisterRequest{
|
||||||
Datacenter: s.config.Datacenter,
|
Datacenter: s.config.Datacenter,
|
||||||
Node: member.Name,
|
Node: member.Name,
|
||||||
|
ID: types.NodeID(member.Tags["id"]),
|
||||||
Address: member.Addr.String(),
|
Address: member.Addr.String(),
|
||||||
Check: &structs.HealthCheck{
|
Check: &structs.HealthCheck{
|
||||||
Node: member.Name,
|
Node: member.Name,
|
||||||
@ -504,6 +509,10 @@ func (s *Server) handleFailedMember(member serf.Member) error {
|
|||||||
Status: structs.HealthCritical,
|
Status: structs.HealthCritical,
|
||||||
Output: SerfCheckFailedOutput,
|
Output: SerfCheckFailedOutput,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// If there's existing information about the node, do not
|
||||||
|
// clobber it.
|
||||||
|
SkipNodeUpdate: true,
|
||||||
}
|
}
|
||||||
_, err = s.raftApply(structs.RegisterRequestType, &req)
|
_, err = s.raftApply(structs.RegisterRequestType, &req)
|
||||||
return err
|
return err
|
||||||
|
@ -354,6 +354,103 @@ func TestLeader_Reconcile(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLeader_Reconcile_Races(t *testing.T) {
|
||||||
|
dir1, s1 := testServer(t)
|
||||||
|
defer os.RemoveAll(dir1)
|
||||||
|
defer s1.Shutdown()
|
||||||
|
|
||||||
|
testutil.WaitForLeader(t, s1.RPC, "dc1")
|
||||||
|
|
||||||
|
dir2, c1 := testClient(t)
|
||||||
|
defer os.RemoveAll(dir2)
|
||||||
|
defer c1.Shutdown()
|
||||||
|
|
||||||
|
addr := fmt.Sprintf("127.0.0.1:%d",
|
||||||
|
s1.config.SerfLANConfig.MemberlistConfig.BindPort)
|
||||||
|
if _, err := c1.JoinLAN([]string{addr}); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the server to reconcile the client and register it.
|
||||||
|
state := s1.fsm.State()
|
||||||
|
var nodeAddr string
|
||||||
|
testutil.WaitForResult(func() (bool, error) {
|
||||||
|
_, node, err := state.GetNode(c1.config.NodeName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if node != nil {
|
||||||
|
nodeAddr = node.Address
|
||||||
|
return true, nil
|
||||||
|
} else {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}, func(err error) {
|
||||||
|
t.Fatalf("client should be registered")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add in some metadata via the catalog (as if the agent synced it
|
||||||
|
// there). We also set the serfHealth check to failing so the reconile
|
||||||
|
// will attempt to flip it back
|
||||||
|
req := structs.RegisterRequest{
|
||||||
|
Datacenter: s1.config.Datacenter,
|
||||||
|
Node: c1.config.NodeName,
|
||||||
|
ID: c1.config.NodeID,
|
||||||
|
Address: nodeAddr,
|
||||||
|
NodeMeta: map[string]string{"hello": "world"},
|
||||||
|
Check: &structs.HealthCheck{
|
||||||
|
Node: c1.config.NodeName,
|
||||||
|
CheckID: SerfCheckID,
|
||||||
|
Name: SerfCheckName,
|
||||||
|
Status: structs.HealthCritical,
|
||||||
|
Output: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var out struct{}
|
||||||
|
if err := s1.RPC("Catalog.Register", &req, &out); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force a reconcile and make sure the metadata stuck around.
|
||||||
|
if err := s1.reconcile(); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
_, node, err := state.GetNode(c1.config.NodeName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if node == nil {
|
||||||
|
t.Fatalf("bad")
|
||||||
|
}
|
||||||
|
if hello, ok := node.Meta["hello"]; !ok || hello != "world" {
|
||||||
|
t.Fatalf("bad")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail the member and wait for the health to go critical.
|
||||||
|
c1.Shutdown()
|
||||||
|
testutil.WaitForResult(func() (bool, error) {
|
||||||
|
_, checks, err := state.NodeChecks(nil, c1.config.NodeName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
return checks[0].Status == structs.HealthCritical, errors.New(checks[0].Status)
|
||||||
|
}, func(err error) {
|
||||||
|
t.Fatalf("check status is %v, should be critical", err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Make sure the metadata didn't get clobbered.
|
||||||
|
_, node, err = state.GetNode(c1.config.NodeName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if node == nil {
|
||||||
|
t.Fatalf("bad")
|
||||||
|
}
|
||||||
|
if hello, ok := node.Meta["hello"]; !ok || hello != "world" {
|
||||||
|
t.Fatalf("bad")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLeader_LeftServer(t *testing.T) {
|
func TestLeader_LeftServer(t *testing.T) {
|
||||||
dir1, s1 := testServer(t)
|
dir1, s1 := testServer(t)
|
||||||
defer os.RemoveAll(dir1)
|
defer os.RemoveAll(dir1)
|
||||||
|
@ -201,6 +201,14 @@ type RegisterRequest struct {
|
|||||||
Service *NodeService
|
Service *NodeService
|
||||||
Check *HealthCheck
|
Check *HealthCheck
|
||||||
Checks HealthChecks
|
Checks HealthChecks
|
||||||
|
|
||||||
|
// SkipNodeUpdate can be used when a register request is intended for
|
||||||
|
// updating a service and/or checks, but doesn't want to overwrite any
|
||||||
|
// node information if the node is already registered. If the node
|
||||||
|
// doesn't exist, it will still be created, but if the node exists, any
|
||||||
|
// node portion of this update will not apply.
|
||||||
|
SkipNodeUpdate bool
|
||||||
|
|
||||||
WriteRequest
|
WriteRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,6 +225,12 @@ func (r *RegisterRequest) ChangesNode(node *Node) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we've been asked to skip the node update, then say there are no
|
||||||
|
// changes.
|
||||||
|
if r.SkipNodeUpdate {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Check if any of the node-level fields are being changed.
|
// Check if any of the node-level fields are being changed.
|
||||||
if r.ID != node.ID ||
|
if r.ID != node.ID ||
|
||||||
r.Node != node.Node ||
|
r.Node != node.Node ||
|
||||||
|
@ -136,6 +136,16 @@ func TestStructs_RegisterRequest_ChangesNode(t *testing.T) {
|
|||||||
t.Fatalf("should change")
|
t.Fatalf("should change")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.SkipNodeUpdate = true
|
||||||
|
if req.ChangesNode(node) {
|
||||||
|
t.Fatalf("should skip")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.SkipNodeUpdate = false
|
||||||
|
if !req.ChangesNode(node) {
|
||||||
|
t.Fatalf("should change")
|
||||||
|
}
|
||||||
|
|
||||||
restore()
|
restore()
|
||||||
if req.ChangesNode(node) {
|
if req.ChangesNode(node) {
|
||||||
t.Fatalf("should not change")
|
t.Fatalf("should not change")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user