mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-08 22:24:17 +08:00
Merge branch 'develop' into master
This commit is contained in:
commit
ee6bea117f
46 changed files with 1215 additions and 727 deletions
4
.github/workflows/deletedroplets.yml
vendored
4
.github/workflows/deletedroplets.yml
vendored
|
@ -12,7 +12,7 @@ jobs:
|
||||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||||
steps:
|
steps:
|
||||||
- name: get logs
|
- name: get logs
|
||||||
uses: dawidd6/action-download-artifact@v7
|
uses: dawidd6/action-download-artifact@v8
|
||||||
with:
|
with:
|
||||||
run_id: ${{ github.event.workflow_run.id}}
|
run_id: ${{ github.event.workflow_run.id}}
|
||||||
if_no_artifact_found: warn
|
if_no_artifact_found: warn
|
||||||
|
@ -75,7 +75,7 @@ jobs:
|
||||||
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
||||||
steps:
|
steps:
|
||||||
- name: get logs
|
- name: get logs
|
||||||
uses: dawidd6/action-download-artifact@v7
|
uses: dawidd6/action-download-artifact@v8
|
||||||
with:
|
with:
|
||||||
run_id: ${{ github.event.workflow_run.id}}
|
run_id: ${{ github.event.workflow_run.id}}
|
||||||
if_no_artifact_found: warn
|
if_no_artifact_found: warn
|
||||||
|
|
|
@ -6,11 +6,13 @@ COPY . .
|
||||||
|
|
||||||
RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} .
|
RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} .
|
||||||
# RUN go build -tags=ee . -o netmaker main.go
|
# RUN go build -tags=ee . -o netmaker main.go
|
||||||
FROM alpine:3.21.0
|
FROM alpine:3.21.2
|
||||||
|
|
||||||
# add a c lib
|
# add a c lib
|
||||||
# set the working directory
|
# set the working directory
|
||||||
WORKDIR /root/
|
WORKDIR /root/
|
||||||
|
RUN apk update && apk upgrade
|
||||||
|
RUN apk add --no-cache sqlite
|
||||||
RUN mkdir -p /etc/netclient/config
|
RUN mkdir -p /etc/netclient/config
|
||||||
COPY --from=builder /app/netmaker .
|
COPY --from=builder /app/netmaker .
|
||||||
COPY --from=builder /app/config config
|
COPY --from=builder /app/config config
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#first stage - builder
|
#first stage - builder
|
||||||
FROM alpine:3.21.0
|
FROM alpine:3.21.2
|
||||||
ARG version
|
ARG version
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./netmaker /root/netmaker
|
COPY ./netmaker /root/netmaker
|
||||||
|
|
|
@ -52,8 +52,8 @@ services:
|
||||||
- caddy_data:/data
|
- caddy_data:/data
|
||||||
- caddy_conf:/config
|
- caddy_conf:/config
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80/tcp"
|
||||||
- "443:443"
|
- "443:443/tcp"
|
||||||
|
|
||||||
coredns:
|
coredns:
|
||||||
#network_mode: host
|
#network_mode: host
|
||||||
|
|
|
@ -37,7 +37,7 @@ type ServerConfig struct {
|
||||||
APIConnString string `yaml:"apiconn"`
|
APIConnString string `yaml:"apiconn"`
|
||||||
APIHost string `yaml:"apihost"`
|
APIHost string `yaml:"apihost"`
|
||||||
APIPort string `yaml:"apiport"`
|
APIPort string `yaml:"apiport"`
|
||||||
Broker string `yam:"broker"`
|
Broker string `yaml:"broker"`
|
||||||
ServerBrokerEndpoint string `yaml:"serverbrokerendpoint"`
|
ServerBrokerEndpoint string `yaml:"serverbrokerendpoint"`
|
||||||
BrokerType string `yaml:"brokertype"`
|
BrokerType string `yaml:"brokertype"`
|
||||||
EmqxRestEndpoint string `yaml:"emqxrestendpoint"`
|
EmqxRestEndpoint string `yaml:"emqxrestendpoint"`
|
||||||
|
@ -92,14 +92,15 @@ type ServerConfig struct {
|
||||||
JwtValidityDuration time.Duration `yaml:"jwt_validity_duration" swaggertype:"primitive,integer" format:"int64"`
|
JwtValidityDuration time.Duration `yaml:"jwt_validity_duration" swaggertype:"primitive,integer" format:"int64"`
|
||||||
RacAutoDisable bool `yaml:"rac_auto_disable"`
|
RacAutoDisable bool `yaml:"rac_auto_disable"`
|
||||||
CacheEnabled string `yaml:"caching_enabled"`
|
CacheEnabled string `yaml:"caching_enabled"`
|
||||||
EndpointDetection bool `json:"endpoint_detection"`
|
EndpointDetection bool `yaml:"endpoint_detection"`
|
||||||
AllowedEmailDomains string `yaml:"allowed_email_domains"`
|
AllowedEmailDomains string `yaml:"allowed_email_domains"`
|
||||||
EmailSenderAddr string `json:"email_sender_addr"`
|
EmailSenderAddr string `yaml:"email_sender_addr"`
|
||||||
EmailSenderUser string `json:"email_sender_user"`
|
EmailSenderUser string `yaml:"email_sender_user"`
|
||||||
EmailSenderPassword string `json:"email_sender_password"`
|
EmailSenderPassword string `yaml:"email_sender_password"`
|
||||||
SmtpHost string `json:"smtp_host"`
|
SmtpHost string `yaml:"smtp_host"`
|
||||||
SmtpPort int `json:"smtp_port"`
|
SmtpPort int `yaml:"smtp_port"`
|
||||||
MetricInterval string `yaml:"metric_interval"`
|
MetricInterval string `yaml:"metric_interval"`
|
||||||
|
MetricsPort int `yaml:"metrics_port"`
|
||||||
ManageDNS bool `yaml:"manage_dns"`
|
ManageDNS bool `yaml:"manage_dns"`
|
||||||
Stun bool `yaml:"stun"`
|
Stun bool `yaml:"stun"`
|
||||||
StunServers string `yaml:"stun_servers"`
|
StunServers string `yaml:"stun_servers"`
|
||||||
|
|
|
@ -24,6 +24,7 @@ var HttpMiddlewares = []mux.MiddlewareFunc{
|
||||||
// HttpHandlers - handler functions for REST interactions
|
// HttpHandlers - handler functions for REST interactions
|
||||||
var HttpHandlers = []interface{}{
|
var HttpHandlers = []interface{}{
|
||||||
nodeHandlers,
|
nodeHandlers,
|
||||||
|
gwHandlers,
|
||||||
userHandlers,
|
userHandlers,
|
||||||
networkHandlers,
|
networkHandlers,
|
||||||
dnsHandlers,
|
dnsHandlers,
|
||||||
|
|
207
controllers/gateway.go
Normal file
207
controllers/gateway.go
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/gravitl/netmaker/logger"
|
||||||
|
"github.com/gravitl/netmaker/logic"
|
||||||
|
"github.com/gravitl/netmaker/models"
|
||||||
|
"github.com/gravitl/netmaker/mq"
|
||||||
|
"github.com/gravitl/netmaker/servercfg"
|
||||||
|
"golang.org/x/exp/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func gwHandlers(r *mux.Router) {
|
||||||
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/gateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createGateway)))).Methods(http.MethodPost)
|
||||||
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/gateway", logic.SecurityCheck(true, http.HandlerFunc(deleteGateway))).Methods(http.MethodDelete)
|
||||||
|
// old relay handlers
|
||||||
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", logic.SecurityCheck(true, http.HandlerFunc(createGateway))).Methods(http.MethodPost)
|
||||||
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", logic.SecurityCheck(true, http.HandlerFunc(deleteGateway))).Methods(http.MethodDelete)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Create a gateway
|
||||||
|
// @Router /api/nodes/{network}/{nodeid}/gateway [post]
|
||||||
|
// @Tags Nodes
|
||||||
|
// @Security oauth2
|
||||||
|
// @Success 200 {object} models.ApiNode
|
||||||
|
// @Failure 500 {object} models.ErrorResponse
|
||||||
|
func createGateway(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
var params = mux.Vars(r)
|
||||||
|
nodeid := params["nodeid"]
|
||||||
|
netid := params["network"]
|
||||||
|
node, err := logic.ValidateParams(nodeid, netid)
|
||||||
|
if err != nil {
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req models.CreateGwReq
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node, err = logic.CreateIngressGateway(netid, nodeid, req.IngressRequest)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"),
|
||||||
|
fmt.Sprintf("failed to create gateway on node [%s] on network [%s]: %v",
|
||||||
|
nodeid, netid, err))
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.RelayRequest.NetID = netid
|
||||||
|
req.RelayRequest.NodeID = nodeid
|
||||||
|
_, relayNode, err := logic.CreateRelay(req.RelayRequest)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(
|
||||||
|
0,
|
||||||
|
r.Header.Get("user"),
|
||||||
|
fmt.Sprintf(
|
||||||
|
"failed to create relay on node [%s] on network [%s]: %v",
|
||||||
|
req.RelayRequest.NodeID,
|
||||||
|
req.RelayRequest.NetID,
|
||||||
|
err,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, relayedNodeID := range relayNode.RelayedNodes {
|
||||||
|
relayedNode, err := logic.GetNodeByID(relayedNodeID)
|
||||||
|
if err == nil {
|
||||||
|
if relayedNode.FailedOverBy != uuid.Nil {
|
||||||
|
go logic.ResetFailedOverPeer(&relayedNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Log(
|
||||||
|
1,
|
||||||
|
r.Header.Get("user"),
|
||||||
|
"created gw node",
|
||||||
|
req.RelayRequest.NodeID,
|
||||||
|
"on network",
|
||||||
|
req.RelayRequest.NetID,
|
||||||
|
)
|
||||||
|
apiNode := relayNode.ConvertToAPINode()
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(apiNode)
|
||||||
|
go func() {
|
||||||
|
if err := mq.NodeUpdate(&node); err != nil {
|
||||||
|
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
|
||||||
|
}
|
||||||
|
mq.PublishPeerUpdate(false)
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Delete a gateway
|
||||||
|
// @Router /api/nodes/{network}/{nodeid}/gateway [delete]
|
||||||
|
// @Tags Nodes
|
||||||
|
// @Security oauth2
|
||||||
|
// @Success 200 {object} models.ApiNode
|
||||||
|
// @Failure 500 {object} models.ErrorResponse
|
||||||
|
func deleteGateway(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
var params = mux.Vars(r)
|
||||||
|
nodeid := params["nodeid"]
|
||||||
|
netid := params["network"]
|
||||||
|
node, err := logic.ValidateParams(nodeid, netid)
|
||||||
|
if err != nil {
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node, removedClients, err := logic.DeleteIngressGateway(nodeid)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"),
|
||||||
|
fmt.Sprintf("failed to delete ingress gateway on node [%s] on network [%s]: %v",
|
||||||
|
nodeid, netid, err))
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNodes, node, err := logic.DeleteRelay(netid, nodeid)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node, err = logic.GetNodeByID(node.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"), "failed to get node", err.Error())
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node.IsGw = false
|
||||||
|
logic.UpsertNode(&node)
|
||||||
|
logger.Log(1, r.Header.Get("user"), "deleted gw", nodeid, "on network", netid)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
host, err := logic.GetHost(node.HostID.String())
|
||||||
|
if err == nil {
|
||||||
|
allNodes, err := logic.GetAllNodes()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, relayedNode := range updateNodes {
|
||||||
|
err = mq.NodeUpdate(&relayedNode)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(
|
||||||
|
1,
|
||||||
|
"relayed node update ",
|
||||||
|
relayedNode.ID.String(),
|
||||||
|
"on network",
|
||||||
|
relayedNode.Network,
|
||||||
|
": ",
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
h, err := logic.GetHost(relayedNode.HostID.String())
|
||||||
|
if err == nil {
|
||||||
|
if h.OS == models.OS_Types.IoT {
|
||||||
|
nodes, err := logic.GetAllNodes()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node.IsRelay = true // for iot update to recognise that it has to delete relay peer
|
||||||
|
if err = mq.PublishSingleHostPeerUpdate(h, nodes, &node, nil, false, nil); err != nil {
|
||||||
|
logger.Log(1, "failed to publish peer update to host", h.ID.String(), ": ", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(removedClients) > 0 {
|
||||||
|
if err := mq.PublishSingleHostPeerUpdate(host, allNodes, nil, removedClients[:], false, nil); err != nil {
|
||||||
|
slog.Error("publishSingleHostUpdate", "host", host.Name, "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mq.PublishPeerUpdate(false)
|
||||||
|
if err := mq.NodeUpdate(&node); err != nil {
|
||||||
|
slog.Error(
|
||||||
|
"error publishing node update to node",
|
||||||
|
"node",
|
||||||
|
node.ID,
|
||||||
|
"error",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if servercfg.IsDNSMode() {
|
||||||
|
logic.SetDNS()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
apiNode := node.ConvertToAPINode()
|
||||||
|
logger.Log(1, r.Header.Get("user"), "deleted ingress gateway", nodeid)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(apiNode)
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -24,6 +24,10 @@ func hostHandlers(r *mux.Router) {
|
||||||
Methods(http.MethodGet)
|
Methods(http.MethodGet)
|
||||||
r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).
|
r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).
|
||||||
Methods(http.MethodPut)
|
Methods(http.MethodPut)
|
||||||
|
r.HandleFunc("/api/hosts/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHosts))).
|
||||||
|
Methods(http.MethodPost)
|
||||||
|
r.HandleFunc("/api/hosts/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHosts))).
|
||||||
|
Methods(http.MethodPost)
|
||||||
r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).
|
r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).
|
||||||
Methods(http.MethodPut)
|
Methods(http.MethodPut)
|
||||||
r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).
|
r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).
|
||||||
|
@ -45,16 +49,64 @@ func hostHandlers(r *mux.Router) {
|
||||||
Methods(http.MethodPost)
|
Methods(http.MethodPost)
|
||||||
r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).
|
r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).
|
||||||
Methods(http.MethodPut)
|
Methods(http.MethodPut)
|
||||||
|
r.HandleFunc("/api/v1/host/{hostid}/peer_info", Authorize(true, false, "host", http.HandlerFunc(getHostPeerInfo))).
|
||||||
|
Methods(http.MethodGet)
|
||||||
r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).
|
r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).
|
||||||
Methods(http.MethodDelete)
|
Methods(http.MethodDelete)
|
||||||
r.HandleFunc("/api/v1/auth-register/host", socketHandler)
|
r.HandleFunc("/api/v1/auth-register/host", socketHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Requests all the hosts to upgrade their version
|
||||||
|
// @Router /api/hosts/upgrade [post]
|
||||||
|
// @Tags Hosts
|
||||||
|
// @Security oauth
|
||||||
|
// @Param force query bool false "Force upgrade"
|
||||||
|
// @Success 200 {string} string "upgrade all hosts request received"
|
||||||
|
func upgradeHosts(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
action := models.Upgrade
|
||||||
|
|
||||||
|
if r.URL.Query().Get("force") == "true" {
|
||||||
|
action = models.ForceUpgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
user := r.Header.Get("user")
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
slog.Info("requesting all hosts to upgrade", "user", user)
|
||||||
|
|
||||||
|
hosts, err := logic.GetAllHosts()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to retrieve all hosts", "user", user, "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, host := range hosts {
|
||||||
|
go func(host models.Host) {
|
||||||
|
hostUpdate := models.HostUpdate{
|
||||||
|
Action: action,
|
||||||
|
Host: host,
|
||||||
|
}
|
||||||
|
if err = mq.HostUpdate(&hostUpdate); err != nil {
|
||||||
|
slog.Error("failed to request host to upgrade", "user", user, "host", host.ID.String(), "error", err)
|
||||||
|
} else {
|
||||||
|
slog.Info("host upgrade requested", "user", user, "host", host.ID.String())
|
||||||
|
}
|
||||||
|
}(host)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
slog.Info("upgrade all hosts request received", "user", user)
|
||||||
|
logic.ReturnSuccessResponse(w, r, "upgrade all hosts request received")
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Upgrade a host
|
// @Summary Upgrade a host
|
||||||
// @Router /api/hosts/{hostid}/upgrade [put]
|
// @Router /api/hosts/{hostid}/upgrade [put]
|
||||||
// @Tags Hosts
|
// @Tags Hosts
|
||||||
// @Security oauth
|
// @Security oauth
|
||||||
// @Param hostid path string true "Host ID"
|
// @Param hostid path string true "Host ID"
|
||||||
|
// @Param force query bool false "Force upgrade"
|
||||||
// @Success 200 {string} string "passed message to upgrade host"
|
// @Success 200 {string} string "passed message to upgrade host"
|
||||||
// @Failure 500 {object} models.ErrorResponse
|
// @Failure 500 {object} models.ErrorResponse
|
||||||
// upgrade host is a handler to send upgrade message to a host
|
// upgrade host is a handler to send upgrade message to a host
|
||||||
|
@ -65,7 +117,14 @@ func upgradeHost(w http.ResponseWriter, r *http.Request) {
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "notfound"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "notfound"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := mq.HostUpdate(&models.HostUpdate{Action: models.Upgrade, Host: *host}); err != nil {
|
|
||||||
|
action := models.Upgrade
|
||||||
|
|
||||||
|
if r.URL.Query().Get("force") == "true" {
|
||||||
|
action = models.ForceUpgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mq.HostUpdate(&models.HostUpdate{Action: action, Host: *host}); err != nil {
|
||||||
slog.Error("failed to upgrade host", "error", err)
|
slog.Error("failed to upgrade host", "error", err)
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
return
|
return
|
||||||
|
@ -176,17 +235,13 @@ func pull(w http.ResponseWriter, r *http.Request) {
|
||||||
slog.Error("failed to get node:", "id", node.ID, "error", err)
|
slog.Error("failed to get node:", "id", node.ID, "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if node.FailedOverBy != uuid.Nil {
|
if node.FailedOverBy != uuid.Nil && r.URL.Query().Get("reset_failovered") == "true" {
|
||||||
logic.ResetFailedOverPeer(&node)
|
logic.ResetFailedOverPeer(&node)
|
||||||
sendPeerUpdate = true
|
sendPeerUpdate = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sendPeerUpdate {
|
if sendPeerUpdate {
|
||||||
reset := true
|
if err := mq.PublishPeerUpdate(false); err != nil {
|
||||||
if os.Getenv("RESET_PEER_UPDATE") != "" {
|
|
||||||
reset = os.Getenv("RESET_PEER_UPDATE") == "true"
|
|
||||||
}
|
|
||||||
if err := mq.PublishPeerUpdate(reset); err != nil {
|
|
||||||
logger.Log(0, "fail to publish peer update: ", err.Error())
|
logger.Log(0, "fail to publish peer update: ", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +375,7 @@ func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
slog.Info("recieved host update", "name", hostUpdate.Host.Name, "id", hostUpdate.Host.ID)
|
slog.Info("recieved host update", "name", hostUpdate.Host.Name, "id", hostUpdate.Host.ID, "action", hostUpdate.Action)
|
||||||
switch hostUpdate.Action {
|
switch hostUpdate.Action {
|
||||||
case models.CheckIn:
|
case models.CheckIn:
|
||||||
sendPeerUpdate = mq.HandleHostCheckin(&hostUpdate.Host, currentHost)
|
sendPeerUpdate = mq.HandleHostCheckin(&hostUpdate.Host, currentHost)
|
||||||
|
@ -537,7 +592,7 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
w,
|
w,
|
||||||
r,
|
r,
|
||||||
logic.FormatError(
|
logic.FormatError(
|
||||||
fmt.Errorf("failed to force delete daemon node: "+err.Error()),
|
fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
|
||||||
"internal",
|
"internal",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -577,7 +632,7 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
w,
|
w,
|
||||||
r,
|
r,
|
||||||
logic.FormatError(
|
logic.FormatError(
|
||||||
fmt.Errorf("failed to force delete daemon node: "+err.Error()),
|
fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
|
||||||
"internal",
|
"internal",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -860,6 +915,45 @@ func updateKeys(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Requests all the hosts to pull
|
||||||
|
// @Router /api/hosts/sync [post]
|
||||||
|
// @Tags Hosts
|
||||||
|
// @Security oauth
|
||||||
|
// @Success 200 {string} string "sync all hosts request received"
|
||||||
|
func syncHosts(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
user := r.Header.Get("user")
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
slog.Info("requesting all hosts to sync", "user", user)
|
||||||
|
|
||||||
|
hosts, err := logic.GetAllHosts()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to retrieve all hosts", "user", user, "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, host := range hosts {
|
||||||
|
go func(host models.Host) {
|
||||||
|
hostUpdate := models.HostUpdate{
|
||||||
|
Action: models.RequestPull,
|
||||||
|
Host: host,
|
||||||
|
}
|
||||||
|
if err = mq.HostUpdate(&hostUpdate); err != nil {
|
||||||
|
slog.Error("failed to request host to sync", "user", user, "host", host.ID.String(), "error", err)
|
||||||
|
} else {
|
||||||
|
slog.Info("host sync requested", "user", user, "host", host.ID.String())
|
||||||
|
}
|
||||||
|
}(host)
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
slog.Info("sync all hosts request received", "user", user)
|
||||||
|
logic.ReturnSuccessResponse(w, r, "sync all hosts request received")
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Requests a host to pull
|
// @Summary Requests a host to pull
|
||||||
// @Router /api/hosts/{hostid}/sync [post]
|
// @Router /api/hosts/{hostid}/sync [post]
|
||||||
// @Tags Hosts
|
// @Tags Hosts
|
||||||
|
@ -892,7 +986,7 @@ func syncHost(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
slog.Info("requested host pull", "user", r.Header.Get("user"), "host", host.ID)
|
slog.Info("requested host pull", "user", r.Header.Get("user"), "host", host.ID.String())
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,3 +1021,33 @@ func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx")
|
logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Fetches host peerinfo
|
||||||
|
// @Router /api/host/{hostid}/peer_info [get]
|
||||||
|
// @Tags Hosts
|
||||||
|
// @Security oauth
|
||||||
|
// @Param hostid path string true "Host ID"
|
||||||
|
// @Success 200 {object} models.SuccessResponse
|
||||||
|
// @Failure 500 {object} models.ErrorResponse
|
||||||
|
func getHostPeerInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hostId := mux.Vars(r)["hostid"]
|
||||||
|
var errorResponse = models.ErrorResponse{}
|
||||||
|
|
||||||
|
host, err := logic.GetHost(hostId)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to retrieve host", "error", err)
|
||||||
|
errorResponse.Code = http.StatusBadRequest
|
||||||
|
errorResponse.Message = err.Error()
|
||||||
|
logic.ReturnErrorResponse(w, r, errorResponse)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
peerInfo, err := logic.GetHostPeerInfo(host)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to retrieve host peerinfo", "error", err)
|
||||||
|
errorResponse.Code = http.StatusBadRequest
|
||||||
|
errorResponse.Message = err.Error()
|
||||||
|
logic.ReturnErrorResponse(w, r, errorResponse)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logic.ReturnSuccessResponseWithJson(w, r, peerInfo, "fetched host peer info")
|
||||||
|
}
|
||||||
|
|
|
@ -434,6 +434,7 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Tags Networks
|
// @Tags Networks
|
||||||
// @Security oauth
|
// @Security oauth
|
||||||
// @Param networkname path string true "Network name"
|
// @Param networkname path string true "Network name"
|
||||||
|
// @Param force query bool false "Force Delete"
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} models.SuccessResponse
|
// @Success 200 {object} models.SuccessResponse
|
||||||
// @Failure 400 {object} models.ErrorResponse
|
// @Failure 400 {object} models.ErrorResponse
|
||||||
|
@ -441,10 +442,18 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
|
||||||
func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
// Set header
|
// Set header
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
force := r.URL.Query().Get("force") == "true"
|
||||||
var params = mux.Vars(r)
|
var params = mux.Vars(r)
|
||||||
network := params["networkname"]
|
network := params["networkname"]
|
||||||
err := logic.DeleteNetwork(network)
|
doneCh := make(chan struct{}, 1)
|
||||||
|
networkNodes, err := logic.GetNetworkNodes(network)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"),
|
||||||
|
fmt.Sprintf("failed to get network nodes [%s]: %v", network, err))
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = logic.DeleteNetwork(network, force, doneCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errtype := "badrequest"
|
errtype := "badrequest"
|
||||||
if strings.Contains(err.Error(), "Node check failed") {
|
if strings.Contains(err.Error(), "Node check failed") {
|
||||||
|
@ -459,7 +468,22 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
go logic.DeleteDefaultNetworkPolicies(models.NetworkID(network))
|
go logic.DeleteDefaultNetworkPolicies(models.NetworkID(network))
|
||||||
//delete network from allocated ip map
|
//delete network from allocated ip map
|
||||||
go logic.RemoveNetworkFromAllocatedIpMap(network)
|
go logic.RemoveNetworkFromAllocatedIpMap(network)
|
||||||
|
go func() {
|
||||||
|
<-doneCh
|
||||||
|
mq.PublishPeerUpdate(true)
|
||||||
|
// send node update to clean up locally
|
||||||
|
for _, node := range networkNodes {
|
||||||
|
node := node
|
||||||
|
node.PendingDelete = true
|
||||||
|
node.Action = models.NODE_DELETE
|
||||||
|
if err := mq.NodeUpdate(&node); err != nil {
|
||||||
|
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if servercfg.IsDNSMode() {
|
||||||
|
logic.SetDNS()
|
||||||
|
}
|
||||||
|
}()
|
||||||
logger.Log(1, r.Header.Get("user"), "deleted network", network)
|
logger.Log(1, r.Header.Get("user"), "deleted network", network)
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode("success")
|
json.NewEncoder(w).Encode("success")
|
||||||
|
|
|
@ -75,11 +75,19 @@ func TestDeleteNetwork(t *testing.T) {
|
||||||
t.Run("NetworkwithNodes", func(t *testing.T) {
|
t.Run("NetworkwithNodes", func(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("DeleteExistingNetwork", func(t *testing.T) {
|
t.Run("DeleteExistingNetwork", func(t *testing.T) {
|
||||||
err := logic.DeleteNetwork("skynet")
|
doneCh := make(chan struct{}, 1)
|
||||||
|
err := logic.DeleteNetwork("skynet", false, doneCh)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
})
|
})
|
||||||
t.Run("NonExistentNetwork", func(t *testing.T) {
|
t.Run("NonExistentNetwork", func(t *testing.T) {
|
||||||
err := logic.DeleteNetwork("skynet")
|
doneCh := make(chan struct{}, 1)
|
||||||
|
err := logic.DeleteNetwork("skynet", false, doneCh)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
createNetv1("test")
|
||||||
|
t.Run("ForceDeleteNetwork", func(t *testing.T) {
|
||||||
|
doneCh := make(chan struct{}, 1)
|
||||||
|
err := logic.DeleteNetwork("test", true, doneCh)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -214,6 +222,15 @@ func createNet() {
|
||||||
logic.CreateNetwork(network)
|
logic.CreateNetwork(network)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func createNetv1(netId string) {
|
||||||
|
var network models.Network
|
||||||
|
network.NetID = netId
|
||||||
|
network.AddressRange = "100.0.0.1/24"
|
||||||
|
_, err := logic.GetNetwork(netId)
|
||||||
|
if err != nil {
|
||||||
|
logic.CreateNetwork(network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createNetDualStack() {
|
func createNetDualStack() {
|
||||||
var network models.Network
|
var network models.Network
|
||||||
|
|
|
@ -28,8 +28,8 @@ func nodeHandlers(r *mux.Router) {
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
|
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost)
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost)
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", logic.SecurityCheck(true, http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", logic.SecurityCheck(true, http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost)
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createGateway)))).Methods(http.MethodPost)
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteGateway))).Methods(http.MethodDelete)
|
||||||
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
|
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
|
||||||
r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
|
r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
|
||||||
}
|
}
|
||||||
|
@ -548,113 +548,6 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// == INGRESS ==
|
|
||||||
|
|
||||||
// @Summary Create an remote access gateway
|
|
||||||
// @Router /api/nodes/{network}/{nodeid}/createingress [post]
|
|
||||||
// @Tags Nodes
|
|
||||||
// @Security oauth2
|
|
||||||
// @Success 200 {object} models.ApiNode
|
|
||||||
// @Failure 500 {object} models.ErrorResponse
|
|
||||||
func createIngressGateway(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var params = mux.Vars(r)
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
nodeid := params["nodeid"]
|
|
||||||
netid := params["network"]
|
|
||||||
node, err := logic.ValidateParams(nodeid, netid)
|
|
||||||
if err != nil {
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var request models.IngressRequest
|
|
||||||
json.NewDecoder(r.Body).Decode(&request)
|
|
||||||
node, err = logic.CreateIngressGateway(netid, nodeid, request)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, r.Header.Get("user"),
|
|
||||||
fmt.Sprintf("failed to create ingress gateway on node [%s] on network [%s]: %v",
|
|
||||||
nodeid, netid, err))
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
apiNode := node.ConvertToAPINode()
|
|
||||||
logger.Log(
|
|
||||||
1,
|
|
||||||
r.Header.Get("user"),
|
|
||||||
"created ingress gateway on node",
|
|
||||||
nodeid,
|
|
||||||
"on network",
|
|
||||||
netid,
|
|
||||||
)
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
json.NewEncoder(w).Encode(apiNode)
|
|
||||||
go func() {
|
|
||||||
if err := mq.NodeUpdate(&node); err != nil {
|
|
||||||
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
|
|
||||||
}
|
|
||||||
mq.PublishPeerUpdate(false)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Summary Delete an remote access gateway
|
|
||||||
// @Router /api/nodes/{network}/{nodeid}/deleteingress [delete]
|
|
||||||
// @Tags Nodes
|
|
||||||
// @Security oauth2
|
|
||||||
// @Success 200 {object} models.ApiNode
|
|
||||||
// @Failure 500 {object} models.ErrorResponse
|
|
||||||
func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
var params = mux.Vars(r)
|
|
||||||
nodeid := params["nodeid"]
|
|
||||||
netid := params["network"]
|
|
||||||
node, err := logic.ValidateParams(nodeid, netid)
|
|
||||||
if err != nil {
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
node, removedClients, err := logic.DeleteIngressGateway(nodeid)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, r.Header.Get("user"),
|
|
||||||
fmt.Sprintf("failed to delete ingress gateway on node [%s] on network [%s]: %v",
|
|
||||||
nodeid, netid, err))
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
apiNode := node.ConvertToAPINode()
|
|
||||||
logger.Log(1, r.Header.Get("user"), "deleted ingress gateway", nodeid)
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
json.NewEncoder(w).Encode(apiNode)
|
|
||||||
|
|
||||||
if len(removedClients) > 0 {
|
|
||||||
host, err := logic.GetHost(node.HostID.String())
|
|
||||||
if err == nil {
|
|
||||||
allNodes, err := logic.GetAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
if err := mq.PublishSingleHostPeerUpdate(host, allNodes, nil, removedClients[:], false, nil); err != nil {
|
|
||||||
slog.Error("publishSingleHostUpdate", "host", host.Name, "error", err)
|
|
||||||
}
|
|
||||||
mq.PublishPeerUpdate(false)
|
|
||||||
if err := mq.NodeUpdate(&node); err != nil {
|
|
||||||
slog.Error(
|
|
||||||
"error publishing node update to node",
|
|
||||||
"node",
|
|
||||||
node.ID,
|
|
||||||
"error",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if servercfg.IsDNSMode() {
|
|
||||||
logic.SetDNS()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Summary Update an individual node
|
// @Summary Update an individual node
|
||||||
// @Router /api/nodes/{network}/{nodeid} [put]
|
// @Router /api/nodes/{network}/{nodeid} [put]
|
||||||
// @Tags Nodes
|
// @Tags Nodes
|
||||||
|
|
|
@ -71,6 +71,8 @@ const (
|
||||||
USER_INVITES_TABLE_NAME = "user_invites"
|
USER_INVITES_TABLE_NAME = "user_invites"
|
||||||
// TAG_TABLE_NAME - table for tags
|
// TAG_TABLE_NAME - table for tags
|
||||||
TAG_TABLE_NAME = "tags"
|
TAG_TABLE_NAME = "tags"
|
||||||
|
// PEER_ACK_TABLE - table for failover peer ack
|
||||||
|
PEER_ACK_TABLE = "peer_ack"
|
||||||
// == ERROR CONSTS ==
|
// == ERROR CONSTS ==
|
||||||
// NO_RECORD - no singular result found
|
// NO_RECORD - no singular result found
|
||||||
NO_RECORD = "no result found"
|
NO_RECORD = "no result found"
|
||||||
|
@ -158,6 +160,7 @@ func createTables() {
|
||||||
CreateTable(USER_INVITES_TABLE_NAME)
|
CreateTable(USER_INVITES_TABLE_NAME)
|
||||||
CreateTable(TAG_TABLE_NAME)
|
CreateTable(TAG_TABLE_NAME)
|
||||||
CreateTable(ACLS_TABLE_NAME)
|
CreateTable(ACLS_TABLE_NAME)
|
||||||
|
CreateTable(PEER_ACK_TABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTable(tableName string) error {
|
func CreateTable(tableName string) error {
|
||||||
|
|
10
go.mod
10
go.mod
|
@ -5,7 +5,7 @@ go 1.23
|
||||||
require (
|
require (
|
||||||
github.com/blang/semver v3.5.1+incompatible
|
github.com/blang/semver v3.5.1+incompatible
|
||||||
github.com/eclipse/paho.mqtt.golang v1.4.3
|
github.com/eclipse/paho.mqtt.golang v1.4.3
|
||||||
github.com/go-playground/validator/v10 v10.23.0
|
github.com/go-playground/validator/v10 v10.24.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1
|
github.com/golang-jwt/jwt/v4 v4.5.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/handlers v1.5.2
|
github.com/gorilla/handlers v1.5.2
|
||||||
|
@ -18,10 +18,10 @@ require (
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/txn2/txeh v1.5.5
|
github.com/txn2/txeh v1.5.5
|
||||||
go.uber.org/automaxprocs v1.6.0
|
go.uber.org/automaxprocs v1.6.0
|
||||||
golang.org/x/crypto v0.30.0
|
golang.org/x/crypto v0.32.0
|
||||||
golang.org/x/net v0.27.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/oauth2 v0.24.0
|
golang.org/x/oauth2 v0.24.0
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.21.0 // indirect
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
@ -50,7 +50,7 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute/metadata v0.3.0 // indirect
|
cloud.google.com/go/compute/metadata v0.3.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
|
20
go.sum
20
go.sum
|
@ -17,8 +17,8 @@ github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQ
|
||||||
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
|
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
|
||||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
@ -27,8 +27,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
|
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
|
||||||
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
@ -101,8 +101,8 @@ go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwE
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
|
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
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/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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
@ -112,8 +112,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
||||||
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -129,8 +129,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
|
|
@ -165,6 +165,7 @@ func storeAclInCache(a models.Acl) {
|
||||||
aclCacheMutex.Lock()
|
aclCacheMutex.Lock()
|
||||||
defer aclCacheMutex.Unlock()
|
defer aclCacheMutex.Unlock()
|
||||||
aclCacheMap[a.ID] = a
|
aclCacheMap[a.ID] = a
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeAclFromCache(a models.Acl) {
|
func removeAclFromCache(a models.Acl) {
|
||||||
|
@ -588,6 +589,7 @@ func IsPeerAllowed(node, peer models.Node, checkDefaultPolicy bool) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// list device policies
|
// list device policies
|
||||||
policies := listDevicePolicies(models.NetworkID(peer.Network))
|
policies := listDevicePolicies(models.NetworkID(peer.Network))
|
||||||
|
|
|
@ -461,9 +461,7 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) {
|
||||||
defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
|
defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
|
||||||
nodes, _ := GetNetworkNodes(node.Network)
|
nodes, _ := GetNetworkNodes(node.Network)
|
||||||
nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...)
|
nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...)
|
||||||
//fmt.Printf("=====> NODES: %+v \n\n", nodes)
|
|
||||||
userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network))
|
userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network))
|
||||||
//fmt.Printf("=====> USER NODES %+v \n\n", userNodes)
|
|
||||||
for _, userNodeI := range userNodes {
|
for _, userNodeI := range userNodes {
|
||||||
for _, peer := range nodes {
|
for _, peer := range nodes {
|
||||||
if peer.IsUserNode {
|
if peer.IsUserNode {
|
||||||
|
|
|
@ -141,14 +141,14 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
|
||||||
return models.Node{}, err
|
return models.Node{}, err
|
||||||
}
|
}
|
||||||
if node.IsRelayed {
|
if node.IsRelayed {
|
||||||
return models.Node{}, errors.New("ingress cannot be created on a relayed node")
|
return models.Node{}, errors.New("gateway cannot be created on a relayed node")
|
||||||
}
|
}
|
||||||
host, err := GetHost(node.HostID.String())
|
host, err := GetHost(node.HostID.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return models.Node{}, err
|
return models.Node{}, err
|
||||||
}
|
}
|
||||||
if host.OS != "linux" {
|
if host.OS != "linux" {
|
||||||
return models.Node{}, errors.New("ingress can only be created on linux based node")
|
return models.Node{}, errors.New("gateway can only be created on linux based node")
|
||||||
}
|
}
|
||||||
|
|
||||||
network, err := GetParentNetwork(netid)
|
network, err := GetParentNetwork(netid)
|
||||||
|
@ -156,12 +156,16 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
|
||||||
return models.Node{}, err
|
return models.Node{}, err
|
||||||
}
|
}
|
||||||
node.IsIngressGateway = true
|
node.IsIngressGateway = true
|
||||||
|
node.IsGw = true
|
||||||
if !servercfg.IsPro {
|
if !servercfg.IsPro {
|
||||||
node.IsInternetGateway = ingress.IsInternetGateway
|
node.IsInternetGateway = ingress.IsInternetGateway
|
||||||
}
|
}
|
||||||
node.IngressGatewayRange = network.AddressRange
|
node.IngressGatewayRange = network.AddressRange
|
||||||
node.IngressGatewayRange6 = network.AddressRange6
|
node.IngressGatewayRange6 = network.AddressRange6
|
||||||
node.IngressDNS = ingress.ExtclientDNS
|
node.IngressDNS = ingress.ExtclientDNS
|
||||||
|
if node.IsInternetGateway && node.IngressDNS == "" {
|
||||||
|
node.IngressDNS = "1.1.1.1"
|
||||||
|
}
|
||||||
node.IngressPersistentKeepalive = 20
|
node.IngressPersistentKeepalive = 20
|
||||||
if ingress.PersistentKeepalive != 0 {
|
if ingress.PersistentKeepalive != 0 {
|
||||||
node.IngressPersistentKeepalive = ingress.PersistentKeepalive
|
node.IngressPersistentKeepalive = ingress.PersistentKeepalive
|
||||||
|
|
|
@ -102,7 +102,7 @@ func RemoveIpFromAllocatedIpMap(networkName string, ip string) {
|
||||||
// AddNetworkToAllocatedIpMap - add network to allocated ip map when network is added
|
// AddNetworkToAllocatedIpMap - add network to allocated ip map when network is added
|
||||||
func AddNetworkToAllocatedIpMap(networkName string) {
|
func AddNetworkToAllocatedIpMap(networkName string) {
|
||||||
networkCacheMutex.Lock()
|
networkCacheMutex.Lock()
|
||||||
allocatedIpMap[networkName] = map[string]net.IP{}
|
allocatedIpMap[networkName] = make(map[string]net.IP)
|
||||||
networkCacheMutex.Unlock()
|
networkCacheMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,23 +171,8 @@ func GetNetworks() ([]models.Network, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNetwork - deletes a network
|
// DeleteNetwork - deletes a network
|
||||||
func DeleteNetwork(network string) error {
|
func DeleteNetwork(network string, force bool, done chan struct{}) error {
|
||||||
// remove ACL for network
|
|
||||||
err := nodeacls.DeleteACLContainer(nodeacls.NetworkID(network))
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(1, "failed to remove the node acls during network delete for network,", network)
|
|
||||||
}
|
|
||||||
// Delete default network enrollment key
|
|
||||||
keys, _ := GetAllEnrollmentKeys()
|
|
||||||
for _, key := range keys {
|
|
||||||
if key.Tags[0] == network {
|
|
||||||
if key.Default {
|
|
||||||
DeleteEnrollmentKey(key.Value, true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nodeCount, err := GetNetworkNonServerNodeCount(network)
|
nodeCount, err := GetNetworkNonServerNodeCount(network)
|
||||||
if nodeCount == 0 || database.IsEmptyRecord(err) {
|
if nodeCount == 0 || database.IsEmptyRecord(err) {
|
||||||
// delete server nodes first then db records
|
// delete server nodes first then db records
|
||||||
|
@ -200,7 +185,50 @@ func DeleteNetwork(network string) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("node check failed. All nodes must be deleted before deleting network")
|
|
||||||
|
// Remove All Nodes
|
||||||
|
go func() {
|
||||||
|
nodes, err := GetNetworkNodes(network)
|
||||||
|
if err == nil {
|
||||||
|
for _, node := range nodes {
|
||||||
|
node := node
|
||||||
|
host, err := GetHost(node.HostID.String())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
DissasociateNodeFromHost(&node, host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove ACL for network
|
||||||
|
err = nodeacls.DeleteACLContainer(nodeacls.NetworkID(network))
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(1, "failed to remove the node acls during network delete for network,", network)
|
||||||
|
}
|
||||||
|
// delete server nodes first then db records
|
||||||
|
err = database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if servercfg.CacheEnabled() {
|
||||||
|
deleteNetworkFromCache(network)
|
||||||
|
}
|
||||||
|
done <- struct{}{}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Delete default network enrollment key
|
||||||
|
keys, _ := GetAllEnrollmentKeys()
|
||||||
|
for _, key := range keys {
|
||||||
|
if key.Tags[0] == network {
|
||||||
|
if key.Default {
|
||||||
|
DeleteEnrollmentKey(key.Value, true)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateNetwork - creates a network in database
|
// CreateNetwork - creates a network in database
|
||||||
|
|
|
@ -40,9 +40,7 @@ func getNodeFromCache(nodeID string) (node models.Node, ok bool) {
|
||||||
}
|
}
|
||||||
func getNodesFromCache() (nodes []models.Node) {
|
func getNodesFromCache() (nodes []models.Node) {
|
||||||
nodeCacheMutex.RLock()
|
nodeCacheMutex.RLock()
|
||||||
for _, node := range nodesCacheMap {
|
nodes = slices.Collect(maps.Values(nodesCacheMap))
|
||||||
nodes = append(nodes, node)
|
|
||||||
}
|
|
||||||
nodeCacheMutex.RUnlock()
|
nodeCacheMutex.RUnlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -141,7 +139,7 @@ func GetNetworkNodesMemory(allNodes []models.Node, network string) []models.Node
|
||||||
defer nodeNetworkCacheMutex.Unlock()
|
defer nodeNetworkCacheMutex.Unlock()
|
||||||
return slices.Collect(maps.Values(networkNodes))
|
return slices.Collect(maps.Values(networkNodes))
|
||||||
}
|
}
|
||||||
var nodes = []models.Node{}
|
var nodes = make([]models.Node, 0, len(allNodes))
|
||||||
for i := range allNodes {
|
for i := range allNodes {
|
||||||
node := allNodes[i]
|
node := allNodes[i]
|
||||||
if node.Network == network {
|
if node.Network == network {
|
||||||
|
@ -239,7 +237,7 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("failed to update node " + currentNode.ID.String() + ", cannot change ID.")
|
return fmt.Errorf("failed to update node %s, cannot change ID", currentNode.ID.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNode - marks node for deletion (and adds to zombie list) if called by UI or deletes node if called by node
|
// DeleteNode - marks node for deletion (and adds to zombie list) if called by UI or deletes node if called by node
|
||||||
|
|
122
logic/peers.go
122
logic/peers.go
|
@ -59,6 +59,80 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetHostPeerInfo - fetches required peer info per network
|
||||||
|
func GetHostPeerInfo(host *models.Host) (models.HostPeerInfo, error) {
|
||||||
|
peerInfo := models.HostPeerInfo{
|
||||||
|
NetworkPeerIDs: make(map[models.NetworkID]models.PeerMap),
|
||||||
|
}
|
||||||
|
allNodes, err := GetAllNodes()
|
||||||
|
if err != nil {
|
||||||
|
return peerInfo, err
|
||||||
|
}
|
||||||
|
for _, nodeID := range host.Nodes {
|
||||||
|
nodeID := nodeID
|
||||||
|
node, err := GetNodeByID(nodeID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !node.Connected || node.PendingDelete || node.Action == models.NODE_DELETE {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
networkPeersInfo := make(models.PeerMap)
|
||||||
|
defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
|
||||||
|
|
||||||
|
currentPeers := GetNetworkNodesMemory(allNodes, node.Network)
|
||||||
|
for _, peer := range currentPeers {
|
||||||
|
peer := peer
|
||||||
|
if peer.ID.String() == node.ID.String() {
|
||||||
|
logger.Log(2, "peer update, skipping self")
|
||||||
|
// skip yourself
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
peerHost, err := GetHost(peer.HostID.String())
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(1, "no peer host", peer.HostID.String(), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var allowedToComm bool
|
||||||
|
if defaultDevicePolicy.Enabled {
|
||||||
|
allowedToComm = true
|
||||||
|
} else {
|
||||||
|
allowedToComm = IsPeerAllowed(node, peer, false)
|
||||||
|
}
|
||||||
|
if peer.Action != models.NODE_DELETE &&
|
||||||
|
!peer.PendingDelete &&
|
||||||
|
peer.Connected &&
|
||||||
|
nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), nodeacls.NodeID(peer.ID.String())) &&
|
||||||
|
(defaultDevicePolicy.Enabled || allowedToComm) {
|
||||||
|
|
||||||
|
networkPeersInfo[peerHost.PublicKey.String()] = models.IDandAddr{
|
||||||
|
ID: peer.ID.String(),
|
||||||
|
HostID: peerHost.ID.String(),
|
||||||
|
Address: peer.PrimaryAddress(),
|
||||||
|
Name: peerHost.Name,
|
||||||
|
Network: peer.Network,
|
||||||
|
ListenPort: peerHost.ListenPort,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var extPeerIDAndAddrs []models.IDandAddr
|
||||||
|
if node.IsIngressGateway {
|
||||||
|
_, extPeerIDAndAddrs, _, err = GetExtPeers(&node, &node)
|
||||||
|
if err == nil {
|
||||||
|
for _, extPeerIdAndAddr := range extPeerIDAndAddrs {
|
||||||
|
networkPeersInfo[extPeerIdAndAddr.ID] = extPeerIdAndAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peerInfo.NetworkPeerIDs[models.NetworkID(node.Network)] = networkPeersInfo
|
||||||
|
}
|
||||||
|
return peerInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetPeerUpdateForHost - gets the consolidated peer update for the host from all networks
|
// GetPeerUpdateForHost - gets the consolidated peer update for the host from all networks
|
||||||
func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.Node,
|
func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.Node,
|
||||||
deletedNode *models.Node, deletedClients []models.ExtClient) (models.HostPeerUpdate, error) {
|
deletedNode *models.Node, deletedClients []models.ExtClient) (models.HostPeerUpdate, error) {
|
||||||
|
@ -79,11 +153,11 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
|
||||||
IngressInfo: make(map[string]models.IngressInfo),
|
IngressInfo: make(map[string]models.IngressInfo),
|
||||||
AclRules: make(map[string]models.AclRule),
|
AclRules: make(map[string]models.AclRule),
|
||||||
},
|
},
|
||||||
PeerIDs: make(models.PeerMap, 0),
|
PeerIDs: make(models.PeerMap, 0),
|
||||||
Peers: []wgtypes.PeerConfig{},
|
Peers: []wgtypes.PeerConfig{},
|
||||||
NodePeers: []wgtypes.PeerConfig{},
|
NodePeers: []wgtypes.PeerConfig{},
|
||||||
HostNetworkInfo: models.HostInfoMap{},
|
HostNetworkInfo: models.HostInfoMap{},
|
||||||
EndpointDetection: servercfg.IsEndpointDetectionEnabled(),
|
ServerConfig: servercfg.ServerInfo,
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if !hostPeerUpdate.FwUpdate.AllowAll {
|
if !hostPeerUpdate.FwUpdate.AllowAll {
|
||||||
|
@ -229,21 +303,19 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
|
||||||
hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(node)...)
|
hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(node)...)
|
||||||
}
|
}
|
||||||
_, isFailOverPeer := node.FailOverPeers[peer.ID.String()]
|
_, isFailOverPeer := node.FailOverPeers[peer.ID.String()]
|
||||||
if servercfg.IsPro {
|
if (node.IsRelayed && node.RelayedBy != peer.ID.String()) ||
|
||||||
if (node.IsRelayed && node.RelayedBy != peer.ID.String()) ||
|
(peer.IsRelayed && peer.RelayedBy != node.ID.String()) || isFailOverPeer {
|
||||||
(peer.IsRelayed && peer.RelayedBy != node.ID.String()) || isFailOverPeer {
|
// if node is relayed and peer is not the relay, set remove to true
|
||||||
// if node is relayed and peer is not the relay, set remove to true
|
if _, ok := peerIndexMap[peerHost.PublicKey.String()]; ok {
|
||||||
if _, ok := peerIndexMap[peerHost.PublicKey.String()]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
peerConfig.Remove = true
|
|
||||||
hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig)
|
|
||||||
peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if node.IsRelayed && node.RelayedBy == peer.ID.String() {
|
peerConfig.Remove = true
|
||||||
hostPeerUpdate = SetDefaultGwForRelayedUpdate(node, peer, hostPeerUpdate)
|
hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig)
|
||||||
}
|
peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if node.IsRelayed && node.RelayedBy == peer.ID.String() {
|
||||||
|
hostPeerUpdate = SetDefaultGwForRelayedUpdate(node, peer, hostPeerUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
uselocal := false
|
uselocal := false
|
||||||
|
@ -297,15 +369,19 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
|
||||||
peerConfig.Endpoint.IP = peer.LocalAddress.IP
|
peerConfig.Endpoint.IP = peer.LocalAddress.IP
|
||||||
peerConfig.Endpoint.Port = peerHost.ListenPort
|
peerConfig.Endpoint.Port = peerHost.ListenPort
|
||||||
}
|
}
|
||||||
allowedips := GetAllowedIPs(&node, &peer, nil)
|
var allowedToComm bool
|
||||||
allowedToComm := IsPeerAllowed(node, peer, false)
|
if defaultDevicePolicy.Enabled {
|
||||||
|
allowedToComm = true
|
||||||
|
} else {
|
||||||
|
allowedToComm = IsPeerAllowed(node, peer, false)
|
||||||
|
}
|
||||||
if peer.Action != models.NODE_DELETE &&
|
if peer.Action != models.NODE_DELETE &&
|
||||||
!peer.PendingDelete &&
|
!peer.PendingDelete &&
|
||||||
peer.Connected &&
|
peer.Connected &&
|
||||||
nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), nodeacls.NodeID(peer.ID.String())) &&
|
nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), nodeacls.NodeID(peer.ID.String())) &&
|
||||||
(defaultDevicePolicy.Enabled || allowedToComm) &&
|
(defaultDevicePolicy.Enabled || allowedToComm) &&
|
||||||
(deletedNode == nil || (deletedNode != nil && peer.ID.String() != deletedNode.ID.String())) {
|
(deletedNode == nil || (deletedNode != nil && peer.ID.String() != deletedNode.ID.String())) {
|
||||||
peerConfig.AllowedIPs = allowedips // only append allowed IPs if valid connection
|
peerConfig.AllowedIPs = GetAllowedIPs(&node, &peer, nil) // only append allowed IPs if valid connection
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodePeer wgtypes.PeerConfig
|
var nodePeer wgtypes.PeerConfig
|
||||||
|
@ -466,10 +542,6 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hostPeerUpdate.ManageDNS = servercfg.GetManageDNS()
|
|
||||||
hostPeerUpdate.Stun = servercfg.IsStunEnabled()
|
|
||||||
hostPeerUpdate.StunServers = servercfg.GetStunServers()
|
|
||||||
return hostPeerUpdate, nil
|
return hostPeerUpdate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
238
logic/relay.go
238
logic/relay.go
|
@ -1,34 +1,246 @@
|
||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/gravitl/netmaker/logger"
|
||||||
|
"github.com/gravitl/netmaker/logic/acls/nodeacls"
|
||||||
"github.com/gravitl/netmaker/models"
|
"github.com/gravitl/netmaker/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
var GetRelays = func() ([]models.Node, error) {
|
// GetRelays - gets all the nodes that are relays
|
||||||
return []models.Node{}, nil
|
func GetRelays() ([]models.Node, error) {
|
||||||
|
nodes, err := GetAllNodes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
relays := make([]models.Node, 0)
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.IsRelay {
|
||||||
|
relays = append(relays, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return relays, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var RelayedAllowedIPs = func(peer, node *models.Node) []net.IPNet {
|
// CreateRelay - creates a relay
|
||||||
return []net.IPNet{}
|
func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error) {
|
||||||
|
var returnnodes []models.Node
|
||||||
|
|
||||||
|
node, err := GetNodeByID(relay.NodeID)
|
||||||
|
if err != nil {
|
||||||
|
return returnnodes, models.Node{}, err
|
||||||
|
}
|
||||||
|
host, err := GetHost(node.HostID.String())
|
||||||
|
if err != nil {
|
||||||
|
return returnnodes, models.Node{}, err
|
||||||
|
}
|
||||||
|
if host.OS != "linux" {
|
||||||
|
return returnnodes, models.Node{}, fmt.Errorf("only linux machines can be gateway nodes")
|
||||||
|
}
|
||||||
|
err = ValidateRelay(relay, false)
|
||||||
|
if err != nil {
|
||||||
|
return returnnodes, models.Node{}, err
|
||||||
|
}
|
||||||
|
node.IsRelay = true
|
||||||
|
node.IsGw = true
|
||||||
|
node.RelayedNodes = relay.RelayedNodes
|
||||||
|
node.SetLastModified()
|
||||||
|
err = UpsertNode(&node)
|
||||||
|
if err != nil {
|
||||||
|
return returnnodes, node, err
|
||||||
|
}
|
||||||
|
returnnodes = SetRelayedNodes(true, relay.NodeID, relay.RelayedNodes)
|
||||||
|
return returnnodes, node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var GetAllowedIpsForRelayed = func(relayed, relay *models.Node) []net.IPNet {
|
// SetRelayedNodes- sets and saves node as relayed
|
||||||
return []net.IPNet{}
|
func SetRelayedNodes(setRelayed bool, relay string, relayed []string) []models.Node {
|
||||||
|
var returnnodes []models.Node
|
||||||
|
for _, id := range relayed {
|
||||||
|
node, err := GetNodeByID(id)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, "setRelayedNodes.GetNodebyID", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node.IsRelayed = setRelayed
|
||||||
|
if setRelayed {
|
||||||
|
node.RelayedBy = relay
|
||||||
|
} else {
|
||||||
|
node.RelayedBy = ""
|
||||||
|
}
|
||||||
|
node.SetLastModified()
|
||||||
|
if err := UpsertNode(&node); err != nil {
|
||||||
|
logger.Log(0, "setRelayedNodes.Insert", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
returnnodes = append(returnnodes, node)
|
||||||
|
}
|
||||||
|
return returnnodes
|
||||||
}
|
}
|
||||||
|
|
||||||
var UpdateRelayed = func(currentNode, newNode *models.Node) {
|
// func GetRelayedNodes(relayNode *models.Node) (models.Node, error) {
|
||||||
|
// var returnnodes []models.Node
|
||||||
|
// networkNodes, err := GetNetworkNodes(relayNode.Network)
|
||||||
|
// if err != nil {
|
||||||
|
// return returnnodes, err
|
||||||
|
// }
|
||||||
|
// for _, node := range networkNodes {
|
||||||
|
// for _, addr := range relayNode.RelayAddrs {
|
||||||
|
// if addr == node.Address.IP.String() || addr == node.Address6.IP.String() {
|
||||||
|
// returnnodes = append(returnnodes, node)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return returnnodes, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ValidateRelay - checks if relay is valid
|
||||||
|
func ValidateRelay(relay models.RelayRequest, update bool) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
node, err := GetNodeByID(relay.NodeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !update && node.IsRelay {
|
||||||
|
return errors.New("node is already acting as a relay")
|
||||||
|
}
|
||||||
|
for _, relayedNodeID := range relay.RelayedNodes {
|
||||||
|
relayedNode, err := GetNodeByID(relayedNodeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if relayedNode.IsIngressGateway {
|
||||||
|
return errors.New("cannot relay an ingress gateway (" + relayedNodeID + ")")
|
||||||
|
}
|
||||||
|
if relayedNode.IsInternetGateway {
|
||||||
|
return errors.New("cannot relay an internet gateway (" + relayedNodeID + ")")
|
||||||
|
}
|
||||||
|
if relayedNode.InternetGwID != "" && relayedNode.InternetGwID != relay.NodeID {
|
||||||
|
return errors.New("cannot relay an internet client (" + relayedNodeID + ")")
|
||||||
|
}
|
||||||
|
if relayedNode.IsFailOver {
|
||||||
|
return errors.New("cannot relay a failOver (" + relayedNodeID + ")")
|
||||||
|
}
|
||||||
|
if relayedNode.FailedOverBy != uuid.Nil {
|
||||||
|
ResetFailedOverPeer(&relayedNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var SetRelayedNodes = func(setRelayed bool, relay string, relayed []string) []models.Node {
|
// UpdateRelayNodes - updates relay nodes
|
||||||
return []models.Node{}
|
func updateRelayNodes(relay string, oldNodes []string, newNodes []string) []models.Node {
|
||||||
|
_ = SetRelayedNodes(false, relay, oldNodes)
|
||||||
|
return SetRelayedNodes(true, relay, newNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RelayUpdates = func(currentNode, newNode *models.Node) bool {
|
func RelayUpdates(currentNode, newNode *models.Node) bool {
|
||||||
return false
|
relayUpdates := false
|
||||||
|
if newNode.IsRelay {
|
||||||
|
if len(newNode.RelayedNodes) != len(currentNode.RelayedNodes) {
|
||||||
|
relayUpdates = true
|
||||||
|
} else {
|
||||||
|
for i, node := range newNode.RelayedNodes {
|
||||||
|
if node != currentNode.RelayedNodes[i] {
|
||||||
|
relayUpdates = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return relayUpdates
|
||||||
}
|
}
|
||||||
|
|
||||||
var ValidateRelay = func(relay models.RelayRequest, update bool) error {
|
// UpdateRelayed - updates a relay's relayed nodes, and sends updates to the relayed nodes over MQ
|
||||||
return nil
|
func UpdateRelayed(currentNode, newNode *models.Node) {
|
||||||
|
updatenodes := updateRelayNodes(currentNode.ID.String(), currentNode.RelayedNodes, newNode.RelayedNodes)
|
||||||
|
if len(updatenodes) > 0 {
|
||||||
|
for _, relayedNode := range updatenodes {
|
||||||
|
node := relayedNode
|
||||||
|
ResetFailedOverPeer(&node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRelay - deletes a relay
|
||||||
|
func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) {
|
||||||
|
var returnnodes []models.Node
|
||||||
|
node, err := GetNodeByID(nodeid)
|
||||||
|
if err != nil {
|
||||||
|
return returnnodes, models.Node{}, err
|
||||||
|
}
|
||||||
|
returnnodes = SetRelayedNodes(false, nodeid, node.RelayedNodes)
|
||||||
|
node.IsRelay = false
|
||||||
|
node.RelayedNodes = []string{}
|
||||||
|
node.SetLastModified()
|
||||||
|
if err = UpsertNode(&node); err != nil {
|
||||||
|
return returnnodes, models.Node{}, err
|
||||||
|
}
|
||||||
|
return returnnodes, node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RelayedAllowedIPs(peer, node *models.Node) []net.IPNet {
|
||||||
|
var allowedIPs = []net.IPNet{}
|
||||||
|
for _, relayedNodeID := range peer.RelayedNodes {
|
||||||
|
if node.ID.String() == relayedNodeID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
relayedNode, err := GetNodeByID(relayedNodeID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
allowed := getRelayedAddresses(relayedNodeID)
|
||||||
|
if relayedNode.IsEgressGateway {
|
||||||
|
allowed = append(allowed, GetEgressIPs(&relayedNode)...)
|
||||||
|
}
|
||||||
|
allowedIPs = append(allowedIPs, allowed...)
|
||||||
|
}
|
||||||
|
return allowedIPs
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllowedIpsForRelayed - returns the peerConfig for a node relayed by relay
|
||||||
|
func GetAllowedIpsForRelayed(relayed, relay *models.Node) (allowedIPs []net.IPNet) {
|
||||||
|
if relayed.RelayedBy != relay.ID.String() {
|
||||||
|
logger.Log(0, "RelayedByRelay called with invalid parameters")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if relay.InternetGwID != "" {
|
||||||
|
return GetAllowedIpForInetNodeClient(relayed, relay)
|
||||||
|
}
|
||||||
|
peers, err := GetNetworkNodes(relay.Network)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, "error getting network clients", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, peer := range peers {
|
||||||
|
if peer.ID == relayed.ID || peer.ID == relay.ID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if nodeacls.AreNodesAllowed(nodeacls.NetworkID(relayed.Network), nodeacls.NodeID(relayed.ID.String()), nodeacls.NodeID(peer.ID.String())) {
|
||||||
|
allowedIPs = append(allowedIPs, GetAllowedIPs(relayed, &peer, nil)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRelayedAddresses(id string) []net.IPNet {
|
||||||
|
addrs := []net.IPNet{}
|
||||||
|
node, err := GetNodeByID(id)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, "getRelayedAddresses: "+err.Error())
|
||||||
|
return addrs
|
||||||
|
}
|
||||||
|
if node.Address.IP != nil {
|
||||||
|
node.Address.Mask = net.CIDRMask(32, 32)
|
||||||
|
addrs = append(addrs, node.Address)
|
||||||
|
}
|
||||||
|
if node.Address6.IP != nil {
|
||||||
|
node.Address6.Mask = net.CIDRMask(128, 128)
|
||||||
|
addrs = append(addrs, node.Address6)
|
||||||
|
}
|
||||||
|
return addrs
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ func getNodeStatus(node *models.Node, t bool) {
|
||||||
node.Status = models.OnlineSt
|
node.Status = models.OnlineSt
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !node.Connected {
|
||||||
|
node.Status = models.Disconnected
|
||||||
|
return
|
||||||
|
}
|
||||||
if time.Since(node.LastCheckIn) > time.Minute*10 {
|
if time.Since(node.LastCheckIn) > time.Minute*10 {
|
||||||
node.Status = models.OfflineSt
|
node.Status = models.OfflineSt
|
||||||
return
|
return
|
||||||
|
|
|
@ -259,7 +259,7 @@ func CheckIDSyntax(id string) error {
|
||||||
if len(id) < 3 {
|
if len(id) < 3 {
|
||||||
return errors.New("name should have min 3 characters")
|
return errors.New("name should have min 3 characters")
|
||||||
}
|
}
|
||||||
reg, err := regexp.Compile("^[a-zA-Z-]+$")
|
reg, err := regexp.Compile("^[a-zA-Z0-9- ]+$")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -91,6 +92,30 @@ func StringSliceContains(slice []string, item string) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
func SetVerbosity(logLevel int) {
|
||||||
|
var level slog.Level
|
||||||
|
switch logLevel {
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
level = slog.LevelInfo
|
||||||
|
case 1:
|
||||||
|
level = slog.LevelError
|
||||||
|
case 2:
|
||||||
|
level = slog.LevelWarn
|
||||||
|
case 3:
|
||||||
|
level = slog.LevelDebug
|
||||||
|
|
||||||
|
default:
|
||||||
|
level = slog.LevelInfo
|
||||||
|
}
|
||||||
|
// Create the logger with the chosen level
|
||||||
|
handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
|
||||||
|
Level: level,
|
||||||
|
})
|
||||||
|
logger := slog.New(handler)
|
||||||
|
slog.SetDefault(logger)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// NormalizeCIDR - returns the first address of CIDR
|
// NormalizeCIDR - returns the first address of CIDR
|
||||||
func NormalizeCIDR(address string) (string, error) {
|
func NormalizeCIDR(address string) (string, error) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ func Run() {
|
||||||
updateHosts()
|
updateHosts()
|
||||||
updateNodes()
|
updateNodes()
|
||||||
updateAcls()
|
updateAcls()
|
||||||
|
migrateToGws()
|
||||||
}
|
}
|
||||||
|
|
||||||
func assignSuperAdmin() {
|
func assignSuperAdmin() {
|
||||||
|
@ -441,3 +442,18 @@ func createDefaultTagsAndPolicies() {
|
||||||
}
|
}
|
||||||
logic.MigrateAclPolicies()
|
logic.MigrateAclPolicies()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func migrateToGws() {
|
||||||
|
nodes, err := logic.GetAllNodes()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.IsIngressGateway || node.IsRelay {
|
||||||
|
node.IsGw = true
|
||||||
|
node.IsIngressGateway = true
|
||||||
|
node.IsRelay = true
|
||||||
|
logic.UpsertNode(&node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
9
models/gateway.go
Normal file
9
models/gateway.go
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
type CreateGwReq struct {
|
||||||
|
IngressRequest
|
||||||
|
RelayRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteGw struct {
|
||||||
|
}
|
|
@ -98,6 +98,8 @@ type HostMqAction string
|
||||||
const (
|
const (
|
||||||
// Upgrade - const to request host to update it's client
|
// Upgrade - const to request host to update it's client
|
||||||
Upgrade HostMqAction = "UPGRADE"
|
Upgrade HostMqAction = "UPGRADE"
|
||||||
|
// ForceUpgrade - const for forcing a host to upgrade its client binary
|
||||||
|
ForceUpgrade HostMqAction = "FORCE_UPGRADE"
|
||||||
// SignalHost - const for host signal action
|
// SignalHost - const for host signal action
|
||||||
SignalHost HostMqAction = "SIGNAL_HOST"
|
SignalHost HostMqAction = "SIGNAL_HOST"
|
||||||
// UpdateHost - constant for host update action
|
// UpdateHost - constant for host update action
|
||||||
|
|
|
@ -48,6 +48,7 @@ type HostNetworkInfo struct {
|
||||||
ListenPort int `json:"listen_port" yaml:"listen_port"`
|
ListenPort int `json:"listen_port" yaml:"listen_port"`
|
||||||
IsStaticPort bool `json:"is_static_port"`
|
IsStaticPort bool `json:"is_static_port"`
|
||||||
IsStatic bool `json:"is_static"`
|
IsStatic bool `json:"is_static"`
|
||||||
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerMap - peer map for ids and addresses in metrics
|
// PeerMap - peer map for ids and addresses in metrics
|
||||||
|
|
|
@ -6,27 +6,35 @@ import (
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type HostPeerInfo struct {
|
||||||
|
NetworkPeerIDs map[NetworkID]PeerMap `json:"network_peers"`
|
||||||
|
}
|
||||||
|
|
||||||
// HostPeerUpdate - struct for host peer updates
|
// HostPeerUpdate - struct for host peer updates
|
||||||
type HostPeerUpdate struct {
|
type HostPeerUpdate struct {
|
||||||
Host Host `json:"host" bson:"host" yaml:"host"`
|
Host Host `json:"host"`
|
||||||
ChangeDefaultGw bool `json:"change_default_gw"`
|
ChangeDefaultGw bool `json:"change_default_gw"`
|
||||||
DefaultGwIp net.IP `json:"default_gw_ip"`
|
DefaultGwIp net.IP `json:"default_gw_ip"`
|
||||||
IsInternetGw bool `json:"is_inet_gw"`
|
IsInternetGw bool `json:"is_inet_gw"`
|
||||||
NodeAddrs []net.IPNet `json:"nodes_addrs" yaml:"nodes_addrs"`
|
NodeAddrs []net.IPNet `json:"nodes_addrs"`
|
||||||
Server string `json:"server" bson:"server" yaml:"server"`
|
Server string `json:"server"`
|
||||||
ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
|
ServerVersion string `json:"serverversion"`
|
||||||
ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
|
ServerAddrs []ServerAddr `json:"serveraddrs"`
|
||||||
|
NodePeers []wgtypes.PeerConfig `json:"node_peers"`
|
||||||
|
Peers []wgtypes.PeerConfig `json:"host_peers"`
|
||||||
|
PeerIDs PeerMap `json:"peerids"`
|
||||||
|
HostNetworkInfo HostInfoMap `json:"host_network_info,omitempty"`
|
||||||
|
EgressRoutes []EgressNetworkRoutes `json:"egress_network_routes"`
|
||||||
|
FwUpdate FwUpdate `json:"fw_update"`
|
||||||
|
ReplacePeers bool `json:"replace_peers"`
|
||||||
|
ServerConfig
|
||||||
|
OldPeerUpdateFields
|
||||||
|
}
|
||||||
|
|
||||||
|
type OldPeerUpdateFields struct {
|
||||||
NodePeers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
|
NodePeers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
|
||||||
Peers []wgtypes.PeerConfig
|
OldPeers []wgtypes.PeerConfig `json:"Peers"`
|
||||||
PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
|
EndpointDetection bool `json:"endpoint_detection"`
|
||||||
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"`
|
|
||||||
ReplacePeers bool `json:"replace_peers"`
|
|
||||||
EndpointDetection bool `json:"endpoint_detection"`
|
|
||||||
ManageDNS bool `yaml:"manage_dns"`
|
|
||||||
Stun bool `yaml:"stun"`
|
|
||||||
StunServers string `yaml:"stun_servers"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FwRule struct {
|
type FwRule struct {
|
||||||
|
|
|
@ -42,9 +42,10 @@ func (network *Network) SetNetworkLastModified() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network.SetDefaults - sets default values for a network struct
|
// Network.SetDefaults - sets default values for a network struct
|
||||||
func (network *Network) SetDefaults() {
|
func (network *Network) SetDefaults() (upsert bool) {
|
||||||
if network.DefaultUDPHolePunch == "" {
|
if network.DefaultUDPHolePunch == "" {
|
||||||
network.DefaultUDPHolePunch = "no"
|
network.DefaultUDPHolePunch = "no"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.DefaultInterface == "" {
|
if network.DefaultInterface == "" {
|
||||||
if len(network.NetID) < 33 {
|
if len(network.NetID) < 33 {
|
||||||
|
@ -52,35 +53,45 @@ func (network *Network) SetDefaults() {
|
||||||
} else {
|
} else {
|
||||||
network.DefaultInterface = network.NetID
|
network.DefaultInterface = network.NetID
|
||||||
}
|
}
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.DefaultListenPort == 0 {
|
if network.DefaultListenPort == 0 {
|
||||||
network.DefaultListenPort = 51821
|
network.DefaultListenPort = 51821
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.NodeLimit == 0 {
|
if network.NodeLimit == 0 {
|
||||||
network.NodeLimit = 999999999
|
network.NodeLimit = 999999999
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.DefaultKeepalive == 0 {
|
if network.DefaultKeepalive == 0 {
|
||||||
network.DefaultKeepalive = 20
|
network.DefaultKeepalive = 20
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
if network.AllowManualSignUp == "" {
|
if network.AllowManualSignUp == "" {
|
||||||
network.AllowManualSignUp = "no"
|
network.AllowManualSignUp = "no"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.IsIPv4 == "" {
|
if network.IsIPv4 == "" {
|
||||||
network.IsIPv4 = "yes"
|
network.IsIPv4 = "yes"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.IsIPv6 == "" {
|
if network.IsIPv6 == "" {
|
||||||
network.IsIPv6 = "no"
|
network.IsIPv6 = "no"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.DefaultMTU == 0 {
|
if network.DefaultMTU == 0 {
|
||||||
network.DefaultMTU = 1280
|
network.DefaultMTU = 1280
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if network.DefaultACL == "" {
|
if network.DefaultACL == "" {
|
||||||
network.DefaultACL = "yes"
|
network.DefaultACL = "yes"
|
||||||
|
upsert = true
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (network *Network) GetNetworkNetworkCIDR4() *net.IPNet {
|
func (network *Network) GetNetworkNetworkCIDR4() *net.IPNet {
|
||||||
|
|
|
@ -14,11 +14,12 @@ import (
|
||||||
type NodeStatus string
|
type NodeStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OnlineSt NodeStatus = "online"
|
OnlineSt NodeStatus = "online"
|
||||||
OfflineSt NodeStatus = "offline"
|
OfflineSt NodeStatus = "offline"
|
||||||
WarningSt NodeStatus = "warning"
|
WarningSt NodeStatus = "warning"
|
||||||
ErrorSt NodeStatus = "error"
|
ErrorSt NodeStatus = "error"
|
||||||
UnKnown NodeStatus = "unknown"
|
UnKnown NodeStatus = "unknown"
|
||||||
|
Disconnected NodeStatus = "disconnected"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LastCheckInThreshold - if node's checkin more than this threshold,then node is declared as offline
|
// LastCheckInThreshold - if node's checkin more than this threshold,then node is declared as offline
|
||||||
|
@ -77,11 +78,12 @@ type CommonNode struct {
|
||||||
Action string `json:"action" yaml:"action"`
|
Action string `json:"action" yaml:"action"`
|
||||||
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
|
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
|
||||||
IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"`
|
IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"`
|
||||||
EgressGatewayRanges []string `json:"egressgatewayranges" yaml:"egressgatewayranges" bson:"egressgatewayranges"`
|
EgressGatewayRanges []string `json:"egressgatewayranges" yaml:"egressgatewayranges"`
|
||||||
IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"`
|
IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"`
|
||||||
IsRelayed bool `json:"isrelayed" yaml:"isrelayed" bson:"isrelayed"`
|
IsRelayed bool `json:"isrelayed" yaml:"isrelayed"`
|
||||||
RelayedBy string `json:"relayedby" yaml:"relayedby" bson:"relayedby"`
|
RelayedBy string `json:"relayedby" yaml:"relayedby"`
|
||||||
IsRelay bool `json:"isrelay" yaml:"isrelay" bson:"isrelay"`
|
IsRelay bool `json:"isrelay" yaml:"isrelay"`
|
||||||
|
IsGw bool `json:"is_gw" yaml:"is_gw"`
|
||||||
RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"`
|
RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"`
|
||||||
IngressDNS string `json:"ingressdns" yaml:"ingressdns"`
|
IngressDNS string `json:"ingressdns" yaml:"ingressdns"`
|
||||||
DNSOn bool `json:"dnson" yaml:"dnson"`
|
DNSOn bool `json:"dnson" yaml:"dnson"`
|
||||||
|
|
|
@ -252,24 +252,26 @@ type NodeJoinResponse struct {
|
||||||
|
|
||||||
// ServerConfig - struct for dealing with the server information for a netclient
|
// ServerConfig - struct for dealing with the server information for a netclient
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
CoreDNSAddr string `yaml:"corednsaddr"`
|
CoreDNSAddr string `yaml:"corednsaddr"`
|
||||||
API string `yaml:"api"`
|
API string `yaml:"api"`
|
||||||
APIPort string `yaml:"apiport"`
|
APIPort string `yaml:"apiport"`
|
||||||
DNSMode string `yaml:"dnsmode"`
|
DNSMode string `yaml:"dnsmode"`
|
||||||
Version string `yaml:"version"`
|
Version string `yaml:"version"`
|
||||||
MQPort string `yaml:"mqport"`
|
MQPort string `yaml:"mqport"`
|
||||||
MQUserName string `yaml:"mq_username"`
|
MQUserName string `yaml:"mq_username"`
|
||||||
MQPassword string `yaml:"mq_password"`
|
MQPassword string `yaml:"mq_password"`
|
||||||
BrokerType string `yaml:"broker_type"`
|
BrokerType string `yaml:"broker_type"`
|
||||||
Server string `yaml:"server"`
|
Server string `yaml:"server"`
|
||||||
Broker string `yaml:"broker"`
|
Broker string `yaml:"broker"`
|
||||||
IsPro bool `yaml:"isee" json:"Is_EE"`
|
IsPro bool `yaml:"isee" json:"Is_EE"`
|
||||||
TrafficKey []byte `yaml:"traffickey"`
|
TrafficKey []byte `yaml:"traffickey"`
|
||||||
MetricInterval string `yaml:"metric_interval"`
|
MetricInterval string `yaml:"metric_interval"`
|
||||||
ManageDNS bool `yaml:"manage_dns"`
|
MetricsPort int `yaml:"metrics_port"`
|
||||||
Stun bool `yaml:"stun"`
|
ManageDNS bool `yaml:"manage_dns"`
|
||||||
StunServers string `yaml:"stun_servers"`
|
Stun bool `yaml:"stun"`
|
||||||
DefaultDomain string `yaml:"default_domain"`
|
StunServers string `yaml:"stun_servers"`
|
||||||
|
EndpointDetection bool `yaml:"endpoint_detection"`
|
||||||
|
DefaultDomain string `yaml:"default_domain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// User.NameInCharset - returns if name is in charset below or not
|
// User.NameInCharset - returns if name is in charset below or not
|
||||||
|
|
|
@ -280,6 +280,7 @@ func HandleHostCheckin(h, currentHost *models.Host) bool {
|
||||||
(h.ListenPort != 0 && h.ListenPort != currentHost.ListenPort) ||
|
(h.ListenPort != 0 && h.ListenPort != currentHost.ListenPort) ||
|
||||||
(h.WgPublicListenPort != 0 && h.WgPublicListenPort != currentHost.WgPublicListenPort) || (!h.EndpointIPv6.Equal(currentHost.EndpointIPv6))
|
(h.WgPublicListenPort != 0 && h.WgPublicListenPort != currentHost.WgPublicListenPort) || (!h.EndpointIPv6.Equal(currentHost.EndpointIPv6))
|
||||||
if ifaceDelta { // only save if something changes
|
if ifaceDelta { // only save if something changes
|
||||||
|
|
||||||
currentHost.EndpointIP = h.EndpointIP
|
currentHost.EndpointIP = h.EndpointIP
|
||||||
currentHost.EndpointIPv6 = h.EndpointIPv6
|
currentHost.EndpointIPv6 = h.EndpointIPv6
|
||||||
currentHost.Interfaces = h.Interfaces
|
currentHost.Interfaces = h.Interfaces
|
||||||
|
|
|
@ -17,7 +17,6 @@ import (
|
||||||
|
|
||||||
// PublishPeerUpdate --- determines and publishes a peer update to all the hosts
|
// PublishPeerUpdate --- determines and publishes a peer update to all the hosts
|
||||||
func PublishPeerUpdate(replacePeers bool) error {
|
func PublishPeerUpdate(replacePeers bool) error {
|
||||||
|
|
||||||
if !servercfg.IsMessageQueueBackend() {
|
if !servercfg.IsMessageQueueBackend() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -114,6 +113,11 @@ func PublishSingleHostPeerUpdate(host *models.Host, allNodes []models.Node, dele
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
peerUpdate.OldPeerUpdateFields = models.OldPeerUpdateFields{
|
||||||
|
NodePeers: peerUpdate.NodePeers,
|
||||||
|
OldPeers: peerUpdate.Peers,
|
||||||
|
EndpointDetection: peerUpdate.ServerConfig.EndpointDetection,
|
||||||
|
}
|
||||||
peerUpdate.ReplacePeers = replacePeers
|
peerUpdate.ReplacePeers = replacePeers
|
||||||
data, err := json.Marshal(&peerUpdate)
|
data, err := json.Marshal(&peerUpdate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
|
|
||||||
// FailOverHandlers - handlers for FailOver
|
// FailOverHandlers - handlers for FailOver
|
||||||
func FailOverHandlers(r *mux.Router) {
|
func FailOverHandlers(r *mux.Router) {
|
||||||
r.HandleFunc("/api/v1/node/{nodeid}/failover", http.HandlerFunc(getfailOver)).
|
r.HandleFunc("/api/v1/node/{nodeid}/failover", controller.Authorize(true, false, "host", http.HandlerFunc(getfailOver))).
|
||||||
Methods(http.MethodGet)
|
Methods(http.MethodGet)
|
||||||
r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(createfailOver))).
|
r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(createfailOver))).
|
||||||
Methods(http.MethodPost)
|
Methods(http.MethodPost)
|
||||||
|
@ -29,6 +29,8 @@ func FailOverHandlers(r *mux.Router) {
|
||||||
Methods(http.MethodPost)
|
Methods(http.MethodPost)
|
||||||
r.HandleFunc("/api/v1/node/{nodeid}/failover_me", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).
|
r.HandleFunc("/api/v1/node/{nodeid}/failover_me", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).
|
||||||
Methods(http.MethodPost)
|
Methods(http.MethodPost)
|
||||||
|
r.HandleFunc("/api/v1/node/{nodeid}/failover_check", controller.Authorize(true, false, "host", http.HandlerFunc(checkfailOverCtx))).
|
||||||
|
Methods(http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Get failover node
|
// @Summary Get failover node
|
||||||
|
@ -44,7 +46,6 @@ func getfailOver(w http.ResponseWriter, r *http.Request) {
|
||||||
// confirm host exists
|
// confirm host exists
|
||||||
node, err := logic.GetNodeByID(nodeid)
|
node, err := logic.GetNodeByID(nodeid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("failed to get node:", "node", nodeid, "error", err.Error())
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -140,6 +141,7 @@ func deletefailOver(w http.ResponseWriter, r *http.Request) {
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
proLogic.RemoveFailOverFromCache(node.Network)
|
||||||
go func() {
|
go func() {
|
||||||
proLogic.ResetFailOver(&node)
|
proLogic.ResetFailOver(&node)
|
||||||
mq.PublishPeerUpdate(false)
|
mq.PublishPeerUpdate(false)
|
||||||
|
@ -265,10 +267,9 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = proLogic.SetFailOverCtx(failOverNode, node, peerNode)
|
err = proLogic.SetFailOverCtx(failOverNode, node, peerNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("failed to create failover", "id", node.ID.String(),
|
slog.Debug("failed to create failover", "id", node.ID.String(),
|
||||||
"network", node.Network, "error", err)
|
"network", node.Network, "error", err)
|
||||||
logic.ReturnErrorResponse(
|
logic.ReturnErrorResponse(
|
||||||
w,
|
w,
|
||||||
|
@ -293,3 +294,135 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
logic.ReturnSuccessResponse(w, r, "relayed successfully")
|
logic.ReturnSuccessResponse(w, r, "relayed successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary checkfailOverCtx
|
||||||
|
// @Router /api/v1/node/{nodeid}/failover_check [get]
|
||||||
|
// @Tags PRO
|
||||||
|
// @Param nodeid path string true "Node ID"
|
||||||
|
// @Accept json
|
||||||
|
// @Param body body models.FailOverMeReq true "Failover request"
|
||||||
|
// @Success 200 {object} models.SuccessResponse
|
||||||
|
// @Failure 400 {object} models.ErrorResponse
|
||||||
|
// @Failure 500 {object} models.ErrorResponse
|
||||||
|
func checkfailOverCtx(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var params = mux.Vars(r)
|
||||||
|
nodeid := params["nodeid"]
|
||||||
|
// confirm host exists
|
||||||
|
node, err := logic.GetNodeByID(nodeid)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"), "failed to get node:", err.Error())
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
host, err := logic.GetHost(node.HostID.String())
|
||||||
|
if err != nil {
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
failOverNode, exists := proLogic.FailOverExists(node.Network)
|
||||||
|
if !exists {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(
|
||||||
|
fmt.Errorf("req-from: %s, failover node doesn't exist in the network", host.Name),
|
||||||
|
"badrequest",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var failOverReq models.FailOverMeReq
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&failOverReq)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
peerNode, err := logic.GetNodeByID(failOverReq.NodeID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("peer not found: ", "nodeid", failOverReq.NodeID, "error", err)
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(errors.New("peer not found"), "badrequest"),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if peerNode.IsFailOver {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(errors.New("peer is acting as failover"), "badrequest"),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if node.IsFailOver {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(errors.New("node is acting as failover"), "badrequest"),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if peerNode.IsFailOver {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(errors.New("peer is acting as failover"), "badrequest"),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if node.IsRelayed && node.RelayedBy == peerNode.ID.String() {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(errors.New("node is relayed by peer node"), "badrequest"),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if node.IsRelay && peerNode.RelayedBy == node.ID.String() {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(errors.New("node acting as relay for the peer node"), "badrequest"),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(
|
||||||
|
errors.New("node acting as internet gw for the peer node"),
|
||||||
|
"badrequest",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() {
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(
|
||||||
|
errors.New("node using a internet gw by the peer node"),
|
||||||
|
"badrequest",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = proLogic.CheckFailOverCtx(failOverNode, node, peerNode)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failover ctx cannot be set ", "error", err)
|
||||||
|
logic.ReturnErrorResponse(
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
logic.FormatError(fmt.Errorf("failover ctx cannot be set: %v", err), "internal"),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
logic.ReturnSuccessResponse(w, r, "failover can be set")
|
||||||
|
}
|
||||||
|
|
|
@ -84,6 +84,9 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if node.IsGw && node.IngressDNS == "" {
|
||||||
|
node.IngressDNS = "1.1.1.1"
|
||||||
|
}
|
||||||
err = logic.UpsertNode(&node)
|
err = logic.UpsertNode(&node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
package controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
proLogic "github.com/gravitl/netmaker/pro/logic"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
controller "github.com/gravitl/netmaker/controllers"
|
|
||||||
"github.com/gravitl/netmaker/logger"
|
|
||||||
"github.com/gravitl/netmaker/logic"
|
|
||||||
"github.com/gravitl/netmaker/models"
|
|
||||||
"github.com/gravitl/netmaker/mq"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RelayHandlers - handle Pro Relays
|
|
||||||
func RelayHandlers(r *mux.Router) {
|
|
||||||
|
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", logic.SecurityCheck(true, http.HandlerFunc(createRelay))).Methods(http.MethodPost)
|
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", logic.SecurityCheck(true, http.HandlerFunc(deleteRelay))).Methods(http.MethodDelete)
|
|
||||||
r.HandleFunc("/api/v1/host/{hostid}/failoverme", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).Methods(http.MethodPost)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Summary Create a relay
|
|
||||||
// @Router /api/nodes/{network}/{nodeid}/createrelay [post]
|
|
||||||
// @Tags PRO
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param network path string true "Network ID"
|
|
||||||
// @Param nodeid path string true "Node ID"
|
|
||||||
// @Param body body models.RelayRequest true "Relay request parameters"
|
|
||||||
// @Success 200 {object} models.ApiNode
|
|
||||||
// @Failure 400 {object} models.ErrorResponse
|
|
||||||
// @Failure 500 {object} models.ErrorResponse
|
|
||||||
func createRelay(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var relayRequest models.RelayRequest
|
|
||||||
var params = mux.Vars(r)
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&relayRequest)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
relayRequest.NetID = params["network"]
|
|
||||||
relayRequest.NodeID = params["nodeid"]
|
|
||||||
_, relayNode, err := proLogic.CreateRelay(relayRequest)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(
|
|
||||||
0,
|
|
||||||
r.Header.Get("user"),
|
|
||||||
fmt.Sprintf(
|
|
||||||
"failed to create relay on node [%s] on network [%s]: %v",
|
|
||||||
relayRequest.NodeID,
|
|
||||||
relayRequest.NetID,
|
|
||||||
err,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, relayedNodeID := range relayNode.RelayedNodes {
|
|
||||||
relayedNode, err := logic.GetNodeByID(relayedNodeID)
|
|
||||||
if err == nil {
|
|
||||||
if relayedNode.FailedOverBy != uuid.Nil {
|
|
||||||
go logic.ResetFailedOverPeer(&relayedNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
go mq.PublishPeerUpdate(false)
|
|
||||||
logger.Log(
|
|
||||||
1,
|
|
||||||
r.Header.Get("user"),
|
|
||||||
"created relay on node",
|
|
||||||
relayRequest.NodeID,
|
|
||||||
"on network",
|
|
||||||
relayRequest.NetID,
|
|
||||||
)
|
|
||||||
apiNode := relayNode.ConvertToAPINode()
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
json.NewEncoder(w).Encode(apiNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Summary Remove a relay
|
|
||||||
// @Router /api/nodes/{network}/{nodeid}/deleterelay [delete]
|
|
||||||
// @Tags PRO
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param network path string true "Network ID"
|
|
||||||
// @Param nodeid path string true "Node ID"
|
|
||||||
// @Success 200 {object} models.ApiNode
|
|
||||||
// @Failure 400 {object} models.ErrorResponse
|
|
||||||
// @Failure 500 {object} models.ErrorResponse
|
|
||||||
func deleteRelay(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
var params = mux.Vars(r)
|
|
||||||
nodeid := params["nodeid"]
|
|
||||||
netid := params["network"]
|
|
||||||
updateNodes, node, err := proLogic.DeleteRelay(netid, nodeid)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.Log(1, r.Header.Get("user"), "deleted relay server", nodeid, "on network", netid)
|
|
||||||
go func() {
|
|
||||||
for _, relayedNode := range updateNodes {
|
|
||||||
err = mq.NodeUpdate(&relayedNode)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(
|
|
||||||
1,
|
|
||||||
"relayed node update ",
|
|
||||||
relayedNode.ID.String(),
|
|
||||||
"on network",
|
|
||||||
relayedNode.Network,
|
|
||||||
": ",
|
|
||||||
err.Error(),
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
h, err := logic.GetHost(relayedNode.HostID.String())
|
|
||||||
if err == nil {
|
|
||||||
if h.OS == models.OS_Types.IoT {
|
|
||||||
nodes, err := logic.GetAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
node.IsRelay = true // for iot update to recognise that it has to delete relay peer
|
|
||||||
if err = mq.PublishSingleHostPeerUpdate(h, nodes, &node, nil, false, nil); err != nil {
|
|
||||||
logger.Log(1, "failed to publish peer update to host", h.ID.String(), ": ", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mq.PublishPeerUpdate(false)
|
|
||||||
}()
|
|
||||||
logger.Log(
|
|
||||||
1,
|
|
||||||
r.Header.Get("user"),
|
|
||||||
"deleted relay on node",
|
|
||||||
node.ID.String(),
|
|
||||||
"on network",
|
|
||||||
node.Network,
|
|
||||||
)
|
|
||||||
apiNode := node.ConvertToAPINode()
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
json.NewEncoder(w).Encode(apiNode)
|
|
||||||
}
|
|
|
@ -29,7 +29,6 @@ func InitPro() {
|
||||||
controller.HttpHandlers = append(
|
controller.HttpHandlers = append(
|
||||||
controller.HttpHandlers,
|
controller.HttpHandlers,
|
||||||
proControllers.MetricHandlers,
|
proControllers.MetricHandlers,
|
||||||
proControllers.RelayHandlers,
|
|
||||||
proControllers.UserHandlers,
|
proControllers.UserHandlers,
|
||||||
proControllers.FailOverHandlers,
|
proControllers.FailOverHandlers,
|
||||||
proControllers.InetHandlers,
|
proControllers.InetHandlers,
|
||||||
|
@ -91,6 +90,7 @@ func InitPro() {
|
||||||
slog.Error("no OAuth provider found or not configured, continuing without OAuth")
|
slog.Error("no OAuth provider found or not configured, continuing without OAuth")
|
||||||
}
|
}
|
||||||
proLogic.LoadNodeMetricsToCache()
|
proLogic.LoadNodeMetricsToCache()
|
||||||
|
proLogic.InitFailOverCache()
|
||||||
})
|
})
|
||||||
logic.ResetFailOver = proLogic.ResetFailOver
|
logic.ResetFailOver = proLogic.ResetFailOver
|
||||||
logic.ResetFailedOverPeer = proLogic.ResetFailedOverPeer
|
logic.ResetFailedOverPeer = proLogic.ResetFailedOverPeer
|
||||||
|
@ -106,13 +106,6 @@ func InitPro() {
|
||||||
logic.GetMetrics = proLogic.GetMetrics
|
logic.GetMetrics = proLogic.GetMetrics
|
||||||
logic.UpdateMetrics = proLogic.UpdateMetrics
|
logic.UpdateMetrics = proLogic.UpdateMetrics
|
||||||
logic.DeleteMetrics = proLogic.DeleteMetrics
|
logic.DeleteMetrics = proLogic.DeleteMetrics
|
||||||
logic.GetRelays = proLogic.GetRelays
|
|
||||||
logic.GetAllowedIpsForRelayed = proLogic.GetAllowedIpsForRelayed
|
|
||||||
logic.RelayedAllowedIPs = proLogic.RelayedAllowedIPs
|
|
||||||
logic.UpdateRelayed = proLogic.UpdateRelayed
|
|
||||||
logic.SetRelayedNodes = proLogic.SetRelayedNodes
|
|
||||||
logic.RelayUpdates = proLogic.RelayUpdates
|
|
||||||
logic.ValidateRelay = proLogic.ValidateRelay
|
|
||||||
logic.GetTrialEndDate = getTrialEndDate
|
logic.GetTrialEndDate = getTrialEndDate
|
||||||
logic.SetDefaultGw = proLogic.SetDefaultGw
|
logic.SetDefaultGw = proLogic.SetDefaultGw
|
||||||
logic.SetDefaultGwForRelayedUpdate = proLogic.SetDefaultGwForRelayedUpdate
|
logic.SetDefaultGwForRelayedUpdate = proLogic.SetDefaultGwForRelayedUpdate
|
||||||
|
|
|
@ -13,7 +13,49 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var failOverCtxMutex = &sync.RWMutex{}
|
var failOverCtxMutex = &sync.RWMutex{}
|
||||||
|
var failOverCacheMutex = &sync.RWMutex{}
|
||||||
|
var failOverCache = make(map[models.NetworkID]string)
|
||||||
|
|
||||||
|
func InitFailOverCache() {
|
||||||
|
failOverCacheMutex.Lock()
|
||||||
|
defer failOverCacheMutex.Unlock()
|
||||||
|
networks, err := logic.GetNetworks()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
allNodes, err := logic.GetAllNodes()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, network := range networks {
|
||||||
|
networkNodes := logic.GetNetworkNodesMemory(allNodes, network.NetID)
|
||||||
|
for _, node := range networkNodes {
|
||||||
|
if node.IsFailOver {
|
||||||
|
failOverCache[models.NetworkID(network.NetID)] = node.ID.String()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckFailOverCtx(failOverNode, victimNode, peerNode models.Node) error {
|
||||||
|
failOverCtxMutex.RLock()
|
||||||
|
defer failOverCtxMutex.RUnlock()
|
||||||
|
if peerNode.FailOverPeers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if victimNode.FailOverPeers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, peerHasFailovered := peerNode.FailOverPeers[victimNode.ID.String()]
|
||||||
|
_, victimHasFailovered := victimNode.FailOverPeers[peerNode.ID.String()]
|
||||||
|
if peerHasFailovered && victimHasFailovered &&
|
||||||
|
victimNode.FailedOverBy == failOverNode.ID && peerNode.FailedOverBy == failOverNode.ID {
|
||||||
|
return errors.New("failover ctx is already set")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func SetFailOverCtx(failOverNode, victimNode, peerNode models.Node) error {
|
func SetFailOverCtx(failOverNode, victimNode, peerNode models.Node) error {
|
||||||
failOverCtxMutex.Lock()
|
failOverCtxMutex.Lock()
|
||||||
defer failOverCtxMutex.Unlock()
|
defer failOverCtxMutex.Unlock()
|
||||||
|
@ -23,13 +65,16 @@ func SetFailOverCtx(failOverNode, victimNode, peerNode models.Node) error {
|
||||||
if victimNode.FailOverPeers == nil {
|
if victimNode.FailOverPeers == nil {
|
||||||
victimNode.FailOverPeers = make(map[string]struct{})
|
victimNode.FailOverPeers = make(map[string]struct{})
|
||||||
}
|
}
|
||||||
|
_, peerHasFailovered := peerNode.FailOverPeers[victimNode.ID.String()]
|
||||||
|
_, victimHasFailovered := victimNode.FailOverPeers[peerNode.ID.String()]
|
||||||
|
if peerHasFailovered && victimHasFailovered &&
|
||||||
|
victimNode.FailedOverBy == failOverNode.ID && peerNode.FailedOverBy == failOverNode.ID {
|
||||||
|
return errors.New("failover ctx is already set")
|
||||||
|
}
|
||||||
peerNode.FailOverPeers[victimNode.ID.String()] = struct{}{}
|
peerNode.FailOverPeers[victimNode.ID.String()] = struct{}{}
|
||||||
victimNode.FailOverPeers[peerNode.ID.String()] = struct{}{}
|
victimNode.FailOverPeers[peerNode.ID.String()] = struct{}{}
|
||||||
victimNode.FailedOverBy = failOverNode.ID
|
victimNode.FailedOverBy = failOverNode.ID
|
||||||
peerNode.FailedOverBy = failOverNode.ID
|
peerNode.FailedOverBy = failOverNode.ID
|
||||||
if err := logic.UpsertNode(&failOverNode); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := logic.UpsertNode(&victimNode); err != nil {
|
if err := logic.UpsertNode(&victimNode); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -50,17 +95,26 @@ func GetFailOverNode(network string, allNodes []models.Node) (models.Node, error
|
||||||
return models.Node{}, errors.New("auto relay not found")
|
return models.Node{}, errors.New("auto relay not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RemoveFailOverFromCache(network string) {
|
||||||
|
failOverCacheMutex.Lock()
|
||||||
|
defer failOverCacheMutex.Unlock()
|
||||||
|
delete(failOverCache, models.NetworkID(network))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetFailOverInCache(node models.Node) {
|
||||||
|
failOverCacheMutex.Lock()
|
||||||
|
defer failOverCacheMutex.Unlock()
|
||||||
|
failOverCache[models.NetworkID(node.Network)] = node.ID.String()
|
||||||
|
}
|
||||||
|
|
||||||
// FailOverExists - checks if failOver exists already in the network
|
// FailOverExists - checks if failOver exists already in the network
|
||||||
func FailOverExists(network string) (failOverNode models.Node, exists bool) {
|
func FailOverExists(network string) (failOverNode models.Node, exists bool) {
|
||||||
nodes, err := logic.GetNetworkNodes(network)
|
failOverCacheMutex.RLock()
|
||||||
if err != nil {
|
defer failOverCacheMutex.RUnlock()
|
||||||
return
|
if nodeID, ok := failOverCache[models.NetworkID(network)]; ok {
|
||||||
}
|
failOverNode, err := logic.GetNodeByID(nodeID)
|
||||||
for _, node := range nodes {
|
if err == nil {
|
||||||
if node.IsFailOver {
|
return failOverNode, true
|
||||||
exists = true
|
|
||||||
failOverNode = node
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -185,5 +239,6 @@ func CreateFailOver(node models.Node) error {
|
||||||
slog.Error("failed to upsert node", "node", node.ID.String(), "error", err)
|
slog.Error("failed to upsert node", "node", node.ID.String(), "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
SetFailOverInCache(node)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,255 +0,0 @@
|
||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/gravitl/netmaker/logger"
|
|
||||||
"github.com/gravitl/netmaker/logic"
|
|
||||||
"github.com/gravitl/netmaker/logic/acls/nodeacls"
|
|
||||||
"github.com/gravitl/netmaker/models"
|
|
||||||
"github.com/gravitl/netmaker/mq"
|
|
||||||
"github.com/gravitl/netmaker/servercfg"
|
|
||||||
"golang.org/x/exp/slog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetRelays - gets all the nodes that are relays
|
|
||||||
func GetRelays() ([]models.Node, error) {
|
|
||||||
nodes, err := logic.GetAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
relays := make([]models.Node, 0)
|
|
||||||
for _, node := range nodes {
|
|
||||||
if node.IsRelay {
|
|
||||||
relays = append(relays, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return relays, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateRelay - creates a relay
|
|
||||||
func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error) {
|
|
||||||
var returnnodes []models.Node
|
|
||||||
|
|
||||||
node, err := logic.GetNodeByID(relay.NodeID)
|
|
||||||
if err != nil {
|
|
||||||
return returnnodes, models.Node{}, err
|
|
||||||
}
|
|
||||||
host, err := logic.GetHost(node.HostID.String())
|
|
||||||
if err != nil {
|
|
||||||
return returnnodes, models.Node{}, err
|
|
||||||
}
|
|
||||||
if host.OS != "linux" {
|
|
||||||
return returnnodes, models.Node{}, fmt.Errorf("only linux machines can be relay nodes")
|
|
||||||
}
|
|
||||||
err = ValidateRelay(relay, false)
|
|
||||||
if err != nil {
|
|
||||||
return returnnodes, models.Node{}, err
|
|
||||||
}
|
|
||||||
node.IsRelay = true
|
|
||||||
node.RelayedNodes = relay.RelayedNodes
|
|
||||||
node.SetLastModified()
|
|
||||||
err = logic.UpsertNode(&node)
|
|
||||||
if err != nil {
|
|
||||||
return returnnodes, node, err
|
|
||||||
}
|
|
||||||
returnnodes = SetRelayedNodes(true, relay.NodeID, relay.RelayedNodes)
|
|
||||||
return returnnodes, node, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRelayedNodes- sets and saves node as relayed
|
|
||||||
func SetRelayedNodes(setRelayed bool, relay string, relayed []string) []models.Node {
|
|
||||||
var returnnodes []models.Node
|
|
||||||
for _, id := range relayed {
|
|
||||||
node, err := logic.GetNodeByID(id)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, "setRelayedNodes.GetNodebyID", err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
node.IsRelayed = setRelayed
|
|
||||||
if setRelayed {
|
|
||||||
node.RelayedBy = relay
|
|
||||||
} else {
|
|
||||||
node.RelayedBy = ""
|
|
||||||
}
|
|
||||||
node.SetLastModified()
|
|
||||||
if err := logic.UpsertNode(&node); err != nil {
|
|
||||||
logger.Log(0, "setRelayedNodes.Insert", err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
returnnodes = append(returnnodes, node)
|
|
||||||
}
|
|
||||||
return returnnodes
|
|
||||||
}
|
|
||||||
|
|
||||||
// func GetRelayedNodes(relayNode *models.Node) (models.Node, error) {
|
|
||||||
// var returnnodes []models.Node
|
|
||||||
// networkNodes, err := GetNetworkNodes(relayNode.Network)
|
|
||||||
// if err != nil {
|
|
||||||
// return returnnodes, err
|
|
||||||
// }
|
|
||||||
// for _, node := range networkNodes {
|
|
||||||
// for _, addr := range relayNode.RelayAddrs {
|
|
||||||
// if addr == node.Address.IP.String() || addr == node.Address6.IP.String() {
|
|
||||||
// returnnodes = append(returnnodes, node)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return returnnodes, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ValidateRelay - checks if relay is valid
|
|
||||||
func ValidateRelay(relay models.RelayRequest, update bool) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
node, err := logic.GetNodeByID(relay.NodeID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !update && node.IsRelay {
|
|
||||||
return errors.New("node is already acting as a relay")
|
|
||||||
}
|
|
||||||
for _, relayedNodeID := range relay.RelayedNodes {
|
|
||||||
relayedNode, err := logic.GetNodeByID(relayedNodeID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if relayedNode.IsIngressGateway {
|
|
||||||
return errors.New("cannot relay an ingress gateway (" + relayedNodeID + ")")
|
|
||||||
}
|
|
||||||
if relayedNode.IsInternetGateway {
|
|
||||||
return errors.New("cannot relay an internet gateway (" + relayedNodeID + ")")
|
|
||||||
}
|
|
||||||
if relayedNode.InternetGwID != "" && relayedNode.InternetGwID != relay.NodeID {
|
|
||||||
return errors.New("cannot relay an internet client (" + relayedNodeID + ")")
|
|
||||||
}
|
|
||||||
if relayedNode.IsFailOver {
|
|
||||||
return errors.New("cannot relay a failOver (" + relayedNodeID + ")")
|
|
||||||
}
|
|
||||||
if relayedNode.FailedOverBy != uuid.Nil {
|
|
||||||
ResetFailedOverPeer(&relayedNode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateRelayNodes - updates relay nodes
|
|
||||||
func updateRelayNodes(relay string, oldNodes []string, newNodes []string) []models.Node {
|
|
||||||
_ = SetRelayedNodes(false, relay, oldNodes)
|
|
||||||
return SetRelayedNodes(true, relay, newNodes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RelayUpdates(currentNode, newNode *models.Node) bool {
|
|
||||||
relayUpdates := false
|
|
||||||
if servercfg.IsPro && newNode.IsRelay {
|
|
||||||
if len(newNode.RelayedNodes) != len(currentNode.RelayedNodes) {
|
|
||||||
relayUpdates = true
|
|
||||||
} else {
|
|
||||||
for i, node := range newNode.RelayedNodes {
|
|
||||||
if node != currentNode.RelayedNodes[i] {
|
|
||||||
relayUpdates = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
for _, relayedNode := range updatenodes {
|
|
||||||
node := relayedNode
|
|
||||||
ResetFailedOverPeer(&node)
|
|
||||||
go func() {
|
|
||||||
if err := mq.NodeUpdate(&node); err != nil {
|
|
||||||
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRelay - deletes a relay
|
|
||||||
func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) {
|
|
||||||
var returnnodes []models.Node
|
|
||||||
node, err := logic.GetNodeByID(nodeid)
|
|
||||||
if err != nil {
|
|
||||||
return returnnodes, models.Node{}, err
|
|
||||||
}
|
|
||||||
returnnodes = SetRelayedNodes(false, nodeid, node.RelayedNodes)
|
|
||||||
node.IsRelay = false
|
|
||||||
node.RelayedNodes = []string{}
|
|
||||||
node.SetLastModified()
|
|
||||||
if err = logic.UpsertNode(&node); err != nil {
|
|
||||||
return returnnodes, models.Node{}, err
|
|
||||||
}
|
|
||||||
return returnnodes, node, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RelayedAllowedIPs(peer, node *models.Node) []net.IPNet {
|
|
||||||
var allowedIPs = []net.IPNet{}
|
|
||||||
for _, relayedNodeID := range peer.RelayedNodes {
|
|
||||||
if node.ID.String() == relayedNodeID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
relayedNode, err := logic.GetNodeByID(relayedNodeID)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
allowed := getRelayedAddresses(relayedNodeID)
|
|
||||||
if relayedNode.IsEgressGateway {
|
|
||||||
allowed = append(allowed, logic.GetEgressIPs(&relayedNode)...)
|
|
||||||
}
|
|
||||||
allowedIPs = append(allowedIPs, allowed...)
|
|
||||||
}
|
|
||||||
return allowedIPs
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllowedIpsForRelayed - returns the peerConfig for a node relayed by relay
|
|
||||||
func GetAllowedIpsForRelayed(relayed, relay *models.Node) (allowedIPs []net.IPNet) {
|
|
||||||
if relayed.RelayedBy != relay.ID.String() {
|
|
||||||
logger.Log(0, "RelayedByRelay called with invalid parameters")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if relay.InternetGwID != "" {
|
|
||||||
return GetAllowedIpForInetNodeClient(relayed, relay)
|
|
||||||
}
|
|
||||||
peers, err := logic.GetNetworkNodes(relay.Network)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, "error getting network clients", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, peer := range peers {
|
|
||||||
if peer.ID == relayed.ID || peer.ID == relay.ID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if nodeacls.AreNodesAllowed(nodeacls.NetworkID(relayed.Network), nodeacls.NodeID(relayed.ID.String()), nodeacls.NodeID(peer.ID.String())) {
|
|
||||||
allowedIPs = append(allowedIPs, logic.GetAllowedIPs(relayed, &peer, nil)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRelayedAddresses(id string) []net.IPNet {
|
|
||||||
addrs := []net.IPNet{}
|
|
||||||
node, err := logic.GetNodeByID(id)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, "getRelayedAddresses: "+err.Error())
|
|
||||||
return addrs
|
|
||||||
}
|
|
||||||
if node.Address.IP != nil {
|
|
||||||
node.Address.Mask = net.CIDRMask(32, 32)
|
|
||||||
addrs = append(addrs, node.Address)
|
|
||||||
}
|
|
||||||
if node.Address6.IP != nil {
|
|
||||||
node.Address6.Mask = net.CIDRMask(128, 128)
|
|
||||||
addrs = append(addrs, node.Address6)
|
|
||||||
}
|
|
||||||
return addrs
|
|
||||||
}
|
|
|
@ -17,6 +17,10 @@ func getNodeStatusOld(node *models.Node) {
|
||||||
node.Status = models.OnlineSt
|
node.Status = models.OnlineSt
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !node.Connected {
|
||||||
|
node.Status = models.Disconnected
|
||||||
|
return
|
||||||
|
}
|
||||||
if time.Since(node.LastCheckIn) > time.Minute*10 {
|
if time.Since(node.LastCheckIn) > time.Minute*10 {
|
||||||
node.Status = models.OfflineSt
|
node.Status = models.OfflineSt
|
||||||
return
|
return
|
||||||
|
@ -31,12 +35,25 @@ func GetNodeStatus(node *models.Node, defaultEnabledPolicy bool) {
|
||||||
node.Status = models.OfflineSt
|
node.Status = models.OfflineSt
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ingNode, err := logic.GetNodeByID(node.StaticNode.IngressGatewayID)
|
||||||
|
if err != nil {
|
||||||
|
node.Status = models.OfflineSt
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !defaultEnabledPolicy {
|
||||||
|
allowed, _ := logic.IsNodeAllowedToCommunicate(*node, ingNode, false)
|
||||||
|
if !allowed {
|
||||||
|
node.Status = models.OnlineSt
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
// check extclient connection from metrics
|
// check extclient connection from metrics
|
||||||
ingressMetrics, err := GetMetrics(node.StaticNode.IngressGatewayID)
|
ingressMetrics, err := GetMetrics(node.StaticNode.IngressGatewayID)
|
||||||
if err != nil || ingressMetrics == nil || ingressMetrics.Connectivity == nil {
|
if err != nil || ingressMetrics == nil || ingressMetrics.Connectivity == nil {
|
||||||
node.Status = models.UnKnown
|
node.Status = models.UnKnown
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if metric, ok := ingressMetrics.Connectivity[node.StaticNode.ClientID]; ok {
|
if metric, ok := ingressMetrics.Connectivity[node.StaticNode.ClientID]; ok {
|
||||||
if metric.Connected {
|
if metric.Connected {
|
||||||
node.Status = models.OnlineSt
|
node.Status = models.OnlineSt
|
||||||
|
@ -46,9 +63,14 @@ func GetNodeStatus(node *models.Node, defaultEnabledPolicy bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.Status = models.UnKnown
|
node.Status = models.UnKnown
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !node.Connected {
|
||||||
|
node.Status = models.Disconnected
|
||||||
|
return
|
||||||
|
}
|
||||||
if time.Since(node.LastCheckIn) > models.LastCheckInThreshold {
|
if time.Since(node.LastCheckIn) > models.LastCheckInThreshold {
|
||||||
node.Status = models.OfflineSt
|
node.Status = models.OfflineSt
|
||||||
return
|
return
|
||||||
|
@ -197,6 +219,7 @@ func checkPeerConnectivity(node *models.Node, metrics *models.Metrics, defaultAc
|
||||||
peerNotConnectedCnt++
|
peerNotConnectedCnt++
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if peerNotConnectedCnt > len(metrics.Connectivity)/2 {
|
if peerNotConnectedCnt > len(metrics.Connectivity)/2 {
|
||||||
node.Status = models.WarningSt
|
node.Status = models.WarningSt
|
||||||
return
|
return
|
||||||
|
|
|
@ -96,3 +96,7 @@ MANAGE_DNS=false
|
||||||
OLD_ACL_SUPPORT=true
|
OLD_ACL_SUPPORT=true
|
||||||
# if STUN is set to true, hole punch is called
|
# if STUN is set to true, hole punch is called
|
||||||
STUN=true
|
STUN=true
|
||||||
|
# Metrics Collection Port
|
||||||
|
METRICS_PORT=51821
|
||||||
|
# Metrics Collection interval in minutes
|
||||||
|
PUBLISH_METRIC_INTERVAL=15
|
||||||
|
|
|
@ -6,7 +6,7 @@ SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
||||||
CONFIG_PATH="$SCRIPT_DIR/$CONFIG_FILE"
|
CONFIG_PATH="$SCRIPT_DIR/$CONFIG_FILE"
|
||||||
NM_QUICK_VERSION="0.1.1"
|
NM_QUICK_VERSION="0.1.1"
|
||||||
LATEST=$(curl -s https://api.github.com/repos/gravitl/netmaker/releases/latest | grep "tag_name" | cut -d : -f 2,3 | tr -d [:space:],\")
|
LATEST=$(curl -s https://api.github.com/repos/gravitl/netmaker/releases/latest | grep "tag_name" | cut -d : -f 2,3 | tr -d [:space:],\")
|
||||||
|
BRANCH=master
|
||||||
if [ $(id -u) -ne 0 ]; then
|
if [ $(id -u) -ne 0 ]; then
|
||||||
echo "This script must be run as root"
|
echo "This script must be run as root"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -617,7 +617,7 @@ install_netmaker() {
|
||||||
|
|
||||||
echo "Pulling config files..."
|
echo "Pulling config files..."
|
||||||
|
|
||||||
local BASE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master"
|
local BASE_URL="https://raw.githubusercontent.com/gravitl/netmaker/$BRANCH"
|
||||||
local COMPOSE_URL="$BASE_URL/compose/docker-compose.yml"
|
local COMPOSE_URL="$BASE_URL/compose/docker-compose.yml"
|
||||||
local CADDY_URL="$BASE_URL/docker/Caddyfile"
|
local CADDY_URL="$BASE_URL/docker/Caddyfile"
|
||||||
if [ "$INSTALL_TYPE" = "pro" ]; then
|
if [ "$INSTALL_TYPE" = "pro" ]; then
|
||||||
|
|
|
@ -14,6 +14,8 @@ import (
|
||||||
"github.com/gravitl/netmaker/models"
|
"github.com/gravitl/netmaker/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ServerInfo = GetServerInfo()
|
||||||
|
|
||||||
// EmqxBrokerType denotes the broker type for EMQX MQTT
|
// EmqxBrokerType denotes the broker type for EMQX MQTT
|
||||||
const EmqxBrokerType = "emqx"
|
const EmqxBrokerType = "emqx"
|
||||||
|
|
||||||
|
@ -141,10 +143,12 @@ func GetServerInfo() models.ServerConfig {
|
||||||
cfg.Version = GetVersion()
|
cfg.Version = GetVersion()
|
||||||
cfg.IsPro = IsPro
|
cfg.IsPro = IsPro
|
||||||
cfg.MetricInterval = GetMetricInterval()
|
cfg.MetricInterval = GetMetricInterval()
|
||||||
|
cfg.MetricsPort = GetMetricsPort()
|
||||||
cfg.ManageDNS = GetManageDNS()
|
cfg.ManageDNS = GetManageDNS()
|
||||||
cfg.Stun = IsStunEnabled()
|
cfg.Stun = IsStunEnabled()
|
||||||
cfg.StunServers = GetStunServers()
|
cfg.StunServers = GetStunServers()
|
||||||
cfg.DefaultDomain = GetDefaultDomain()
|
cfg.DefaultDomain = GetDefaultDomain()
|
||||||
|
cfg.EndpointDetection = IsEndpointDetectionEnabled()
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,6 +658,19 @@ func GetMqUserName() string {
|
||||||
return password
|
return password
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMetricsPort - get metrics port
|
||||||
|
func GetMetricsPort() int {
|
||||||
|
p := 51821
|
||||||
|
if os.Getenv("METRICS_PORT") != "" {
|
||||||
|
pStr := os.Getenv("METRICS_PORT")
|
||||||
|
pInt, err := strconv.Atoi(pStr)
|
||||||
|
if err == nil && pInt != 0 {
|
||||||
|
p = pInt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// GetMetricInterval - get the publish metric interval
|
// GetMetricInterval - get the publish metric interval
|
||||||
func GetMetricIntervalInMinutes() time.Duration {
|
func GetMetricIntervalInMinutes() time.Duration {
|
||||||
//default 15 minutes
|
//default 15 minutes
|
||||||
|
|
|
@ -59,32 +59,8 @@ func setNetworkDefaults() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, network := range networks {
|
for _, network := range networks {
|
||||||
update := false
|
if network.SetDefaults() {
|
||||||
newNet := network
|
logic.SaveNetwork(&network)
|
||||||
if strings.Contains(network.NetID, ".") {
|
|
||||||
newNet.NetID = strings.ReplaceAll(network.NetID, ".", "")
|
|
||||||
newNet.DefaultInterface = strings.ReplaceAll(network.DefaultInterface, ".", "")
|
|
||||||
update = true
|
|
||||||
}
|
|
||||||
if strings.ContainsAny(network.NetID, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
|
|
||||||
newNet.NetID = strings.ToLower(network.NetID)
|
|
||||||
newNet.DefaultInterface = strings.ToLower(network.DefaultInterface)
|
|
||||||
update = true
|
|
||||||
}
|
|
||||||
if update {
|
|
||||||
newNet.SetDefaults()
|
|
||||||
if err := logic.SaveNetwork(&newNet); err != nil {
|
|
||||||
logger.Log(0, "error saving networks during initial update:", err.Error())
|
|
||||||
}
|
|
||||||
if err := logic.DeleteNetwork(network.NetID); err != nil {
|
|
||||||
logger.Log(0, "error deleting old network:", err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
network.SetDefaults()
|
|
||||||
_, _, _, err = logic.UpdateNetwork(&network, &network)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log(0, "could not set defaults on network", network.NetID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// RetryStrategy specifies a strategy to retry an operation after waiting a while,
|
// RetryStrategy specifies a strategy to retry an operation after waiting a while,
|
||||||
// with hooks for successful and unsuccessful (>=max) tries.
|
// with hooks for successful and unsuccessful (>=max) tries.
|
||||||
|
@ -39,3 +43,19 @@ func (rs RetryStrategy) DoStrategy() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TraceCaller() {
|
||||||
|
// Skip 1 frame to get the caller of this function
|
||||||
|
pc, file, line, ok := runtime.Caller(2)
|
||||||
|
if !ok {
|
||||||
|
slog.Debug("Unable to get caller information")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get function name from the program counter (pc)
|
||||||
|
funcName := runtime.FuncForPC(pc).Name()
|
||||||
|
|
||||||
|
// Print trace details
|
||||||
|
slog.Debug("Called from function: %s\n", "func-name", funcName)
|
||||||
|
slog.Debug("File: %s, Line: %d\n", "file", file, "line-no", line)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue