Merge pull request #2674 from gravitl/release-v0.21.2

v0.21.2
This commit is contained in:
Abhishek K 2023-11-19 20:34:26 +04:00 committed by GitHub
commit 5af7a6a50f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 539 additions and 236 deletions

View file

@ -31,6 +31,7 @@ body:
label: Version
description: What version are you running?
options:
- v0.21.2
- v0.21.1
- v0.21.0
- v0.20.6

View file

@ -16,7 +16,7 @@
<p align="center">
<a href="https://github.com/gravitl/netmaker/releases">
<img src="https://img.shields.io/badge/Version-0.21.1-informational?style=flat-square" />
<img src="https://img.shields.io/badge/Version-0.21.2-informational?style=flat-square" />
</a>
<a href="https://hub.docker.com/r/gravitl/netmaker/tags">
<img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />
@ -57,7 +57,7 @@ These are the instructions for deploying a Netmaker server on your own cloud VM
1. Get a cloud VM with Ubuntu 22.04 and a public IP.
2. Open ports 443, 80, 3479, 8089 and 51821-51830/udp on the VM firewall and in cloud security settings.
3. (recommended) Prepare DNS - Set a wildcard subdomain in your DNS settings for Netmaker, e.g. *.netmaker.example.com, which points to your VM's pubic IP.
3. (recommended) Prepare DNS - Set a wildcard subdomain in your DNS settings for Netmaker, e.g. *.netmaker.example.com, which points to your VM's public IP.
4. Run the script:
`sudo wget -qO /root/nm-quick.sh https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh && sudo chmod +x /root/nm-quick.sh && sudo /root/nm-quick.sh`

View file

