summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2023-10-22 23:55:49 +0300
committerPaul Buetow <paul@buetow.org>2023-10-22 23:55:49 +0300
commit8650dd57474e991515c93169151e6187205c9ff3 (patch)
treeef205edf763a91e737a47eb8cf04a817f7e78d4b /internal
parent61919768cfe4df8fbd709e8e6034f4c4c83def27 (diff)
refactor Nodes
Diffstat (limited to 'internal')
-rw-r--r--internal/client/client.go6
-rw-r--r--internal/config/config.go105
-rw-r--r--internal/config/config_test.go28
-rw-r--r--internal/quorum/quorum.go14
-rw-r--r--internal/quorum/quorum_test.go42
5 files changed, 124 insertions, 71 deletions
diff --git a/internal/client/client.go b/internal/client/client.go
index 3cb2775..f05fcba 100644
--- a/internal/client/client.go
+++ b/internal/client/client.go
@@ -13,8 +13,10 @@ func Start(ctx context.Context, conf config.Config, myVoteCh <-chan vote.Vote) {
log.Println("client: starting")
fanOut := make([]chan vote.Vote, len(conf.Nodes))
- for i, node := range conf.Nodes {
- fanOut[i] = startConnection(ctx, node)
+ nodeNum := 0
+ for _, node := range conf.Nodes {
+ fanOut[nodeNum] = startConnection(ctx, node.Hostname)
+ nodeNum++
}
go func() {
diff --git a/internal/config/config.go b/internal/config/config.go
index a882268..b5030ee 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -11,19 +11,26 @@ import (
"codeberg.org/snonux/gorum/internal/utils"
)
+type Node struct {
+ Port int
+ Priority int
+ Alias string `json:",omitempty"`
+ Hostname string
+ originalId string
+}
+
type Config struct {
- StateDir string
- ScoreFile string
- WinnerFile string
- Address string
- Nodes []string
- LoopIntervalS int64 `json:"LoopIntervalS,omitempty"`
- MyID string `json:"MyID,omitempty"`
- RelaxedMode bool `json:"RelaxedMode,omitempty"`
- nodeNumberCache map[string]int
- EmailTo string `json:"EmailTo,omitempty"`
- EmailFrom string `json:"EmailFrom,omitempty"`
- SMTPServer string `json:"SMTPServer,omitempty"`
+ StateDir string
+ ScoreFile string
+ WinnerFile string
+ Address string
+ Nodes map[string]Node
+ LoopIntervalS int64 `json:"LoopIntervalS,omitempty"`
+ MyID string `json:"MyID,omitempty"`
+ RelaxedMode bool `json:"RelaxedMode,omitempty"`
+ EmailTo string `json:"EmailTo,omitempty"`
+ EmailFrom string `json:"EmailFrom,omitempty"`
+ SMTPServer string `json:"SMTPServer,omitempty"`
}
func NewFromConfigFile(configFile string) (Config, error) {
@@ -45,6 +52,15 @@ func NewFromConfigFile(configFile string) (Config, error) {
return conf, err
}
+ // Make it so that the key is the Hostname for internal lookup.
+ newNodes := make(map[string]Node, len(conf.Nodes))
+ for id, node := range conf.Nodes {
+ log.Printf("adding node %s: %v", id, node)
+ node.originalId = id
+ newNodes[node.Hostname] = node
+ }
+ conf.Nodes = newNodes
+
return conf.setDefaults()
}
@@ -70,9 +86,14 @@ func WithAddress(address string) func(*Config) {
}
}
-func WithNodes(nodes ...string) func(*Config) {
+func WithNodes(nodes ...Node) func(*Config) {
return func(conf *Config) {
- conf.Nodes = append(conf.Nodes, nodes...)
+ if conf.Nodes == nil {
+ conf.Nodes = make(map[string]Node)
+ }
+ for _, node := range nodes {
+ conf.Nodes[node.Hostname] = node
+ }
}
}
@@ -106,35 +127,20 @@ func (conf Config) setDefaults() (Config, error) {
conf.MyID = hostname
}
- conf.nodeNumberCache = make(map[string]int, len(conf.Nodes))
- for i, node := range conf.Nodes {
- conf.nodeNumberCache[utils.StripPort(node)] = i
- }
return conf, nil
}
-func (conf Config) NodeNumber(node string) int {
- node = utils.StripPort(node)
- nodeNumber, ok := conf.nodeNumberCache[node]
- if ok {
- return nodeNumber
+func (conf Config) NodePriority(id string) (int, error) {
+ node, err := conf.findNode(id)
+ if err != nil {
+ return 0, err
}
-
- log.Println("config:",
- fmt.Errorf("node %s not found - it will affect it's score!", node))
- return 0
+ return node.Priority, nil
}
func (conf Config) IsNode(remoteAddr string) bool {
- remoteAddr = utils.StripPort(remoteAddr)
-
- for _, node := range conf.Nodes {
- if remoteAddr == utils.StripPort(node) {
- return true
- }
- }
-
- return false
+ _, err := conf.findNode(utils.StripPort(remoteAddr))
+ return err == nil
}
func (conf Config) IsNodeWithLookup(remoteAddr string,
@@ -142,19 +148,38 @@ func (conf Config) IsNodeWithLookup(remoteAddr string,
remoteAddr = utils.StripPort(remoteAddr)
- for _, node := range conf.Nodes {
- ips, err := lookupIP(utils.StripPort(node))
+ compare := func(hostname string) bool {
+ ips, err := lookupIP(hostname)
if err != nil {
log.Println("config:", err)
- continue
+ return false
}
-
for _, ip := range ips {
if remoteAddr == ip.String() {
return true
}
}
+ return false
}
+ for _, node := range conf.Nodes {
+ if compare(node.Hostname) || compare(node.Alias) {
+ return true
+ }
+ }
return false
}
+
+func (conf Config) findNode(hostname string) (Node, error) {
+ if node, ok := conf.Nodes[hostname]; ok {
+ return node, nil
+ }
+
+ for _, node := range conf.Nodes {
+ if hostname == node.Alias {
+ return node, nil
+ }
+ }
+
+ return Node{}, fmt.Errorf("node %s not found", hostname)
+}
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index e24c048..900f045 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -6,30 +6,32 @@ import (
"testing"
)
-func TestNodeNumber(t *testing.T) {
+func TestNodePriority(t *testing.T) {
t.Parallel()
- conf, _ := New(WithNodes("localhost:1234", "hamburger:4321"))
+ conf, _ := New(WithNodes(
+ Node{Hostname: "localhost", Port: 1234, Priority: 200},
+ Node{Hostname: "hamburger", Port: 4321, Priority: 100}))
- num := conf.NodeNumber("localhost")
- if num != 0 {
- t.Errorf("localhost should be node number 0 but is %d", num)
+ num, _ := conf.NodePriority("localhost")
+ if num != 200 {
+ t.Errorf("localhost should have priority 200 but has %d", num)
}
-
- num = conf.NodeNumber("hamburger")
- if num != 1 {
- t.Errorf("hamburger should be node number 1 but is %d", num)
+ num, _ = conf.NodePriority("hamburger")
+ if num != 100 {
+ t.Errorf("hamburger should have priority 100 but has %d", num)
}
}
func TestIsNode(t *testing.T) {
t.Parallel()
- conf, _ := New(WithNodes("localhost:1234", "hamburger:4321"))
+ conf, _ := New(WithNodes(
+ Node{Hostname: "localhost", Port: 1234, Priority: 200},
+ Node{Hostname: "hamburger", Port: 4321, Priority: 100}))
remoteAddr := "localhost:323232"
if !conf.IsNode(remoteAddr) {
t.Errorf("%s should be node of %v", remoteAddr, conf.Nodes)
}
-
remoteAddr = "foo.zone:2345"
if conf.IsNode(remoteAddr) {
t.Errorf("%s should not be node of %v", remoteAddr, conf.Nodes)
@@ -38,7 +40,9 @@ func TestIsNode(t *testing.T) {
func TestIsNodeWithLookup(t *testing.T) {
t.Parallel()
- conf, _ := New(WithNodes("localhost:1234", "hamburger:4321"))
+ conf, _ := New(WithNodes(
+ Node{Hostname: "localhost", Port: 1234, Priority: 200},
+ Node{Hostname: "hamburger", Port: 4321, Priority: 100}))
lookupIP := func(addr string) ([]net.IP, error) {
switch addr {
diff --git a/internal/quorum/quorum.go b/internal/quorum/quorum.go
index 9bce682..ab24063 100644
--- a/internal/quorum/quorum.go
+++ b/internal/quorum/quorum.go
@@ -113,8 +113,13 @@ func (quo Quorum) scores() (scores Scores) {
}
for _, id := range vote.IDs {
score := scoreMap[id]
- nodeNumber := quo.conf.NodeNumber(id)
- scoreMap[id] = score + 100 + (len(quo.conf.Nodes) - nodeNumber)
+ priority, err := quo.conf.NodePriority(id)
+ if err != nil {
+ log.Println(err)
+ scoreMap[id] = score
+ continue
+ }
+ scoreMap[id] = 10*score + priority
}
}
@@ -154,8 +159,9 @@ func (quo *Quorum) strs() (string, string) {
}
sb.WriteString(score.ID)
- sb.WriteString(" (node #")
- sb.WriteString(strconv.Itoa(quo.conf.NodeNumber(score.ID)))
+ sb.WriteString(" (priority ")
+ priority, _ := quo.conf.NodePriority(score.ID)
+ sb.WriteString(strconv.Itoa(priority))
sb.WriteString(") with total score of ")
sb.WriteString(strconv.Itoa(score.Value))
diff --git a/internal/quorum/quorum_test.go b/internal/quorum/quorum_test.go
index 0a8a35c..c1ad813 100644
--- a/internal/quorum/quorum_test.go
+++ b/internal/quorum/quorum_test.go
@@ -13,7 +13,11 @@ var inOneHour = time.Now().Add(1 * time.Hour)
func TestScore(t *testing.T) {
t.Parallel()
- conf, _ := config.New(config.WithNodes("foo:1234", "bar:4321", "baz:3444"))
+ conf, _ := config.New(config.WithNodes(
+ config.Node{Hostname: "foo", Port: 1234, Priority: 3},
+ config.Node{Hostname: "bar", Port: 4321, Priority: 2},
+ config.Node{Hostname: "baz", Port: 3444, Priority: 1}))
+
quo := New(conf)
vote1, _ := vote.New(conf, "foo", "bar")
@@ -42,8 +46,8 @@ func TestScore(t *testing.T) {
}
t.Log(scores)
- if scores[0].ID != "bar" || scores[0].Value != 306 {
- t.Errorf("Expected score[0] to be {bar,306}: %v", scores[0])
+ if scores[0].ID != "bar" || scores[0].Value != 222 {
+ t.Errorf("Expected score[0] to be {bar,222}: %v", scores[0])
}
winner, _ := scores.Winner()
@@ -71,18 +75,22 @@ func TestTieScore(t *testing.T) {
}
t.Run("First tie score test", func(t *testing.T) {
- // If it is a tie, the first particpant (here: "foo") will win.
- conf, _ := config.New(config.WithNodes("foo:1234", "bar:4321", "baz:3444"))
+ // If it is a tie, the particpant with the highest prio (here: "foo") will win.
+ conf, _ := config.New(config.WithNodes(
+ config.Node{Hostname: "foo", Port: 1234, Priority: 3},
+ config.Node{Hostname: "bar", Port: 4321, Priority: 2},
+ config.Node{Hostname: "baz", Port: 3444, Priority: 1}))
quo := New(conf)
addVotes(conf, quo)
scores := quo.scores()
+ t.Log("scores", scores)
if len(scores) != 3 {
t.Errorf("Expected scores to be of length 3: %v", scores)
}
- if scores[0].ID != "foo" || scores[0].Value != 309 {
- t.Errorf("Expected score[0] to be {foo,309}: %v", scores[0])
+ if scores[0].ID != "foo" || scores[0].Value != 333 {
+ t.Errorf("Expected score[0] to be {foo,333}: %v", scores[0])
}
winner := scores[0].ID
@@ -92,8 +100,11 @@ func TestTieScore(t *testing.T) {
})
t.Run("Second tie score test", func(t *testing.T) {
- // If it is a tie, the first particpant (here: "bar") will win.
- conf, _ := config.New(config.WithNodes("bar:1234", "foo:4321", "baz:3444"))
+ // If it is a tie, the particpant with the highest prio (here: "bar") will win.
+ conf, _ := config.New(config.WithNodes(
+ config.Node{Hostname: "bar", Port: 1234, Priority: 3},
+ config.Node{Hostname: "foo", Port: 4321, Priority: 2},
+ config.Node{Hostname: "baz", Port: 3444, Priority: 1}))
quo := New(conf)
addVotes(conf, quo)
@@ -102,8 +113,8 @@ func TestTieScore(t *testing.T) {
if len(scores) != 3 {
t.Errorf("Expected scores to be of length 3: %v", scores)
}
- if scores[0].ID != "bar" || scores[0].Value != 309 {
- t.Errorf("Expected score[0] to be {bar,309}: %v", scores[0])
+ if scores[0].ID != "bar" || scores[0].Value != 333 {
+ t.Errorf("Expected score[0] to be {bar,333}: %v", scores[0])
}
winner := scores[0].ID
@@ -114,7 +125,10 @@ func TestTieScore(t *testing.T) {
}
func TestExpire(t *testing.T) {
- conf, _ := config.New(config.WithNodes("foo:1234", "bar:4321", "bay:2212"))
+ conf, _ := config.New(config.WithNodes(
+ config.Node{Hostname: "foo", Port: 1234, Priority: 3},
+ config.Node{Hostname: "bar", Port: 4321, Priority: 2},
+ config.Node{Hostname: "bay", Port: 2212, Priority: 1}))
quo := New(conf)
vote1, _ := vote.New(conf, "bar", "baz", "bay")
@@ -146,7 +160,9 @@ func TestExpire(t *testing.T) {
}
func TestLiveNodes(t *testing.T) {
- conf, _ := config.New(config.WithNodes("foo:1234", "bay:4321"))
+ conf, _ := config.New(config.WithNodes(
+ config.Node{Hostname: "foo", Port: 1234, Priority: 3},
+ config.Node{Hostname: "bay", Port: 4321, Priority: 1}))
quo := New(conf)
vote1, _ := vote.New(conf, "bar", "baz", "bay")