fixed network tests that failed with nodes

This commit is contained in:
Matthew R Kasun
2021-04-24 18:03:26 -04:00
parent f28937c1f6
commit ae826002cd
6 changed files with 1165 additions and 721 deletions

View File

@@ -1,226 +1,226 @@
package controller package controller
import ( import (
"gopkg.in/go-playground/validator.v9" "context"
"log" "fmt"
"fmt" "log"
"golang.org/x/crypto/bcrypt" "net"
"github.com/gravitl/netmaker/mongoconn" "time"
"github.com/gravitl/netmaker/functions"
"context"
"go.mongodb.org/mongo-driver/bson"
"time"
"net"
"github.com/gravitl/netmaker/models"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/gravitl/netmaker/functions"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mongoconn"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
"golang.org/x/crypto/bcrypt"
"gopkg.in/go-playground/validator.v9"
) )
func GetPeersList(networkName string) ([]models.PeersResponse, error) { func GetPeersList(networkName string) ([]models.PeersResponse, error) {
var peers []models.PeersResponse var peers []models.PeersResponse
//Connection mongoDB with mongoconn class //Connection mongoDB with mongoconn class
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
//Get all nodes in the relevant network which are NOT in pending state //Get all nodes in the relevant network which are NOT in pending state
filter := bson.M{"network": networkName, "ispending": false} filter := bson.M{"network": networkName, "ispending": false}
cur, err := collection.Find(ctx, filter) cur, err := collection.Find(ctx, filter)
if err != nil { if err != nil {
return peers, err return peers, err
} }
// Close the cursor once finished and cancel if it takes too long // Close the cursor once finished and cancel if it takes too long
defer cancel() defer cancel()
for cur.Next(context.TODO()) { for cur.Next(context.TODO()) {
var peer models.PeersResponse var peer models.PeersResponse
err := cur.Decode(&peer) err := cur.Decode(&peer)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// add the node to our node array // add the node to our node array
//maybe better to just return this? But then that's just GetNodes... //maybe better to just return this? But then that's just GetNodes...
peers = append(peers, peer) peers = append(peers, peer)
} }
//Uh oh, fatal error! This needs some better error handling //Uh oh, fatal error! This needs some better error handling
//TODO: needs appropriate error handling so the server doesnt shut down. //TODO: needs appropriate error handling so the server doesnt shut down.
if err := cur.Err(); err != nil { if err := cur.Err(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
return peers, err return peers, err
} }
func ValidateNode(operation string, networkName string, node models.Node) error { func ValidateNode(operation string, networkName string, node models.Node) error {
v := validator.New() v := validator.New()
_ = v.RegisterValidation("endpoint_check", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("endpoint_check", func(fl validator.FieldLevel) bool {
//var isFieldUnique bool = functions.IsFieldUnique(networkName, "endpoint", node.Endpoint) //var isFieldUnique bool = functions.IsFieldUnique(networkName, "endpoint", node.Endpoint)
isIpv4 := functions.IsIpv4Net(node.Endpoint) isIpv4 := functions.IsIpv4Net(node.Endpoint)
notEmptyCheck := node.Endpoint != "" notEmptyCheck := node.Endpoint != ""
return (notEmptyCheck && isIpv4) || operation == "update" return (notEmptyCheck && isIpv4)
}) })
_ = v.RegisterValidation("localaddress_check", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("localaddress_check", func(fl validator.FieldLevel) bool {
//var isFieldUnique bool = functions.IsFieldUnique(networkName, "endpoint", node.Endpoint) //var isFieldUnique bool = functions.IsFieldUnique(networkName, "endpoint", node.Endpoint)
isIpv4 := functions.IsIpv4Net(node.LocalAddress) isIpv4 := functions.IsIpv4Net(node.LocalAddress)
notEmptyCheck := node.LocalAddress != "" notEmptyCheck := node.LocalAddress != ""
return (notEmptyCheck && isIpv4) || operation == "update" return (notEmptyCheck && isIpv4)
}) })
_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
var isFieldUnique bool = functions.IsFieldUnique(networkName, "macaddress", node.MacAddress)
return isFieldUnique || operation == "update"
})
_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("macaddress_valid", func(fl validator.FieldLevel) bool {
var isFieldUnique bool = functions.IsFieldUnique(networkName, "macaddress", node.MacAddress) _, err := net.ParseMAC(node.MacAddress)
return isFieldUnique || operation == "update" return err == nil
}) })
_ = v.RegisterValidation("macaddress_valid", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("name_valid", func(fl validator.FieldLevel) bool {
_, err := net.ParseMAC(node.MacAddress) isvalid := functions.NameInNodeCharSet(node.Name)
return err == nil return isvalid
}) })
_ = v.RegisterValidation("name_valid", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
isvalid := functions.NameInNodeCharSet(node.Name)
return isvalid
})
_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
_, err := node.GetNetwork() _, err := node.GetNetwork()
return err == nil return err == nil
}) })
_ = v.RegisterValidation("pubkey_check", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("pubkey_check", func(fl validator.FieldLevel) bool {
notEmptyCheck := node.PublicKey != "" notEmptyCheck := node.PublicKey != ""
isBase64 := functions.IsBase64(node.PublicKey) isBase64 := functions.IsBase64(node.PublicKey)
return (notEmptyCheck && isBase64) || operation == "update" return (notEmptyCheck && isBase64)
}) })
_ = v.RegisterValidation("password_check", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("password_check", func(fl validator.FieldLevel) bool {
notEmptyCheck := node.Password != "" notEmptyCheck := node.Password != ""
goodLength := len(node.Password) > 5 goodLength := len(node.Password) > 5
return (notEmptyCheck && goodLength) || operation == "update" return (notEmptyCheck && goodLength)
}) })
err := v.Struct(node) err := v.Struct(node)
if err != nil { if err != nil {
for _, e := range err.(validator.ValidationErrors) { for _, e := range err.(validator.ValidationErrors) {
fmt.Println(e) fmt.Println(e)
} }
} }
return err return err
} }
func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) { func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) {
//Question: Is there a better way of doing this than a bunch of "if" statements? probably... //Question: Is there a better way of doing this than a bunch of "if" statements? probably...
//Eventually, lets have a better way to check if any of the fields are filled out... //Eventually, lets have a better way to check if any of the fields are filled out...
queryMac := node.MacAddress queryMac := node.MacAddress
queryNetwork := node.Network queryNetwork := node.Network
notifynetwork := false notifynetwork := false
if nodechange.Address != "" { if nodechange.Address != "" {
node.Address = nodechange.Address node.Address = nodechange.Address
notifynetwork = true notifynetwork = true
} }
if nodechange.Name != "" { if nodechange.Name != "" {
node.Name = nodechange.Name node.Name = nodechange.Name
} }
if nodechange.LocalAddress != "" { if nodechange.LocalAddress != "" {
node.LocalAddress = nodechange.LocalAddress node.LocalAddress = nodechange.LocalAddress
} }
if nodechange.ListenPort != 0 { if nodechange.ListenPort != 0 {
node.ListenPort = nodechange.ListenPort node.ListenPort = nodechange.ListenPort
} }
if nodechange.ExpirationDateTime != 0 { if nodechange.ExpirationDateTime != 0 {
node.ExpirationDateTime = nodechange.ExpirationDateTime node.ExpirationDateTime = nodechange.ExpirationDateTime
} }
if nodechange.PostDown != "" { if nodechange.PostDown != "" {
node.PostDown = nodechange.PostDown node.PostDown = nodechange.PostDown
} }
if nodechange.Interface != "" { if nodechange.Interface != "" {
node.Interface = nodechange.Interface node.Interface = nodechange.Interface
} }
if nodechange.PostUp != "" { if nodechange.PostUp != "" {
node.PostUp = nodechange.PostUp node.PostUp = nodechange.PostUp
} }
if nodechange.AccessKey != "" { if nodechange.AccessKey != "" {
node.AccessKey = nodechange.AccessKey node.AccessKey = nodechange.AccessKey
} }
if nodechange.Endpoint != "" { if nodechange.Endpoint != "" {
node.Endpoint = nodechange.Endpoint node.Endpoint = nodechange.Endpoint
notifynetwork = true notifynetwork = true
} }
if nodechange.SaveConfig != nil { if nodechange.SaveConfig != nil {
node.SaveConfig = nodechange.SaveConfig node.SaveConfig = nodechange.SaveConfig
} }
if nodechange.PersistentKeepalive != 0 { if nodechange.PersistentKeepalive != 0 {
node.PersistentKeepalive = nodechange.PersistentKeepalive node.PersistentKeepalive = nodechange.PersistentKeepalive
} }
if nodechange.Password != "" { if nodechange.Password != "" {
err := bcrypt.CompareHashAndPassword([]byte(nodechange.Password), []byte(node.Password)) err := bcrypt.CompareHashAndPassword([]byte(nodechange.Password), []byte(node.Password))
if err != nil && nodechange.Password != node.Password { if err != nil && nodechange.Password != node.Password {
hash, err := bcrypt.GenerateFromPassword([]byte(nodechange.Password), 5) hash, err := bcrypt.GenerateFromPassword([]byte(nodechange.Password), 5)
if err != nil { if err != nil {
return node, err return node, err
} }
nodechange.Password = string(hash) nodechange.Password = string(hash)
node.Password = nodechange.Password node.Password = nodechange.Password
}
}
if nodechange.MacAddress != "" {
node.MacAddress = nodechange.MacAddress
}
if nodechange.PublicKey != "" {
node.PublicKey = nodechange.PublicKey
node.KeyUpdateTimeStamp = time.Now().Unix()
notifynetwork = true
} }
}
if nodechange.MacAddress != "" {
node.MacAddress = nodechange.MacAddress
}
if nodechange.PublicKey != "" {
node.PublicKey = nodechange.PublicKey
node.KeyUpdateTimeStamp = time.Now().Unix()
notifynetwork = true
}
//collection := mongoconn.ConnectDB() //collection := mongoconn.ConnectDB()
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// Create filter // Create filter
filter := bson.M{"macaddress": queryMac, "network": queryNetwork} filter := bson.M{"macaddress": queryMac, "network": queryNetwork}
node.SetLastModified() node.SetLastModified()
// prepare update model. // prepare update model.
update := bson.D{ update := bson.D{
{"$set", bson.D{ {"$set", bson.D{
{"name", node.Name}, {"name", node.Name},
{"password", node.Password}, {"password", node.Password},
{"listenport", node.ListenPort}, {"listenport", node.ListenPort},
{"publickey", node.PublicKey}, {"publickey", node.PublicKey},
{"keyupdatetimestamp", node.KeyUpdateTimeStamp}, {"keyupdatetimestamp", node.KeyUpdateTimeStamp},
{"expdatetime", node.ExpirationDateTime}, {"expdatetime", node.ExpirationDateTime},
{"endpoint", node.Endpoint}, {"endpoint", node.Endpoint},
{"postup", node.PostUp}, {"postup", node.PostUp},
{"postdown", node.PostDown}, {"postdown", node.PostDown},
{"macaddress", node.MacAddress}, {"macaddress", node.MacAddress},
{"localaddress", node.LocalAddress}, {"localaddress", node.LocalAddress},
{"persistentkeepalive", node.PersistentKeepalive}, {"persistentkeepalive", node.PersistentKeepalive},
{"saveconfig", node.SaveConfig}, {"saveconfig", node.SaveConfig},
{"accesskey", node.AccessKey}, {"accesskey", node.AccessKey},
{"interface", node.Interface}, {"interface", node.Interface},
{"lastmodified", node.LastModified}, {"lastmodified", node.LastModified},
}}, }},
} }
var nodeupdate models.Node var nodeupdate models.Node
errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate) errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
if errN != nil { if errN != nil {
return nodeupdate, errN return nodeupdate, errN
} }
if nodechange.MacAddress != "" {
queryMac = nodechange.MacAddress
}
returnnode, errN := GetNode(queryMac, queryNetwork) returnnode, errN := GetNode(queryMac, queryNetwork)
defer cancel() defer cancel()
@@ -232,17 +232,17 @@ func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) {
return returnnode, errN return returnnode, errN
} }
func DeleteNode(macaddress string, network string) (bool, error) { func DeleteNode(macaddress string, network string) (bool, error) {
deleted := false deleted := false
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
filter := bson.M{"macaddress": macaddress, "network": network} filter := bson.M{"macaddress": macaddress, "network": network}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
result, err := collection.DeleteOne(ctx, filter) result, err := collection.DeleteOne(ctx, filter)
deletecount := result.DeletedCount deletecount := result.DeletedCount
@@ -250,9 +250,9 @@ func DeleteNode(macaddress string, network string) (bool, error) {
deleted = true deleted = true
} }
defer cancel() defer cancel()
err = SetNetworkNodesLastModified(network) err = SetNetworkNodesLastModified(network)
fmt.Println("Deleted node " + macaddress + " from network " + network) fmt.Println("Deleted node " + macaddress + " from network " + network)
return deleted, err return deleted, err
@@ -260,90 +260,88 @@ func DeleteNode(macaddress string, network string) (bool, error) {
func GetNode(macaddress string, network string) (models.Node, error) { func GetNode(macaddress string, network string) (models.Node, error) {
var node models.Node var node models.Node
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"macaddress": macaddress, "network": network} filter := bson.M{"macaddress": macaddress, "network": network}
err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&node) err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&node)
defer cancel() defer cancel()
return node, err return node, err
} }
func CreateNode(node models.Node, networkName string) (models.Node, error) { func CreateNode(node models.Node, networkName string) (models.Node, error) {
//encrypt that password so we never see it again //encrypt that password so we never see it again
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5) hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
if err != nil { if err != nil {
return node, err return node, err
} }
//set password to encrypted password //set password to encrypted password
node.Password = string(hash) node.Password = string(hash)
node.Network = networkName
node.Network = networkName //node.SetDefaults()
//Umm, why am I doing this again?
//TODO: Why am I using a local function instead of the struct function? I really dont know.
//I think I thought it didn't work but uhhh...idk
//anyways, this sets some sensible variables for unset params.
node.SetDefaults()
//node.SetDefaults() //Another DB call here...Inefficient
//Umm, why am I doing this again? //Anyways, this scrolls through all the IP Addresses in the network range and checks against nodes
//TODO: Why am I using a local function instead of the struct function? I really dont know. //until one is open and then returns it
//I think I thought it didn't work but uhhh...idk node.Address, err = functions.UniqueAddress(networkName)
//anyways, this sets some sensible variables for unset params.
node.SetDefaults()
//Another DB call here...Inefficient if err != nil {
//Anyways, this scrolls through all the IP Addresses in the network range and checks against nodes return node, err
//until one is open and then returns it }
node.Address, err = functions.UniqueAddress(networkName)
if err != nil { //IDK why these aren't a part of "set defaults. Pretty dumb.
return node, err //TODO: This is dumb. Consolidate and fix.
} node.SetLastModified()
node.SetDefaultName()
//IDK why these aren't a part of "set defaults. Pretty dumb.
//TODO: This is dumb. Consolidate and fix.
node.SetLastModified()
node.SetDefaultName()
node.SetLastCheckIn() node.SetLastCheckIn()
node.SetLastPeerUpdate() node.SetLastPeerUpdate()
node.KeyUpdateTimeStamp = time.Now().Unix() node.KeyUpdateTimeStamp = time.Now().Unix()
//Create a JWT for the node //Create a JWT for the node
tokenString, _ := functions.CreateJWT(node.MacAddress, networkName) tokenString, _ := functions.CreateJWT(node.MacAddress, networkName)
if tokenString == "" { if tokenString == "" {
//returnErrorResponse(w, r, errorResponse) //returnErrorResponse(w, r, errorResponse)
return node, err return node, err
} }
// connect db // connect db
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// insert our node to the node db.
result, err := collection.InsertOne(ctx, node)
_ = result
// insert our node to the node db. defer cancel()
result, err := collection.InsertOne(ctx, node)
_ = result
defer cancel() if err != nil {
return node, err
}
//return response for if node is pending
if !node.IsPending {
if err != nil { functions.DecrimentKey(node.Network, node.AccessKey)
return node, err
}
//return response for if node is pending
if !node.IsPending {
functions.DecrimentKey(node.Network, node.AccessKey) }
}
SetNetworkNodesLastModified(node.Network) SetNetworkNodesLastModified(node.Network)
return node, err return node, err
} }
func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse, error) { func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse, error) {
@@ -351,28 +349,28 @@ func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse,
var response models.CheckInResponse var response models.CheckInResponse
parentnetwork, err := functions.GetParentNetwork(networkName) parentnetwork, err := functions.GetParentNetwork(networkName)
if err != nil{ if err != nil {
err = fmt.Errorf("%w; Couldnt retrieve Network " + networkName + ": ", err) err = fmt.Errorf("%w; Couldnt retrieve Network "+networkName+": ", err)
return response, err return response, err
} }
parentnode, err := functions.GetNodeByMacAddress(networkName, node.MacAddress) parentnode, err := functions.GetNodeByMacAddress(networkName, node.MacAddress)
if err != nil{ if err != nil {
err = fmt.Errorf("%w; Couldnt Get Node " + node.MacAddress, err) err = fmt.Errorf("%w; Couldnt Get Node "+node.MacAddress, err)
return response, err return response, err
} }
if parentnode.IsPending { if parentnode.IsPending {
err = fmt.Errorf("%w; Node checking in is still pending: " + node.MacAddress, err) err = fmt.Errorf("%w; Node checking in is still pending: "+node.MacAddress, err)
response.IsPending = true response.IsPending = true
return response, err return response, err
} }
networklm := parentnetwork.NetworkLastModified networklm := parentnetwork.NetworkLastModified
peerslm := parentnetwork.NodesLastModified peerslm := parentnetwork.NodesLastModified
gkeyupdate := parentnetwork.KeyUpdateTimeStamp gkeyupdate := parentnetwork.KeyUpdateTimeStamp
nkeyupdate := parentnode.KeyUpdateTimeStamp nkeyupdate := parentnode.KeyUpdateTimeStamp
peerlistlm := parentnode.LastPeerUpdate peerlistlm := parentnode.LastPeerUpdate
parentnodelm := parentnode.LastModified parentnodelm := parentnode.LastModified
parentnodelastcheckin := parentnode.LastCheckIn parentnodelastcheckin := parentnode.LastCheckIn
if parentnodelastcheckin < parentnodelm { if parentnodelastcheckin < parentnodelm {
@@ -388,53 +386,53 @@ func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse,
if nkeyupdate < gkeyupdate { if nkeyupdate < gkeyupdate {
response.NeedKeyUpdate = true response.NeedKeyUpdate = true
} }
if time.Now().Unix() > parentnode.ExpirationDateTime { if time.Now().Unix() > parentnode.ExpirationDateTime {
response.NeedDelete = true response.NeedDelete = true
_, err = DeleteNode(node.MacAddress, networkName) _, err = DeleteNode(node.MacAddress, networkName)
} else { } else {
err = TimestampNode(parentnode, true, false, false) err = TimestampNode(parentnode, true, false, false)
if err != nil{ if err != nil {
err = fmt.Errorf("%w; Couldnt Timestamp Node: ", err) err = fmt.Errorf("%w; Couldnt Timestamp Node: ", err)
return response, err return response, err
} }
} }
response.Success = true response.Success = true
return response, err return response, err
} }
func SetNetworkNodesLastModified(networkName string) error { func SetNetworkNodesLastModified(networkName string) error {
timestamp := time.Now().Unix() timestamp := time.Now().Unix()
collection := mongoconn.Client.Database("netmaker").Collection("networks") collection := mongoconn.Client.Database("netmaker").Collection("networks")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// Create filter // Create filter
filter := bson.M{"netid": networkName} filter := bson.M{"netid": networkName}
// prepare update model. // prepare update model.
update := bson.D{ update := bson.D{
{"$set", bson.D{ {"$set", bson.D{
{"nodeslastmodified", timestamp}, {"nodeslastmodified", timestamp},
}}, }},
} }
result := collection.FindOneAndUpdate(ctx, filter, update) result := collection.FindOneAndUpdate(ctx, filter, update)
defer cancel() defer cancel()
if result.Err() != nil { if result.Err() != nil {
return result.Err() return result.Err()
} }
return nil return nil
} }
func TimestampNode(node models.Node, updatecheckin bool, updatepeers bool, updatelm bool) error{ func TimestampNode(node models.Node, updatecheckin bool, updatepeers bool, updatelm bool) error {
if updatelm { if updatelm {
node.SetLastModified() node.SetLastModified()
} }
if updatecheckin { if updatecheckin {
@@ -444,27 +442,25 @@ func TimestampNode(node models.Node, updatecheckin bool, updatepeers bool, updat
node.SetLastPeerUpdate() node.SetLastPeerUpdate()
} }
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// Create filter // Create filter
filter := bson.M{"macaddress": node.MacAddress, "network": node.Network} filter := bson.M{"macaddress": node.MacAddress, "network": node.Network}
// prepare update model. // prepare update model.
update := bson.D{ update := bson.D{
{"$set", bson.D{ {"$set", bson.D{
{"lastmodified", node.LastModified}, {"lastmodified", node.LastModified},
{"lastpeerupdate", node.LastPeerUpdate}, {"lastpeerupdate", node.LastPeerUpdate},
{"lastcheckin", node.LastCheckIn}, {"lastcheckin", node.LastCheckIn},
}}, }},
} }
var nodeupdate models.Node var nodeupdate models.Node
err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate) err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
defer cancel() defer cancel()
return err return err
} }

View File

@@ -387,6 +387,12 @@ func checkIn(w http.ResponseWriter, r *http.Request) {
} }
//TODO: check node last modified vs network last modified //TODO: check node last modified vs network last modified
//Get Updated node to return
node, err = GetNode(params["macaddress"], params["network"])
if err != nil {
returnErrorResponse(w, r, formatError(err, "internal"))
return
}
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(node) json.NewEncoder(w).Encode(node)
@@ -660,6 +666,10 @@ func validateGateway(gateway models.GatewayRequest) error {
if empty || !isIpv4 { if empty || !isIpv4 {
err = errors.New("IP Range Not Valid") err = errors.New("IP Range Not Valid")
} }
empty = gateway.Interface == ""
if empty {
err = errors.New("Interface cannot be empty")
}
return err return err
} }

