UpgradeMembersWithoutRole assigns the Spare raft role to all cluster members that are not currently part of the raft configuration. It's used for upgrading a cluster from a version without roles support.
(gateway *Gateway, members []db.NodeInfo)
| 140 | // UpgradeMembersWithoutRole assigns the Spare raft role to all cluster members that are not currently part of the |
| 141 | // raft configuration. It's used for upgrading a cluster from a version without roles support. |
| 142 | func UpgradeMembersWithoutRole(gateway *Gateway, members []db.NodeInfo) error { |
| 143 | nodes, err := gateway.currentRaftNodes() |
| 144 | if errors.Is(err, ErrNotLeader) { |
| 145 | return nil |
| 146 | } |
| 147 | |
| 148 | if err != nil { |
| 149 | return fmt.Errorf("Failed to get current raft members: %w", err) |
| 150 | } |
| 151 | |
| 152 | // Convert raft node list to map keyed on ID. |
| 153 | raftNodeIDs := map[uint64]bool{} |
| 154 | for _, node := range nodes { |
| 155 | raftNodeIDs[node.ID] = true |
| 156 | } |
| 157 | |
| 158 | cowsqlClient, err := gateway.getClient() |
| 159 | if err != nil { |
| 160 | return fmt.Errorf("Failed to connect to local cowsql member: %w", err) |
| 161 | } |
| 162 | |
| 163 | defer logger.WarnOnError(cowsqlClient.Close, "Failed to close client") |
| 164 | |
| 165 | // Check that each member is present in the raft configuration, and add it if not. |
| 166 | for _, member := range members { |
| 167 | found := false |
| 168 | for _, node := range nodes { |
| 169 | if member.ID == 1 && node.ID == 1 || member.Address == node.Address { |
| 170 | found = true |
| 171 | break |
| 172 | } |
| 173 | } |
| 174 | if found { |
| 175 | continue |
| 176 | } |
| 177 | |
| 178 | // Try to use the same ID as the node, but it might not be possible if it's use. |
| 179 | id := uint64(member.ID) |
| 180 | _, ok := raftNodeIDs[id] |
| 181 | if ok { |
| 182 | for _, other := range members { |
| 183 | _, ok := raftNodeIDs[uint64(other.ID)] |
| 184 | if !ok { |
| 185 | id = uint64(other.ID) // Found unused raft ID for member. |
| 186 | break |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | // This can't really happen (but has in the past) since there are always at least as many |
| 191 | // members as there are nodes, and all of them have different IDs. |
| 192 | if id == uint64(member.ID) { |
| 193 | logger.Error("No available raft ID for cluster member", logger.Ctx{"memberID": member.ID, "members": members, "raftMembers": nodes}) |
| 194 | return fmt.Errorf("No available raft ID for cluster member ID %d", member.ID) |
| 195 | } |
| 196 | } |
| 197 | raftNodeIDs[id] = true |
| 198 | |
| 199 | info := db.RaftNode{ |
searching dependent graphs…