File: raft.go

package info (click to toggle)
incus 6.0.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,392 kB
  • sloc: sh: 16,313; ansic: 3,121; python: 457; makefile: 337; ruby: 51; sql: 50; lisp: 6
file content (67 lines) | stat: -rw-r--r-- 2,086 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package node

import (
	"context"

	"github.com/cowsql/go-cowsql/client"

	"github.com/lxc/incus/v6/internal/server/db"
)

// DetermineRaftNode figures out what raft node ID and address we have, if any.
//
// This decision is based on the value of the cluster.https_address config key
// and on the rows in the raft_nodes table, both stored in the node-level
// SQLite database.
//
// The following rules are applied:
//
//   - If no cluster.https_address config key is set, this is a non-clustered node
//     and the returned RaftNode will have ID 1 but no address, to signal that
//     the node should setup an in-memory raft cluster where the node itself
//     is the only member and leader.
//
//   - If cluster.https_address config key is set, but there is no row in the
//     raft_nodes table, this is a brand new clustered node that is joining a
//     cluster, and same behavior as the previous case applies.
//
//   - If cluster.https_address config key is set and there is at least one row
//     in the raft_nodes table, then this node is considered a raft node if
//     cluster.https_address matches one of the rows in raft_nodes. In that case,
//     the matching db.RaftNode row is returned, otherwise nil.
func DetermineRaftNode(ctx context.Context, tx *db.NodeTx) (*db.RaftNode, error) {
	config, err := ConfigLoad(ctx, tx)
	if err != nil {
		return nil, err
	}

	address := config.ClusterAddress()

	// If cluster.https_address is an empty string, then this server is
	// not running in clustering mode.
	if address == "" {
		nodeInfo := client.NodeInfo{ID: 1}
		return &db.RaftNode{NodeInfo: nodeInfo, Name: ""}, nil
	}

	nodes, err := tx.GetRaftNodes(ctx)
	if err != nil {
		return nil, err
	}

	// If cluster.https_address and the raft_nodes table is not populated,
	// this must be a joining node.
	if len(nodes) == 0 {
		nodeInfo := client.NodeInfo{ID: 1}
		return &db.RaftNode{NodeInfo: nodeInfo, Name: ""}, nil
	}

	// Try to find a matching node.
	for _, node := range nodes {
		if node.Address == address {
			return &node, nil
		}
	}

	return nil, nil
}