View File

@@ -5,20 +5,21 @@
package functions package functions
import ( import (
"fmt" "context"
"errors" "encoding/base64"
"math/rand" "errors"
"time" "fmt"
"context" "math/rand"
"encoding/base64" "net"
"strings" "strings"
"net" "time"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mongoconn" "github.com/gravitl/netmaker/models"
"go.mongodb.org/mongo-driver/bson" "github.com/gravitl/netmaker/mongoconn"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
) )
//Takes in an arbitrary field and value for field and checks to see if any other //Takes in an arbitrary field and value for field and checks to see if any other
@@ -26,28 +27,27 @@ import (
func CreateServerToken(netID string) (string, error) { func CreateServerToken(netID string) (string, error) {
fmt.Println("Creating token.") fmt.Println("Creating token.")
var network models.Network var network models.Network
var accesskey models.AccessKey var accesskey models.AccessKey
network, err := GetParentNetwork(netID) network, err := GetParentNetwork(netID)
if err != nil { if err != nil {
return "", err return "", err
} }
accesskey.Name = GenKeyName() accesskey.Name = GenKeyName()
accesskey.Value = GenKey() accesskey.Value = GenKey()
accesskey.Uses = 1 accesskey.Uses = 1
_, gconf, errG := GetGlobalConfig() _, gconf, errG := GetGlobalConfig()
if errG != nil { if errG != nil {
return "", errG return "", errG
} }
address := "localhost" + gconf.PortGRPC address := "localhost" + gconf.PortGRPC
privAddr := ""
if *network.IsLocal {
privAddr = network.LocalRange
}
privAddr := ""
if *network.IsLocal {
privAddr = network.LocalRange
}
fmt.Println("Token details:") fmt.Println("Token details:")
fmt.Println(" grpc address + port: " + address) fmt.Println(" grpc address + port: " + address)
@@ -58,73 +58,72 @@ func CreateServerToken(netID string) (string, error) {
accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec)) accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec))
fmt.Println(" access string: " + accesskey.AccessString) fmt.Println(" access string: " + accesskey.AccessString)
network.AccessKeys = append(network.AccessKeys, accesskey)
network.AccessKeys = append(network.AccessKeys, accesskey) collection := mongoconn.Client.Database("netmaker").Collection("networks")
collection := mongoconn.Client.Database("netmaker").Collection("networks") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // Create filter
filter := bson.M{"netid": netID}
// Create filter // Read update model from body request
filter := bson.M{"netid": netID} fmt.Println("Adding key to " + network.NetID)
// Read update model from body request // prepare update model.
fmt.Println("Adding key to " + network.NetID) update := bson.D{
{"$set", bson.D{
{"accesskeys", network.AccessKeys},
}},
}
// prepare update model. errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
update := bson.D{
{"$set", bson.D{
{"accesskeys", network.AccessKeys},
}},
}
errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network) defer cancel()
defer cancel() if errN != nil {
return "", errN
if errN != nil { }
return "", errN return accesskey.AccessString, nil
}
return accesskey.AccessString, nil
} }
func IsFieldUnique(network string, field string, value string) bool { func IsFieldUnique(network string, field string, value string) bool {
var node models.Node var node models.Node
isunique := true isunique := true
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{field: value, "network": network} filter := bson.M{field: value, "network": network}
err := collection.FindOne(ctx, filter).Decode(&node) err := collection.FindOne(ctx, filter).Decode(&node)
defer cancel() defer cancel()
if err != nil { if err != nil {
return isunique return isunique
} }
if (node.Name != "") { if node.Name != "" {
isunique = false isunique = false
} }
return isunique return isunique
} }
func NetworkExists(name string) (bool, error) { func NetworkExists(name string) (bool, error) {
collection := mongoconn.Client.Database("netmaker").Collection("networks") collection := mongoconn.Client.Database("netmaker").Collection("networks")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"netid": name} filter := bson.M{"netid": name}
var result bson.M var result bson.M
err := collection.FindOne(ctx, filter).Decode(&result) err := collection.FindOne(ctx, filter).Decode(&result)
defer cancel() defer cancel()
@@ -143,100 +142,101 @@ func NetworkExists(name string) (bool, error) {
//for each node, it gets a unique address. That requires checking against all other nodes once more //for each node, it gets a unique address. That requires checking against all other nodes once more
func UpdateNetworkNodeAddresses(networkName string) error { func UpdateNetworkNodeAddresses(networkName string) error {
//Connection mongoDB with mongoconn class //Connection mongoDB with mongoconn class
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"network": networkName} filter := bson.M{"network": networkName}
cur, err := collection.Find(ctx, filter) cur, err := collection.Find(ctx, filter)
if err != nil { if err != nil {
return err return err
} }
defer cancel() defer cancel()
for cur.Next(context.TODO()) { for cur.Next(context.TODO()) {
var node models.Node var node models.Node
err := cur.Decode(&node) err := cur.Decode(&node)
if err != nil { if err != nil {
fmt.Println("error in node address assignment!") fmt.Println("error in node address assignment!")
return err return err
} }
ipaddr, iperr := UniqueAddress(networkName) ipaddr, iperr := UniqueAddress(networkName)
if iperr != nil { if iperr != nil {
fmt.Println("error in node address assignment!") fmt.Println("error in node address assignment!")
return iperr return iperr
} }
filter := bson.M{"macaddress": node.MacAddress} filter := bson.M{"macaddress": node.MacAddress}
update := bson.D{{"$set", bson.D{{"address", ipaddr}}}} update := bson.D{{"$set", bson.D{{"address", ipaddr}}}}
errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node) errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
defer cancel() defer cancel()
if errN != nil { if errN != nil {
return errN return errN
} }
} }
return err return err
} }
//TODO TODO TODO!!!!! //TODO TODO TODO!!!!!
func UpdateNetworkPrivateAddresses(networkName string) error { func UpdateNetworkPrivateAddresses(networkName string) error {
//Connection mongoDB with mongoconn class //Connection mongoDB with mongoconn class
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"network": networkName} filter := bson.M{"network": networkName}
cur, err := collection.Find(ctx, filter) cur, err := collection.Find(ctx, filter)
if err != nil { if err != nil {
return err return err
} }
defer cancel() defer cancel()
for cur.Next(context.TODO()) { for cur.Next(context.TODO()) {
var node models.Node var node models.Node
err := cur.Decode(&node) err := cur.Decode(&node)
if err != nil { if err != nil {
fmt.Println("error in node address assignment!") fmt.Println("error in node address assignment!")
return err return err
} }
ipaddr, iperr := UniqueAddress(networkName) ipaddr, iperr := UniqueAddress(networkName)
if iperr != nil { if iperr != nil {
fmt.Println("error in node address assignment!") fmt.Println("error in node address assignment!")
return iperr return iperr
} }
filter := bson.M{"macaddress": node.MacAddress} filter := bson.M{"macaddress": node.MacAddress}
update := bson.D{{"$set", bson.D{{"address", ipaddr}}}} update := bson.D{{"$set", bson.D{{"address", ipaddr}}}}
errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node) errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
defer cancel() defer cancel()
if errN != nil { if errN != nil {
return errN return errN
} }
} }
return err return err
} }
//Checks to see if any other networks have the same name (id) //Checks to see if any other networks have the same name (id)
func IsNetworkNameUnique(name string) (bool, error ){ func IsNetworkNameUnique(name string) (bool, error) {
isunique := true isunique := true
dbs, err := ListNetworks() dbs, err := ListNetworks()
if err != nil { if err != nil {
return false, err return false, err
@@ -249,92 +249,90 @@ func IsNetworkNameUnique(name string) (bool, error ){
} }
} }
return isunique, nil return isunique, nil
} }
func IsNetworkDisplayNameUnique(name string) (bool, error){ func IsNetworkDisplayNameUnique(name string) (bool, error) {
isunique := true isunique := true
dbs, err := ListNetworks() dbs, err := ListNetworks()
if err != nil { if err != nil {
return false, err return false, err
} }
for i := 0; i < len(dbs); i++ {
for i := 0; i < len(dbs); i++ { if name == dbs[i].DisplayName {
isunique = false
}
}
if name == dbs[i].DisplayName { return isunique, nil
isunique = false
}
}
return isunique, nil
} }
func GetNetworkNodeNumber(networkName string) (int, error){ func GetNetworkNodeNumber(networkName string) (int, error) {
collection := mongoconn.Client.Database("wirecat").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"network": networkName} filter := bson.M{"network": networkName}
count, err := collection.CountDocuments(ctx, filter) count, err := collection.CountDocuments(ctx, filter)
returncount := int(count) returncount := int(count)
//not sure if this is the right way of handling this error... //not sure if this is the right way of handling this error...
if err != nil { if err != nil {
return 9999, err return 9999, err
} }
defer cancel() defer cancel()
return returncount, err return returncount, err
} }
//Kind of a weird name. Should just be GetNetworks I think. Consider changing. //Kind of a weird name. Should just be GetNetworks I think. Consider changing.
//Anyway, returns all the networks //Anyway, returns all the networks
func ListNetworks() ([]models.Network, error){ func ListNetworks() ([]models.Network, error) {
var networks []models.Network var networks []models.Network
collection := mongoconn.Client.Database("netmaker").Collection("networks") collection := mongoconn.Client.Database("netmaker").Collection("networks")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
cur, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0})) cur, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0}))
if err != nil { if err != nil {
return networks, err return networks, err
} }
defer cancel() defer cancel()
for cur.Next(context.TODO()) { for cur.Next(context.TODO()) {
var network models.Network var network models.Network
err := cur.Decode(&network) err := cur.Decode(&network)
if err != nil { if err != nil {
return networks, err return networks, err
} }
// add network our array // add network our array
networks = append(networks, network) networks = append(networks, network)
} }
if err := cur.Err(); err != nil { if err := cur.Err(); err != nil {
return networks, err return networks, err
} }
return networks, err return networks, err
} }
//Checks to see if access key is valid //Checks to see if access key is valid
//Does so by checking against all keys and seeing if any have the same value //Does so by checking against all keys and seeing if any have the same value
//may want to hash values before comparing...consider this //may want to hash values before comparing...consider this
//TODO: No error handling!!!! //TODO: No error handling!!!!
func IsKeyValid(networkname string, keyvalue string) bool{ func IsKeyValid(networkname string, keyvalue string) bool {
network, _ := GetParentNetwork(networkname) network, _ := GetParentNetwork(networkname)
var key models.AccessKey var key models.AccessKey
@@ -342,48 +340,49 @@ func IsKeyValid(networkname string, keyvalue string) bool{
isvalid := false isvalid := false
for i := len(network.AccessKeys) - 1; i >= 0; i-- { for i := len(network.AccessKeys) - 1; i >= 0; i-- {
currentkey:= network.AccessKeys[i] currentkey := network.AccessKeys[i]
if currentkey.Value == keyvalue { if currentkey.Value == keyvalue {
key = currentkey key = currentkey
foundkey = true foundkey = true
} }
} }
if foundkey { if foundkey {
if key.Uses > 0 { if key.Uses > 0 {
isvalid = true isvalid = true
} }
} }
return isvalid return isvalid
} }
//TODO: Contains a fatal error return. Need to change //TODO: Contains a fatal error return. Need to change
//This just gets a network object from a network name //This just gets a network object from a network name
//Should probably just be GetNetwork. kind of a dumb name. //Should probably just be GetNetwork. kind of a dumb name.
//Used in contexts where it's not the Parent network. //Used in contexts where it's not the Parent network.
func GetParentNetwork(networkname string) (models.Network, error) { func GetParentNetwork(networkname string) (models.Network, error) {
var network models.Network var network models.Network
collection := mongoconn.Client.Database("netmaker").Collection("networks") collection := mongoconn.Client.Database("netmaker").Collection("networks")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"netid": networkname} filter := bson.M{"netid": networkname}
err := collection.FindOne(ctx, filter).Decode(&network) err := collection.FindOne(ctx, filter).Decode(&network)
defer cancel() defer cancel()
if err != nil { if err != nil {
return network, err return network, err
} }
return network, nil return network, nil
} }
//Check for valid IPv4 address //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
} }
//Similar to above but checks if Cidr range is valid //Similar to above but checks if Cidr range is valid
@@ -391,15 +390,15 @@ func IsIpv4Net(host string) bool {
//still not good error handling //still not good error handling
func IsIpv4CIDR(host string) bool { func IsIpv4CIDR(host string) bool {
ip, ipnet, err := net.ParseCIDR(host) ip, ipnet, err := net.ParseCIDR(host)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
fmt.Println("Address Range is not valid!") fmt.Println("Address Range is not valid!")
return false return false
} }
return ip != nil && ipnet != nil return ip != nil && ipnet != nil
} }
//This is used to validate public keys (make sure they're base64 encoded like all public keys should be). //This is used to validate public keys (make sure they're base64 encoded like all public keys should be).
@@ -414,28 +413,28 @@ func IsBase64(s string) bool {
//TODO: Check references. This seems unnecessary. //TODO: Check references. This seems unnecessary.
func GetNodeObj(id primitive.ObjectID) models.Node { func GetNodeObj(id primitive.ObjectID) models.Node {
var node models.Node var node models.Node
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"_id": id} filter := bson.M{"_id": id}
err := collection.FindOne(ctx, filter).Decode(&node) err := collection.FindOne(ctx, filter).Decode(&node)
defer cancel() defer cancel()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
fmt.Println("Did not get the node...") fmt.Println("Did not get the node...")
return node return node
} }
fmt.Println("Got node " + node.Name) fmt.Println("Got node " + node.Name)
return node return node
} }
//This checks to make sure a network name is valid. //This checks to make sure a network name is valid.
//Switch to REGEX? //Switch to REGEX?
func NameInNetworkCharSet(name string) bool{ func NameInNetworkCharSet(name string) bool {
charset := "abcdefghijklmnopqrstuvwxyz1234567890-_" charset := "abcdefghijklmnopqrstuvwxyz1234567890-_"
@@ -447,26 +446,25 @@ func NameInNetworkCharSet(name string) bool{
return true return true
} }
func NameInNodeCharSet(name string) bool{ func NameInNodeCharSet(name string) bool {
charset := "abcdefghijklmnopqrstuvwxyz1234567890-" charset := "abcdefghijklmnopqrstuvwxyz1234567890-"
for _, char := range name { for _, char := range name {
if !strings.Contains(charset, strings.ToLower(string(char))) { if !strings.Contains(charset, strings.ToLower(string(char))) {
return false return false
} }
} }
return true return true
} }
//This returns a node based on its mac address. //This returns a node based on its mac address.
//The mac address acts as the Unique ID for nodes. //The mac address acts as the Unique ID for nodes.
//Is this a dumb thing to do? I thought it was cool but maybe it's dumb. //Is this a dumb thing to do? I thought it was cool but maybe it's dumb.
//It doesn't really provide a tangible benefit over a random ID //It doesn't really provide a tangible benefit over a random ID
func GetNodeByMacAddress(network string, macaddress string) (models.Node, error) { func GetNodeByMacAddress(network string, macaddress string) (models.Node, error) {
var node models.Node var node models.Node
filter := bson.M{"macaddress": macaddress, "network": network} filter := bson.M{"macaddress": macaddress, "network": network}
@@ -474,14 +472,14 @@ func GetNodeByMacAddress(network string, macaddress string) (models.Node, error)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
err := collection.FindOne(ctx, filter).Decode(&node) err := collection.FindOne(ctx, filter).Decode(&node)
defer cancel() defer cancel()
if err != nil { if err != nil {
return node, err return node, err
} }
return node, nil return node, nil
} }
//This returns a unique address for a node to use //This returns a unique address for a node to use
@@ -489,14 +487,14 @@ func GetNodeByMacAddress(network string, macaddress string) (models.Node, error)
//and checks against all nodes to see if it's taken, until it finds one. //and checks against all nodes to see if it's taken, until it finds one.
//TODO: We do not handle a case where we run out of addresses. //TODO: We do not handle a case where we run out of addresses.
//We will need to handle that eventually //We will need to handle that eventually
func UniqueAddress(networkName string) (string, error){ func UniqueAddress(networkName string) (string, error) {
var network models.Network var network models.Network
network, err := GetParentNetwork(networkName) network, err := GetParentNetwork(networkName)
if err != nil { if err != nil {
fmt.Println("UniqueAddress encountered an error") fmt.Println("UniqueAddress encountered an error")
return "666", err return "666", err
} }
offset := true offset := true
ip, ipnet, err := net.ParseCIDR(network.AddressRange) ip, ipnet, err := net.ParseCIDR(network.AddressRange)
@@ -509,7 +507,7 @@ func UniqueAddress(networkName string) (string, error){
offset = false offset = false
continue continue
} }
if IsIPUnique(networkName, ip.String()){ if IsIPUnique(networkName, ip.String()) {
return ip.String(), err return ip.String(), err
} }
} }
@@ -523,46 +521,44 @@ func GetGlobalConfig() (bool, models.GlobalConfig, error) {
create := false create := false
filter := bson.M{} filter := bson.M{}
var globalconf models.GlobalConfig var globalconf models.GlobalConfig
collection := mongoconn.Client.Database("netmaker").Collection("config") collection := mongoconn.Client.Database("netmaker").Collection("config")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
err := collection.FindOne(ctx, filter).Decode(&globalconf) err := collection.FindOne(ctx, filter).Decode(&globalconf)
defer cancel() defer cancel()
if err == mongo.ErrNoDocuments { if err == mongo.ErrNoDocuments {
fmt.Println("Global config does not exist. Need to create.") fmt.Println("Global config does not exist. Need to create.")
create = true create = true
return create, globalconf, err return create, globalconf, err
} else if err != nil { } else if err != nil {
fmt.Println(err) fmt.Println(err)
fmt.Println("Could not get global config") fmt.Println("Could not get global config")
return create, globalconf, err return create, globalconf, err
} }
return create, globalconf, err return create, globalconf, err
} }
//generate an access key value //generate an access key value
func GenKey() string { func GenKey() string {
var seededRand *rand.Rand = rand.New( var seededRand *rand.Rand = rand.New(
rand.NewSource(time.Now().UnixNano())) rand.NewSource(time.Now().UnixNano()))
length := 16 length := 16
charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length) b := make([]byte, length)
for i := range b { for i := range b {
b[i] = charset[seededRand.Intn(len(charset))] b[i] = charset[seededRand.Intn(len(charset))]
} }
return string(b) return string(b)
} }
//generate a key value //generate a key value
@@ -571,17 +567,17 @@ func GenKey() string {
//have a "base string" a "length" and a "charset" //have a "base string" a "length" and a "charset"
func GenKeyName() string { func GenKeyName() string {
var seededRand *rand.Rand = rand.New( var seededRand *rand.Rand = rand.New(
rand.NewSource(time.Now().UnixNano())) rand.NewSource(time.Now().UnixNano()))
length := 5 length := 5
charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length) b := make([]byte, length)
for i := range b { for i := range b {
b[i] = charset[seededRand.Intn(len(charset))] b[i] = charset[seededRand.Intn(len(charset))]
} }
return "key-" + string(b) return "key-" + string(b)
} }
//checks if IP is unique in the address range //checks if IP is unique in the address range
@@ -592,21 +588,21 @@ func IsIPUnique(network string, ip string) bool {
isunique := true isunique := true
collection := mongoconn.Client.Database("netmaker").Collection("nodes") collection := mongoconn.Client.Database("netmaker").Collection("nodes")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"address": ip, "network": network} filter := bson.M{"address": ip, "network": network}
err := collection.FindOne(ctx, filter).Decode(&node) err := collection.FindOne(ctx, filter).Decode(&node)
defer cancel() defer cancel()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return isunique return isunique
} }
if (node.Address == ip) { if node.Address == ip {
isunique = false isunique = false
} }
return isunique return isunique
@@ -616,77 +612,79 @@ func IsIPUnique(network string, ip string) bool {
//reduces value by one and deletes if necessary //reduces value by one and deletes if necessary
func DecrimentKey(networkName string, keyvalue string) { func DecrimentKey(networkName string, keyvalue string) {
var network models.Network var network models.Network
network, err := GetParentNetwork(networkName) network, err := GetParentNetwork(networkName)
if err != nil { if err != nil {
return return
} }
for i := len(network.AccessKeys) - 1; i >= 0; i-- { for i := len(network.AccessKeys) - 1; i >= 0; i-- {
currentkey := network.AccessKeys[i] currentkey := network.AccessKeys[i]
if currentkey.Value == keyvalue { if currentkey.Value == keyvalue {
network.AccessKeys[i].Uses-- network.AccessKeys[i].Uses--
if network.AccessKeys[i].Uses < 1 { if network.AccessKeys[i].Uses < 1 {
//this is the part where it will call the delete //this is the part where it will call the delete
//not sure if there's edge cases I'm missing //not sure if there's edge cases I'm missing
DeleteKey(network, i) DeleteKey(network, i)
return return
} }
} }
} }
collection := mongoconn.Client.Database("netmaker").Collection("networks") collection := mongoconn.Client.Database("netmaker").Collection("networks")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
filter := bson.M{"netid": network.NetID} filter := bson.M{"netid": network.NetID}
update := bson.D{ update := bson.D{
{"$set", bson.D{ {"$set", bson.D{
{"accesskeys", network.AccessKeys}, {"accesskeys", network.AccessKeys},
}}, }},
} }
errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network) errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
defer cancel() defer cancel()
if errN != nil { if errN != nil {
return return
} }
} }
//takes the logic from controllers.deleteKey //takes the logic from controllers.deleteKey
func DeleteKey(network models.Network, i int) { func DeleteKey(network models.Network, i int) {
network.AccessKeys = append(network.AccessKeys[:i], network.AccessKeys = append(network.AccessKeys[:i],
network.AccessKeys[i+1:]...) network.AccessKeys[i+1:]...)
collection := mongoconn.Client.Database("netmaker").Collection("networks") collection := mongoconn.Client.Database("netmaker").Collection("networks")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// Create filter // Create filter
filter := bson.M{"netid": network.NetID} filter := bson.M{"netid": network.NetID}
// prepare update model. // prepare update model.
update := bson.D{ update := bson.D{
{"$set", bson.D{ {"$set", bson.D{
{"accesskeys", network.AccessKeys}, {"accesskeys", network.AccessKeys},
}}, }},
} }
errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network) errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
defer cancel() defer cancel()
if errN != nil { if errN != nil {
return return
} }
} }
//increments an IP over the previous //increments an IP over the previous
func Inc(ip net.IP) { func Inc(ip net.IP) {
for j := len(ip)-1; j>=0; j-- { for j := len(ip) - 1; j >= 0; j-- {
ip[j]++ ip[j]++
if ip[j] > 0 { if ip[j] > 0 {
break break

View File

@@ -216,22 +216,14 @@ func networkExists(t *testing.T) bool {
return false return false
} }
func TestJunk(t *testing.T) {
deleteNetworks(t)
}
func deleteNetworks(t *testing.T) { func deleteNetworks(t *testing.T) {
//delete all network nodes //delete all node
var nodes []models.ReturnNode deleteAllNodes(t)
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet", "secretkey") response, err := api(t, "", http.MethodGet, baseURL+"/api/networks", "secretkey")
assert.Nil(t, err, err)
if response.StatusCode == http.StatusOK {
err = json.NewDecoder(response.Body).Decode(&nodes)
response.Body.Close()
assert.Nil(t, err, err)
for _, node := range nodes {
resp, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/skynet/"+node.MacAddress, "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
}
response, err = api(t, "", http.MethodGet, baseURL+"/api/networks", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
if response.StatusCode == http.StatusOK { if response.StatusCode == http.StatusOK {
defer response.Body.Close() defer response.Body.Close()
@@ -260,12 +252,24 @@ func getNetworkNodes(t *testing.T) []models.ReturnNode {
return nodes return nodes
} }
func deleteNode(t *testing.T, node models.ReturnNode) { func deleteNode(t *testing.T) {
response, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/skynet/"+node.MacAddress, "secretkey") response, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Equal(t, http.StatusOK, response.StatusCode)
} }
func deleteAllNodes(t *testing.T) {
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
var nodes []models.ReturnNode
defer response.Body.Close()
json.NewDecoder(response.Body).Decode(&nodes)
for _, node := range nodes {
resp, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/"+node.Network+"/"+node.MacAddress, "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
}
func createNode(t *testing.T) { func createNode(t *testing.T) {
var node models.Node var node models.Node
key := createAccessKey(t) key := createAccessKey(t)
@@ -291,3 +295,9 @@ func getNode(t *testing.T) models.Node {
assert.Nil(t, err, err) assert.Nil(t, err, err)
return node return node
} }
func setup(t *testing.T) {
deleteNetworks(t)
createNetwork(t)
createNode(t)
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/mongo"
) )
func TestCreateNetwork(t *testing.T) { func TestCreateNetwork(t *testing.T) {
@@ -118,6 +117,7 @@ func TestGetNetwork(t *testing.T) {
func TestDeleteNetwork(t *testing.T) { func TestDeleteNetwork(t *testing.T) {
t.Run("InvalidKey", func(t *testing.T) { t.Run("InvalidKey", func(t *testing.T) {
setup(t)
response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "badkey") response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "badkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
defer response.Body.Close() defer response.Body.Close()
@@ -128,17 +128,6 @@ func TestDeleteNetwork(t *testing.T) {
assert.Equal(t, http.StatusUnauthorized, message.Code) assert.Equal(t, http.StatusUnauthorized, message.Code)
assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message)
}) })
t.Run("ValidKey", func(t *testing.T) {
response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "secretkey")
assert.Nil(t, err, err)
defer response.Body.Close()
var message mongo.DeleteResult
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
assert.Equal(t, int64(1), message.DeletedCount)
})
t.Run("Badnetwork", func(t *testing.T) { t.Run("Badnetwork", func(t *testing.T) {
response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/badnetwork", "secretkey") response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/badnetwork", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
@@ -150,7 +139,33 @@ func TestDeleteNetwork(t *testing.T) {
assert.Equal(t, http.StatusNotFound, response.StatusCode) assert.Equal(t, http.StatusNotFound, response.StatusCode)
}) })
t.Run("NodesExist", func(t *testing.T) { t.Run("NodesExist", func(t *testing.T) {
setup(t)
node := getNode(t)
t.Log(node)
response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusForbidden, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Contains(t, message.Message, "Node check failed")
assert.Equal(t, http.StatusForbidden, message.Code)
})
t.Run("ValidKey", func(t *testing.T) {
type Message struct {
DeletedCount int64
}
setup(t)
deleteAllNodes(t)
response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "secretkey")
assert.Nil(t, err, err)
defer response.Body.Close()
var message Message
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
assert.Equal(t, int64(1), message.DeletedCount)
}) })
} }

View File

@@ -4,75 +4,214 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"testing" "testing"
"time"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/crypto/bcrypt"
) )
func setup(t *testing.T) { func TestRainyDay(t *testing.T) {
deleteNetworks(t) t.Run("badkey", func(t *testing.T) {
createNetwork(t) response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes", "badkey")
createNode(t) assert.Nil(t, err, err)
} assert.Equal(t, http.StatusUnauthorized, response.StatusCode)
})
func TestJunk(t *testing.T) { t.Run("badURL", func(t *testing.T) {
deleteNetworks(t) response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/adm/skynet/01:02:03:04:05:07", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusNotFound, response.StatusCode)
})
t.Run("NonExistentNetwork", func(t *testing.T) {
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/badnet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusNotFound, response.StatusCode)
})
} }
func TestGetAllNodes(t *testing.T) { func TestGetAllNodes(t *testing.T) {
setup(t) setup(t)
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes", "secretkey") t.Run("NodesExist", func(t *testing.T) {
assert.Nil(t, err, err) response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes", "secretkey")
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Nil(t, err, err)
var nodes []models.ReturnNode assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close() var nodes []models.ReturnNode
err = json.NewDecoder(response.Body).Decode(&nodes) defer response.Body.Close()
assert.Nil(t, err, err) err = json.NewDecoder(response.Body).Decode(&nodes)
for _, node := range nodes { assert.Nil(t, err, err)
assert.NotNil(t, node, "empty node") assert.NotEmpty(t, nodes)
} })
t.Run("NodeDoesNotExist", func(t *testing.T) {
deleteNode(t)
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
var nodes []models.ReturnNode
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&nodes)
assert.Nil(t, err, err)
assert.Empty(t, nodes)
})
} }
func TestGetNetworkNodes(t *testing.T) { func TestGetNetworkNodes(t *testing.T) {
setup(t) setup(t)
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet", "secretkey") t.Run("NodeExists", func(t *testing.T) {
assert.Nil(t, err, err) response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet", "secretkey")
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Nil(t, err, err)
var nodes []models.ReturnNode assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close() var nodes []models.ReturnNode
err = json.NewDecoder(response.Body).Decode(&nodes) defer response.Body.Close()
assert.Nil(t, err, err) err = json.NewDecoder(response.Body).Decode(&nodes)
for _, node := range nodes { assert.Nil(t, err, err)
assert.NotNil(t, node, "empty node") assert.NotEmpty(t, nodes)
} })
t.Run("NodeDoesNotExit", func(t *testing.T) {
deleteNode(t)
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
var nodes []models.ReturnNode
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&nodes)
assert.Nil(t, err, err)
assert.Empty(t, nodes)
})
} }
func TestGetNode(t *testing.T) { func TestGetNode(t *testing.T) {
setup(t) setup(t)
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey") t.Run("NodeExists", func(t *testing.T) {
assert.Nil(t, err, err) response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey")
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Nil(t, err, err)
var node models.Node assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close() var node models.Node
err = json.NewDecoder(response.Body).Decode(&node) defer response.Body.Close()
assert.Nil(t, err, err) err = json.NewDecoder(response.Body).Decode(&node)
assert.Equal(t, "01:02:03:04:05:06", node.MacAddress) assert.Nil(t, err, err)
assert.Equal(t, "01:02:03:04:05:06", node.MacAddress)
})
t.Run("NodeDoesNotExist", func(t *testing.T) {
deleteNode(t)
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
})
} }
func TestUpdateNode(t *testing.T) { func TestUpdateNode(t *testing.T) {
var data models.Node
setup(t) setup(t)
var data struct {
Name string t.Run("UpdateMulti", func(t *testing.T) {
} data.MacAddress = "01:02:03:04:05:05"
data.Name = "NewName" data.Name = "NewName"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey") data.PublicKey = "DM5qhLAE20PG9BbfBCgfr+Ac9D2NDOwCtY1rbYDLf34="
assert.Nil(t, err, err) data.Password = "newpass"
assert.Equal(t, http.StatusOK, response.StatusCode) data.LocalAddress = "192.168.0.2"
var node models.Node data.Endpoint = "10.100.100.5"
defer response.Body.Close() response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey")
err = json.NewDecoder(response.Body).Decode(&node) assert.Nil(t, err, err)
assert.Nil(t, err, err) assert.Equal(t, http.StatusOK, response.StatusCode)
assert.Equal(t, data.Name, node.Name) defer response.Body.Close()
var node models.Node
t.Log(response.Body)
err = json.NewDecoder(response.Body).Decode(&node)
assert.Nil(t, err, err)
assert.Equal(t, data.Name, node.Name)
assert.Equal(t, data.PublicKey, node.PublicKey)
err = bcrypt.CompareHashAndPassword([]byte(node.Password), []byte(data.Password))
assert.Nil(t, err, err)
assert.Equal(t, data.LocalAddress, node.LocalAddress)
assert.Equal(t, data.Endpoint, node.Endpoint)
})
t.Run("InvalidMacAddress", func(t *testing.T) {
data.MacAddress = "10:11:12:13:14:15:16"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'MacAddress' failed")
})
t.Run("InvalidEndpoint", func(t *testing.T) {
data.Endpoint = "10.10.10.300"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'Endpoint' failed")
})
t.Run("InvalidLocalAddress", func(t *testing.T) {
data.LocalAddress = "10.10.10.300"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'LocalAddress' failed")
})
t.Run("InvalidName", func(t *testing.T) {
var data struct {
Name string
}
data.Name = "New*Name"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'Name' failed")
})
t.Run("InvalidPublicKey", func(t *testing.T) {
data.PublicKey = "xxx"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'PublicKey' failed")
})
t.Run("InvalidPassword", func(t *testing.T) {
data.Password = "1234"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'Password' failed")
})
t.Run("EmptyPassword", func(t *testing.T) {
data.Password = ""
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'Password' failed")
})
} }
func TestDeleteNode(t *testing.T) { func TestDeleteNode(t *testing.T) {
@@ -103,33 +242,75 @@ func TestDeleteNode(t *testing.T) {
} }
func TestCheckIn(t *testing.T) { func TestCheckIn(t *testing.T) {
//get node
//oldNode := getNode(t)
setup(t) setup(t)
response, err := api(t, "", http.MethodPost, baseURL+"/api/nodes/skynet/01:02:03:04:05:06/checkin", "secretkey") oldNode := getNode(t)
assert.Nil(t, err, err) time.Sleep(1 * time.Second)
assert.Equal(t, http.StatusOK, response.StatusCode) t.Run("Valid", func(t *testing.T) {
var node models.Node response, err := api(t, "", http.MethodPost, baseURL+"/api/nodes/skynet/01:02:03:04:05:06/checkin", "secretkey")
defer response.Body.Close() assert.Nil(t, err, err)
err = json.NewDecoder(response.Body).Decode(&node) assert.Equal(t, http.StatusOK, response.StatusCode)
assert.Nil(t, err, err) var node models.Node
//assert.Greater(t, node.LastCheckIn, oldNode.LastCheckin) defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&node)
assert.Nil(t, err, err)
assert.Greater(t, node.LastCheckIn, oldNode.LastCheckIn)
})
t.Run("NodeDoesNotExist", func(t *testing.T) {
deleteNode(t)
response, err := api(t, "", http.MethodPost, baseURL+"/api/nodes/skynet/01:02:03:04:05:06/checkin", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusInternalServerError, message.Code)
assert.Equal(t, "mongo: no documents in result", message.Message)
})
} }
func TestCreateGateway(t *testing.T) { func TestCreateGateway(t *testing.T) {
setup(t) setup(t)
//assert.False(t, node.IsGateway) //assert.False(t, node.IsGateway)
var gateway models.GatewayRequest var gateway models.GatewayRequest
gateway.RangeString = "0.0.0.0/0" t.Run("Valid", func(t *testing.T) {
gateway.Interface = "eth0" gateway.RangeString = "0.0.0.0/0"
response, err := api(t, gateway, http.MethodPost, baseURL+"/api/nodes/skynet/01:02:03:04:05:06/creategateway", "secretkey") gateway.Interface = "eth0"
assert.Nil(t, err, err) response, err := api(t, gateway, http.MethodPost, baseURL+"/api/nodes/skynet/01:02:03:04:05:06/creategateway", "secretkey")
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Nil(t, err, err)
defer response.Body.Close() assert.Equal(t, http.StatusOK, response.StatusCode)
var message models.Node defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message) var message models.Node
assert.Nil(t, err, err) err = json.NewDecoder(response.Body).Decode(&message)
assert.True(t, message.IsGateway) assert.Nil(t, err, err)
assert.True(t, message.IsGateway)
})
t.Run("BadRange", func(t *testing.T) {
gateway.RangeString = "0.0.0.0/36"
gateway.Interface = "eth0"
response, err := api(t, gateway, http.MethodPost, baseURL+"/api/nodes/skynet/01:02:03:04:05:06/creategateway", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusInternalServerError, message.Code)
assert.Equal(t, "IP Range Not Valid", message.Message)
})
t.Run("BadInterface", func(t *testing.T) {
gateway.RangeString = "0.0.0.0/0"
gateway.Interface = ""
response, err := api(t, gateway, http.MethodPost, baseURL+"/api/nodes/skynet/01:02:03:04:05:06/creategateway", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusInternalServerError, message.Code)
assert.Equal(t, "Interface cannot be empty", message.Message)
})
} }
func TestDeleteGateway(t *testing.T) { func TestDeleteGateway(t *testing.T) {
@@ -158,49 +339,283 @@ func TestUncordonNode(t *testing.T) {
} }
func TestCreateNode(t *testing.T) { func TestCreateNode(t *testing.T) {
deleteNetworks(t) setup(t)
createNetwork(t)
key := createAccessKey(t) key := createAccessKey(t)
t.Run("NodeExists", func(t *testing.T) {
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = "tobedetermined"
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.100.4"
var node models.Node response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
node.AccessKey = key.Value assert.Nil(t, err, err)
node.MacAddress = "01:02:03:04:05:06" assert.Equal(t, http.StatusBadRequest, response.StatusCode)
node.Name = "myNode" defer response.Body.Close()
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=" var message models.ErrorResponse
node.Password = "tobedetermined" err = json.NewDecoder(response.Body).Decode(&message)
node.LocalAddress = "192.168.0.1" assert.Nil(t, err, err)
node.Endpoint = "10.100.100.4" assert.Equal(t, http.StatusBadRequest, response.StatusCode)
assert.Contains(t, message.Message, "Field validation for 'MacAddress' failed on the 'macaddress_unique' tag")
})
t.Run("BadKey", func(t *testing.T) {
deleteNode(t)
var node models.Node
node.AccessKey = "badkey"
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = "tobedetermined"
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.100.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusUnauthorized, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusUnauthorized, response.StatusCode)
assert.Contains(t, message.Message, "W1R3: Key invalid, or none provided")
})
t.Run("BadMac", func(t *testing.T) {
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "badmac"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = "tobedetermined"
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.100.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'MacAddress' failed on the 'macaddress_valid' tag")
})
t.Run("BadPublicKey", func(t *testing.T) {
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "xxx"
node.Password = "tobedetermined"
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.100.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'PublicKey' failed")
})
t.Run("BadPass", func(t *testing.T) {
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = ""
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.100.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Error:Field validation for 'Password' failed")
})
t.Run("BadLocalAddress", func(t *testing.T) {
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = "tobedetermined"
node.LocalAddress = "192.168.300.1"
node.Endpoint = "10.100.100.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'LocalAddress' failed")
})
t.Run("BadEndpoint", func(t *testing.T) {
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = "tobedetermined"
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.300.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Contains(t, message.Message, "Field validation for 'Endpoint' failed")
})
t.Run("NetworkDoesNotExist", func(t *testing.T) {
deleteNetworks(t)
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = "tobedetermined"
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.100.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusNotFound, response.StatusCode)
defer response.Body.Close()
var message models.ErrorResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusNotFound, message.Code)
assert.Contains(t, "W1R3: Network does not exist! ", message.Message)
})
t.Run("Valid", func(t *testing.T) {
setup(t)
deleteNode(t)
key := createAccessKey(t)
var node models.Node
node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode"
node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
node.Password = "tobedetermined"
node.LocalAddress = "192.168.0.1"
node.Endpoint = "10.100.100.4"
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close()
var message models.Node
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, node.Name, message.Name)
t.Log(message)
})
response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close()
var message models.Node
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, node.Name, message.Name)
t.Log(message.Password)
} }
func TestGetLastModified(t *testing.T) { func TestGetLastModified(t *testing.T) {
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/adm/skynet/lastmodified", "secretkey") deleteNetworks(t)
assert.Nil(t, err, err) createNetwork(t)
assert.Equal(t, http.StatusOK, response.StatusCode) t.Run("Valid", func(t *testing.T) {
assert.NotNil(t, response.Body, "no time returned") response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/adm/skynet/lastmodified", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
})
deleteNetworks(t)
t.Run("NoNetwork", func(t *testing.T) {
response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/adm/skynet/lastmodified", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusNotFound, response.StatusCode)
})
} }
func TestNodeAuthenticate(t *testing.T) { func TestNodeAuthenticate(t *testing.T) {
setup(t) setup(t)
var authRequest models.AuthParams t.Run("Valid", func(t *testing.T) {
authRequest.MacAddress = "01:02:03:04:05:06" var authRequest models.AuthParams
authRequest.Password = "tobedetermined" authRequest.MacAddress = "01:02:03:04:05:06"
response, err := api(t, authRequest, http.MethodPost, "http://localhost:8081:/api/nodes/adm/skynet/authenticate", "") authRequest.Password = "tobedetermined"
assert.Nil(t, err, err) response, err := api(t, authRequest, http.MethodPost, "http://localhost:8081:/api/nodes/adm/skynet/authenticate", "")
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Nil(t, err, err)
defer response.Body.Close() assert.Equal(t, http.StatusOK, response.StatusCode)
var message models.SuccessResponse defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&message) var message models.SuccessResponse
assert.Nil(t, err, err) err = json.NewDecoder(response.Body).Decode(&message)
assert.Equal(t, http.StatusOK, message.Code) assert.Nil(t, err, err)
assert.Equal(t, "W1R3: Device 01:02:03:04:05:06 Authorized", message.Message) assert.Equal(t, http.StatusOK, message.Code)
assert.Equal(t, "W1R3: Device 01:02:03:04:05:06 Authorized", message.Message)
})
t.Run("MacEmpty", func(t *testing.T) {
var authRequest models.AuthParams
authRequest.MacAddress = ""
authRequest.Password = "tobedetermined"
response, err := api(t, authRequest, http.MethodPost, "http://localhost:8081:/api/nodes/adm/skynet/authenticate", "")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.SuccessResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Equal(t, "W1R3: MacAddress can't be empty", message.Message)
})
t.Run("EmptyPass", func(t *testing.T) {
var authRequest models.AuthParams
authRequest.MacAddress = "01:02:03:04:05:06"
authRequest.Password = ""
response, err := api(t, authRequest, http.MethodPost, "http://localhost:8081:/api/nodes/adm/skynet/authenticate", "")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.SuccessResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Equal(t, "W1R3: Password can't be empty", message.Message)
})
t.Run("BadPass", func(t *testing.T) {
var authRequest models.AuthParams
authRequest.MacAddress = "01:02:03:04:05:06"
authRequest.Password = "badpass"
response, err := api(t, authRequest, http.MethodPost, "http://localhost:8081:/api/nodes/adm/skynet/authenticate", "")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.SuccessResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Equal(t, "crypto/bcrypt: hashedPassword is not the hash of the given password", message.Message)
})
t.Run("BadMac", func(t *testing.T) {
var authRequest models.AuthParams
authRequest.MacAddress = "01:02:03:04:05:07"
authRequest.Password = "tobedetermined"
response, err := api(t, authRequest, http.MethodPost, "http://localhost:8081:/api/nodes/adm/skynet/authenticate", "")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
defer response.Body.Close()
var message models.SuccessResponse
err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, message.Code)
assert.Equal(t, "mongo: no documents in result", message.Message)
})
} }