Skip to content

Commit 6f52314

Browse files
committed
Fixed function GetNodeID that was not working due to wrong type when searching node from its ID
Thus, all tests about renaming were not working properly. Added the full test cas that allowed me to detect it.
1 parent bbf5822 commit 6f52314

File tree

2 files changed

+131
-10
lines changed

2 files changed

+131
-10
lines changed

agent/consul/state/catalog.go

+24-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package state
22

33
import (
4+
"encoding/hex"
45
"fmt"
56
"strings"
67

@@ -375,12 +376,12 @@ func (s *Store) ensureNodeTxn(tx *memdb.Txn, idx uint64, node *structs.Node) err
375376
// name is the same.
376377
var n *structs.Node
377378
if node.ID != "" {
378-
existing, err := tx.First("nodes", "uuid", string(node.ID))
379+
existing, err := getNodeIDTxn(tx, node.ID)
379380
if err != nil {
380381
return fmt.Errorf("node lookup failed: %s", err)
381382
}
382383
if existing != nil {
383-
n = existing.(*structs.Node)
384+
n = existing
384385
if n.Node != node.Node {
385386
// Lets first get all nodes and check whether name do match, we do not allow clash on nodes without ID
386387
dupNameError := s.ensureNoNodeWithSimilarNameTxn(tx, node, false)
@@ -461,6 +462,25 @@ func (s *Store) GetNode(id string) (uint64, *structs.Node, error) {
461462
return idx, nil, nil
462463
}
463464

465+
func getNodeIDTxn(tx *memdb.Txn, id types.NodeID) (*structs.Node, error) {
466+
sanitized := strings.Replace(string(id), "-", "", -1)
467+
sanitizedLength := len(sanitized)
468+
if sanitizedLength%2 != 0 {
469+
return nil, fmt.Errorf("Input (without hyphens) must be even length")
470+
}
471+
472+
dec, err := hex.DecodeString(sanitized)
473+
474+
node, err := tx.First("nodes", "uuid", dec)
475+
if err != nil {
476+
return nil, fmt.Errorf("node lookup failed: %s", err)
477+
}
478+
if node != nil {
479+
return node.(*structs.Node), nil
480+
}
481+
return nil, nil
482+
}
483+
464484
// GetNodeID is used to retrieve a node registration by node ID.
465485
func (s *Store) GetNodeID(id types.NodeID) (uint64, *structs.Node, error) {
466486
tx := s.db.Txn(false)
@@ -470,14 +490,8 @@ func (s *Store) GetNodeID(id types.NodeID) (uint64, *structs.Node, error) {
470490
idx := maxIndexTxn(tx, "nodes")
471491

472492
// Retrieve the node from the state store
473-
node, err := tx.First("nodes", "uuid", string(id))
474-
if err != nil {
475-
return 0, nil, fmt.Errorf("node lookup failed: %s", err)
476-
}
477-
if node != nil {
478-
return idx, node.(*structs.Node), nil
479-
}
480-
return idx, nil, nil
493+
node, err := getNodeIDTxn(tx, id)
494+
return idx, node, err
481495
}
482496

483497
// Nodes is used to return all of the known nodes.

agent/consul/state/catalog_test.go

+107
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,113 @@ func TestStateStore_EnsureNodeDeprecated(t *testing.T) {
477477
}
478478
}
479479

480+
func TestNodeRenamingNodes(t *testing.T) {
481+
s := testStateStore(t)
482+
483+
nodeID1 := types.NodeID("b789bf0a-d96b-4f70-a4a6-ac5dfaece53d")
484+
nodeID2 := types.NodeID("27bee224-a4d7-45d0-9b8e-65b3c94a61ba")
485+
486+
// Node1 with ID
487+
in1 := &structs.Node{
488+
ID: nodeID1,
489+
Node: "node1",
490+
Address: "1.1.1.1",
491+
}
492+
493+
if err := s.EnsureNode(1, in1); err != nil {
494+
t.Fatalf("err: %s", err)
495+
}
496+
497+
// Node2 with ID
498+
in2 := &structs.Node{
499+
ID: nodeID2,
500+
Node: "node2",
501+
Address: "1.1.1.2",
502+
}
503+
504+
if err := s.EnsureNode(2, in2); err != nil {
505+
t.Fatalf("err: %s", err)
506+
}
507+
508+
// Node3 without ID
509+
in3 := &structs.Node{
510+
Node: "node3",
511+
Address: "1.1.1.3",
512+
}
513+
514+
if err := s.EnsureNode(3, in3); err != nil {
515+
t.Fatalf("err: %s", err)
516+
}
517+
518+
if _, node, err := s.GetNodeID(nodeID1); err != nil || node == nil || node.ID != nodeID1 {
519+
t.Fatalf("err: %s, node:= %q", err, node)
520+
}
521+
522+
if _, node, err := s.GetNodeID(nodeID2); err != nil && node == nil || node.ID != nodeID2 {
523+
t.Fatalf("err: %s", err)
524+
}
525+
526+
// Renaming node2 into node1 should fail
527+
in2Modify := &structs.Node{
528+
ID: nodeID2,
529+
Node: "node1",
530+
Address: "1.1.1.2",
531+
}
532+
if err := s.EnsureNode(4, in2Modify); err == nil {
533+
t.Fatalf("Renaming node2 into node1 should fail")
534+
}
535+
536+
// Conflict with case insensitive matching as well
537+
in2Modify = &structs.Node{
538+
ID: nodeID2,
539+
Node: "NoDe1",
540+
Address: "1.1.1.2",
541+
}
542+
if err := s.EnsureNode(5, in2Modify); err == nil {
543+
t.Fatalf("Renaming node2 into node1 should fail")
544+
}
545+
546+
// Conflict with case insensitive on node without ID
547+
in2Modify = &structs.Node{
548+
ID: nodeID2,
549+
Node: "NoDe3",
550+
Address: "1.1.1.2",
551+
}
552+
if err := s.EnsureNode(6, in2Modify); err == nil {
553+
t.Fatalf("Renaming node2 into node1 should fail")
554+
}
555+
556+
// No conflict, should work
557+
in2Modify = &structs.Node{
558+
ID: nodeID2,
559+
Node: "node2bis",
560+
Address: "1.1.1.2",
561+
}
562+
if err := s.EnsureNode(6, in2Modify); err != nil {
563+
t.Fatalf("Renaming node2 into node1 should fail")
564+
}
565+
566+
// Retrieve the node again
567+
idx, out, err := s.GetNode("node2bis")
568+
if err != nil {
569+
t.Fatalf("err: %s", err)
570+
}
571+
572+
// Retrieve the node again
573+
idx2, out2, err := s.GetNodeID(nodeID2)
574+
if err != nil {
575+
t.Fatalf("err: %s", err)
576+
}
577+
578+
if idx != idx2 {
579+
t.Fatalf("node should be the same")
580+
}
581+
582+
if out.ID != out2.ID || out.Node != out2.Node {
583+
t.Fatalf("all should match")
584+
}
585+
}
586+
480587
func TestStateStore_EnsureNode(t *testing.T) {
481588
s := testStateStore(t)
482589

0 commit comments

Comments
 (0)