mirror of
https://github.com/gravitl/netmaker.git
synced 2025-10-06 17:29:15 +08:00
merge conflicts resolved
This commit is contained in:
@@ -19,7 +19,8 @@ services:
|
|||||||
- sqldata:/root/data
|
- sqldata:/root/data
|
||||||
- mosquitto_data:/etc/netmaker
|
- mosquitto_data:/etc/netmaker
|
||||||
environment:
|
environment:
|
||||||
SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
|
BROKER_NAME: "broker.NETMAKER_BASE_DOMAIN"
|
||||||
|
SERVER_NAME: "NETMAKER_BASE_DOMAIN"
|
||||||
SERVER_HOST: "SERVER_PUBLIC_IP"
|
SERVER_HOST: "SERVER_PUBLIC_IP"
|
||||||
SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
|
SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
|
||||||
COREDNS_ADDR: "SERVER_PUBLIC_IP"
|
COREDNS_ADDR: "SERVER_PUBLIC_IP"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
//Environment file for getting variables
|
// Environment file for getting variables
|
||||||
//Currently the only thing it does is set the master password
|
// Currently the only thing it does is set the master password
|
||||||
//Should probably have it take over functions from OS such as port and mongodb connection details
|
// Should probably have it take over functions from OS such as port and mongodb connection details
|
||||||
//Reads from the config/environments/dev.yaml file by default
|
// Reads from the config/environments/dev.yaml file by default
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -69,6 +69,7 @@ type ServerConfig struct {
|
|||||||
MQPort string `yaml:"mqport"`
|
MQPort string `yaml:"mqport"`
|
||||||
MQServerPort string `yaml:"mqserverport"`
|
MQServerPort string `yaml:"mqserverport"`
|
||||||
Server string `yaml:"server"`
|
Server string `yaml:"server"`
|
||||||
|
Broker string `yam:"broker"`
|
||||||
PublicIPService string `yaml:"publicipservice"`
|
PublicIPService string `yaml:"publicipservice"`
|
||||||
MQAdminPassword string `yaml:"mqadminpassword"`
|
MQAdminPassword string `yaml:"mqadminpassword"`
|
||||||
MetricsExporter string `yaml:"metrics_exporter"`
|
MetricsExporter string `yaml:"metrics_exporter"`
|
||||||
|
@@ -2,6 +2,7 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -40,13 +41,13 @@ func nodeHandlers(r *mux.Router) {
|
|||||||
//
|
//
|
||||||
// Authenticate to make further API calls related to a network.
|
// Authenticate to make further API calls related to a network.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: successResponse
|
// 200: successResponse
|
||||||
func authenticate(response http.ResponseWriter, request *http.Request) {
|
func authenticate(response http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
var authRequest models.AuthParams
|
var authRequest models.AuthParams
|
||||||
@@ -343,13 +344,13 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
|
|||||||
//
|
//
|
||||||
// Gets all nodes associated with network including pending nodes.
|
// Gets all nodes associated with network including pending nodes.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeSliceResponse
|
// 200: nodeSliceResponse
|
||||||
func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -382,13 +383,14 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Get all nodes across all networks.
|
// Get all nodes across all networks.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: nodeSliceResponse
|
||||||
//
|
//
|
||||||
// Responses:
|
|
||||||
// 200: nodeSliceResponse
|
|
||||||
// Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
|
// Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
|
||||||
func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -439,13 +441,13 @@ func getUsersNodes(user models.User) ([]models.Node, error) {
|
|||||||
//
|
//
|
||||||
// Get an individual node.
|
// Get an individual node.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeResponse
|
// 200: nodeResponse
|
||||||
func getNode(w http.ResponseWriter, r *http.Request) {
|
func getNode(w http.ResponseWriter, r *http.Request) {
|
||||||
// set header.
|
// set header.
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -504,13 +506,13 @@ func getNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Create a node on a network.
|
// Create a node on a network.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeGetResponse
|
// 200: nodeGetResponse
|
||||||
func createNode(w http.ResponseWriter, r *http.Request) {
|
func createNode(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
@@ -547,6 +549,12 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !logic.IsVersionComptatible(node.Version) {
|
||||||
|
err := errors.New("incomatible netclient version")
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
node.Network = networkName
|
node.Network = networkName
|
||||||
|
|
||||||
network, err := logic.GetNetworkByNode(&node)
|
network, err := logic.GetNetworkByNode(&node)
|
||||||
@@ -631,7 +639,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
if !updatedUserNode { // user was found but not updated, so delete node
|
if !updatedUserNode { // user was found but not updated, so delete node
|
||||||
logger.Log(0, "failed to add node to user", keyName)
|
logger.Log(0, "failed to add node to user", keyName)
|
||||||
logic.DeleteNodeByID(&node, true)
|
logic.DeleteNode(&node, true)
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -645,12 +653,12 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create client for this node in Mq
|
// Create client for this host in Mq
|
||||||
event := mq.MqDynsecPayload{
|
event := mq.MqDynsecPayload{
|
||||||
Commands: []mq.MqDynSecCmd{
|
Commands: []mq.MqDynSecCmd{
|
||||||
{ // delete if any client exists already
|
{ // delete if any client exists already
|
||||||
Command: mq.DeleteClientCmd,
|
Command: mq.DeleteClientCmd,
|
||||||
Username: node.ID,
|
Username: node.HostID,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Command: mq.CreateRoleCmd,
|
Command: mq.CreateRoleCmd,
|
||||||
@@ -660,7 +668,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Command: mq.CreateClientCmd,
|
Command: mq.CreateClientCmd,
|
||||||
Username: node.ID,
|
Username: node.HostID,
|
||||||
Password: nodePassword,
|
Password: nodePassword,
|
||||||
Textname: node.Name,
|
Textname: node.Name,
|
||||||
Roles: []mq.MqDynSecRole{
|
Roles: []mq.MqDynSecRole{
|
||||||
@@ -700,13 +708,14 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Takes a node out of pending state.
|
// Takes a node out of pending state.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: nodeResponse
|
||||||
//
|
//
|
||||||
// Responses:
|
|
||||||
// 200: nodeResponse
|
|
||||||
// Takes node out of pending state
|
// Takes node out of pending state
|
||||||
// TODO: May want to use cordon/uncordon terminology instead of "ispending".
|
// TODO: May want to use cordon/uncordon terminology instead of "ispending".
|
||||||
func uncordonNode(w http.ResponseWriter, r *http.Request) {
|
func uncordonNode(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -733,13 +742,13 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Create an egress gateway.
|
// Create an egress gateway.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeResponse
|
// 200: nodeResponse
|
||||||
func createEgressGateway(w http.ResponseWriter, r *http.Request) {
|
func createEgressGateway(w http.ResponseWriter, r *http.Request) {
|
||||||
var gateway models.EgressGatewayRequest
|
var gateway models.EgressGatewayRequest
|
||||||
var params = mux.Vars(r)
|
var params = mux.Vars(r)
|
||||||
@@ -772,13 +781,13 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Delete an egress gateway.
|
// Delete an egress gateway.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeResponse
|
// 200: nodeResponse
|
||||||
func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
|
func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
var params = mux.Vars(r)
|
var params = mux.Vars(r)
|
||||||
@@ -806,13 +815,13 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Create an ingress gateway.
|
// Create an ingress gateway.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeResponse
|
// 200: nodeResponse
|
||||||
func createIngressGateway(w http.ResponseWriter, r *http.Request) {
|
func createIngressGateway(w http.ResponseWriter, r *http.Request) {
|
||||||
var params = mux.Vars(r)
|
var params = mux.Vars(r)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -850,13 +859,13 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Delete an ingress gateway.
|
// Delete an ingress gateway.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeResponse
|
// 200: nodeResponse
|
||||||
func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
|
func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
var params = mux.Vars(r)
|
var params = mux.Vars(r)
|
||||||
@@ -888,13 +897,13 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Update an individual node.
|
// Update an individual node.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeResponse
|
// 200: nodeResponse
|
||||||
func updateNode(w http.ResponseWriter, r *http.Request) {
|
func updateNode(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
@@ -998,13 +1007,13 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// Delete an individual node.
|
// Delete an individual node.
|
||||||
//
|
//
|
||||||
// Schemes: https
|
// Schemes: https
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// oauth
|
// oauth
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: nodeResponse
|
// 200: nodeResponse
|
||||||
func deleteNode(w http.ResponseWriter, r *http.Request) {
|
func deleteNode(w http.ResponseWriter, r *http.Request) {
|
||||||
// Set header
|
// Set header
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -1013,22 +1022,11 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
var params = mux.Vars(r)
|
var params = mux.Vars(r)
|
||||||
var nodeid = params["nodeid"]
|
var nodeid = params["nodeid"]
|
||||||
fromNode := r.Header.Get("requestfrom") == "node"
|
fromNode := r.Header.Get("requestfrom") == "node"
|
||||||
var node, err = logic.GetNodeByID(nodeid)
|
node, err := logic.GetNodeByID(nodeid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if fromNode {
|
logger.Log(0, "error retrieving node to delete", err.Error())
|
||||||
node, err = logic.GetDeletedNodeByID(nodeid)
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||||
if err != nil {
|
return
|
||||||
logger.Log(0, r.Header.Get("user"),
|
|
||||||
fmt.Sprintf("error fetching node from deleted nodes [ %s ] info: %v", nodeid, err))
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.Log(0, r.Header.Get("user"),
|
|
||||||
fmt.Sprintf("error fetching node [ %s ] info: %v", nodeid, err))
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if isServer(&node) {
|
if isServer(&node) {
|
||||||
err := fmt.Errorf("cannot delete server node")
|
err := fmt.Errorf("cannot delete server node")
|
||||||
@@ -1044,34 +1042,35 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//send update to node to be deleted before deleting on server otherwise message cannot be sent
|
if err := logic.DeleteNode(&node, fromNode); err != nil {
|
||||||
node.Action = models.NODE_DELETE
|
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
|
||||||
|
|
||||||
err = logic.DeleteNodeByID(&node, fromNode)
|
|
||||||
if err != nil {
|
|
||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if fromNode {
|
if fromNode {
|
||||||
// deletes node related role and client
|
//check if server should be removed from mq
|
||||||
event := mq.MqDynsecPayload{
|
found := false
|
||||||
Commands: []mq.MqDynSecCmd{
|
// err is irrelevent
|
||||||
{
|
nodes, _ := logic.GetAllNodes()
|
||||||
Command: mq.DeleteClientCmd,
|
for _, nodetocheck := range nodes {
|
||||||
Username: nodeid,
|
if nodetocheck.HostID == node.HostID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
// deletes node related role and client
|
||||||
|
event := mq.MqDynsecPayload{
|
||||||
|
Commands: []mq.MqDynSecCmd{
|
||||||
|
{
|
||||||
|
Command: mq.DeleteClientCmd,
|
||||||
|
Username: node.HostID,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
if err := mq.PublishEventToDynSecTopic(event); err != nil {
|
||||||
|
logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
|
||||||
if err := mq.PublishEventToDynSecTopic(event); err != nil {
|
event.Commands, err.Error()))
|
||||||
logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
|
}
|
||||||
event.Commands, err.Error()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if servercfg.Is_EE {
|
|
||||||
if err = logic.EnterpriseResetAllPeersFailovers(node.ID, node.Network); err != nil {
|
|
||||||
logger.Log(0, "failed to reset failover lists during node delete for node", node.Name, node.Network)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")
|
logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")
|
||||||
|
3
go.mod
3
go.mod
@@ -50,6 +50,8 @@ require (
|
|||||||
gortc.io/stun v1.23.0
|
gortc.io/stun v1.23.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/matryer/is v1.4.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute v1.7.0 // indirect
|
cloud.google.com/go/compute v1.7.0 // indirect
|
||||||
fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 // indirect
|
fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 // indirect
|
||||||
@@ -77,6 +79,7 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/go-cmp v0.5.8 // indirect
|
github.com/google/go-cmp v0.5.8 // indirect
|
||||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||||
|
github.com/hashicorp/go-version v1.6.0
|
||||||
github.com/josharian/native v1.0.0 // indirect
|
github.com/josharian/native v1.0.0 // indirect
|
||||||
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
|
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
4
go.sum
4
go.sum
@@ -301,6 +301,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
|
|||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||||
|
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
@@ -341,6 +343,8 @@ github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|||||||
github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc=
|
github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||||
|
@@ -16,7 +16,11 @@ spec:
|
|||||||
hostNetwork: true
|
hostNetwork: true
|
||||||
containers:
|
containers:
|
||||||
- name: netclient
|
- name: netclient
|
||||||
|
<<<<<<< HEAD
|
||||||
image: gravitl/netclient:v0.17.0
|
image: gravitl/netclient:v0.17.0
|
||||||
|
=======
|
||||||
|
image: gravitl/netclient:v0.16.3
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
env:
|
env:
|
||||||
- name: TOKEN
|
- name: TOKEN
|
||||||
value: "TOKEN_VALUE"
|
value: "TOKEN_VALUE"
|
||||||
|
@@ -28,7 +28,11 @@ spec:
|
|||||||
# - "<node label value>"
|
# - "<node label value>"
|
||||||
containers:
|
containers:
|
||||||
- name: netclient
|
- name: netclient
|
||||||
|
<<<<<<< HEAD
|
||||||
image: gravitl/netclient:v0.17.0
|
image: gravitl/netclient:v0.17.0
|
||||||
|
=======
|
||||||
|
image: gravitl/netclient:v0.16.3
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
env:
|
env:
|
||||||
- name: TOKEN
|
- name: TOKEN
|
||||||
value: "TOKEN_VALUE"
|
value: "TOKEN_VALUE"
|
||||||
|
@@ -83,7 +83,11 @@ spec:
|
|||||||
value: "Kubernetes"
|
value: "Kubernetes"
|
||||||
- name: VERBOSITY
|
- name: VERBOSITY
|
||||||
value: "3"
|
value: "3"
|
||||||
|
<<<<<<< HEAD
|
||||||
image: gravitl/netmaker:v0.17.0
|
image: gravitl/netmaker:v0.17.0
|
||||||
|
=======
|
||||||
|
image: gravitl/netmaker:v0.16.3
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
name: netmaker
|
name: netmaker
|
||||||
ports:
|
ports:
|
||||||
|
@@ -15,7 +15,11 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: netmaker-ui
|
- name: netmaker-ui
|
||||||
|
<<<<<<< HEAD
|
||||||
image: gravitl/netmaker-ui:v0.17.0
|
image: gravitl/netmaker-ui:v0.17.0
|
||||||
|
=======
|
||||||
|
image: gravitl/netmaker-ui:v0.16.3
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 443
|
- containerPort: 443
|
||||||
env:
|
env:
|
||||||
|
@@ -54,7 +54,7 @@ func DeleteNetwork(network string) error {
|
|||||||
servers, err := GetSortedNetworkServerNodes(network)
|
servers, err := GetSortedNetworkServerNodes(network)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, s := range servers {
|
for _, s := range servers {
|
||||||
if err = DeleteNodeByID(&s, true); err != nil {
|
if err = DeleteNode(&s, true); err != nil {
|
||||||
logger.Log(2, "could not removed server", s.Name, "before deleting network", network)
|
logger.Log(2, "could not removed server", s.Name, "before deleting network", network)
|
||||||
} else {
|
} else {
|
||||||
logger.Log(2, "removed server", s.Name, "before deleting network", network)
|
logger.Log(2, "removed server", s.Name, "before deleting network", network)
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -22,8 +23,14 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RELAY_NODE_ERR - error to return if relay node is unfound
|
const (
|
||||||
const RELAY_NODE_ERR = "could not find relay for node"
|
// RELAY_NODE_ERR - error to return if relay node is unfound
|
||||||
|
RELAY_NODE_ERR = "could not find relay for node"
|
||||||
|
// NodePurgeTime time to wait for node to response to a NODE_DELETE actions
|
||||||
|
NodePurgeTime = time.Second * 10
|
||||||
|
// NodePurgeCheckTime is how often to check nodes for Pending Delete
|
||||||
|
NodePurgeCheckTime = time.Second * 30
|
||||||
|
)
|
||||||
|
|
||||||
// GetNetworkNodes - gets the nodes of a network
|
// GetNetworkNodes - gets the nodes of a network
|
||||||
func GetNetworkNodes(network string) ([]models.Node, error) {
|
func GetNetworkNodes(network string) ([]models.Node, error) {
|
||||||
@@ -160,8 +167,31 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
|
|||||||
return fmt.Errorf("failed to update node " + currentNode.ID + ", cannot change ID.")
|
return fmt.Errorf("failed to update node " + currentNode.ID + ", cannot change ID.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNodeByID - deletes a node from database or moves into delete nodes table
|
// DeleteNode - marks node for deletion if called by UI or deletes node if called by node
|
||||||
func DeleteNodeByID(node *models.Node, exterminate bool) error {
|
func DeleteNode(node *models.Node, purge bool) error {
|
||||||
|
if !purge {
|
||||||
|
newnode := node
|
||||||
|
newnode.PendingDelete = true
|
||||||
|
newnode.Action = models.NODE_DELETE
|
||||||
|
if err := UpdateNode(node, newnode); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := DeleteNodeByID(node); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if servercfg.Is_EE {
|
||||||
|
if err := EnterpriseResetAllPeersFailovers(node.ID, node.Network); err != nil {
|
||||||
|
logger.Log(0, "failed to reset failover lists during node delete for node", node.Name, node.Network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteNodeByID - deletes a node from database
|
||||||
|
func DeleteNodeByID(node *models.Node) error {
|
||||||
var err error
|
var err error
|
||||||
var key = node.ID
|
var key = node.ID
|
||||||
//delete any ext clients as required
|
//delete any ext clients as required
|
||||||
@@ -170,27 +200,11 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
|
|||||||
logger.Log(0, "failed to deleted ext clients", err.Error())
|
logger.Log(0, "failed to deleted ext clients", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !exterminate {
|
|
||||||
node.Action = models.NODE_DELETE
|
|
||||||
nodedata, err := json.Marshal(&node)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = database.Insert(key, string(nodedata), database.DELETED_NODES_TABLE_NAME)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
|
|
||||||
logger.Log(2, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
|
if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
|
||||||
if !database.IsEmptyRecord(err) {
|
if !database.IsEmptyRecord(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if servercfg.IsDNSMode() {
|
if servercfg.IsDNSMode() {
|
||||||
SetDNS()
|
SetDNS()
|
||||||
}
|
}
|
||||||
@@ -200,7 +214,6 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
|
|||||||
logger.Log(0, "failed to dissasociate", node.OwnerID, "from node", node.ID, ":", err.Error())
|
logger.Log(0, "failed to dissasociate", node.OwnerID, "from node", node.ID, ":", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = nodeacls.RemoveNodeACL(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID))
|
_, err = nodeacls.RemoveNodeACL(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// ignoring for now, could hit a nil pointer if delete called twice
|
// ignoring for now, could hit a nil pointer if delete called twice
|
||||||
@@ -210,11 +223,9 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
|
|||||||
if err = DeleteMetrics(node.ID); err != nil {
|
if err = DeleteMetrics(node.ID); err != nil {
|
||||||
logger.Log(1, "unable to remove metrics from DB for node", node.ID, err.Error())
|
logger.Log(1, "unable to remove metrics from DB for node", node.ID, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.IsServer == "yes" {
|
if node.IsServer == "yes" {
|
||||||
return removeLocalServer(node)
|
return removeLocalServer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,6 +335,9 @@ func CreateNode(node *models.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
node.ID = uuid.NewString()
|
node.ID = uuid.NewString()
|
||||||
|
if node.IsServer == "yes" {
|
||||||
|
node.HostID = uuid.NewString()
|
||||||
|
}
|
||||||
|
|
||||||
//Create a JWT for the node
|
//Create a JWT for the node
|
||||||
tokenString, _ := CreateJWT(node.ID, node.MacAddress, node.Network)
|
tokenString, _ := CreateJWT(node.ID, node.MacAddress, node.Network)
|
||||||
@@ -770,4 +784,34 @@ func updateProNodeACLS(node *models.Node) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PurgePendingNodes(ctx context.Context) {
|
||||||
|
ticker := time.NewTicker(NodePurgeCheckTime)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
nodes, err := GetAllNodes()
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, "PurgePendingNodes failed to retrieve nodes", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.PendingDelete {
|
||||||
|
modified := time.Unix(node.LastModified, 0)
|
||||||
|
if time.Since(modified) > NodePurgeTime {
|
||||||
|
if err := DeleteNode(&node, true); err != nil {
|
||||||
|
logger.Log(0, "failed to purge node", node.ID, err.Error())
|
||||||
|
} else {
|
||||||
|
logger.Log(0, "purged node ", node.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// == END PRO ==
|
// == END PRO ==
|
||||||
|
@@ -257,6 +257,8 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
|
|||||||
if peer.LocalListenPort != 0 {
|
if peer.LocalListenPort != 0 {
|
||||||
peer.ListenPort = peer.LocalListenPort
|
peer.ListenPort = peer.LocalListenPort
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -208,7 +208,7 @@ func ServerUpdate(serverNode *models.Node, ifaceDelta bool) error {
|
|||||||
|
|
||||||
var err = ServerPull(serverNode, ifaceDelta)
|
var err = ServerPull(serverNode, ifaceDelta)
|
||||||
if isDeleteError(err) {
|
if isDeleteError(err) {
|
||||||
return DeleteNodeByID(serverNode, true)
|
return DeleteNode(serverNode, true)
|
||||||
} else if err != nil && !ifaceDelta {
|
} else if err != nil && !ifaceDelta {
|
||||||
err = ServerPull(serverNode, true)
|
err = ServerPull(serverNode, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -239,7 +239,7 @@ func checkNodeActions(node *models.Node) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.Action == models.NODE_DELETE {
|
if node.Action == models.NODE_DELETE {
|
||||||
err := DeleteNodeByID(node, true)
|
err := DeleteNode(node, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log(1, "error deleting locally:", err.Error())
|
logger.Log(1, "error deleting locally:", err.Error())
|
||||||
}
|
}
|
||||||
|
31
logic/version.go
Normal file
31
logic/version.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-version"
|
||||||
|
)
|
||||||
|
|
||||||
|
const MinVersion = "v0.17.0"
|
||||||
|
|
||||||
|
// IsVersionCompatible checks that the version passed is compabtible (>=) with MinVersion
|
||||||
|
func IsVersionComptatible(ver string) bool {
|
||||||
|
// during dev, assume developers know what they are doing
|
||||||
|
if ver == "dev" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
trimmed := strings.TrimFunc(ver, func(r rune) bool {
|
||||||
|
return !unicode.IsNumber(r)
|
||||||
|
})
|
||||||
|
v, err := version.NewVersion(trimmed)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
constraint, err := version.NewConstraint(">= " + MinVersion)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return constraint.Check(v)
|
||||||
|
|
||||||
|
}
|
35
logic/version_test.go
Normal file
35
logic/version_test.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matryer/is"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVersion(t *testing.T) {
|
||||||
|
t.Run("valid version", func(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
valid := IsVersionComptatible("v0.17.1-testing")
|
||||||
|
is.Equal(valid, true)
|
||||||
|
})
|
||||||
|
t.Run("dev version", func(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
valid := IsVersionComptatible("dev")
|
||||||
|
is.Equal(valid, true)
|
||||||
|
})
|
||||||
|
t.Run("invalid version", func(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
valid := IsVersionComptatible("v0.14.2-refactor")
|
||||||
|
is.Equal(valid, false)
|
||||||
|
})
|
||||||
|
t.Run("no version", func(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
valid := IsVersionComptatible("testing")
|
||||||
|
is.Equal(valid, false)
|
||||||
|
})
|
||||||
|
t.Run("incomplete version", func(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
valid := IsVersionComptatible("0.18")
|
||||||
|
is.Equal(valid, true)
|
||||||
|
})
|
||||||
|
}
|
@@ -74,7 +74,7 @@ func ManageZombies(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if time.Since(time.Unix(node.LastCheckIn, 0)) > time.Minute*ZOMBIE_DELETE_TIME {
|
if time.Since(time.Unix(node.LastCheckIn, 0)) > time.Minute*ZOMBIE_DELETE_TIME {
|
||||||
if err := DeleteNodeByID(&node, true); err != nil {
|
if err := DeleteNode(&node, true); err != nil {
|
||||||
logger.Log(1, "error deleting zombie node", zombies[i], err.Error())
|
logger.Log(1, "error deleting zombie node", zombies[i], err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
1
main.go
1
main.go
@@ -209,6 +209,7 @@ func runMessageQueue(wg *sync.WaitGroup) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
go mq.Keepalive(ctx)
|
go mq.Keepalive(ctx)
|
||||||
go logic.ManageZombies(ctx)
|
go logic.ManageZombies(ctx)
|
||||||
|
go logic.PurgePendingNodes(ctx)
|
||||||
quit := make(chan os.Signal, 1)
|
quit := make(chan os.Signal, 1)
|
||||||
signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
|
signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
|
||||||
<-quit
|
<-quit
|
||||||
|
@@ -43,14 +43,23 @@ var seededRand *rand.Rand = rand.New(
|
|||||||
type NodeCheckin struct {
|
type NodeCheckin struct {
|
||||||
Version string
|
Version string
|
||||||
Connected string
|
Connected string
|
||||||
|
Ifaces []Iface
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iface struct for local interfaces of a node
|
||||||
|
type Iface struct {
|
||||||
|
Name string
|
||||||
|
Address net.IPNet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node - struct for node model
|
// Node - struct for node model
|
||||||
type Node struct {
|
type Node struct {
|
||||||
ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5,id_unique"`
|
ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5,id_unique"`
|
||||||
|
HostID string `json:"hostid,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5,id_unique"`
|
||||||
Address string `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
|
Address string `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
|
||||||
Address6 string `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
|
Address6 string `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
|
||||||
LocalAddress string `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty"`
|
LocalAddress string `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty"`
|
||||||
|
Interfaces []Iface `json:"interfaces" yaml:"interfaces"`
|
||||||
Name string `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
|
Name string `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
|
||||||
NetworkSettings Network `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
|
NetworkSettings Network `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
|
||||||
ListenPort int32 `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
|
ListenPort int32 `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
|
||||||
@@ -102,6 +111,7 @@ type Node struct {
|
|||||||
FirewallInUse string `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"`
|
FirewallInUse string `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"`
|
||||||
InternetGateway string `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"`
|
InternetGateway string `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"`
|
||||||
Connected string `json:"connected" bson:"connected" yaml:"connected" validate:"checkyesorno"`
|
Connected string `json:"connected" bson:"connected" yaml:"connected" validate:"checkyesorno"`
|
||||||
|
PendingDelete bool `json:"pendingdelete" bson:"pendingdelete" yaml:"pendingdelete"`
|
||||||
// == PRO ==
|
// == PRO ==
|
||||||
DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"`
|
DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"`
|
||||||
OwnerID string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"`
|
OwnerID string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"`
|
||||||
|
@@ -220,6 +220,7 @@ type ServerConfig struct {
|
|||||||
Version string `yaml:"version"`
|
Version string `yaml:"version"`
|
||||||
MQPort string `yaml:"mqport"`
|
MQPort string `yaml:"mqport"`
|
||||||
Server string `yaml:"server"`
|
Server string `yaml:"server"`
|
||||||
|
Broker string `yaml:"broker"`
|
||||||
Is_EE bool `yaml:"isee"`
|
Is_EE bool `yaml:"isee"`
|
||||||
StunPort string `yaml:"stun_port"`
|
StunPort string `yaml:"stun_port"`
|
||||||
}
|
}
|
||||||
|
@@ -52,6 +52,7 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
|
|||||||
node.SetLastCheckIn()
|
node.SetLastCheckIn()
|
||||||
node.Version = checkin.Version
|
node.Version = checkin.Version
|
||||||
node.Connected = checkin.Connected
|
node.Connected = checkin.Connected
|
||||||
|
node.Interfaces = checkin.Ifaces
|
||||||
if err := logic.UpdateNode(&node, &node); err != nil {
|
if err := logic.UpdateNode(&node, &node); err != nil {
|
||||||
logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
|
logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
<assemblyIdentity
|
<assemblyIdentity
|
||||||
|
<<<<<<< HEAD
|
||||||
version="0.17.0.0"
|
version="0.17.0.0"
|
||||||
|
=======
|
||||||
|
version="0.16.3.0"
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
processorArchitecture="*"
|
processorArchitecture="*"
|
||||||
name="netclient.exe"
|
name="netclient.exe"
|
||||||
type="win32"
|
type="win32"
|
||||||
|
@@ -17,11 +17,14 @@ cat << "EOF"
|
|||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
echo "-----------------------------------------------------"
|
echo "-----------------------------------------------------"
|
||||||
echo "Would you like to install Netmaker Community Edition (CE), or Netmaker Enterprise Edition (EE)?"
|
echo "Would you like to install Netmaker Community Edition (CE), or Netmaker Enterprise Edition (EE)?"
|
||||||
@@ -66,12 +69,24 @@ confirm() {(
|
|||||||
read -p 'Does everything look right? [y/n]: ' yn
|
read -p 'Does everything look right? [y/n]: ' yn
|
||||||
case $yn in
|
case $yn in
|
||||||
[Yy]* ) override="true"; break;;
|
[Yy]* ) override="true"; break;;
|
||||||
|
<<<<<<< HEAD
|
||||||
[Nn]* ) echo "exiting..."; exit 1;;
|
[Nn]* ) echo "exiting..."; exit 1;;
|
||||||
|
=======
|
||||||
|
[Nn]* ) echo "exiting..."; exit;;
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
* ) echo "Please answer yes or no.";;
|
* ) echo "Please answer yes or no.";;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
if [ $(id -u) -ne 0 ]; then
|
||||||
|
echo "This script must be run as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
echo "checking dependencies..."
|
echo "checking dependencies..."
|
||||||
|
|
||||||
OS=$(uname)
|
OS=$(uname)
|
||||||
@@ -124,9 +139,12 @@ if [ -z "${install_cmd}" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
set -- $dependencies
|
set -- $dependencies
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
${update_cmd}
|
${update_cmd}
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
while [ -n "$1" ]; do
|
while [ -n "$1" ]; do
|
||||||
if [ "${OS}" = "FreeBSD" ]; then
|
if [ "${OS}" = "FreeBSD" ]; then
|
||||||
is_installed=$(pkg check -d $1 | grep "Checking" | grep "done")
|
is_installed=$(pkg check -d $1 | grep "Checking" | grep "done")
|
||||||
@@ -189,12 +207,22 @@ COREDNS_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
|
|||||||
SERVER_PUBLIC_IP=$(curl -s ifconfig.me)
|
SERVER_PUBLIC_IP=$(curl -s ifconfig.me)
|
||||||
MASTER_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
|
MASTER_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
|
||||||
MQ_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
|
MQ_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
|
||||||
|
<<<<<<< HEAD
|
||||||
DOMAIN_TYPE=""
|
DOMAIN_TYPE=""
|
||||||
|
|
||||||
echo "-----------------------------------------------------"
|
echo "-----------------------------------------------------"
|
||||||
echo "Would you like to use your own domain for netmaker, or an auto-generated domain?"
|
echo "Would you like to use your own domain for netmaker, or an auto-generated domain?"
|
||||||
echo "To use your own domain, add a Wildcard DNS record (e.x: *.netmaker.example.com) pointing to $SERVER_PUBLIC_IP"
|
echo "To use your own domain, add a Wildcard DNS record (e.x: *.netmaker.example.com) pointing to $SERVER_PUBLIC_IP"
|
||||||
echo "-----------------------------------------------------"
|
echo "-----------------------------------------------------"
|
||||||
|
=======
|
||||||
|
EMAIL="$(echo $RANDOM | md5sum | head -c 16)@email.com"
|
||||||
|
DOMAIN_TYPE=""
|
||||||
|
|
||||||
|
echo "-----------------------------------------------------"
|
||||||
|
echo "Would you like to use your own domain for netmaker, or an auto-generated domain?"
|
||||||
|
echo "To use your own domain, add a Wildcard DNS record (e.x: *.netmaker.example.com) pointing to $SERVER_PUBLIC_IP"
|
||||||
|
echo "-----------------------------------------------------"
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
select domain_option in "Auto Generated ($NETMAKER_BASE_DOMAIN)" "Custom Domain (e.x: netmaker.example.com)"; do
|
select domain_option in "Auto Generated ($NETMAKER_BASE_DOMAIN)" "Custom Domain (e.x: netmaker.example.com)"; do
|
||||||
case $REPLY in
|
case $REPLY in
|
||||||
1)
|
1)
|
||||||
@@ -212,9 +240,15 @@ select domain_option in "Auto Generated ($NETMAKER_BASE_DOMAIN)" "Custom Domain
|
|||||||
*) echo "invalid option $REPLY";;
|
*) echo "invalid option $REPLY";;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
wait_seconds 2
|
wait_seconds 2
|
||||||
|
|
||||||
|
=======
|
||||||
|
|
||||||
|
wait_seconds 2
|
||||||
|
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
echo "-----------------------------------------------------"
|
echo "-----------------------------------------------------"
|
||||||
echo "The following subdomains will be used:"
|
echo "The following subdomains will be used:"
|
||||||
echo " dashboard.$NETMAKER_BASE_DOMAIN"
|
echo " dashboard.$NETMAKER_BASE_DOMAIN"
|
||||||
@@ -225,6 +259,7 @@ if [ "$INSTALL_TYPE" = "ee" ]; then
|
|||||||
echo " prometheus.$NETMAKER_BASE_DOMAIN"
|
echo " prometheus.$NETMAKER_BASE_DOMAIN"
|
||||||
echo " netmaker-exporter.$NETMAKER_BASE_DOMAIN"
|
echo " netmaker-exporter.$NETMAKER_BASE_DOMAIN"
|
||||||
echo " grafana.$NETMAKER_BASE_DOMAIN"
|
echo " grafana.$NETMAKER_BASE_DOMAIN"
|
||||||
|
<<<<<<< HEAD
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "-----------------------------------------------------"
|
echo "-----------------------------------------------------"
|
||||||
@@ -266,6 +301,45 @@ if [ -z "$GET_EMAIL" ]; then
|
|||||||
else
|
else
|
||||||
EMAIL="$GET_EMAIL"
|
EMAIL="$GET_EMAIL"
|
||||||
fi
|
fi
|
||||||
|
=======
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "-----------------------------------------------------"
|
||||||
|
|
||||||
|
if [[ "$DOMAIN_TYPE" == "custom" ]]; then
|
||||||
|
echo "before continuing, confirm DNS is configured correctly, with records pointing to $SERVER_PUBLIC_IP"
|
||||||
|
confirm
|
||||||
|
fi
|
||||||
|
|
||||||
|
wait_seconds 1
|
||||||
|
|
||||||
|
if [ "$INSTALL_TYPE" = "ee" ]; then
|
||||||
|
|
||||||
|
echo "-----------------------------------------------------"
|
||||||
|
echo "Provide Details for EE installation:"
|
||||||
|
echo " 1. Log into https://dashboard.license.netmaker.io"
|
||||||
|
echo " 2. Copy License Key Value: https://dashboard.license.netmaker.io/license-keys"
|
||||||
|
echo " 3. Retrieve Account ID: https://dashboard.license.netmaker.io/user"
|
||||||
|
echo " 4. note email address"
|
||||||
|
echo "-----------------------------------------------------"
|
||||||
|
unset LICENSE_KEY
|
||||||
|
while [ -z "$LICENSE_KEY" ]; do
|
||||||
|
read -p "License Key: " LICENSE_KEY
|
||||||
|
done
|
||||||
|
unset ACCOUNT_ID
|
||||||
|
while [ -z ${ACCOUNT_ID} ]; do
|
||||||
|
read -p "Account ID: " ACCOUNT_ID
|
||||||
|
done
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset EMAIL
|
||||||
|
while [ -z ${EMAIL} ]; do
|
||||||
|
read -p "Email Address (for LetsEncrypt): " EMAIL
|
||||||
|
done
|
||||||
|
|
||||||
|
wait_seconds 2
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
|
|
||||||
wait_seconds 2
|
wait_seconds 2
|
||||||
|
|
||||||
@@ -295,6 +369,7 @@ wait_seconds 3
|
|||||||
echo "Pulling config files..."
|
echo "Pulling config files..."
|
||||||
|
|
||||||
COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.yml"
|
COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.yml"
|
||||||
|
<<<<<<< HEAD
|
||||||
CADDY_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/docker/Caddyfile"
|
CADDY_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/docker/Caddyfile"
|
||||||
if [ "$INSTALL_TYPE" = "ee" ]; then
|
if [ "$INSTALL_TYPE" = "ee" ]; then
|
||||||
COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.ee.yml"
|
COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.ee.yml"
|
||||||
@@ -302,6 +377,13 @@ if [ "$INSTALL_TYPE" = "ee" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
wget -O /root/docker-compose.yml $COMPOSE_URL && wget -O /root/mosquitto.conf https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf && wget -O /root/Caddyfile $CADDY_URL && wget -q -O /root/wait.sh https://raw.githubusercontent.com/gravitl/netmaker/master/docker/wait.sh && chmod +x /root/wait.sh
|
wget -O /root/docker-compose.yml $COMPOSE_URL && wget -O /root/mosquitto.conf https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf && wget -O /root/Caddyfile $CADDY_URL && wget -q -O /root/wait.sh https://raw.githubusercontent.com/gravitl/netmaker/master/docker/wait.sh && chmod +x /root/wait.sh
|
||||||
|
=======
|
||||||
|
if [ "$INSTALL_TYPE" = "ee" ]; then
|
||||||
|
COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.ee.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
wget -O docker-compose.yml $COMPOSE_URL && wget -O /root/mosquitto.conf https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf && wget -q -O /root/wait.sh https://raw.githubusercontent.com/gravitl/netmaker/develop/docker/wait.sh && chmod +x wait.sh
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
|
|
||||||
mkdir -p /etc/netmaker
|
mkdir -p /etc/netmaker
|
||||||
|
|
||||||
@@ -311,7 +393,11 @@ sed -i "s/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/docker-compose.yml
|
|||||||
sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile
|
sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile
|
||||||
sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml
|
sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml
|
||||||
sed -i "s/REPLACE_MASTER_KEY/$MASTER_KEY/g" /root/docker-compose.yml
|
sed -i "s/REPLACE_MASTER_KEY/$MASTER_KEY/g" /root/docker-compose.yml
|
||||||
|
<<<<<<< HEAD
|
||||||
sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile
|
sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile
|
||||||
|
=======
|
||||||
|
sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/docker-compose.yml
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
sed -i "s/REPLACE_MQ_ADMIN_PASSWORD/$MQ_PASSWORD/g" /root/docker-compose.yml
|
sed -i "s/REPLACE_MQ_ADMIN_PASSWORD/$MQ_PASSWORD/g" /root/docker-compose.yml
|
||||||
if [ "$INSTALL_TYPE" = "ee" ]; then
|
if [ "$INSTALL_TYPE" = "ee" ]; then
|
||||||
sed -i "s~YOUR_LICENSE_KEY~$LICENSE_KEY~g" /root/docker-compose.yml
|
sed -i "s~YOUR_LICENSE_KEY~$LICENSE_KEY~g" /root/docker-compose.yml
|
||||||
@@ -368,6 +454,7 @@ wait_seconds 3
|
|||||||
|
|
||||||
echo "Configuring netmaker server as ingress gateway"
|
echo "Configuring netmaker server as ingress gateway"
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
for i in 1 2 3 4 5 6
|
for i in 1 2 3 4 5 6
|
||||||
do
|
do
|
||||||
echo " waiting for server node to become available"
|
echo " waiting for server node to become available"
|
||||||
@@ -386,6 +473,16 @@ do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
=======
|
||||||
|
|
||||||
|
while [ -z "$SERVER_ID" ]; do
|
||||||
|
echo "waiting for server node to become available"
|
||||||
|
wait_seconds 2
|
||||||
|
curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker)
|
||||||
|
SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
|
||||||
|
done
|
||||||
|
|
||||||
|
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
|
||||||
curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress
|
curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress
|
||||||
|
|
||||||
)}
|
)}
|
||||||
|
@@ -96,6 +96,8 @@ func GetServerConfig() config.ServerConfig {
|
|||||||
// GetServerConfig - gets the server config into memory from file or env
|
// GetServerConfig - gets the server config into memory from file or env
|
||||||
func GetServerInfo() models.ServerConfig {
|
func GetServerInfo() models.ServerConfig {
|
||||||
var cfg models.ServerConfig
|
var cfg models.ServerConfig
|
||||||
|
cfg.Server = GetServer()
|
||||||
|
cfg.Broker = GetBroker()
|
||||||
cfg.API = GetAPIConnString()
|
cfg.API = GetAPIConnString()
|
||||||
cfg.CoreDNSAddr = GetCoreDNSAddr()
|
cfg.CoreDNSAddr = GetCoreDNSAddr()
|
||||||
cfg.APIPort = GetAPIPort()
|
cfg.APIPort = GetAPIPort()
|
||||||
@@ -105,7 +107,6 @@ func GetServerInfo() models.ServerConfig {
|
|||||||
cfg.DNSMode = "on"
|
cfg.DNSMode = "on"
|
||||||
}
|
}
|
||||||
cfg.Version = GetVersion()
|
cfg.Version = GetVersion()
|
||||||
cfg.Server = GetServer()
|
|
||||||
cfg.Is_EE = Is_EE
|
cfg.Is_EE = Is_EE
|
||||||
cfg.StunPort = GetStunPort()
|
cfg.StunPort = GetStunPort()
|
||||||
|
|
||||||
@@ -385,6 +386,17 @@ func GetServer() string {
|
|||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBroker - gets the broker name
|
||||||
|
func GetBroker() string {
|
||||||
|
server := ""
|
||||||
|
if os.Getenv("BROKER_NAME") != "" {
|
||||||
|
server = os.Getenv("BROKER_NAME")
|
||||||
|
} else if config.Config.Server.Broker != "" {
|
||||||
|
server = config.Config.Server.Broker
|
||||||
|
}
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
func GetVerbosity() int32 {
|
func GetVerbosity() int32 {
|
||||||
var verbosity = 0
|
var verbosity = 0
|
||||||
var err error
|
var err error
|
||||||
|
Reference in New Issue
Block a user