diff --git a/consul/catalog_endpoint.go b/consul/catalog_endpoint.go index 4abe02584..a5b674869 100644 --- a/consul/catalog_endpoint.go +++ b/consul/catalog_endpoint.go @@ -90,11 +90,13 @@ func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error } } - _, err = c.srv.raftApply(structs.RegisterRequestType, args) + resp, err := c.srv.raftApply(structs.RegisterRequestType, args) if err != nil { return err } - + if respErr, ok := resp.(error); ok { + return respErr + } return nil } diff --git a/consul/state/catalog.go b/consul/state/catalog.go index ca5eb6110..bbfddb23b 100644 --- a/consul/state/catalog.go +++ b/consul/state/catalog.go @@ -165,22 +165,45 @@ func (s *StateStore) EnsureNode(idx uint64, node *structs.Node) error { // registration or modify an existing one in the state store. It allows // passing in a memdb transaction so it may be part of a larger txn. func (s *StateStore) ensureNodeTxn(tx *memdb.Txn, idx uint64, node *structs.Node) error { - // Check for an existing node - existing, err := tx.First("nodes", "id", node.Node) - if err != nil { - return fmt.Errorf("node name lookup failed: %s", err) + // See if there's an existing node with this UUID, and make sure the + // name is the same. + var n *structs.Node + if node.ID != "" { + existing, err := tx.First("nodes", "uuid", string(node.ID)) + if err != nil { + return fmt.Errorf("node lookup failed: %s", err) + } + if existing != nil { + n = existing.(*structs.Node) + fmt.Printf("XXX %#v\n", *n) + if n.Node != node.Node { + return fmt.Errorf("node ID %q for node %q aliases existing node %q", + node.ID, node.Node, n.Node) + } + } } - // Get the indexes - if existing != nil { - node.CreateIndex = existing.(*structs.Node).CreateIndex + // Check for an existing node by name to support nodes with no IDs. + if n == nil { + existing, err := tx.First("nodes", "id", node.Node) + if err != nil { + return fmt.Errorf("node name lookup failed: %s", err) + } + if existing != nil { + n = existing.(*structs.Node) + } + } + + // Get the indexes. + if n != nil { + node.CreateIndex = n.CreateIndex node.ModifyIndex = idx } else { node.CreateIndex = idx node.ModifyIndex = idx } - // Insert the node and update the index + // Insert the node and update the index. if err := tx.Insert("nodes", node); err != nil { return fmt.Errorf("failed inserting node: %s", err) } diff --git a/consul/state/catalog_test.go b/consul/state/catalog_test.go index 88dcff5a8..21bf59ab6 100644 --- a/consul/state/catalog_test.go +++ b/consul/state/catalog_test.go @@ -4,6 +4,7 @@ import ( "fmt" "reflect" "sort" + "strings" "testing" "github.com/hashicorp/consul/consul/structs" @@ -419,6 +420,23 @@ func TestStateStore_EnsureNode(t *testing.T) { if idx != 3 { t.Fatalf("bad index: %d", idx) } + + // Add an ID to the node + in.ID = types.NodeID("cda916bc-a357-4a19-b886-59419fcee50c") + if err := s.EnsureNode(4, in); err != nil { + t.Fatalf("err: %v", err) + } + + // Now try to add another node with the same ID + in = &structs.Node{ + Node: "nope", + ID: types.NodeID("cda916bc-a357-4a19-b886-59419fcee50c"), + Address: "1.2.3.4", + } + err = s.EnsureNode(5, in) + if err == nil || !strings.Contains(err.Error(), "aliases existing node") { + t.Fatalf("err: %v", err) + } } func TestStateStore_GetNodes(t *testing.T) {