| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 | package logicimport (	"encoding/json"	"errors"	"fmt"	"sort"	"time"	"github.com/go-playground/validator/v10"	"github.com/gravitl/netmaker/database"	"github.com/gravitl/netmaker/logger"	"github.com/gravitl/netmaker/models"	"github.com/gravitl/netmaker/validation")// GetNetworkNodes - gets the nodes of a networkfunc GetNetworkNodes(network string) ([]models.Node, error) {	var nodes []models.Node	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		if database.IsEmptyRecord(err) {			return []models.Node{}, nil		}		return nodes, err	}	for _, value := range collection {		var node models.Node		err := json.Unmarshal([]byte(value), &node)		if err != nil {			continue		}		if node.Network == network {			nodes = append(nodes, node)		}	}	return nodes, nil}// GetSortedNetworkServerNodes - gets nodes of a network, except sorted by update timefunc GetSortedNetworkServerNodes(network string) ([]models.Node, error) {	var nodes []models.Node	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		if database.IsEmptyRecord(err) {			return []models.Node{}, nil		}		return nodes, err	}	for _, value := range collection {		var node models.Node		err := json.Unmarshal([]byte(value), &node)		if err != nil {			continue		}		if node.Network == network && node.IsServer == "yes" {			nodes = append(nodes, node)		}	}	sort.Sort(models.NodesArray(nodes))	return nodes, nil}// UncordonNode - approves a node to join a networkfunc UncordonNode(network, macaddress string) (models.Node, error) {	node, err := GetNodeByMacAddress(network, macaddress)	if err != nil {		return models.Node{}, err	}	node.SetLastModified()	node.IsPending = "no"	node.PullChanges = "yes"	data, err := json.Marshal(&node)	if err != nil {		return node, err	}	key, err := GetRecordKey(node.MacAddress, node.Network)	if err != nil {		return node, err	}	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)	return node, err}// GetPeers - gets the peers of a given nodefunc GetPeers(node *models.Node) ([]models.Node, error) {	if IsLeader(node) {		SetNetworkServerPeers(node)	}	excludeIsRelayed := node.IsRelay != "yes"	var relayedNode string	if node.IsRelayed == "yes" {		relayedNode = node.Address	}	peers, err := GetPeersList(node.Network, excludeIsRelayed, relayedNode)	if err != nil {		return nil, err	}	return peers, nil}// IsLeader - determines if a given server node is a leaderfunc IsLeader(node *models.Node) bool {	nodes, err := GetSortedNetworkServerNodes(node.Network)	if err != nil {		logger.Log(0, "ERROR: COULD NOT RETRIEVE SERVER NODES. THIS WILL BREAK HOLE PUNCHING.")		return false	}	for _, n := range nodes {		if n.LastModified > time.Now().Add(-1*time.Minute).Unix() {			return n.Address == node.Address		}	}	return len(nodes) <= 1 || nodes[1].Address == node.Address}// == DB related functions ==// UpdateNode - takes a node and updates another node with it's valuesfunc UpdateNode(currentNode *models.Node, newNode *models.Node) error {	newNode.Fill(currentNode)	if err := ValidateNode(newNode, true); err != nil {		return err	}	newNode.SetID()	if newNode.ID == currentNode.ID {		newNode.SetLastModified()		if data, err := json.Marshal(newNode); err != nil {			return err		} else {			return database.Insert(newNode.ID, string(data), database.NODES_TABLE_NAME)		}	}	return fmt.Errorf("failed to update node " + newNode.MacAddress + ", cannot change macaddress.")}// IsNodeIDUnique - checks if node id is uniquefunc IsNodeIDUnique(node *models.Node) (bool, error) {	_, err := database.FetchRecord(database.NODES_TABLE_NAME, node.ID)	return database.IsEmptyRecord(err), err}// ValidateNode - validates node valuesfunc ValidateNode(node *models.Node, isUpdate bool) error {	v := validator.New()	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {		if isUpdate {			return true		}		isFieldUnique, _ := IsNodeIDUnique(node)		return isFieldUnique	})	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {		_, err := GetNetworkByNode(node)		return err == nil	})	_ = v.RegisterValidation("in_charset", func(fl validator.FieldLevel) bool {		isgood := node.NameInNodeCharSet()		return isgood	})	_ = v.RegisterValidation("checkyesorno", func(fl validator.FieldLevel) bool {		return validation.CheckYesOrNo(fl)	})	err := v.Struct(node)	return err}// GetAllNodes - returns all nodes in the DBfunc GetAllNodes() ([]models.Node, error) {	var nodes []models.Node	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		if database.IsEmptyRecord(err) {			return []models.Node{}, nil		}		return []models.Node{}, err	}	for _, value := range collection {		var node models.Node		if err := json.Unmarshal([]byte(value), &node); err != nil {			return []models.Node{}, err		}		// add node to our array		nodes = append(nodes, node)	}	return nodes, nil}// CheckIsServer - check if a node is the server nodefunc CheckIsServer(node *models.Node) bool {	nodeData, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil && !database.IsEmptyRecord(err) {		return false	}	for _, value := range nodeData {		var tmpNode models.Node		if err := json.Unmarshal([]byte(value), &tmpNode); err != nil {			continue		}		if tmpNode.Network == node.Network && tmpNode.MacAddress != node.MacAddress {			return false		}	}	return true}// GetNetworkByNode - gets the network model from a nodefunc GetNetworkByNode(node *models.Node) (models.Network, error) {	var network = models.Network{}	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, node.Network)	if err != nil {		return network, err	}	if err = json.Unmarshal([]byte(networkData), &network); err != nil {		return models.Network{}, err	}	return network, nil}// SetNodeDefaults - sets the defaults of a node to avoid empty fieldsfunc SetNodeDefaults(node *models.Node) {	//TODO: Maybe I should make Network a part of the node struct. Then we can just query the Network object for stuff.	parentNetwork, _ := GetNetworkByNode(node)	node.ExpirationDateTime = time.Now().Unix() + models.TEN_YEARS_IN_SECONDS	if node.ListenPort == 0 {		node.ListenPort = parentNetwork.DefaultListenPort	}	if node.SaveConfig == "" {		if parentNetwork.DefaultSaveConfig != "" {			node.SaveConfig = parentNetwork.DefaultSaveConfig		} else {			node.SaveConfig = "yes"		}	}	if node.Interface == "" {		node.Interface = parentNetwork.DefaultInterface	}	if node.PersistentKeepalive == 0 {		node.PersistentKeepalive = parentNetwork.DefaultKeepalive	}	if node.PostUp == "" {		postup := parentNetwork.DefaultPostUp		node.PostUp = postup	}	if node.PostDown == "" {		postdown := parentNetwork.DefaultPostDown		node.PostDown = postdown	}	if node.IsStatic == "" {		node.IsStatic = "no"	}	if node.UDPHolePunch == "" {		node.UDPHolePunch = parentNetwork.DefaultUDPHolePunch		if node.UDPHolePunch == "" {			node.UDPHolePunch = "yes"		}	}	// == Parent Network settings ==	if node.IsDualStack == "" {		node.IsDualStack = parentNetwork.IsDualStack	}	if node.MTU == 0 {		node.MTU = parentNetwork.DefaultMTU	}	// == node defaults if not set by parent ==	node.SetIPForwardingDefault()	node.SetDNSOnDefault()	node.SetIsLocalDefault()	node.SetIsDualStackDefault()	node.SetLastModified()	node.SetDefaultName()	node.SetLastCheckIn()	node.SetLastPeerUpdate()	node.SetRoamingDefault()	node.SetPullChangesDefault()	node.SetDefaultAction()	node.SetID()	node.SetIsServerDefault()	node.SetIsStaticDefault()	node.SetDefaultEgressGateway()	node.SetDefaultIngressGateway()	node.SetDefaulIsPending()	node.SetDefaultMTU()	node.SetDefaultIsRelayed()	node.SetDefaultIsRelay()	node.KeyUpdateTimeStamp = time.Now().Unix()}// GetRecordKey - get record keyfunc GetRecordKey(id string, network string) (string, error) {	if id == "" || network == "" {		return "", errors.New("unable to get record key")	}	return id + "###" + network, nil}// GetNodeByMacAddress - gets a node by mac addressfunc GetNodeByMacAddress(network string, macaddress string) (models.Node, error) {	var node models.Node	key, err := GetRecordKey(macaddress, network)	if err != nil {		return node, err	}	record, err := database.FetchRecord(database.NODES_TABLE_NAME, key)	if err != nil {		return models.Node{}, err	}	if err = json.Unmarshal([]byte(record), &node); err != nil {		return models.Node{}, err	}	SetNodeDefaults(&node)	return node, nil}// GetDeletedNodeByMacAddress - get a deleted nodefunc GetDeletedNodeByMacAddress(network string, macaddress string) (models.Node, error) {	var node models.Node	key, err := GetRecordKey(macaddress, network)	if err != nil {		return node, err	}	record, err := database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)	if err != nil {		return models.Node{}, err	}	if err = json.Unmarshal([]byte(record), &node); err != nil {		return models.Node{}, err	}	SetNodeDefaults(&node)	return node, nil}// GetNodeRelay - gets the relay node of a given networkfunc GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)	var relay models.Node	if err != nil {		if database.IsEmptyRecord(err) {			return relay, nil		}		logger.Log(2, err.Error())		return relay, err	}	for _, value := range collection {		err := json.Unmarshal([]byte(value), &relay)		if err != nil {			logger.Log(2, err.Error())			continue		}		if relay.IsRelay == "yes" {			for _, addr := range relay.RelayAddrs {				if addr == relayedNodeAddr {					return relay, nil				}			}		}	}	return relay, errors.New("could not find relay for node " + relayedNodeAddr)}
 |