Merge pull request #620 from gravitl/feature_v0.10.0_better_server

Feature v0.10.0 better server
This commit is contained in:
dcarns 2022-01-18 15:33:22 -05:00 committed by GitHub
commit de8c4d782d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 406 additions and 347 deletions

View file

@ -12,7 +12,6 @@ import (
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"github.com/gravitl/netmaker/serverctl"
) )
const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL" const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
@ -226,9 +225,8 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
} }
if servercfg.IsClientMode() != "off" { if servercfg.IsClientMode() != "off" {
var success bool err = logic.ServerJoin(&network)
success, err = serverctl.AddNetwork(&network) if err != nil {
if err != nil || !success {
logic.DeleteNetwork(network.NetID) logic.DeleteNetwork(network.NetID)
if err == nil { if err == nil {
err = errors.New("Failed to add server to network " + network.DisplayName) err = errors.New("Failed to add server to network " + network.DisplayName)

View file

@ -32,7 +32,6 @@ func nodeHandlers(r *mux.Router) {
r.HandleFunc("/api/nodes/{network}", createNode).Methods("POST") r.HandleFunc("/api/nodes/{network}", createNode).Methods("POST")
r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET") r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods("POST") r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods("POST")
} }
func authenticate(response http.ResponseWriter, request *http.Request) { func authenticate(response http.ResponseWriter, request *http.Request) {
@ -186,7 +185,7 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
r.Header.Set("ismasterkey", "yes") r.Header.Set("ismasterkey", "yes")
} }
if !isadmin && params["network"] != "" { if !isadmin && params["network"] != "" {
if functions.SliceContains(networks, params["network"]) { if logic.StringSliceContains(networks, params["network"]) {
isnetadmin = true isnetadmin = true
} }
} }
@ -404,6 +403,11 @@ func createNode(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
if err = runServerPeerUpdate(node.Network, true); err != nil {
logger.Log(1, "internal error when creating node:", node.ID)
}
logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network) logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)
@ -414,11 +418,15 @@ func createNode(w http.ResponseWriter, r *http.Request) {
func uncordonNode(w http.ResponseWriter, r *http.Request) { func uncordonNode(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r) var params = mux.Vars(r)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
node, err := logic.UncordonNode(params["nodeid"]) var nodeid = params["nodeid"]
node, err := logic.UncordonNode(nodeid)
if err != nil { if err != nil {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
if err = runServerPeerUpdate(node.Network, false); err != nil {
logger.Log(1, "internal error when approving node:", nodeid)
}
logger.Log(1, r.Header.Get("user"), "uncordoned node", node.Name) logger.Log(1, r.Header.Get("user"), "uncordoned node", node.Name)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode("SUCCESS") json.NewEncoder(w).Encode("SUCCESS")
@ -440,6 +448,9 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
if err = runServerPeerUpdate(gateway.NetID, true); err != nil {
logger.Log(1, "internal error when setting peers after creating egress on node:", gateway.NodeID)
}
logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID) logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)
@ -455,6 +466,9 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
if err = runServerPeerUpdate(netid, true); err != nil {
logger.Log(1, "internal error when setting peers after removing egress on node:", nodeid)
}
logger.Log(1, r.Header.Get("user"), "deleted egress gateway", nodeid, "on network", netid) logger.Log(1, r.Header.Get("user"), "deleted egress gateway", nodeid, "on network", netid)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)
@ -472,6 +486,7 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid) logger.Log(1, r.Header.Get("user"), "created ingress gateway on node", nodeid, "on network", netid)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)
@ -486,6 +501,7 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
logger.Log(1, r.Header.Get("user"), "deleted ingress gateway", nodeid) logger.Log(1, r.Header.Get("user"), "deleted ingress gateway", nodeid)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)
@ -530,11 +546,14 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
newNode.PostUp = node.PostUp newNode.PostUp = node.PostUp
} }
var shouldPeersUpdate = logic.ShouldPeersUpdate(&node, &newNode)
err = logic.UpdateNode(&node, &newNode) err = logic.UpdateNode(&node, &newNode)
if err != nil { if err != nil {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
if relayupdate { if relayupdate {
logic.UpdateRelay(node.Network, node.RelayAddrs, newNode.RelayAddrs) logic.UpdateRelay(node.Network, node.RelayAddrs, newNode.RelayAddrs)
if err = logic.NetworkNodesUpdatePullChanges(node.Network); err != nil { if err = logic.NetworkNodesUpdatePullChanges(node.Network); err != nil {
@ -542,9 +561,11 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
} }
} }
if servercfg.IsDNSMode() { if servercfg.IsDNSMode() { // TODO check when this should be updated..
err = logic.SetDNS() err = logic.SetDNS()
} }
err = runServerPeerUpdate(node.Network, shouldPeersUpdate)
if err != nil { if err != nil {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
@ -572,6 +593,12 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
return return
} }
err = runServerPeerUpdate(node.Network, true)
if err != nil {
returnErrorResponse(w, r, formatError(err, "internal"))
return
}
logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"]) logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"])
returnSuccessResponse(w, r, nodeid+" deleted.") returnSuccessResponse(w, r, nodeid+" deleted.")
} }

View file