@ -15,6 +15,7 @@ import (
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mq"
"github.com/gravitl/netmaker/servercfg"
"golang.org/x/exp/slog"
)
// SessionHandler - called by the HTTP router when user
@ -202,7 +203,7 @@ func SessionHandler(conn *websocket.Conn) {
if err = conn.WriteMessage(messageType, reponseData); err != nil {
logger.Log(0, "error during message writing:", err.Error())
}
go CheckNetRegAndHostUpdate(netsToAdd[:], &result.Host)
go CheckNetRegAndHostUpdate(netsToAdd[:], &result.Host, uuid.Nil)
case <-timeout: // the read from req.answerCh has timed out
if err = conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")); err != nil {
logger.Log(0, "error during timeout message writing:", err.Error())
@ -221,7 +222,7 @@ func SessionHandler(conn *websocket.Conn) {
}
// CheckNetRegAndHostUpdate - run through networks and send a host update
func CheckNetRegAndHostUpdate(networks []string, h *models.Host) {
func CheckNetRegAndHostUpdate(networks []string, h *models.Host, relayNodeId uuid.UUID) {
// publish host update through MQ
for i := range networks {
network := networks[i]
@ -231,6 +232,14 @@ func CheckNetRegAndHostUpdate(networks []string, h *models.Host) {
logger.Log(0, "failed to add host to network:", h.ID.String(), h.Name, network, err.Error())
continue
}
if relayNodeId != uuid.Nil && !newNode.IsRelayed {
newNode.IsRelayed = true
newNode.RelayedBy = relayNodeId.String()
slog.Info(fmt.Sprintf("adding relayed node %s to relay %s on network %s", newNode.ID.String(), relayNodeId.String(), network))
if err := logic.UpsertNode(newNode); err != nil {
slog.Error("failed to update node", "nodeid", relayNodeId.String())
}
}
logger.Log(1, "added new node", newNode.ID.String(), "to host", h.Name)
hostactions.AddAction(models.HostUpdate{
Action: models.JoinHostToNetwork,

View file

@ -3,7 +3,7 @@ version: "3.4"
services:
netclient:
container_name: netclient
image: 'gravitl/netclient:v0.21.1'
image: 'gravitl/netclient:v0.21.2'
hostname: netmaker-1
network_mode: host
restart: on-failure

View file

@ -10,7 +10,7 @@
//
// Schemes: https
// BasePath: /
// Version: 0.21.1
// Version: 0.21.2
// Host: api.demo.netmaker.io
//
// Consumes:

View file

@ -6,6 +6,7 @@ import (
"net/http"
"time"
"github.com/google/uuid"
"github.com/gorilla/mux"
"github.com/gravitl/netmaker/auth"
@ -26,6 +27,8 @@ func enrollmentKeyHandlers(r *mux.Router) {
Methods(http.MethodDelete)
r.HandleFunc("/api/v1/host/register/{token}", http.HandlerFunc(handleHostRegister)).
Methods(http.MethodPost)
r.HandleFunc("/api/v1/enrollment-keys/{keyID}", logic.SecurityCheck(true, http.HandlerFunc(updateEnrollmentKey))).
Methods(http.MethodPut)
}
// swagger:route GET /api/v1/enrollment-keys enrollmentKeys getEnrollmentKeys
@ -113,12 +116,23 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
newTime = time.Unix(enrollmentKeyBody.Expiration, 0)
}
relayId := uuid.Nil
if enrollmentKeyBody.Relay != "" {
relayId, err = uuid.Parse(enrollmentKeyBody.Relay)
if err != nil {
logger.Log(0, r.Header.Get("user"), "error parsing relay id: ", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
}
newEnrollmentKey, err := logic.CreateEnrollmentKey(
enrollmentKeyBody.UsesRemaining,
newTime,
enrollmentKeyBody.Networks,
enrollmentKeyBody.Tags,
enrollmentKeyBody.Unlimited,
relayId,
)
if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to create enrollment key:", err.Error())
@ -136,6 +150,57 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(newEnrollmentKey)
}
// swagger:route PUT /api/v1/enrollment-keys/:id enrollmentKeys updateEnrollmentKey
//
// Updates an EnrollmentKey for hosts to use on Netmaker server. Updates only the relay to use.
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: EnrollmentKey
func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) {
var enrollmentKeyBody models.APIEnrollmentKey
params := mux.Vars(r)
keyId := params["keyID"]
err := json.NewDecoder(r.Body).Decode(&enrollmentKeyBody)
if err != nil {
slog.Error("error decoding request body", "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
relayId := uuid.Nil
if enrollmentKeyBody.Relay != "" {
relayId, err = uuid.Parse(enrollmentKeyBody.Relay)
if err != nil {
slog.Error("error parsing relay id", "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
}
newEnrollmentKey, err := logic.UpdateEnrollmentKey(keyId, relayId)
if err != nil {
slog.Error("failed to update enrollment key", "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
if err = logic.Tokenize(newEnrollmentKey, servercfg.GetAPIHost()); err != nil {
slog.Error("failed to update enrollment key", "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
slog.Info("updated enrollment key", "id", keyId)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(newEnrollmentKey)
}
// swagger:route POST /api/v1/enrollment-keys/{token} enrollmentKeys handleHostRegister
//
// Handles a Netclient registration with server and add nodes accordingly.
@ -286,5 +351,5 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(&response)
// notify host of changes, peer and node updates
go auth.CheckNetRegAndHostUpdate(enrollmentKey.Networks, &newHost)
go auth.CheckNetRegAndHostUpdate(enrollmentKey.Networks, &newHost, enrollmentKey.Relay)
}

View file

@ -7,6 +7,7 @@ import (
"net/http"
"github.com/gorilla/mux"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
@ -123,11 +124,12 @@ func pull(w http.ResponseWriter, r *http.Request) {
serverConf.TrafficKey = key
response := models.HostPull{
Host: *host,
Nodes: logic.GetHostNodes(host),
ServerConfig: serverConf,
Peers: hPU.Peers,
PeerIDs: hPU.PeerIDs,
Host: *host,
Nodes: logic.GetHostNodes(host),
ServerConfig: serverConf,
Peers: hPU.Peers,
PeerIDs: hPU.PeerIDs,
HostNetworkInfo: hPU.HostNetworkInfo,
}
logger.Log(1, hostID, "completed a pull")
@ -226,6 +228,19 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
for _, nodeID := range currHost.Nodes {
node, err := logic.GetNodeByID(nodeID)
if err != nil {
slog.Error("failed to get node", "nodeid", nodeID, "error", err)
continue
}
var gwClients []models.ExtClient
if node.IsIngressGateway {
gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
}
go mq.PublishMqUpdatesForDeletedNode(node, false, gwClients)
}
if err = logic.RemoveHost(currHost, forceDelete); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
@ -285,6 +300,7 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
Node: *newNode,
})
mq.PublishPeerUpdate()
mq.HandleNewNodeDNS(currHost, newNode)
}()
logger.Log(2, r.Header.Get("user"), fmt.Sprintf("added host %s to network %s", currHost.Name, network))
w.WriteHeader(http.StatusOK)
@ -314,6 +330,24 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
// confirm host exists
currHost, err := logic.GetHost(hostid)
if err != nil {
if database.IsEmptyRecord(err) {
// check if there is any daemon nodes that needs to be deleted
node, err := logic.GetNodeByHostRef(hostid, network)
if err != nil {
slog.Error("couldn't get node for host", "hostid", hostid, "network", network, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if err = logic.DeleteNodeByID(&node); err != nil {
slog.Error("failed to force delete daemon node",
"nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to force delete daemon node: "+err.Error()), "internal"))
return
}
logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
return
}
logger.Log(0, r.Header.Get("user"), "failed to find host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
@ -321,58 +355,37 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
node, err := logic.UpdateHostNetwork(currHost, network, false)
if err != nil {
if node == nil && forceDelete {
// force cleanup the node
node, err := logic.GetNodeByHostRef(hostid, network)
if err != nil {
slog.Error("couldn't get node for host", "hostid", hostid, "network", network, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if err = logic.DeleteNodeByID(&node); err != nil {
slog.Error("failed to force delete daemon node",
"nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to force delete daemon node: "+err.Error()), "internal"))
return
}
logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
return
}
logger.Log(0, r.Header.Get("user"), "failed to remove host from network:", hostid, network, err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
if node.IsRelayed {
// cleanup node from relayednodes on relay node
relayNode, err := logic.GetNodeByID(node.RelayedBy)
if err == nil {
relayedNodes := []string{}
for _, relayedNodeID := range relayNode.RelayedNodes {
if relayedNodeID == node.ID.String() {
continue
}
relayedNodes = append(relayedNodes, relayedNodeID)
}
relayNode.RelayedNodes = relayedNodes
logic.UpsertNode(&relayNode)
}
}
if node.IsRelay {
// unset all the relayed nodes
logic.SetRelayedNodes(false, node.ID.String(), node.RelayedNodes)
}
var gwClients []models.ExtClient
if node.IsIngressGateway {
// delete ext clients belonging to ingress gateway
go func(node models.Node) {
if err = logic.DeleteGatewayExtClients(node.ID.String(), node.Network); err != nil {
slog.Error("failed to delete extclients", "gatewayid", node.ID.String(), "network", node.Network, "error", err.Error())
}
}(*node)
gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
}
logger.Log(1, "deleting node", node.ID.String(), "from host", currHost.Name)
if err := logic.DeleteNode(node, forceDelete); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
return
}
node.Action = models.NODE_DELETE
node.PendingDelete = true
go func() {
// notify node change
if err := mq.NodeUpdate(node); err != nil {
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
}
// notify of peer change
err = mq.PublishDeletedNodePeerUpdate(node)
if err != nil {
logger.Log(1, "error publishing peer update ", err.Error())
}
if err := mq.PublishDNSDelete(node, currHost); err != nil {
logger.Log(1, "error publishing dns update", err.Error())
}
}()
go mq.PublishMqUpdatesForDeletedNode(*node, true, gwClients)
logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network))
w.WriteHeader(http.StatusOK)
}

View file

@ -614,6 +614,7 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
if err := mq.NodeUpdate(&node); err != nil {
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
}
mq.PublishDeleteAllExtclientsDNS(node.Network, removedClients)
}()
}
}
@ -725,35 +726,10 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
}
forceDelete := r.URL.Query().Get("force") == "true"
fromNode := r.Header.Get("requestfrom") == "node"
if node.IsRelayed {
// cleanup node from relayednodes on relay node
relayNode, err := logic.GetNodeByID(node.RelayedBy)
if err == nil {
relayedNodes := []string{}
for _, relayedNodeID := range relayNode.RelayedNodes {
if relayedNodeID == node.ID.String() {
continue
}
relayedNodes = append(relayedNodes, relayedNodeID)
}
relayNode.RelayedNodes = relayedNodes
logic.UpsertNode(&relayNode)
}
}
if node.IsRelay {
// unset all the relayed nodes
logic.SetRelayedNodes(false, node.ID.String(), node.RelayedNodes)
}
var gwClients []models.ExtClient
if node.IsIngressGateway {
// delete ext clients belonging to ingress gatewa
go func(node models.Node) {
if err = logic.DeleteGatewayExtClients(node.ID.String(), node.Network); err != nil {
slog.Error("failed to delete extclients", "gatewayid", node.ID.String(), "network", node.Network, "error", err.Error())
}
}(node)
gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
}
purge := forceDelete || fromNode
if err := logic.DeleteNode(&node, purge); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
@ -762,23 +738,7 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")
logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"])
go func() { // notify of peer change
if !fromNode {
if err := mq.NodeUpdate(&node); err != nil {
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
}
}
if err := mq.PublishDeletedNodePeerUpdate(&node); err != nil {
logger.Log(1, "error publishing peer update ", err.Error())
}
host, err := logic.GetHost(node.HostID.String())
if err != nil {
logger.Log(1, "failed to retrieve host for node", node.ID.String(), err.Error())
}
if err := mq.PublishDNSDelete(&node, host); err != nil {
logger.Log(1, "error publishing dns update", err.Error())
}
}()
go mq.PublishMqUpdatesForDeletedNode(node, !fromNode, gwClients)
}
func validateParams(nodeid, netid string) (models.Node, error) {

14
go.mod
View file

@ -6,7 +6,7 @@ require (
github.com/eclipse/paho.mqtt.golang v1.4.3
github.com/go-playground/validator/v10 v10.15.5
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/uuid v1.3.1
github.com/google/uuid v1.4.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/lib/pq v1.10.9
@ -15,10 +15,10 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.8.4
github.com/txn2/txeh v1.5.5
golang.org/x/crypto v0.13.0
golang.org/x/net v0.15.0 // indirect
golang.org/x/oauth2 v0.12.0
golang.org/x/sys v0.12.0 // indirect
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.13.0
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb
google.golang.org/protobuf v1.31.0 // indirect
@ -32,7 +32,7 @@ require (
)
require (
github.com/coreos/go-oidc/v3 v3.6.0
github.com/coreos/go-oidc/v3 v3.7.0
github.com/gorilla/websocket v1.5.0
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
)
@ -67,5 +67,5 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
golang.org/x/sync v0.1.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/appengine v1.6.8 // indirect
)

52
go.sum
View file

@ -7,8 +7,8 @@ filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5E
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/c-robinson/iplib v1.0.7 h1:Dh9AINAlkc+NsNzZuFiVs+pi3AjN+0B7mu01KHdJKHU=
github.com/c-robinson/iplib v1.0.7/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o=
github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc=
github.com/coreos/go-oidc/v3 v3.7.0 h1:FTdj0uexT4diYIPlF4yoFVI5MRO1r5+SEcIpEw9vC0o=
github.com/coreos/go-oidc/v3 v3.7.0/go.mod h1:yQzSCqBnK3e6Fs5l+f5i0F8Kwf0zpH9bPEsbY00KanM=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -34,15 +34,15 @@ github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7N
github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
@ -101,34 +101,52 @@ github.com/txn2/txeh v1.5.5/go.mod h1:qYzGG9kCzeVEI12geK4IlanHWY8X4uy/I3NcW7mk8g
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb h1:9aqVcYEDHmSNb0uOWukxV5lHV09WqiSiCuhEgWNETLY=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb/go.mod h1:mQqgjkW8GQQcJQsbBvK890TKqUK1DfKWkuBGbOkuMHQ=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=

View file

@ -16,7 +16,7 @@ spec:
hostNetwork: true
containers:
- name: netclient
image: gravitl/netclient:v0.21.1
image: gravitl/netclient:v0.21.2
env:
- name: TOKEN
value: "TOKEN_VALUE"

View file

@ -28,7 +28,7 @@ spec:
# - "<node label value>"
containers:
- name: netclient
image: gravitl/netclient:v0.21.1
image: gravitl/netclient:v0.21.2
env:
- name: TOKEN
value: "TOKEN_VALUE"

View file

@ -15,7 +15,7 @@ spec:
spec:
containers:
- name: netmaker-ui
image: gravitl/netmaker-ui:v0.21.1
image: gravitl/netmaker-ui:v0.21.2
ports:
- containerPort: 443
env:

View file

@ -2,6 +2,7 @@ package logic
import (
"encoding/json"
"fmt"
"os"
"regexp"
"sort"
@ -87,7 +88,7 @@ func GetNodeDNS(network string) ([]models.DNSEntry, error) {
continue
}
var entry = models.DNSEntry{}
entry.Name = host.Name
entry.Name = fmt.Sprintf("%s.%s", host.Name, network)
entry.Network = network
if node.Address.IP != nil {
entry.Address = node.Address.IP.String()

View file

@ -7,8 +7,10 @@ import (
"fmt"
"time"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/models"
"golang.org/x/exp/slices"
)
// EnrollmentErrors - struct for holding EnrollmentKey error messages
@ -29,12 +31,12 @@ var EnrollmentErrors = struct {
}
// CreateEnrollmentKey - creates a new enrollment key in db
func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string, unlimited bool) (k *models.EnrollmentKey, err error) {
func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string, unlimited bool, relay uuid.UUID) (*models.EnrollmentKey, error) {
newKeyID, err := getUniqueEnrollmentID()
if err != nil {
return nil, err
}
k = &models.EnrollmentKey{
k := &models.EnrollmentKey{
Value: newKeyID,
Expiration: time.Time{},
UsesRemaining: 0,
@ -42,6 +44,7 @@ func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string
Networks: []string{},
Tags: []string{},
Type: models.Undefined,
Relay: relay,
}
if uses > 0 {
k.UsesRemaining = uses
@ -61,10 +64,51 @@ func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string
if ok := k.Validate(); !ok {
return nil, EnrollmentErrors.InvalidCreate
}
if relay != uuid.Nil {
relayNode, err := GetNodeByID(relay.String())
if err != nil {
return nil, err
}
if !slices.Contains(k.Networks, relayNode.Network) {
return nil, errors.New("relay node not in key's networks")
}
if !relayNode.IsRelay {
return nil, errors.New("relay node is not a relay")
}
}
if err = upsertEnrollmentKey(k); err != nil {
return nil, err
}
return
return k, nil
}
// UpdateEnrollmentKey - updates an existing enrollment key's associated relay
func UpdateEnrollmentKey(keyId string, relayId uuid.UUID) (*models.EnrollmentKey, error) {
key, err := GetEnrollmentKey(keyId)
if err != nil {
return nil, err
}
if relayId != uuid.Nil {
relayNode, err := GetNodeByID(relayId.String())
if err != nil {
return nil, err
}
if !slices.Contains(key.Networks, relayNode.Network) {
return nil, errors.New("relay node not in key's networks")
}
if !relayNode.IsRelay {
return nil, errors.New("relay node is not a relay")
}
}
key.Relay = relayId
if err = upsertEnrollmentKey(key); err != nil {
return nil, err
}
return key, nil
}
// GetAllEnrollmentKeys - fetches all enrollment keys from DB

View file

@ -4,6 +4,7 @@ import (
"testing"
"time"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert"
@ -13,35 +14,35 @@ func TestCreateEnrollmentKey(t *testing.T) {
database.InitializeDatabase()
defer database.CloseDB()
t.Run("Can_Not_Create_Key", func(t *testing.T) {
newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, false)
newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, false, uuid.Nil)
assert.Nil(t, newKey)
assert.NotNil(t, err)
assert.Equal(t, err, EnrollmentErrors.InvalidCreate)
})
t.Run("Can_Create_Key_Uses", func(t *testing.T) {
newKey, err := CreateEnrollmentKey(1, time.Time{}, nil, nil, false)
newKey, err := CreateEnrollmentKey(1, time.Time{}, nil, nil, false, uuid.Nil)
assert.Nil(t, err)
assert.Equal(t, 1, newKey.UsesRemaining)
assert.True(t, newKey.IsValid())
})
t.Run("Can_Create_Key_Time", func(t *testing.T) {
newKey, err := CreateEnrollmentKey(0, time.Now().Add(time.Minute), nil, nil, false)
newKey, err := CreateEnrollmentKey(0, time.Now().Add(time.Minute), nil, nil, false, uuid.Nil)
assert.Nil(t, err)
assert.True(t, newKey.IsValid())
})
t.Run("Can_Create_Key_Unlimited", func(t *testing.T) {
newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, true)
newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, true, uuid.Nil)
assert.Nil(t, err)
assert.True(t, newKey.IsValid())
})
t.Run("Can_Create_Key_WithNetworks", func(t *testing.T) {
newKey, err := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true)
newKey, err := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil)
assert.Nil(t, err)
assert.True(t, newKey.IsValid())
assert.True(t, len(newKey.Networks) == 2)
})
t.Run("Can_Create_Key_WithTags", func(t *testing.T) {
newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, []string{"tag1", "tag2"}, true)
newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, []string{"tag1", "tag2"}, true, uuid.Nil)
assert.Nil(t, err)
assert.True(t, newKey.IsValid())
assert.True(t, len(newKey.Tags) == 2)
@ -61,7 +62,7 @@ func TestCreateEnrollmentKey(t *testing.T) {
func TestDelete_EnrollmentKey(t *testing.T) {
database.InitializeDatabase()
defer database.CloseDB()
newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true)
newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil)
t.Run("Can_Delete_Key", func(t *testing.T) {
assert.True(t, newKey.IsValid())
err := DeleteEnrollmentKey(newKey.Value)
@ -82,7 +83,7 @@ func TestDelete_EnrollmentKey(t *testing.T) {
func TestDecrement_EnrollmentKey(t *testing.T) {
database.InitializeDatabase()
defer database.CloseDB()
newKey, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, false)
newKey, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, false, uuid.Nil)
t.Run("Check_initial_uses", func(t *testing.T) {
assert.True(t, newKey.IsValid())
assert.Equal(t, newKey.UsesRemaining, 1)
@ -106,9 +107,9 @@ func TestDecrement_EnrollmentKey(t *testing.T) {
func TestUsability_EnrollmentKey(t *testing.T) {
database.InitializeDatabase()
defer database.CloseDB()
key1, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, false)
key2, _ := CreateEnrollmentKey(0, time.Now().Add(time.Minute<<4), nil, nil, false)
key3, _ := CreateEnrollmentKey(0, time.Time{}, nil, nil, true)
key1, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, false, uuid.Nil)
key2, _ := CreateEnrollmentKey(0, time.Now().Add(time.Minute<<4), nil, nil, false, uuid.Nil)
key3, _ := CreateEnrollmentKey(0, time.Time{}, nil, nil, true, uuid.Nil)
t.Run("Check if valid use key can be used", func(t *testing.T) {
assert.Equal(t, key1.UsesRemaining, 1)
ok := TryToUseEnrollmentKey(key1)
@ -144,7 +145,7 @@ func removeAllEnrollments() {
func TestTokenize_EnrollmentKeys(t *testing.T) {
database.InitializeDatabase()
defer database.CloseDB()
newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true)
newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil)
const defaultValue = "MwE5MwE5MwE5MwE5MwE5MwE5MwE5MwE5"
const b64value = "eyJzZXJ2ZXIiOiJhcGkubXlzZXJ2ZXIuY29tIiwidmFsdWUiOiJNd0U1TXdFNU13RTVNd0U1TXdFNU13RTVNd0U1TXdFNSJ9"
const serverAddr = "api.myserver.com"
@ -177,7 +178,7 @@ func TestTokenize_EnrollmentKeys(t *testing.T) {
func TestDeTokenize_EnrollmentKeys(t *testing.T) {
database.InitializeDatabase()
defer database.CloseDB()
newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true)
newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil)
const b64Value = "eyJzZXJ2ZXIiOiJhcGkubXlzZXJ2ZXIuY29tIiwidmFsdWUiOiJNd0U1TXdFNU13RTVNd0U1TXdFNU13RTVNd0U1TXdFNSJ9"
const serverAddr = "api.myserver.com"

View file

@ -107,7 +107,7 @@ func GetNetworkExtClients(network string) ([]models.ExtClient, error) {
if err != nil {
continue
}
key, err := GetRecordKey(extclient.ClientID, network)
key, err := GetRecordKey(extclient.ClientID, extclient.Network)
if err == nil {
storeExtClientInCache(key, extclient)
}
@ -137,6 +137,21 @@ func GetExtClient(clientid string, network string) (models.ExtClient, error) {
return extclient, err
}
// GetGwExtclients - return all ext clients attached to the passed gw id
func GetGwExtclients(nodeID, network string) []models.ExtClient {
gwClients := []models.ExtClient{}
clients, err := GetNetworkExtClients(network)
if err != nil {
return gwClients
}
for _, client := range clients {
if client.IngressGatewayID == nodeID {
gwClients = append(gwClients, client)
}
}
return gwClients
}
// GetExtClient - gets a single ext client on a network
func GetExtClientByPubKey(publicKey string, network string) (*models.ExtClient, error) {
netClients, err := GetNetworkExtClients(network)

View file

@ -199,7 +199,6 @@ func UpdateHost(newHost, currentHost *models.Host) {
newHost.Nodes = currentHost.Nodes
newHost.PublicKey = currentHost.PublicKey
newHost.TrafficKeyPublic = currentHost.TrafficKeyPublic
// changeable fields
if len(newHost.Version) == 0 {
newHost.Version = currentHost.Version
@ -393,7 +392,7 @@ func DissasociateNodeFromHost(n *models.Node, h *models.Host) error {
}
}
}()
if err := deleteNodeByID(n); err != nil {
if err := DeleteNodeByID(n); err != nil {
return err
}

View file

@ -23,7 +23,6 @@ func GetNetworks() ([]models.Network, error) {
var networks []models.Network
collection, err := database.FetchRecords(database.NETWORKS_TABLE_NAME)
if err != nil {
return networks, err
}
@ -72,6 +71,9 @@ func CreateNetwork(network models.Network) (models.Network, error) {
}
network.AddressRange6 = normalizedRange
}
if !IsNetworkCIDRUnique(network.GetNetworkNetworkCIDR4(), network.GetNetworkNetworkCIDR6()) {
return models.Network{}, errors.New("network cidr already in use")
}
network.SetDefaults()
network.SetNodesLastModified()
@ -101,6 +103,27 @@ func GetNetworkNonServerNodeCount(networkName string) (int, error) {
return len(nodes), err
}
func IsNetworkCIDRUnique(cidr4 *net.IPNet, cidr6 *net.IPNet) bool {
networks, err := GetNetworks()
if err != nil {
return database.IsEmptyRecord(err)
}
for _, network := range networks {
if intersect(network.GetNetworkNetworkCIDR4(), cidr4) ||
intersect(network.GetNetworkNetworkCIDR6(), cidr6) {
return false
}
}
return true
}
func intersect(n1, n2 *net.IPNet) bool {
if n1 == nil || n2 == nil {
return false
}
return n2.Contains(n1.IP) || n1.Contains(n2.IP)
}
// GetParentNetwork - get parent network
func GetParentNetwork(networkname string) (models.Network, error) {

View file

@ -183,6 +183,33 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
func DeleteNode(node *models.Node, purge bool) error {
alreadyDeleted := node.PendingDelete || node.Action == models.NODE_DELETE
node.Action = models.NODE_DELETE
//delete ext clients if node is ingress gw
if node.IsIngressGateway {
if err := DeleteGatewayExtClients(node.ID.String(), node.Network); err != nil {
slog.Error("failed to delete ext clients", "nodeid", node.ID.String(), "error", err.Error())
}
}
if node.IsRelayed {
// cleanup node from relayednodes on relay node
relayNode, err := GetNodeByID(node.RelayedBy)
if err == nil {
relayedNodes := []string{}
for _, relayedNodeID := range relayNode.RelayedNodes {
if relayedNodeID == node.ID.String() {
continue
}
relayedNodes = append(relayedNodes, relayedNodeID)
}
relayNode.RelayedNodes = relayedNodes
UpsertNode(&relayNode)
}
}
if node.IsRelay {
// unset all the relayed nodes
SetRelayedNodes(false, node.ID.String(), node.RelayedNodes)
}
if !purge && !alreadyDeleted {
newnode := *node
newnode.PendingDelete = true
@ -198,7 +225,7 @@ func DeleteNode(node *models.Node, purge bool) error {
host, err := GetHost(node.HostID.String())
if err != nil {
logger.Log(1, "no host found for node", node.ID.String(), "deleting..")
if delErr := deleteNodeByID(node); delErr != nil {
if delErr := DeleteNodeByID(node); delErr != nil {
logger.Log(0, "failed to delete node", node.ID.String(), delErr.Error())
}
return err
@ -215,16 +242,25 @@ func DeleteNode(node *models.Node, purge bool) error {
return nil
}
// deleteNodeByID - deletes a node from database
func deleteNodeByID(node *models.Node) error {
var err error
var key = node.ID.String()
//delete any ext clients as required
if node.IsIngressGateway {
if err := DeleteGatewayExtClients(node.ID.String(), node.Network); err != nil {
logger.Log(0, "failed to deleted ext clients", err.Error())
// GetNodeByHostRef - gets the node by host id and network
func GetNodeByHostRef(hostid, network string) (node models.Node, err error) {
nodes, err := GetNetworkNodes(network)
if err != nil {
return models.Node{}, err
}
for _, node := range nodes {
if node.HostID.String() == hostid && node.Network == network {
return node, nil
}
}
return models.Node{}, errors.New("node not found")
}
// DeleteNodeByID - deletes a node from database
func DeleteNodeByID(node *models.Node) error {
var err error
var key = node.ID.String()
if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
if !database.IsEmptyRecord(err) {
return err

View file

@ -38,8 +38,6 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
HostNetworkInfo: models.HostInfoMap{},
}
// endpoint detection always comes from the server
hostPeerUpdate.EndpointDetection = servercfg.EndpointDetectionEnabled()
slog.Debug("peer update for host", "hostId", host.ID.String())
peerIndexMap := make(map[string]int)
for _, nodeID := range host.Nodes {

View file

@ -107,6 +107,7 @@ func ManageZombies(ctx context.Context, peerUpdate chan *models.Node) {
logger.Log(1, "error deleting zombie node", zombies[i].String(), err.Error())
continue
}
node.PendingDelete = true
node.Action = models.NODE_DELETE
peerUpdate <- &node
logger.Log(1, "deleting zombie node", node.ID.String())
@ -120,14 +121,17 @@ func ManageZombies(ctx context.Context, peerUpdate chan *models.Node) {
host, err := GetHost(hostZombies[i].String())
if err != nil {
logger.Log(1, "error retrieving zombie host", err.Error())
logger.Log(1, "deleting ", host.ID.String(), " from zombie list")
zombies = append(zombies[:i], zombies[i+1:]...)
if host != nil {
logger.Log(1, "deleting ", host.ID.String(), " from zombie list")
}
hostZombies = append(hostZombies[:i], hostZombies[i+1:]...)
continue
}
if len(host.Nodes) == 0 {
if err := RemoveHost(host, true); err != nil {
logger.Log(0, "error deleting zombie host", host.ID.String(), err.Error())
}
hostZombies = append(hostZombies[:i], hostZombies[i+1:]...)
}
}
}

18
main.go
View file

@ -28,7 +28,8 @@ import (
"golang.org/x/exp/slog"
)
var version = "v0.21.1"
var version = "v0.21.2"
// Start DB Connection and start API Request Handler
func main() {
@ -48,6 +49,7 @@ func main() {
defer stop()
var waitGroup sync.WaitGroup
startControllers(&waitGroup, ctx) // start the api endpoint and mq and stun
startHooks()
<-ctx.Done()
waitGroup.Wait()
}
@ -63,6 +65,14 @@ func setupConfig(absoluteConfigPath string) {
}
}
func startHooks() {
err := logic.TimerCheckpoint()
if err != nil {
logger.Log(1, "Timer error occurred: ", err.Error())
}
logic.EnterpriseCheck()
}
func initialize() { // Client Mode Prereq Check
var err error
@ -82,12 +92,6 @@ func initialize() { // Client Mode Prereq Check
logic.SetJWTSecret()
err = logic.TimerCheckpoint()
if err != nil {
logger.Log(1, "Timer error occurred: ", err.Error())
}
logic.EnterpriseCheck()
var authProvider = auth.InitializeAuthProvider()
if authProvider != "" {
logger.Log(0, "OAuth provider,", authProvider+",", "initialized")

View file

@ -32,6 +32,7 @@ type ApiHost struct {
RelayedHosts []string `json:"relay_hosts" yaml:"relay_hosts" bson:"relay_hosts"`
NatType string `json:"nat_type" yaml:"nat_type"`
PersistentKeepalive int `json:"persistentkeepalive" yaml:"persistentkeepalive"`
AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"`
}
// Host.ConvertNMHostToAPI - converts a Netmaker host to an API editable host
@ -60,6 +61,7 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost {
a.IsDefault = h.IsDefault
a.NatType = h.NatType
a.PersistentKeepalive = int(h.PersistentKeepalive.Seconds())
a.AutoUpdate = h.AutoUpdate
return &a
}
@ -98,5 +100,6 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host {
h.NatType = currentHost.NatType
h.TurnEndpoint = currentHost.TurnEndpoint
h.PersistentKeepalive = time.Duration(a.PersistentKeepalive) * time.Second
h.AutoUpdate = a.AutoUpdate
return &h
}

View file

@ -2,6 +2,8 @@ package models
import (
"time"
"github.com/google/uuid"
)
const (
@ -39,6 +41,7 @@ type EnrollmentKey struct {
Tags []string `json:"tags"`
Token string `json:"token,omitempty"` // B64 value of EnrollmentToken
Type KeyType `json:"type"`
Relay uuid.UUID `json:"relay"`
}
// APIEnrollmentKey - used to create enrollment keys via API
@ -49,6 +52,7 @@ type APIEnrollmentKey struct {
Unlimited bool `json:"unlimited"`
Tags []string `json:"tags"`
Type KeyType `json:"type"`
Relay string `json:"relay"`
}
// RegisterResponse - the response to a successful enrollment register

View file

@ -160,4 +160,5 @@ type RegisterMsg struct {
User string `json:"user,omitempty"`
Password string `json:"password,omitempty"`
JoinAll bool `json:"join_all,omitempty"`
Relay string `json:"relay,omitempty"`
}

View file

@ -8,18 +8,17 @@ import (
// HostPeerUpdate - struct for host peer updates
type HostPeerUpdate struct {
Host Host `json:"host" bson:"host" yaml:"host"`
NodeAddrs []net.IPNet `json:"nodes_addrs" yaml:"nodes_addrs"`
Server string `json:"server" bson:"server" yaml:"server"`
ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
NodePeers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
Peers []wgtypes.PeerConfig
PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
EndpointDetection bool `json:"endpointdetection" yaml:"endpointdetection"`
HostNetworkInfo HostInfoMap `json:"host_network_info,omitempty" bson:"host_network_info,omitempty" yaml:"host_network_info,omitempty"`
EgressRoutes []EgressNetworkRoutes `json:"egress_network_routes"`
FwUpdate FwUpdate `json:"fw_update"`
Host Host `json:"host" bson:"host" yaml:"host"`
NodeAddrs []net.IPNet `json:"nodes_addrs" yaml:"nodes_addrs"`
Server string `json:"server" bson:"server" yaml:"server"`
ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
NodePeers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
Peers []wgtypes.PeerConfig
PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
HostNetworkInfo HostInfoMap `json:"host_network_info,omitempty" bson:"host_network_info,omitempty" yaml:"host_network_info,omitempty"`
EgressRoutes []EgressNetworkRoutes `json:"egress_network_routes"`
FwUpdate FwUpdate `json:"fw_update"`
}
// IngressInfo - struct for ingress info

View file

@ -1,6 +1,7 @@
package models
import (
"net"
"time"
)
@ -81,3 +82,18 @@ func (network *Network) SetDefaults() {
network.DefaultACL = "yes"
}
}
func (network *Network) GetNetworkNetworkCIDR4() *net.IPNet {
if network.AddressRange == "" {
return nil
}
_, netCidr, _ := net.ParseCIDR(network.AddressRange)
return netCidr
}
func (network *Network) GetNetworkNetworkCIDR6() *net.IPNet {
if network.AddressRange6 == "" {
return nil
}
_, netCidr, _ := net.ParseCIDR(network.AddressRange6)
return netCidr
}

View file

@ -223,11 +223,12 @@ type TrafficKeys struct {
// HostPull - response of a host's pull
type HostPull struct {
Host Host `json:"host" yaml:"host"`
Nodes []Node `json:"nodes" yaml:"nodes"`
Peers []wgtypes.PeerConfig `json:"peers" yaml:"peers"`
ServerConfig ServerConfig `json:"server_config" yaml:"server_config"`
PeerIDs PeerMap `json:"peer_ids,omitempty" yaml:"peer_ids,omitempty"`
Host Host `json:"host" yaml:"host"`
Nodes []Node `json:"nodes" yaml:"nodes"`
Peers []wgtypes.PeerConfig `json:"peers" yaml:"peers"`
ServerConfig ServerConfig `json:"server_config" yaml:"server_config"`
PeerIDs PeerMap `json:"peer_ids,omitempty" yaml:"peer_ids,omitempty"`
HostNetworkInfo HostInfoMap `json:"host_network_info,omitempty" yaml:"host_network_info,omitempty"`
}
// NodeGet - struct for a single node get response

View file

@ -60,7 +60,21 @@ func UpdateNode(client mqtt.Client, msg mqtt.Message) {
return
}
if ifaceDelta { // reduce number of unneeded updates, by only sending on iface changes
if err = PublishPeerUpdate(); err != nil {
if !newNode.Connected {
err = PublishDeletedNodePeerUpdate(&newNode)
host, err := logic.GetHost(newNode.HostID.String())
if err != nil {
slog.Error("failed to get host for the node", "nodeid", newNode.ID.String(), "error", err)
return
}
allNodes, err := logic.GetAllNodes()
if err == nil {
PublishSingleHostPeerUpdate(host, allNodes, nil, nil)
}
} else {
err = PublishPeerUpdate()
}
if err != nil {
slog.Warn("error updating peers when node informed the server of an interface change", "nodeid", currentNode.ID, "error", err)
}
}
@ -116,7 +130,7 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
slog.Error("failed peers publish after join acknowledged", "name", hostUpdate.Host.Name, "id", currentHost.ID, "error", err)
return
}
if err = handleNewNodeDNS(&hu.Host, &hu.Node); err != nil {
if err = HandleNewNodeDNS(&hu.Host, &hu.Node); err != nil {
slog.Error("failed to send dns update after node added to host", "name", hostUpdate.Host.Name, "id", currentHost.ID, "error", err)
return
}
@ -159,6 +173,22 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
return
}
}
// notify of deleted peer change
go func(host models.Host) {
for _, nodeID := range host.Nodes {
node, err := logic.GetNodeByID(nodeID)
if err == nil {
var gwClients []models.ExtClient
if node.IsIngressGateway {
gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
}
go PublishMqUpdatesForDeletedNode(node, false, gwClients)
}
}
}(*currentHost)
if err := logic.DisassociateAllNodesFromHost(currentHost.ID.String()); err != nil {
slog.Error("failed to delete all nodes of host", "id", currentHost.ID, "error", err)
return
@ -217,7 +247,7 @@ func ClientPeerUpdate(client mqtt.Client, msg mqtt.Message) {
slog.Info("sent peer updates after signal received from", "id", id)
}
func handleNewNodeDNS(host *models.Host, node *models.Node) error {
func HandleNewNodeDNS(host *models.Host, node *models.Node) error {
dns := models.DNSUpdate{
Action: models.DNSInsert,
Name: host.Name + "." + node.Network,

View file

@ -10,6 +10,7 @@ import (
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg"
"golang.org/x/exp/slog"
)
// PublishPeerUpdate --- determines and publishes a peer update to all the hosts
@ -95,10 +96,6 @@ func PublishSingleHostPeerUpdate(host *models.Host, allNodes []models.Node, dele
if err != nil {
return err
}
if len(peerUpdate.Peers) == 0 { // no peers to send
return nil
}
data, err := json.Marshal(&peerUpdate)
if err != nil {
return err
@ -169,6 +166,27 @@ func ServerStartNotify() error {
return nil
}
// PublishDNSUpdatev1 - published dns updates to all nodes passed
func PublishDNSUpdatev1(network string, dns models.DNSUpdate, nodes []models.Node) error {
for _, node := range nodes {
host, err := logic.GetHost(node.HostID.String())
if err != nil {
logger.Log(0, "error retrieving host for dns update", node.HostID.String(), err.Error())
continue
}
data, err := json.Marshal(dns)
if err != nil {
logger.Log(0, "failed to encode dns data for node", node.ID.String(), err.Error())
}
if err := publish(host, "dns/update/"+host.ID.String()+"/"+servercfg.GetServer(), data); err != nil {
logger.Log(0, "error publishing dns update to host", host.ID.String(), err.Error())
continue
}
logger.Log(3, "published dns update to host", host.ID.String())
}
return nil
}
// PublishDNSUpdate publishes a dns update to all nodes on a network
func PublishDNSUpdate(network string, dns models.DNSUpdate) error {
nodes, err := logic.GetNetworkNodes(network)
@ -215,6 +233,32 @@ func PublishAllDNS(newnode *models.Node) error {
return nil
}
// PublishMqUpdatesForDeletedNode - published all the required updates for deleted node
func PublishMqUpdatesForDeletedNode(node models.Node, sendNodeUpdate bool, gwClients []models.ExtClient) {
// notify of peer change
node.PendingDelete = true
node.Action = models.NODE_DELETE
if sendNodeUpdate {
if err := NodeUpdate(&node); err != nil {
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
}
}
if err := PublishDeletedNodePeerUpdate(&node); err != nil {
logger.Log(1, "error publishing peer update ", err.Error())
}
host, err := logic.GetHost(node.HostID.String())
if err != nil {
logger.Log(1, "failed to retrieve host for node", node.ID.String(), err.Error())
}
if err := PublishDNSDelete(&node, host); err != nil {
logger.Log(1, "error publishing dns update", err.Error())
}
if err := PublishDeleteAllExtclientsDNS(node.Network, gwClients); err != nil {
logger.Log(1, "error publishing ext dns update", err.Error())
}
}
// PublishDNSDelete publish a dns update deleting a node to all hosts on a network
func PublishDNSDelete(node *models.Node, host *models.Host) error {
dns := models.DNSUpdate{
@ -299,6 +343,22 @@ func PublishExtClientDNSUpdate(old, new models.ExtClient, network string) error
return nil
}
// PublishDeleteAllExtclientsDNS - publish to delete all passed ext clients dns entries
func PublishDeleteAllExtclientsDNS(network string, clients []models.ExtClient) error {
nodes, err := logic.GetNetworkNodes(network)
if err != nil {
return err
}
for _, client := range clients {
dns := models.DNSUpdate{
Action: models.DNSDeleteByName,
Name: client.ClientID + "." + client.Network,
}
go PublishDNSUpdatev1(client.Network, dns, nodes)
}
return nil
}
// PublishDeleteExtClientDNS publish dns update to delete extclient entry
func PublishDeleteExtClientDNS(client *models.ExtClient) error {
dns := models.DNSUpdate{

View file

@ -34,7 +34,7 @@ func decryptMsgWithHost(host *models.Host, msg []byte) ([]byte, error) {
func DecryptMsg(node *models.Node, msg []byte) ([]byte, error) {
if len(msg) <= 24 { // make sure message is of appropriate length
return nil, fmt.Errorf("recieved invalid message from broker %v", msg)
return nil, fmt.Errorf("received invalid message from broker %v", msg)
}
host, err := logic.GetHost(node.HostID.String())
if err != nil {

View file

@ -213,28 +213,43 @@ func validateLicenseKey(encryptedData []byte, publicKey *[32]byte) ([]byte, erro
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Accept", "application/json")
client := &http.Client{}
var body []byte
validateResponse, err := client.Do(req)
if err != nil { // check cache
body, err = getCachedResponse()
if err != nil {
return nil, err
}
slog.Warn("proceeding with cached response, Netmaker API may be down")
} else {
defer validateResponse.Body.Close()
if validateResponse.StatusCode != 200 {
return nil, fmt.Errorf("could not validate license, got status code %d", validateResponse.StatusCode)
} // if you received a 200 cache the response locally
return getCachedResponse()
}
defer validateResponse.Body.Close()
code := validateResponse.StatusCode
body, err = io.ReadAll(validateResponse.Body)
// if we received a 200, cache the response locally
if code == http.StatusOK {
body, err := io.ReadAll(validateResponse.Body)
if err != nil {
slog.Warn("failed to parse response", "error", err)
return nil, err
}
cacheResponse(body)
if err := cacheResponse(body); err != nil {
slog.Warn("failed to cache response", "error", err)
}
return body, nil
}
return body, err
// at this point the backend returned some undesired state
// inform failure via logs
body, _ := io.ReadAll(validateResponse.Body)
err = fmt.Errorf("could not validate license with validation backend (status={%d}, body={%s})",
validateResponse.StatusCode, string(body))
slog.Warn(err.Error())
// try to use cache if we had a temporary error
if code == http.StatusServiceUnavailable || code == http.StatusGatewayTimeout {
slog.Warn("proceeding with cached response, Netmaker API may be down")
return getCachedResponse()
}
// at this point the error is irreversible, return it
return nil, err
}
func getAccountsHost() string {

View file

@ -149,6 +149,7 @@ func RelayUpdates(currentNode, newNode *models.Node) bool {
return relayUpdates
}
// UpdateRelayed - updates a relay's relayed nodes, and sends updates to the relayed nodes over MQ
func UpdateRelayed(currentNode, newNode *models.Node) {
updatenodes := updateRelayNodes(currentNode.ID.String(), currentNode.RelayedNodes, newNode.RelayedNodes)
if len(updatenodes) > 0 {

View file

@ -1,20 +1,19 @@
# Netmaker v0.21.1
# Netmaker v0.21.2
## Whats New
- Remote access client session management, refer users section in docs for more details
- Can now create generic DNS entries
- Upgrade client version to match server version from UI
- Moved PersistentKeepAlive setting from node to host level
- Auto Relay via Enrollment key
- Local Routing Improvements
## What's Fixed
- Extclients DNS now properly set from ingress dns value provided
- Allow role update of OAuth user
- Fixed zombie node issue
- Inconsistency in DNS Entries for Network has been fixed
- Unique network CIDR validation
- Fixed extclient caching decrepancies
- Deleted node peer update fixes when disconnected from network
- Force Deletion of Daemon Nodes that are stuck in removing state
## known issues
- Windows installer does not install WireGuard
- netclient-gui will continously display error dialog if netmaker server is offline
- Mac IPv6 addresses/route issues
- Docker client can not re-join after complete deletion
- netclient-gui network tab blank after disconnect

View file

@ -19,7 +19,6 @@ NETMAKER_TENANT_ID=
LICENSE_KEY=
SERVER_IMAGE_TAG=
UI_IMAGE_TAG=
NETCLIENT_ENDPOINT_DETECTION=disabled
# used for HA - identifies this server vs other servers
NODE_ID=netmaker-server-1
METRICS_EXPORTER=off

View file

@ -309,7 +309,7 @@ save_config() { (
"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "STUN_PORT" "VERBOSITY"
"TURN_PORT" "USE_TURN" "DEBUG_MODE" "TURN_API_PORT" "REST_BACKEND"
"DISABLE_REMOTE_IP_CHECK" "NETCLIENT_ENDPOINT_DETECTION" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
"DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE")
for name in "${toCopy[@]}"; do
save_config_item $name "${!name}"
@ -370,7 +370,6 @@ local_install_setup() { (
else
cp docker/Caddyfile "$SCRIPT_DIR/Caddyfile"
fi
cp scripts/nm-certs.sh "$SCRIPT_DIR/nm-certs.sh"
cp scripts/netmaker.default.env "$SCRIPT_DIR/netmaker.default.env"
cp docker/mosquitto.conf "$SCRIPT_DIR/mosquitto.conf"
cp docker/wait.sh "$SCRIPT_DIR/wait.sh"
@ -776,8 +775,9 @@ install_netmaker() {
export COMPOSE_HTTP_TIMEOUT=120
# start docker and rebuild containers / networks
docker-compose -f "$SCRIPT_DIR"/docker-compose.yml up -d --force-recreate
cd "${SCRIPT_DIR}"
docker-compose up -d --force-recreate
cd -
wait_seconds 2
}

View file

@ -1,6 +1,6 @@
#!/bin/bash
LATEST="v0.21.1"
LATEST="v0.21.2"
INSTALL_PATH="/root"
trap restore_old_netmaker_instructions

View file

@ -179,7 +179,7 @@ save_config() { (
"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "STUN_PORT" "VERBOSITY"
"TURN_PORT" "USE_TURN" "DEBUG_MODE" "TURN_API_PORT" "REST_BACKEND"
"DISABLE_REMOTE_IP_CHECK" "NETCLIENT_ENDPOINT_DETECTION" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
"DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE")
for name in "${toCopy[@]}"; do
save_config_item $name "${!name}"

View file

@ -53,11 +53,6 @@ func GetServerConfig() config.ServerConfig {
} else {
cfg.NetclientAutoUpdate = "disabled"
}
if EndpointDetectionEnabled() {
cfg.NetclientEndpointDetection = "enabled"
} else {
cfg.NetclientEndpointDetection = "disabled"
}
if IsRestBackend() {
cfg.RestBackend = "on"
}
@ -405,17 +400,6 @@ func AutoUpdateEnabled() bool {
return true
}
// EndpointDetectionEnabled returns a boolean indicating whether netclient endpoint detection is enabled or disabled
// default is enabled
func EndpointDetectionEnabled() bool {
if os.Getenv("NETCLIENT_ENDPOINT_DETECTION") == "disabled" {
return false
} else if config.Config.Server.NetclientEndpointDetection == "disabled" {
return false
}
return true
}
// IsDNSMode - should it run with DNS
func IsDNSMode() bool {
isdns := true

View file

@ -1149,7 +1149,7 @@ info:
API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
title: Netmaker
version: 0.21.1
version: 0.21.2
paths:
/api/dns:
get: