merge conflicts resolved

This commit is contained in:
Abhishek Kondur 2022-12-02 10:08:01 +05:30
commit 5b7ead91e6
23 changed files with 398 additions and 136 deletions

View file

@ -19,7 +19,8 @@ services:
- sqldata:/root/data
- mosquitto_data:/etc/netmaker
environment:
SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
BROKER_NAME: "broker.NETMAKER_BASE_DOMAIN"
SERVER_NAME: "NETMAKER_BASE_DOMAIN"
SERVER_HOST: "SERVER_PUBLIC_IP"
SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
COREDNS_ADDR: "SERVER_PUBLIC_IP"

View file

@ -1,7 +1,7 @@
//Environment file for getting variables
//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
//Reads from the config/environments/dev.yaml file by default
// Environment file for getting variables
// 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
// Reads from the config/environments/dev.yaml file by default
package config
import (
@ -69,6 +69,7 @@ type ServerConfig struct {
MQPort string `yaml:"mqport"`
MQServerPort string `yaml:"mqserverport"`
Server string `yaml:"server"`
Broker string `yam:"broker"`
PublicIPService string `yaml:"publicipservice"`
MQAdminPassword string `yaml:"mqadminpassword"`
MetricsExporter string `yaml:"metrics_exporter"`

View file

@ -2,6 +2,7 @@ package controller
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
@ -40,13 +41,13 @@ func nodeHandlers(r *mux.Router) {
//
// Authenticate to make further API calls related to a network.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: successResponse
// Responses:
// 200: successResponse
func authenticate(response http.ResponseWriter, request *http.Request) {
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.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeSliceResponse
// Responses:
// 200: nodeSliceResponse
func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
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.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// 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
func getAllNodes(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
@ -439,13 +441,13 @@ func getUsersNodes(user models.User) ([]models.Node, error) {
//
// Get an individual node.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
// Responses:
// 200: nodeResponse
func getNode(w http.ResponseWriter, r *http.Request) {
// set header.
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.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeGetResponse
// Responses:
// 200: nodeGetResponse
func createNode(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
@ -547,6 +549,12 @@ func createNode(w http.ResponseWriter, r *http.Request) {
return
}
if !logic.IsVersionComptatible(node.Version) {
err := errors.New("incomatible netclient version")
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
node.Network = networkName
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
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"))
return
}
@ -645,12 +653,12 @@ func createNode(w http.ResponseWriter, r *http.Request) {
return
}
// Create client for this node in Mq
// Create client for this host in Mq
event := mq.MqDynsecPayload{
Commands: []mq.MqDynSecCmd{
{ // delete if any client exists already
Command: mq.DeleteClientCmd,
Username: node.ID,
Username: node.HostID,
},
{
Command: mq.CreateRoleCmd,
@ -660,7 +668,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
},
{
Command: mq.CreateClientCmd,
Username: node.ID,
Username: node.HostID,
Password: nodePassword,
Textname: node.Name,
Roles: []mq.MqDynSecRole{
@ -700,13 +708,14 @@ func createNode(w http.ResponseWriter, r *http.Request) {
//
// Takes a node out of pending state.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
//
// Responses:
// 200: nodeResponse
// Takes node out of pending state
// TODO: May want to use cordon/uncordon terminology instead of "ispending".
func uncordonNode(w http.ResponseWriter, r *http.Request) {
@ -733,13 +742,13 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
//
// Create an egress gateway.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
// Responses:
// 200: nodeResponse
func createEgressGateway(w http.ResponseWriter, r *http.Request) {
var gateway models.EgressGatewayRequest
var params = mux.Vars(r)
@ -772,13 +781,13 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
//
// Delete an egress gateway.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
// Responses:
// 200: nodeResponse
func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r)
@ -806,13 +815,13 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
//
// Create an ingress gateway.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
// Responses:
// 200: nodeResponse
func createIngressGateway(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r)
w.Header().Set("Content-Type", "application/json")
@ -850,13 +859,13 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
//
// Delete an ingress gateway.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
// Responses:
// 200: nodeResponse
func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var params = mux.Vars(r)
@ -888,13 +897,13 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
//
// Update an individual node.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
// Responses:
// 200: nodeResponse
func updateNode(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
@ -998,13 +1007,13 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
//
// Delete an individual node.
//
// Schemes: https
// Schemes: https
//
// Security:
// oauth
// Security:
// oauth
//
// Responses:
// 200: nodeResponse
// Responses:
// 200: nodeResponse
func deleteNode(w http.ResponseWriter, r *http.Request) {
// Set header
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 nodeid = params["nodeid"]
fromNode := r.Header.Get("requestfrom") == "node"
var node, err = logic.GetNodeByID(nodeid)
node, err := logic.GetNodeByID(nodeid)
if err != nil {
if fromNode {
node, err = logic.GetDeletedNodeByID(nodeid)
if err != nil {
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
}
logger.Log(0, "error retrieving node to delete", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if isServer(&node) {
err := fmt.Errorf("cannot delete server node")
@ -1044,34 +1042,35 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
return
}
}
//send update to node to be deleted before deleting on server otherwise message cannot be sent
node.Action = models.NODE_DELETE
err = logic.DeleteNodeByID(&node, fromNode)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
if err := logic.DeleteNode(&node, fromNode); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
return
}
if fromNode {
// deletes node related role and client
event := mq.MqDynsecPayload{
Commands: []mq.MqDynSecCmd{
{
Command: mq.DeleteClientCmd,
Username: nodeid,
//check if server should be removed from mq
found := false
// err is irrelevent
nodes, _ := logic.GetAllNodes()
for _, nodetocheck := range nodes {
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",
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)
}
if err := mq.PublishEventToDynSecTopic(event); err != nil {
logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
event.Commands, err.Error()))
}
}
}
logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")

3
go.mod
View file

@ -50,6 +50,8 @@ require (
gortc.io/stun v1.23.0
)
require github.com/matryer/is v1.4.0
require (
cloud.google.com/go/compute v1.7.0 // 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/google/go-cmp v0.5.8 // 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/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
github.com/kr/text v0.2.0 // indirect

4
go.sum
View file

@ -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-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-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/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=
@ -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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
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-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=

View file

@ -16,7 +16,11 @@ spec:
hostNetwork: true
containers:
- name: netclient
<<<<<<< HEAD
image: gravitl/netclient:v0.17.0
=======
image: gravitl/netclient:v0.16.3
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
env:
- name: TOKEN
value: "TOKEN_VALUE"

View file

@ -28,7 +28,11 @@ spec:
# - "<node label value>"
containers:
- name: netclient
<<<<<<< HEAD
image: gravitl/netclient:v0.17.0
=======
image: gravitl/netclient:v0.16.3
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
env:
- name: TOKEN
value: "TOKEN_VALUE"

View file

@ -83,7 +83,11 @@ spec:
value: "Kubernetes"
- name: VERBOSITY
value: "3"
<<<<<<< HEAD
image: gravitl/netmaker:v0.17.0
=======
image: gravitl/netmaker:v0.16.3
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
imagePullPolicy: Always
name: netmaker
ports:

View file

@ -15,7 +15,11 @@ spec:
spec:
containers:
- name: netmaker-ui
<<<<<<< HEAD
image: gravitl/netmaker-ui:v0.17.0
=======
image: gravitl/netmaker-ui:v0.16.3
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
ports:
- containerPort: 443
env:

View file

@ -54,7 +54,7 @@ func DeleteNetwork(network string) error {
servers, err := GetSortedNetworkServerNodes(network)
if err == nil {
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)
} else {
logger.Log(2, "removed server", s.Name, "before deleting network", network)

View file

@ -1,6 +1,7 @@
package logic
import (
"context"
"encoding/json"
"errors"
"fmt"
@ -22,8 +23,14 @@ import (
"golang.org/x/crypto/bcrypt"
)
// RELAY_NODE_ERR - error to return if relay node is unfound
const RELAY_NODE_ERR = "could not find relay for node"
const (
// 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
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.")
}
// DeleteNodeByID - deletes a node from database or moves into delete nodes table
func DeleteNodeByID(node *models.Node, exterminate bool) error {
// DeleteNode - marks node for deletion if called by UI or deletes node if called by node
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 key = node.ID
//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())
}
}
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 !database.IsEmptyRecord(err) {
return err
}
}
if servercfg.IsDNSMode() {
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())
}
}
_, err = nodeacls.RemoveNodeACL(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID))
if err != nil {
// 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 {
logger.Log(1, "unable to remove metrics from DB for node", node.ID, err.Error())
}
if node.IsServer == "yes" {
return removeLocalServer(node)
}
return nil
}
@ -324,6 +335,9 @@ func CreateNode(node *models.Node) error {
}
node.ID = uuid.NewString()
if node.IsServer == "yes" {
node.HostID = uuid.NewString()
}
//Create a JWT for the node
tokenString, _ := CreateJWT(node.ID, node.MacAddress, node.Network)
@ -770,4 +784,34 @@ func updateProNodeACLS(node *models.Node) error {
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 ==

View file

@ -257,6 +257,8 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
if peer.LocalListenPort != 0 {
peer.ListenPort = peer.LocalListenPort
}
} else {
continue
}
}

View file

@ -208,7 +208,7 @@ func ServerUpdate(serverNode *models.Node, ifaceDelta bool) error {
var err = ServerPull(serverNode, ifaceDelta)
if isDeleteError(err) {
return DeleteNodeByID(serverNode, true)
return DeleteNode(serverNode, true)
} else if err != nil && !ifaceDelta {
err = ServerPull(serverNode, true)
if err != nil {
@ -239,7 +239,7 @@ func checkNodeActions(node *models.Node) string {
}
}
if node.Action == models.NODE_DELETE {
err := DeleteNodeByID(node, true)
err := DeleteNode(node, true)
if err != nil {
logger.Log(1, "error deleting locally:", err.Error())
}

31
logic/version.go Normal file
View 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
View 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)
})
}

View file

@ -74,7 +74,7 @@ func ManageZombies(ctx context.Context) {
continue
}
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())
continue
}

View file

@ -209,6 +209,7 @@ func runMessageQueue(wg *sync.WaitGroup) {
ctx, cancel := context.WithCancel(context.Background())
go mq.Keepalive(ctx)
go logic.ManageZombies(ctx)
go logic.PurgePendingNodes(ctx)
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
<-quit

View file

@ -43,14 +43,23 @@ var seededRand *rand.Rand = rand.New(
type NodeCheckin struct {
Version 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
type Node struct {
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"`
Address6 string `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
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"`
NetworkSettings Network `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
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"`
InternetGateway string `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"`
Connected string `json:"connected" bson:"connected" yaml:"connected" validate:"checkyesorno"`
PendingDelete bool `json:"pendingdelete" bson:"pendingdelete" yaml:"pendingdelete"`
// == PRO ==
DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"`
OwnerID string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"`

View file

@ -220,6 +220,7 @@ type ServerConfig struct {
Version string `yaml:"version"`
MQPort string `yaml:"mqport"`
Server string `yaml:"server"`
Broker string `yaml:"broker"`
Is_EE bool `yaml:"isee"`
StunPort string `yaml:"stun_port"`
}

View file

@ -52,6 +52,7 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
node.SetLastCheckIn()
node.Version = checkin.Version
node.Connected = checkin.Connected
node.Interfaces = checkin.Ifaces
if err := logic.UpdateNode(&node, &node); err != nil {
logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
return

View file

@ -1,7 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
<<<<<<< HEAD
version="0.17.0.0"
=======
version="0.16.3.0"
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
processorArchitecture="*"
name="netclient.exe"
type="win32"

View file

@ -17,11 +17,14 @@ cat << "EOF"
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EOF
<<<<<<< HEAD
if [ $(id -u) -ne 0 ]; then
echo "This script must be run as root"
exit 1
fi
=======
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
if [ -z "$1" ]; then
echo "-----------------------------------------------------"
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
case $yn in
[Yy]* ) override="true"; break;;
<<<<<<< HEAD
[Nn]* ) echo "exiting..."; exit 1;;
=======
[Nn]* ) echo "exiting..."; exit;;
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
* ) echo "Please answer yes or no.";;
esac
done
)}
<<<<<<< HEAD
=======
if [ $(id -u) -ne 0 ]; then
echo "This script must be run as root"
exit 1
fi
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
echo "checking dependencies..."
OS=$(uname)
@ -124,9 +139,12 @@ if [ -z "${install_cmd}" ]; then
fi
set -- $dependencies
<<<<<<< HEAD
${update_cmd}
=======
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
while [ -n "$1" ]; do
if [ "${OS}" = "FreeBSD" ]; then
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)
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 '')
<<<<<<< HEAD
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 "-----------------------------------------------------"
=======
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
case $REPLY in
1)
@ -212,9 +240,15 @@ select domain_option in "Auto Generated ($NETMAKER_BASE_DOMAIN)" "Custom Domain
*) echo "invalid option $REPLY";;
esac
done
<<<<<<< HEAD
wait_seconds 2
=======
wait_seconds 2
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
echo "-----------------------------------------------------"
echo "The following subdomains will be used:"
echo " dashboard.$NETMAKER_BASE_DOMAIN"
@ -225,6 +259,7 @@ if [ "$INSTALL_TYPE" = "ee" ]; then
echo " prometheus.$NETMAKER_BASE_DOMAIN"
echo " netmaker-exporter.$NETMAKER_BASE_DOMAIN"
echo " grafana.$NETMAKER_BASE_DOMAIN"
<<<<<<< HEAD
fi
echo "-----------------------------------------------------"
@ -266,6 +301,45 @@ if [ -z "$GET_EMAIL" ]; then
else
EMAIL="$GET_EMAIL"
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
@ -295,6 +369,7 @@ wait_seconds 3
echo "Pulling config files..."
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"
if [ "$INSTALL_TYPE" = "ee" ]; then
COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.ee.yml"
@ -302,6 +377,13 @@ if [ "$INSTALL_TYPE" = "ee" ]; then
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
=======
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
@ -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/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/docker-compose.yml
>>>>>>> 407c6ed20a427153acb4901db7e61d3016823cc4
sed -i "s/REPLACE_MQ_ADMIN_PASSWORD/$MQ_PASSWORD/g" /root/docker-compose.yml
if [ "$INSTALL_TYPE" = "ee" ]; then
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"
<<<<<<< HEAD
for i in 1 2 3 4 5 6
do
echo " waiting for server node to become available"
@ -386,6 +473,16 @@ do
fi
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
)}

View file

@ -96,6 +96,8 @@ func GetServerConfig() config.ServerConfig {
// GetServerConfig - gets the server config into memory from file or env
func GetServerInfo() models.ServerConfig {
var cfg models.ServerConfig
cfg.Server = GetServer()
cfg.Broker = GetBroker()
cfg.API = GetAPIConnString()
cfg.CoreDNSAddr = GetCoreDNSAddr()
cfg.APIPort = GetAPIPort()
@ -105,7 +107,6 @@ func GetServerInfo() models.ServerConfig {
cfg.DNSMode = "on"
}
cfg.Version = GetVersion()
cfg.Server = GetServer()
cfg.Is_EE = Is_EE
cfg.StunPort = GetStunPort()
@ -385,6 +386,17 @@ func GetServer() string {
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 {
var verbosity = 0
var err error