@ -86,6 +86,12 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
return nil, err return nil, err
} }
err = runServerPeerUpdate(node.Network, true)
if err != nil {
logger.Log(1, "internal error when setting peers after node,", node.ID, "was created (gRPC)")
}
logger.Log(0, "new node,", node.Name, ", added on network,"+node.Network)
return response, nil return response, nil
} }
@ -106,6 +112,7 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
newnode.PostDown = node.PostDown newnode.PostDown = node.PostDown
newnode.PostUp = node.PostUp newnode.PostUp = node.PostUp
} }
var shouldPeersUpdate = logic.ShouldPeersUpdate(&node, &newnode)
err = logic.UpdateNode(&node, &newnode) err = logic.UpdateNode(&node, &newnode)
if err != nil { if err != nil {
@ -119,6 +126,10 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
if errN != nil { if errN != nil {
return nil, err return nil, err
} }
err = runServerPeerUpdate(newnode.Network, shouldPeersUpdate)
if err != nil {
logger.Log(1, "could not update peers on gRPC after node,", newnode.ID, "updated (gRPC), \nerror:", err.Error())
}
return &nodepb.Object{ return &nodepb.Object{
Data: string(nodeData), Data: string(nodeData),
Type: nodepb.NODE_TYPE, Type: nodepb.NODE_TYPE,
@ -138,6 +149,11 @@ func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object)
return nil, err return nil, err
} }
err = runServerPeerUpdate(node.Network, true)
if err != nil {
logger.Log(1, "internal error when setting peers after deleting node:", node.ID, "over gRPC")
}
return &nodepb.Object{ return &nodepb.Object{
Data: "success", Data: "success",
Type: nodepb.STRING_TYPE, Type: nodepb.STRING_TYPE,
@ -152,9 +168,6 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
return nil, err return nil, err
} }
if node.IsServer == "yes" && logic.IsLeader(&node) {
logic.SetNetworkServerPeers(&node)
}
excludeIsRelayed := node.IsRelay != "yes" excludeIsRelayed := node.IsRelay != "yes"
var relayedNode string var relayedNode string
if node.IsRelayed == "yes" { if node.IsRelayed == "yes" {

View file

@ -26,6 +26,9 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
if err = runServerPeerUpdate(relay.NetID, true); err != nil {
logger.Log(1, "internal error when creating relay on node:", relay.NodeID)
}
logger.Log(1, r.Header.Get("user"), "created relay on node", relay.NodeID, "on network", relay.NetID) logger.Log(1, r.Header.Get("user"), "created relay on node", relay.NodeID, "on network", relay.NetID)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)
@ -41,6 +44,9 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal")) returnErrorResponse(w, r, formatError(err, "internal"))
return return
} }
if err = runServerPeerUpdate(netid, true); err != nil {
logger.Log(1, "internal error when deleting relay on node:", nodeid)
}
logger.Log(1, r.Header.Get("user"), "deleted egress gateway", nodeid, "on network", netid) logger.Log(1, r.Header.Get("user"), "deleted egress gateway", nodeid, "on network", netid)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)

View file

@ -9,7 +9,6 @@ import (
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"github.com/gravitl/netmaker/serverctl"
) )
func serverHandlers(r *mux.Router) { func serverHandlers(r *mux.Router) {
@ -70,9 +69,8 @@ func removeNetwork(w http.ResponseWriter, r *http.Request) {
// get params // get params
var params = mux.Vars(r) var params = mux.Vars(r)
success, err := serverctl.RemoveNetwork(params["network"]) err := logic.DeleteNetwork(params["network"])
if err != nil {
if err != nil || !success {
json.NewEncoder(w).Encode("Could not remove server from network " + params["network"]) json.NewEncoder(w).Encode("Could not remove server from network " + params["network"])
return return
} }

View file

@ -0,0 +1,23 @@
package controller
import (
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
)
func runServerPeerUpdate(network string, shouldPeerUpdate bool) error {
var currentServerNodeID, err = logic.GetNetworkServerNodeID(network)
if err != nil {
return err
}
var currentServerNode, currErr = logic.GetNodeByID(currentServerNodeID)
if currErr != nil {
return currErr
}
if err = logic.ServerUpdate(&currentServerNode, shouldPeerUpdate); err != nil {
logger.Log(1, "server node:", currentServerNode.ID, "failed update")
return err
}
return nil
}

View file

@ -31,20 +31,6 @@ func ParseIntClient(value string) (models.IntClient, error) {
return intClient, err return intClient, err
} }
//Takes in an arbitrary field and value for field and checks to see if any other
//node has that value for the same field within the network
// SliceContains - sees if a slice contains something
func SliceContains(slice []string, item string) bool {
set := make(map[string]struct{}, len(slice))
for _, s := range slice {
set[s] = struct{}{}
}
_, ok := set[item]
return ok
}
// GetPeersList - gets peers for given network // GetPeersList - gets peers for given network
func GetPeersList(networkName string) ([]models.PeersResponse, error) { func GetPeersList(networkName string) ([]models.PeersResponse, error) {

View file

@ -9,30 +9,22 @@ import (
"time" "time"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"github.com/gravitl/netmaker/validation" "github.com/gravitl/netmaker/validation"
"golang.org/x/crypto/bcrypt"
) )
// GetNetworkNodes - gets the nodes of a network // GetNetworkNodes - gets the nodes of a network
func GetNetworkNodes(network string) ([]models.Node, error) { func GetNetworkNodes(network string) ([]models.Node, error) {
var nodes = []models.Node{} var nodes, err = GetAllNodes()
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
if err != nil { if err != nil {
if database.IsEmptyRecord(err) { return []models.Node{}, err
return []models.Node{}, nil
}
return nodes, err
} }
for _, value := range collection { for _, node := range nodes {
var node models.Node
err := json.Unmarshal([]byte(value), &node)
if err != nil {
continue
}
if node.Network == network { if node.Network == network {
nodes = append(nodes, node) nodes = append(nodes, node)
} }
@ -86,7 +78,7 @@ func UncordonNode(nodeid string) (models.Node, error) {
// GetPeers - gets the peers of a given node // GetPeers - gets the peers of a given node
func GetPeers(node *models.Node) ([]models.Node, error) { func GetPeers(node *models.Node) ([]models.Node, error) {
if IsLeader(node) { if IsLeader(node) {
SetNetworkServerPeers(node) setNetworkServerPeers(node)
} }
excludeIsRelayed := node.IsRelay != "yes" excludeIsRelayed := node.IsRelay != "yes"
var relayedNode string var relayedNode string
@ -166,6 +158,128 @@ func ValidateNode(node *models.Node, isUpdate bool) error {
return err return err
} }
// CreateNode - creates a node in database
func CreateNode(node *models.Node) error {
//encrypt that password so we never see it
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
if err != nil {
return err
}
//set password to encrypted password
node.Password = string(hash)
if node.Name == models.NODE_SERVER_NAME {
node.IsServer = "yes"
}
if node.DNSOn == "" {
if servercfg.IsDNSMode() {
node.DNSOn = "yes"
} else {
node.DNSOn = "no"
}
}
SetNodeDefaults(node)
node.Address, err = UniqueAddress(node.Network)
if err != nil {
return err
}
node.Address6, err = UniqueAddress6(node.Network)
if err != nil {
return err
}
// TODO: This covers legacy nodes, eventually want to remove legacy check
if node.IsServer == "yes" {
node.ID = uuid.NewString()
} else if node.IsServer != "yes" || (node.ID == "" || strings.Contains(node.ID, "###")) {
node.ID = uuid.NewString()
}
//Create a JWT for the node
tokenString, _ := CreateJWT(node.ID, node.MacAddress, node.Network)
if tokenString == "" {
//returnErrorResponse(w, r, errorResponse)
return err
}
err = ValidateNode(node, false)
if err != nil {
return err
}
nodebytes, err := json.Marshal(&node)
if err != nil {
return err
}
err = database.Insert(node.ID, string(nodebytes), database.NODES_TABLE_NAME)
if err != nil {
return err
}
if node.IsPending != "yes" {
DecrimentKey(node.Network, node.AccessKey)
}
SetNetworkNodesLastModified(node.Network)
if servercfg.IsDNSMode() {
err = SetDNS()
}
return err
}
// ShouldPeersUpdate - takes old node and sees if certain fields changing would trigger a peer update
func ShouldPeersUpdate(currentNode *models.Node, newNode *models.Node) bool {
SetNodeDefaults(newNode)
// single comparison statements
if newNode.Endpoint != currentNode.Endpoint ||
newNode.LocalAddress != currentNode.LocalAddress ||
newNode.PublicKey != currentNode.PublicKey ||
newNode.Address != currentNode.Address ||
newNode.IsEgressGateway != currentNode.IsEgressGateway ||
newNode.IsIngressGateway != currentNode.IsIngressGateway ||
newNode.IsRelay != currentNode.IsRelay ||
newNode.UDPHolePunch != currentNode.UDPHolePunch ||
newNode.IsPending != currentNode.IsPending ||
len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) ||
len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
return true
}
// multi-comparison statements
if newNode.IsDualStack == "yes" {
if newNode.Address6 != currentNode.Address6 {
return true
}
}
if newNode.IsEgressGateway == "yes" {
if len(currentNode.EgressGatewayRanges) != len(newNode.EgressGatewayRanges) {
return true
}
for _, address := range newNode.EgressGatewayRanges {
if !StringSliceContains(currentNode.EgressGatewayRanges, address) {
return true
}
}
}
if newNode.IsRelay == "yes" {
if len(currentNode.RelayAddrs) != len(newNode.RelayAddrs) {
return true
}
for _, address := range newNode.RelayAddrs {
if !StringSliceContains(currentNode.RelayAddrs, address) {
return true
}
}
}
for _, address := range newNode.AllowedIPs {
if !StringSliceContains(currentNode.AllowedIPs, address) {
return true
}
}
return false
}
// GetAllNodes - returns all nodes in the DB // GetAllNodes - returns all nodes in the DB
func GetAllNodes() ([]models.Node, error) { func GetAllNodes() ([]models.Node, error) {
var nodes []models.Node var nodes []models.Node

View file

@ -17,6 +17,7 @@ import (
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
// == Public ==
// == Join, Checkin, and Leave for Server == // == Join, Checkin, and Leave for Server ==
// KUBERNETES_LISTEN_PORT - starting port for Kubernetes in order to use NodePort range // KUBERNETES_LISTEN_PORT - starting port for Kubernetes in order to use NodePort range
@ -26,7 +27,7 @@ const KUBERNETES_LISTEN_PORT = 31821
const KUBERNETES_SERVER_MTU = 1024 const KUBERNETES_SERVER_MTU = 1024
// ServerJoin - responsible for joining a server to a network // ServerJoin - responsible for joining a server to a network
func ServerJoin(networkSettings *models.Network, serverID string) error { func ServerJoin(networkSettings *models.Network) error {
if networkSettings == nil || networkSettings.NetID == "" { if networkSettings == nil || networkSettings.NetID == "" {
return errors.New("no network provided") return errors.New("no network provided")
@ -119,7 +120,7 @@ func ServerJoin(networkSettings *models.Network, serverID string) error {
if err = StorePrivKey(node.ID, privateKey); err != nil { if err = StorePrivKey(node.ID, privateKey); err != nil {
return err return err
} }
if err = ServerPush(node); err != nil { if err = serverPush(node); err != nil {
return err return err
} }
@ -137,18 +138,12 @@ func ServerJoin(networkSettings *models.Network, serverID string) error {
return nil return nil
} }
// ServerCheckin - runs pulls and pushes for server // ServerUpdate - updates the server
func ServerCheckin(serverID string, mac string, network string) error { // replaces legacy Checkin code
var serverNode = &models.Node{} func ServerUpdate(serverNode *models.Node, shouldPeerUpdate bool) error {
var currentNode, err = GetNodeByIDorMacAddress(serverID, mac, network) var err = serverPull(serverNode, shouldPeerUpdate)
if err != nil {
return err
}
serverNode = &currentNode
err = ServerPull(serverNode, false)
if isDeleteError(err) { if isDeleteError(err) {
return ServerLeave(currentNode.ID) return DeleteNodeByID(serverNode, true)
} else if err != nil { } else if err != nil {
return err return err
} }
@ -158,66 +153,7 @@ func ServerCheckin(serverID string, mac string, network string) error {
return errors.New("node has been removed") return errors.New("node has been removed")
} }
return ServerPush(serverNode) return serverPush(serverNode)
}
// ServerPull - pulls current config/peers for server
func ServerPull(serverNode *models.Node, onErr bool) error {
var err error
if serverNode.IPForwarding == "yes" {
if err = setIPForwardingLinux(); err != nil {
return err
}
}
serverNode.OS = runtime.GOOS
if serverNode.PullChanges == "yes" || onErr {
// check for interface change
// checks if address is in use by another interface
var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
if !isIfacePresent {
if err = deleteInterface(oldIfaceName, serverNode.PostDown); err != nil {
logger.Log(1, "could not delete old interface", oldIfaceName)
}
logger.Log(1, "removed old interface", oldIfaceName)
}
serverNode.PullChanges = "no"
if err = setWGConfig(serverNode, false); err != nil {
return err
}
// handle server side update
if err = UpdateNode(serverNode, serverNode); err != nil {
return err
}
} else {
if err = setWGConfig(serverNode, true); err != nil {
if errors.Is(err, os.ErrNotExist) {
return ServerPull(serverNode, true)
} else {
return err
}
}
}
return nil
}
// ServerPush - pushes config changes for server checkins/join
func ServerPush(serverNode *models.Node) error {
serverNode.OS = runtime.GOOS
serverNode.SetLastCheckIn()
return UpdateNode(serverNode, serverNode)
}
// ServerLeave - removes a server node
func ServerLeave(serverID string) error {
var serverNode, err = GetNodeByID(serverID)
if err != nil {
return err
}
return DeleteNodeByID(&serverNode, true)
} }
/** /**
@ -231,17 +167,14 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
var gateways []string var gateways []string
var peers []wgtypes.PeerConfig var peers []wgtypes.PeerConfig
var nodes []models.Node // fill above fields from server or client var nodes []models.Node // fill above fields from server or client
var err error
var nodecfg, err = GetNodeByIDorMacAddress(serverNode.ID, serverNode.MacAddress, serverNode.Network) nodes, err = GetPeers(serverNode)
if err != nil {
return nil, hasGateway, gateways, err
}
nodes, err = GetPeers(&nodecfg)
if err != nil { if err != nil {
return nil, hasGateway, gateways, err return nil, hasGateway, gateways, err
} }
keepalive := nodecfg.PersistentKeepalive keepalive := serverNode.PersistentKeepalive
keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s") keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
if err != nil { if err != nil {
logger.Log(1, "Issue with format of keepalive duration value, Please view server config:", err.Error()) logger.Log(1, "Issue with format of keepalive duration value, Please view server config:", err.Error())
@ -255,11 +188,11 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
return peers, hasGateway, gateways, err return peers, hasGateway, gateways, err
} }
if nodecfg.PublicKey == node.PublicKey { if serverNode.PublicKey == node.PublicKey {
continue continue
} }
if nodecfg.Endpoint == node.Endpoint { if serverNode.Endpoint == node.Endpoint {
if nodecfg.LocalAddress != node.LocalAddress && node.LocalAddress != "" { if serverNode.LocalAddress != node.LocalAddress && node.LocalAddress != "" {
node.Endpoint = node.LocalAddress node.Endpoint = node.LocalAddress
} else { } else {
continue continue
@ -304,8 +237,8 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
logger.Log(2, "egress IP range of", iprange, "overlaps with", node.Endpoint, ", omitting") logger.Log(2, "egress IP range of", iprange, "overlaps with", node.Endpoint, ", omitting")
continue // skip adding egress range if overlaps with node's ip continue // skip adding egress range if overlaps with node's ip
} }
if ipnet.Contains(net.ParseIP(nodecfg.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node if ipnet.Contains(net.ParseIP(serverNode.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
logger.Log(2, "egress IP range of", iprange, "overlaps with", nodecfg.LocalAddress, ", omitting") logger.Log(2, "egress IP range of", iprange, "overlaps with", serverNode.LocalAddress, ", omitting")
continue // skip adding egress range if overlaps with node's local ip continue // skip adding egress range if overlaps with node's local ip
} }
gateways = append(gateways, iprange) gateways = append(gateways, iprange)
@ -422,7 +355,7 @@ func checkNodeActions(node *models.Node) string {
} }
} }
if node.Action == models.NODE_DELETE { if node.Action == models.NODE_DELETE {
err := ServerLeave(node.ID) err := DeleteNodeByID(node, true)
if err != nil { if err != nil {
logger.Log(1, "error deleting locally:", err.Error()) logger.Log(1, "error deleting locally:", err.Error())
} }
@ -431,6 +364,49 @@ func checkNodeActions(node *models.Node) string {
return "" return ""
} }
// == Private ==
func serverPull(serverNode *models.Node, onErr bool) error {
var err error
if serverNode.IPForwarding == "yes" {
if err = setIPForwardingLinux(); err != nil {
return err
}
}
serverNode.OS = runtime.GOOS
if serverNode.PullChanges == "yes" || onErr {
// check for interface change
// checks if address is in use by another interface
var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
if !isIfacePresent {
if err = deleteInterface(oldIfaceName, serverNode.PostDown); err != nil {
logger.Log(1, "could not delete old interface", oldIfaceName)
}
logger.Log(1, "removed old interface", oldIfaceName)
}
serverNode.PullChanges = "no"
if err = setWGConfig(serverNode, false); err != nil {
return err
}
// handle server side update
if err = UpdateNode(serverNode, serverNode); err != nil {
return err
}
} else {
if err = setWGConfig(serverNode, true); err != nil {
if errors.Is(err, os.ErrNotExist) {
return serverPull(serverNode, true)
} else {
return err
}
}
}
return nil
}
func getServerLocalIP(networkSettings *models.Network) (string, error) { func getServerLocalIP(networkSettings *models.Network) (string, error) {
var networkCIDR = networkSettings.LocalRange var networkCIDR = networkSettings.LocalRange
@ -452,3 +428,9 @@ func getServerLocalIP(networkSettings *models.Network) (string, error) {
} }
return "", errors.New("could not find a local ip for server") return "", errors.New("could not find a local ip for server")
} }
func serverPush(serverNode *models.Node) error {
serverNode.OS = runtime.GOOS
serverNode.SetLastCheckIn()
return UpdateNode(serverNode, serverNode)
}

View file

@ -5,17 +5,16 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"math/rand" "math/rand"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/netclient/ncutils" "github.com/gravitl/netmaker/netclient/ncutils"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"golang.org/x/crypto/bcrypt"
) )
// IsBase64 - checks if a string is in base64 format // IsBase64 - checks if a string is in base64 format
@ -31,15 +30,13 @@ func CheckEndpoint(endpoint string) bool {
return len(endpointarr) == 2 return len(endpointarr) == 2
} }
// SetNetworkServerPeers - sets the network server peers of a given node // FileExists - checks if local file exists
func SetNetworkServerPeers(node *models.Node) { func FileExists(f string) bool {
if currentPeersList, err := GetSystemPeers(node); err == nil { info, err := os.Stat(f)
if database.SetPeers(currentPeersList, node.Network) { if os.IsNotExist(err) {
logger.Log(1, "set new peers on network", node.Network) return false
}
} else {
logger.Log(1, "could not set peers on network", node.Network, ":", err.Error())
} }
return !info.IsDir()
} }
// DeleteNodeByMacAddress - deletes a node from database or moves into delete nodes table // DeleteNodeByMacAddress - deletes a node from database or moves into delete nodes table
@ -75,72 +72,6 @@ func DeleteNodeByMacAddress(node *models.Node, exterminate bool) error {
return removeLocalServer(node) return removeLocalServer(node)
} }
// CreateNode - creates a node in database
func CreateNode(node *models.Node) error {
//encrypt that password so we never see it
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
if err != nil {
return err
}
//set password to encrypted password
node.Password = string(hash)
if node.Name == models.NODE_SERVER_NAME {
node.IsServer = "yes"
}
if node.DNSOn == "" {
if servercfg.IsDNSMode() {
node.DNSOn = "yes"
} else {
node.DNSOn = "no"
}
}
SetNodeDefaults(node)
node.Address, err = UniqueAddress(node.Network)
if err != nil {
return err
}
node.Address6, err = UniqueAddress6(node.Network)
if err != nil {
return err
}
// TODO: This covers legacy nodes, eventually want to remove legacy check
if node.IsServer == "yes" {
node.ID = uuid.NewString()
} else if node.IsServer != "yes" || (node.ID == "" || strings.Contains(node.ID, "###")) {
node.ID = uuid.NewString()
}
//Create a JWT for the node
tokenString, _ := CreateJWT(node.ID, node.MacAddress, node.Network)
if tokenString == "" {
//returnErrorResponse(w, r, errorResponse)
return err
}
err = ValidateNode(node, false)
if err != nil {
return err
}
nodebytes, err := json.Marshal(&node)
if err != nil {
return err
}
err = database.Insert(node.ID, string(nodebytes), database.NODES_TABLE_NAME)
if err != nil {
return err
}
if node.IsPending != "yes" {
DecrimentKey(node.Network, node.AccessKey)
}
SetNetworkNodesLastModified(node.Network)
if servercfg.IsDNSMode() {
err = SetDNS()
}
return err
}
// SetNetworkNodesLastModified - sets the network nodes last modified // SetNetworkNodesLastModified - sets the network nodes last modified
func SetNetworkNodesLastModified(networkName string) error { func SetNetworkNodesLastModified(networkName string) error {
@ -402,3 +333,16 @@ func StringSliceContains(slice []string, item string) bool {
} }
return false return false
} }
// == private ==
// sets the network server peers of a given node
func setNetworkServerPeers(serverNode *models.Node) {
if currentPeersList, err := getSystemPeers(serverNode); err == nil {
if database.SetPeers(currentPeersList, serverNode.Network) {
logger.Log(1, "set new peers on network", serverNode.Network)
}
} else {
logger.Log(1, "could not set peers on network", serverNode.Network, ":", err.Error())
}
}

View file

@ -16,8 +16,18 @@ import (
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
// GetSystemPeers - gets the server peers // RemoveConf - removes a configuration for a given WireGuard interface
func GetSystemPeers(node *models.Node) (map[string]string, error) { func RemoveConf(iface string, printlog bool) error {
var err error
confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
err = removeWGQuickConf(confPath, printlog)
return err
}
// == Private Functions ==
// gets the server peers locally
func getSystemPeers(node *models.Node) (map[string]string, error) {
peers := make(map[string]string) peers := make(map[string]string)
client, err := wgctrl.New() client, err := wgctrl.New()
@ -37,16 +47,6 @@ func GetSystemPeers(node *models.Node) (map[string]string, error) {
return peers, nil return peers, nil
} }
// RemoveConf - removes a configuration for a given WireGuard interface
func RemoveConf(iface string, printlog bool) error {
var err error
confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
err = removeWGQuickConf(confPath, printlog)
return err
}
// == Private Functions ==
func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error { func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
key, err := wgtypes.ParseKey(privkey) key, err := wgtypes.ParseKey(privkey)
@ -93,16 +93,6 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
logger.Log(1, "error writing wg conf file to", confPath, ":", err.Error()) logger.Log(1, "error writing wg conf file to", confPath, ":", err.Error())
return err return err
} }
if ncutils.IsWindows() {
wgConfPath := ncutils.GetWGPathSpecific() + ifacename + ".conf"
logger.Log(1, "writing wg conf file to:", confPath)
err = os.WriteFile(wgConfPath, []byte(newConf), 0644)
if err != nil {
logger.Log(1, "error writing wg conf file to", wgConfPath, ":", err.Error())
return err
}
confPath = wgConfPath
}
// spin up userspace + apply the conf file // spin up userspace + apply the conf file
var deviceiface = ifacename var deviceiface = ifacename
d, _ := wgclient.Device(deviceiface) d, _ := wgclient.Device(deviceiface)
@ -182,9 +172,10 @@ func setKernelDevice(ifacename string, address string) error {
return err return err
} }
_, _ = ncutils.RunCmd("ip link delete dev "+ifacename, false) // == best effort ==
_, _ = ncutils.RunCmd(ipExec+" link add dev "+ifacename+" type wireguard", true) ncutils.RunCmd("ip link delete dev "+ifacename, false)
_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address+"/24", true) // this is a bug waiting to happen ncutils.RunCmd(ipExec+" link add dev "+ifacename+" type wireguard", true)
ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address+"/24", true) // this is a bug waiting to happen
return nil return nil
} }

17
main.go
View file

@ -9,7 +9,6 @@ import (
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"sync" "sync"
"time"
"github.com/gravitl/netmaker/auth" "github.com/gravitl/netmaker/auth"
controller "github.com/gravitl/netmaker/controllers" controller "github.com/gravitl/netmaker/controllers"
@ -110,25 +109,9 @@ func startControllers() {
logger.Log(0, "No Server Mode selected, so nothing is being served! Set either Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) to 'true'.") logger.Log(0, "No Server Mode selected, so nothing is being served! Set either Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) to 'true'.")
} }
if servercfg.IsClientMode() == "on" {
var checkintime = time.Duration(servercfg.GetServerCheckinInterval()) * time.Second
for { // best effort currently
var serverGroup sync.WaitGroup
serverGroup.Add(1)
go runClient(&serverGroup)
serverGroup.Wait()
time.Sleep(checkintime)
}
}
waitnetwork.Wait() waitnetwork.Wait()
} }
func runClient(wg *sync.WaitGroup) {
defer wg.Done()
go serverctl.HandleContainedClient()
}
func runGRPC(wg *sync.WaitGroup) { func runGRPC(wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()

View file

@ -73,6 +73,7 @@ type Node struct {
OS string `json:"os" bson:"os" yaml:"os"` OS string `json:"os" bson:"os" yaml:"os"`
MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"` MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"`
Version string `json:"version" bson:"version" yaml:"version"` Version string `json:"version" bson:"version" yaml:"version"`
ExcludedAddrs []string `json:"excludedaddrs" bson:"excludedaddrs" yaml:"excludedaddrs"`
} }
// NodesArray - used for node sorting // NodesArray - used for node sorting
@ -107,78 +108,91 @@ func (node *Node) SetDefaulIsPending() {
} }
} }
// Node.SetDefaultIsRelayed - set default is relayed
func (node *Node) SetDefaultIsRelayed() { func (node *Node) SetDefaultIsRelayed() {
if node.IsRelayed == "" { if node.IsRelayed == "" {
node.IsRelayed = "no" node.IsRelayed = "no"
} }
} }
// Node.SetDefaultIsRelay - set default isrelay
func (node *Node) SetDefaultIsRelay() { func (node *Node) SetDefaultIsRelay() {
if node.IsRelay == "" { if node.IsRelay == "" {
node.IsRelay = "no" node.IsRelay = "no"
} }
} }
// Node.SetDefaultEgressGateway - sets default egress gateway status
func (node *Node) SetDefaultEgressGateway() { func (node *Node) SetDefaultEgressGateway() {
if node.IsEgressGateway == "" { if node.IsEgressGateway == "" {
node.IsEgressGateway = "no" node.IsEgressGateway = "no"
} }
} }
// Node.SetDefaultIngressGateway - sets default ingress gateway status
func (node *Node) SetDefaultIngressGateway() { func (node *Node) SetDefaultIngressGateway() {
if node.IsIngressGateway == "" { if node.IsIngressGateway == "" {
node.IsIngressGateway = "no" node.IsIngressGateway = "no"
} }
} }
// Node.SetDefaultAction - sets default action status
func (node *Node) SetDefaultAction() { func (node *Node) SetDefaultAction() {
if node.Action == "" { if node.Action == "" {
node.Action = NODE_NOOP node.Action = NODE_NOOP
} }
} }
// Node.SetRoamingDefault - sets default roaming status
func (node *Node) SetRoamingDefault() { func (node *Node) SetRoamingDefault() {
if node.Roaming == "" { if node.Roaming == "" {
node.Roaming = "yes" node.Roaming = "yes"
} }
} }
// Node.SetPullChangesDefault - sets default pull changes status
func (node *Node) SetPullChangesDefault() { func (node *Node) SetPullChangesDefault() {
if node.PullChanges == "" { if node.PullChanges == "" {
node.PullChanges = "no" node.PullChanges = "no"
} }
} }
// Node.SetIPForwardingDefault - set ip forwarding default
func (node *Node) SetIPForwardingDefault() { func (node *Node) SetIPForwardingDefault() {
if node.IPForwarding == "" { if node.IPForwarding == "" {
node.IPForwarding = "yes" node.IPForwarding = "yes"
} }
} }
// Node.SetIsLocalDefault - set is local default
func (node *Node) SetIsLocalDefault() { func (node *Node) SetIsLocalDefault() {
if node.IsLocal == "" { if node.IsLocal == "" {
node.IsLocal = "no" node.IsLocal = "no"
} }
} }
// Node.SetDNSOnDefault - sets dns on default
func (node *Node) SetDNSOnDefault() { func (node *Node) SetDNSOnDefault() {
if node.DNSOn == "" { if node.DNSOn == "" {
node.DNSOn = "yes" node.DNSOn = "yes"
} }
} }
// Node.SetIsDualStackDefault - set is dual stack default status
func (node *Node) SetIsDualStackDefault() { func (node *Node) SetIsDualStackDefault() {
if node.IsDualStack == "" { if node.IsDualStack == "" {
node.IsDualStack = "no" node.IsDualStack = "no"
} }
} }
// Node.SetIsServerDefault - sets node isserver default
func (node *Node) SetIsServerDefault() { func (node *Node) SetIsServerDefault() {
if node.IsServer != "yes" { if node.IsServer != "yes" {
node.IsServer = "no" node.IsServer = "no"
} }
} }
// Node.SetIsStaticDefault - set is static default
func (node *Node) SetIsStaticDefault() { func (node *Node) SetIsStaticDefault() {
if node.IsServer == "yes" { if node.IsServer == "yes" {
node.IsStatic = "yes" node.IsStatic = "yes"
@ -187,28 +201,41 @@ func (node *Node) SetIsStaticDefault() {
} }
} }
// Node.SetLastModified - set last modified initial time
func (node *Node) SetLastModified() { func (node *Node) SetLastModified() {
node.LastModified = time.Now().Unix() node.LastModified = time.Now().Unix()
} }
// Node.SetLastCheckIn - time.Now().Unix()
func (node *Node) SetLastCheckIn() { func (node *Node) SetLastCheckIn() {
node.LastCheckIn = time.Now().Unix() node.LastCheckIn = time.Now().Unix()
} }
// Node.SetLastPeerUpdate - sets last peer update time
func (node *Node) SetLastPeerUpdate() { func (node *Node) SetLastPeerUpdate() {
node.LastPeerUpdate = time.Now().Unix() node.LastPeerUpdate = time.Now().Unix()
} }
// Node.SetExpirationDateTime - sets node expiry time
func (node *Node) SetExpirationDateTime() { func (node *Node) SetExpirationDateTime() {
node.ExpirationDateTime = time.Now().Unix() + TEN_YEARS_IN_SECONDS node.ExpirationDateTime = time.Now().Unix() + TEN_YEARS_IN_SECONDS
} }
// Node.SetDefaultName - sets a random name to node
func (node *Node) SetDefaultName() { func (node *Node) SetDefaultName() {
if node.Name == "" { if node.Name == "" {
node.Name = GenerateNodeName() node.Name = GenerateNodeName()
} }
} }
// Node.SetDefaultExcludedAddrs - sets ExcludedAddrs to empty array if nil
func (node *Node) SetDefaultExcludedAddrs() {
if node.ExcludedAddrs == nil {
node.ExcludedAddrs = make([]string, 0)
}
}
// Node.Fill - fills other node data into calling node data if not set on calling node
func (newNode *Node) Fill(currentNode *Node) { func (newNode *Node) Fill(currentNode *Node) {
newNode.ID = currentNode.ID newNode.ID = currentNode.ID
@ -354,8 +381,15 @@ func (newNode *Node) Fill(currentNode *Node) {
if newNode.IsRelayed == "" { if newNode.IsRelayed == "" {
newNode.IsRelayed = currentNode.IsRelayed newNode.IsRelayed = currentNode.IsRelayed
} }
if newNode.Version == "" {
newNode.Version = currentNode.Version
}
if newNode.ExcludedAddrs == nil || len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) {
newNode.ExcludedAddrs = currentNode.ExcludedAddrs
}
} }
// StringWithCharset - returns random string inside defined charset
func StringWithCharset(length int, charset string) string { func StringWithCharset(length int, charset string) string {
b := make([]byte, length) b := make([]byte, length)
for i := range b { for i := range b {
@ -364,13 +398,14 @@ func StringWithCharset(length int, charset string) string {
return string(b) return string(b)
} }
//Check for valid IPv4 address // IsIpv4Net - check for valid IPv4 address
//Note: We dont handle IPv6 AT ALL!!!!! This definitely is needed at some point // Note: We dont handle IPv6 AT ALL!!!!! This definitely is needed at some point
//But for iteration 1, lets just stick to IPv4. Keep it simple stupid. // But for iteration 1, lets just stick to IPv4. Keep it simple stupid.
func IsIpv4Net(host string) bool { func IsIpv4Net(host string) bool {
return net.ParseIP(host) != nil return net.ParseIP(host) != nil
} }
// Node.NameInNodeCharset - returns if name is in charset below or not
func (node *Node) NameInNodeCharSet() bool { func (node *Node) NameInNodeCharSet() bool {
charset := "abcdefghijklmnopqrstuvwxyz1234567890-" charset := "abcdefghijklmnopqrstuvwxyz1234567890-"

View file

@ -156,3 +156,10 @@ type RelayRequest struct {
NetID string `json:"netid" bson:"netid"` NetID string `json:"netid" bson:"netid"`
RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs"` RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs"`
} }
// ServerUpdateData - contains data to configure server
// and if it should set peers
type ServerUpdateData struct {
UpdatePeers bool `json:"updatepeers" bson:"updatepeers"`
Node Node `json:"servernode" bson:"servernode"`
}

View file

@ -1,51 +1,17 @@
package serverctl package serverctl
import ( import (
"encoding/json"
"errors" "errors"
"net" "net"
"os" "os"
"strings" "strings"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/netclient/ncutils" "github.com/gravitl/netmaker/netclient/ncutils"
"github.com/gravitl/netmaker/servercfg"
) )
// GetServerWGConf - gets the server WG configuration
func GetServerWGConf() (models.IntClient, error) {
var server models.IntClient
collection, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
if err != nil {
return models.IntClient{}, errors.New("could not find comms server")
}
for _, value := range collection {
json.Unmarshal([]byte(value), &server)
if server.Network == "comms" && server.IsServer == "yes" {
return server, nil
}
}
return models.IntClient{}, errors.New("could not find comms server")
}
// FileExists - checks if local file exists
func FileExists(f string) bool {
info, err := os.Stat(f)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
// RemoveNetwork - removes a network locally on server
func RemoveNetwork(network string) (bool, error) {
err := logic.ServerLeave(network)
return true, err
}
// InitServerNetclient - intializes the server netclient // InitServerNetclient - intializes the server netclient
func InitServerNetclient() error { func InitServerNetclient() error {
netclientDir := ncutils.GetNetclientPath() netclientDir := ncutils.GetNetclientPath()
@ -59,78 +25,42 @@ func InitServerNetclient() error {
return nil return nil
} }
// HandleContainedClient - function for checkins on server // SyncServerNetwork - ensures a wg interface and node exists for server
func HandleContainedClient() error { func SyncServerNetwork(serverNode *models.Node) error {
servernets, err := logic.GetNetworks() serverNetworkSettings, err := logic.GetNetwork(serverNode.Network)
if err != nil && !database.IsEmptyRecord(err) { if err != nil {
return err return err
} }
if len(servernets) > 0 {
if err != nil {
return err
}
for _, serverNet := range servernets {
var serverID, err = logic.GetNetworkServerNodeID(serverNet.NetID)
if err != nil {
logger.Log(1, "error occurred during server checkin:", err.Error())
continue
}
err = logic.ServerCheckin(serverID, servercfg.GetNodeID(), serverNet.NetID)
if err != nil {
logger.Log(1, "error occurred during server checkin:", err.Error())
} else {
logger.Log(3, "completed peers check of network", serverNet.NetID)
}
}
syncErr := SyncNetworks(servernets[:])
if syncErr != nil {
logger.Log(1, "error syncing networks:", syncErr.Error())
syncErr = nil
}
// logger.Log("completed a checkin call", 3)
}
return nil
}
// SyncNetworks - syncs the networks for servers
func SyncNetworks(servernets []models.Network) error {
localnets, err := net.Interfaces() localnets, err := net.Interfaces()
if err != nil { if err != nil {
return err return err
} }
// check networks to join exists := false
for _, servernet := range servernets { for _, localnet := range localnets {
exists := false if serverNetworkSettings.DefaultInterface == localnet.Name {
for _, localnet := range localnets { exists = true
if servernet.DefaultInterface == localnet.Name {
exists = true
}
} }
if !exists { }
success, err := AddNetwork(&servernet) if !exists {
if err != nil || !success { err := logic.ServerJoin(&serverNetworkSettings)
if err == nil { if err != nil {
err = errors.New("network add failed for " + servernet.NetID) if err == nil {
} err = errors.New("network add failed for " + serverNetworkSettings.NetID)
if !strings.Contains(err.Error(), "macaddress_unique") { // ignore macaddress unique error throws }
logger.Log(1, "error adding network", servernet.NetID, "during sync:", err.Error()) if !strings.Contains(err.Error(), "macaddress_unique") { // ignore macaddress unique error throws
} logger.Log(1, "error adding network", serverNetworkSettings.NetID, "during sync:", err.Error())
} }
} }
} }
// check networks to leave
for _, localnet := range localnets { for _, localnet := range localnets {
if strings.Contains(localnet.Name, "nm-") { if strings.Contains(localnet.Name, "nm-") {
var exists = "" var exists = ""
for _, servernet := range servernets { if serverNetworkSettings.DefaultInterface == localnet.Name {
if servernet.DefaultInterface == localnet.Name { exists = serverNetworkSettings.NetID
exists = servernet.NetID
}
} }
if exists == "" { if exists == "" {
success, err := RemoveNetwork(exists) err := logic.DeleteNodeByID(serverNode, true)
if err != nil || !success { if err != nil {
if err == nil { if err == nil {
err = errors.New("network delete failed for " + exists) err = errors.New("network delete failed for " + exists)
} }
@ -139,12 +69,5 @@ func SyncNetworks(servernets []models.Network) error {
} }
} }
} }
return nil return nil
} }
// AddNetwork - add a network to server in client mode
func AddNetwork(networkSettings *models.Network) (bool, error) {
var err = logic.ServerJoin(networkSettings, servercfg.GetNodeID())
return true, err
}

29
serverctl/serverq.go Normal file
View file

@ -0,0 +1,29 @@
package serverctl
import (
"fmt"
"github.com/gravitl/netmaker/models"
)
// ServerQueue - holds data to be updated across the server
var ServerQueue chan models.ServerUpdateData
func init() {
ServerQueue = make(chan models.ServerUpdateData, 100)
}
// Push - Pushes ServerUpdateData to be used later
func Push(serverData models.ServerUpdateData) {
ServerQueue <- serverData
}
// Pop - fetches first available data from queue
func Pop() (models.ServerUpdateData, error) {
select {
case serverData := <-ServerQueue:
return serverData, nil
default:
return models.ServerUpdateData{}, fmt.Errorf("empty server queue")
}
}