netmaker/pro/logic/failover.go

150 lines
3.8 KiB
Go

package logic
import (
"errors"
"net"
"github.com/google/uuid"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"golang.org/x/exp/slog"
)
func SetFailOverCtx(failOverNode, victimNode, peerNode models.Node) error {
if peerNode.FailOverPeers == nil {
peerNode.FailOverPeers = make(map[string]struct{})
}
if victimNode.FailOverPeers == nil {
victimNode.FailOverPeers = make(map[string]struct{})
}
peerNode.FailOverPeers[victimNode.ID.String()] = struct{}{}
victimNode.FailOverPeers[peerNode.ID.String()] = struct{}{}
victimNode.FailedOverBy = failOverNode.ID
peerNode.FailedOverBy = failOverNode.ID
if err := logic.UpsertNode(&failOverNode); err != nil {
return err
}
if err := logic.UpsertNode(&victimNode); err != nil {
return err
}
if err := logic.UpsertNode(&peerNode); err != nil {
return err
}
return nil
}
// GetFailOverNode - gets the host acting as failOver
func GetFailOverNode(network string, allNodes []models.Node) (models.Node, error) {
nodes := logic.GetNetworkNodesMemory(allNodes, network)
for _, node := range nodes {
if node.IsFailOver {
return node, nil
}
}
return models.Node{}, errors.New("auto relay not found")
}
// FailOverExists - checks if failOver exists already in the network
func FailOverExists(network string) (failOverNode models.Node, exists bool) {
nodes, err := logic.GetNetworkNodes(network)
if err != nil {
return
}
for _, node := range nodes {
if node.IsFailOver {
exists = true
failOverNode = node
return
}
}
return
}
// ResetFailedOverPeer - removes failed over node from network peers
func ResetFailedOverPeer(failedOveredNode *models.Node) error {
nodes, err := logic.GetNetworkNodes(failedOveredNode.Network)
if err != nil {
return err
}
failedOveredNode.FailedOverBy = uuid.Nil
failedOveredNode.FailOverPeers = make(map[string]struct{})
err = logic.UpsertNode(failedOveredNode)
if err != nil {
return err
}
for _, node := range nodes {
if node.FailOverPeers == nil || node.ID == failedOveredNode.ID {
continue
}
delete(node.FailOverPeers, failedOveredNode.ID.String())
logic.UpsertNode(&node)
}
return nil
}
// ResetFailOver - reset failovered peers
func ResetFailOver(failOverNode *models.Node) error {
// Unset FailedOverPeers
nodes, err := logic.GetNetworkNodes(failOverNode.Network)
if err != nil {
return err
}
for _, node := range nodes {
if node.FailedOverBy == failOverNode.ID {
node.FailedOverBy = uuid.Nil
node.FailOverPeers = make(map[string]struct{})
logic.UpsertNode(&node)
}
}
return nil
}
// GetFailOverPeerIps - adds the failedOvered peerIps by the peer
func GetFailOverPeerIps(peer, node *models.Node) []net.IPNet {
allowedips := []net.IPNet{}
for failOverpeerID := range node.FailOverPeers {
failOverpeer, err := logic.GetNodeByID(failOverpeerID)
if err == nil && failOverpeer.FailedOverBy == peer.ID {
if failOverpeer.Address.IP != nil {
allowed := net.IPNet{
IP: failOverpeer.Address.IP,
Mask: net.CIDRMask(32, 32),
}
allowedips = append(allowedips, allowed)
}
if failOverpeer.Address6.IP != nil {
allowed := net.IPNet{
IP: failOverpeer.Address6.IP,
Mask: net.CIDRMask(128, 128),
}
allowedips = append(allowedips, allowed)
}
}
}
return allowedips
}
func CreateFailOver(node models.Node) error {
if _, exists := FailOverExists(node.Network); exists {
return errors.New("failover already exists in the network")
}
host, err := logic.GetHost(node.HostID.String())
if err != nil {
return err
}
if host.OS != models.OS_Types.Linux {
return err
}
if node.IsRelayed {
return err
}
node.IsFailOver = true
err = logic.UpsertNode(&node)
if err != nil {
slog.Error("failed to upsert node", "node", node.ID.String(), "error", err)
return err
}
return nil
}