mirror of
https://github.com/gravitl/netmaker.git
synced 2024-09-21 07:46:04 +08:00
commit
5af7a6a50f
1
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
|
@ -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
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
// Schemes: https
|
||||
// BasePath: /
|
||||
// Version: 0.21.1
|
||||
// Version: 0.21.2
|
||||
// Host: api.demo.netmaker.io
|
||||
//
|
||||
// Consumes:
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
14
go.mod
|
@ -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
52
go.sum
|
@ -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=
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
18
main.go
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
17
release.md
17
release.md
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
LATEST="v0.21.1"
|
||||
LATEST="v0.21.2"
|
||||
INSTALL_PATH="/root"
|
||||
|
||||
trap restore_old_netmaker_instructions
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue