began refactor

This commit is contained in:
0xdcarns 2022-01-17 17:44:12 -05:00
parent 2a5405982e
commit 916866f73c
9 changed files with 243 additions and 280 deletions

View file

@ -12,7 +12,6 @@ import (
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg"
"github.com/gravitl/netmaker/serverctl"
)
const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
@ -226,9 +225,8 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
}
if servercfg.IsClientMode() != "off" {
var success bool
success, err = serverctl.AddNetwork(&network)
if err != nil || !success {
err = logic.ServerJoin(&network)
if err != nil {
logic.DeleteNetwork(network.NetID)
if err == nil {
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/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods("POST")
}
func authenticate(response http.ResponseWriter, request *http.Request) {
@ -535,6 +534,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
returnErrorResponse(w, r, formatError(err, "internal"))
return
}
if relayupdate {
logic.UpdateRelay(node.Network, node.RelayAddrs, newNode.RelayAddrs)
if err = logic.NetworkNodesUpdatePullChanges(node.Network); err != nil {
@ -542,7 +542,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
}
}
if servercfg.IsDNSMode() {
if servercfg.IsDNSMode() { // TODO check when this should be updated..
err = logic.SetDNS()
}
if err != nil {

View file

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

View file

@ -0,0 +1,58 @@
package controller
import (
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/serverctl"
)
func runServerUpdateIfNeeded(currentNode *models.Node, newNode *models.Node) error {
// check if a peer/server update is needed
var serverData = serverctl.ServerUpdateData{
UpdatePeers: logic.ShouldPeersUpdate(currentNode, newNode),
}
if currentNode.IsServer == "yes" {
serverData.ServerNode = *currentNode
}
serverctl.Push(serverData)
return handleServerUpdate()
}
func handleServerUpdate() error {
var settings, settingsErr = serverctl.Pop()
if settingsErr != nil {
return settingsErr
}
var currentServerNodeID, err = logic.GetNetworkServerNodeID(settings.ServerNode.Network)
if err != nil {
return err
}
// ensure server client is available
if settings.UpdatePeers || (settings.ServerNode.ID == currentServerNodeID) {
serverctl.SyncServerNetwork(&settings.ServerNode)
}
// if peers should update, update peers on network
if settings.UpdatePeers {
if err = handlePeerUpdate(&settings.ServerNode); err != nil {
return err
}
logger.Log(1, "updated peers on network:", settings.ServerNode.Network)
}
// if the server node had an update, run the update function
if settings.ServerNode.ID == currentServerNodeID {
if err = logic.ServerUpdate(&settings.ServerNode); err != nil {
return err
}
logger.Log(1, "server node:", settings.ServerNode.ID, "was updated")
}
return nil
}
// tells server to update it's peers
func handlePeerUpdate(serverNode *models.Node) error {
logger.Log(1, "updating peers on network:", serverNode.Network)
logic.SetNetworkServerPeers(serverNode)
return nil
}

View file

@ -9,11 +9,13 @@ import (
"time"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg"
"github.com/gravitl/netmaker/validation"
"golang.org/x/crypto/bcrypt"
)
// GetNetworkNodes - gets the nodes of a network
@ -166,8 +168,75 @@ func ValidateNode(node *models.Node, isUpdate bool) error {
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 ||
@ -177,6 +246,8 @@ func ShouldPeersUpdate(currentNode *models.Node, newNode *models.Node) bool {
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
}

View file

@ -26,7 +26,7 @@ const KUBERNETES_LISTEN_PORT = 31821
const KUBERNETES_SERVER_MTU = 1024
// 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 == "" {
return errors.New("no network provided")
@ -119,7 +119,7 @@ func ServerJoin(networkSettings *models.Network, serverID string) error {
if err = StorePrivKey(node.ID, privateKey); err != nil {
return err
}
if err = ServerPush(node); err != nil {
if err = serverPush(node); err != nil {
return err
}
@ -137,18 +137,12 @@ func ServerJoin(networkSettings *models.Network, serverID string) error {
return nil
}
// ServerCheckin - runs pulls and pushes for server
func ServerCheckin(serverID string, mac string, network string) error {
var serverNode = &models.Node{}
var currentNode, err = GetNodeByIDorMacAddress(serverID, mac, network)
if err != nil {
return err
}
serverNode = &currentNode
err = ServerPull(serverNode, false)
// ServerUpdate - updates the server
// replaces legacy Checkin code
func ServerUpdate(serverNode *models.Node) error {
var err = serverPull(serverNode, false)
if isDeleteError(err) {
return ServerLeave(currentNode.ID)
return DeleteNodeByID(serverNode, true)
} else if err != nil {
return err
}
@ -158,66 +152,7 @@ func ServerCheckin(serverID string, mac string, network string) error {
return errors.New("node has been removed")
}
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)
return serverPush(serverNode)
}
/**
@ -422,7 +357,7 @@ func checkNodeActions(node *models.Node) string {
}
}
if node.Action == models.NODE_DELETE {
err := ServerLeave(node.ID)
err := DeleteNodeByID(node, true)
if err != nil {
logger.Log(1, "error deleting locally:", err.Error())
}
@ -431,6 +366,47 @@ func checkNodeActions(node *models.Node) string {
return ""
}
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) {
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")
}
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/json"
"math/rand"
"os"
"strconv"
"strings"
"time"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/netclient/ncutils"
"github.com/gravitl/netmaker/servercfg"
"golang.org/x/crypto/bcrypt"
)
// IsBase64 - checks if a string is in base64 format
@ -31,14 +30,23 @@ func CheckEndpoint(endpoint string) bool {
return len(endpointarr) == 2
}
// 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()
}
// SetNetworkServerPeers - sets the network server peers of a given node
func SetNetworkServerPeers(node *models.Node) {
if currentPeersList, err := GetSystemPeers(node); err == nil {
if database.SetPeers(currentPeersList, node.Network) {
logger.Log(1, "set new peers on network", node.Network)
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", node.Network, ":", err.Error())
logger.Log(1, "could not set peers on network", serverNode.Network, ":", err.Error())
}
}
@ -75,72 +83,6 @@ func DeleteNodeByMacAddress(node *models.Node, exterminate bool) error {
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
func SetNetworkNodesLastModified(networkName string) error {

View file

@ -16,8 +16,18 @@ import (
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
// GetSystemPeers - gets the server peers
func GetSystemPeers(node *models.Node) (map[string]string, error) {
// 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 ==
// gets the server peers locally
func getSystemPeers(node *models.Node) (map[string]string, error) {
peers := make(map[string]string)
client, err := wgctrl.New()
@ -37,16 +47,6 @@ func GetSystemPeers(node *models.Node) (map[string]string, error) {
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 {
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())
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
var deviceiface = ifacename
d, _ := wgclient.Device(deviceiface)
@ -182,9 +172,10 @@ func setKernelDevice(ifacename string, address string) error {
return err
}
_, _ = ncutils.RunCmd("ip link delete dev "+ifacename, false)
_, _ = 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
// == best effort ==
ncutils.RunCmd("ip link delete dev "+ifacename, false)
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
}

View file

@ -1,51 +1,17 @@
package serverctl
import (
"encoding/json"
"errors"
"net"
"os"
"strings"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"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
func InitServerNetclient() error {
netclientDir := ncutils.GetNetclientPath()
@ -59,78 +25,42 @@ func InitServerNetclient() error {
return nil
}
// HandleContainedClient - function for checkins on server
func HandleContainedClient() error {
servernets, err := logic.GetNetworks()
if err != nil && !database.IsEmptyRecord(err) {
// SyncServerNetwork - ensures a wg interface and node exists for server
func SyncServerNetwork(serverNode *models.Node) error {
serverNetworkSettings, err := logic.GetNetwork(serverNode.Network)
if err != nil {
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()
if err != nil {
return err
}
// check networks to join
for _, servernet := range servernets {
exists := false
for _, localnet := range localnets {
if servernet.DefaultInterface == localnet.Name {
exists = true
}
exists := false
for _, localnet := range localnets {
if serverNetworkSettings.DefaultInterface == localnet.Name {
exists = true
}
if !exists {
success, err := AddNetwork(&servernet)
if err != nil || !success {
if err == nil {
err = errors.New("network add failed for " + servernet.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 !exists {
err := logic.ServerJoin(&serverNetworkSettings)
if err != nil {
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", serverNetworkSettings.NetID, "during sync:", err.Error())
}
}
}
// check networks to leave
for _, localnet := range localnets {
if strings.Contains(localnet.Name, "nm-") {
var exists = ""
for _, servernet := range servernets {
if servernet.DefaultInterface == localnet.Name {
exists = servernet.NetID
}
if serverNetworkSettings.DefaultInterface == localnet.Name {
exists = serverNetworkSettings.NetID
}
if exists == "" {
success, err := RemoveNetwork(exists)
if err != nil || !success {
err := logic.DeleteNodeByID(serverNode, true)
if err != nil {
if err == nil {
err = errors.New("network delete failed for " + exists)
}
@ -139,12 +69,5 @@ func SyncNetworks(servernets []models.Network) error {
}
}
}
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
}