Browse Source

merge develop

0xdcarns 2 years ago
parent
commit
48aad9780c

+ 47 - 0
cli/cmd/enrollment_key/create.go

@@ -0,0 +1,47 @@
+package enrollment_key
+
+import (
+	"strings"
+
+	"github.com/gravitl/netmaker/cli/functions"
+	"github.com/gravitl/netmaker/models"
+	"github.com/spf13/cobra"
+)
+
+var (
+	expiration    int
+	usesRemaining int
+	networks      string
+	unlimited     bool
+	tags          string
+)
+
+var enrollmentKeyCreateCmd = &cobra.Command{
+	Use:   "create",
+	Args:  cobra.NoArgs,
+	Short: "Create an enrollment key",
+	Long:  `Create an enrollment key`,
+	Run: func(cmd *cobra.Command, args []string) {
+		enrollKey := &models.APIEnrollmentKey{
+			Expiration:    int64(expiration),
+			UsesRemaining: usesRemaining,
+			Unlimited:     unlimited,
+		}
+		if networks != "" {
+			enrollKey.Networks = strings.Split(networks, ",")
+		}
+		if tags != "" {
+			enrollKey.Tags = strings.Split(tags, ",")
+		}
+		functions.PrettyPrint(functions.CreateEnrollmentKey(enrollKey))
+	},
+}
+
+func init() {
+	enrollmentKeyCreateCmd.Flags().IntVar(&expiration, "expiration", 0, "Expiration time of the key in UNIX timestamp format")
+	enrollmentKeyCreateCmd.Flags().IntVar(&usesRemaining, "uses", 0, "Number of times this key can be used")
+	enrollmentKeyCreateCmd.Flags().StringVar(&networks, "networks", "", "Comma-separated list of networks which the enrollment key can access")
+	enrollmentKeyCreateCmd.Flags().BoolVar(&unlimited, "unlimited", false, "Should the key have unlimited uses ?")
+	enrollmentKeyCreateCmd.Flags().StringVar(&tags, "tags", "", "Comma-separated list of any additional tags")
+	rootCmd.AddCommand(enrollmentKeyCreateCmd)
+}

+ 23 - 0
cli/cmd/enrollment_key/delete.go

@@ -0,0 +1,23 @@
+package enrollment_key
+
+import (
+	"fmt"
+
+	"github.com/gravitl/netmaker/cli/functions"
+	"github.com/spf13/cobra"
+)
+
+var enrollmentKeyDeleteCmd = &cobra.Command{
+	Use:   "delete keyID",
+	Args:  cobra.ExactArgs(1),
+	Short: "Delete an enrollment key",
+	Long:  `Delete an enrollment key`,
+	Run: func(cmd *cobra.Command, args []string) {
+		functions.DeleteEnrollmentKey(args[0])
+		fmt.Println("Enrollment key ", args[0], " deleted")
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(enrollmentKeyDeleteCmd)
+}

+ 20 - 0
cli/cmd/enrollment_key/list.go

@@ -0,0 +1,20 @@
+package enrollment_key
+
+import (
+	"github.com/gravitl/netmaker/cli/functions"
+	"github.com/spf13/cobra"
+)
+
+var enrollmentKeyListCmd = &cobra.Command{
+	Use:   "list",
+	Args:  cobra.NoArgs,
+	Short: "List enrollment keys",
+	Long:  `List enrollment keys`,
+	Run: func(cmd *cobra.Command, args []string) {
+		functions.PrettyPrint(functions.GetEnrollmentKeys())
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(enrollmentKeyListCmd)
+}

+ 28 - 0
cli/cmd/enrollment_key/root.go

@@ -0,0 +1,28 @@
+package enrollment_key
+
+import (
+	"os"
+
+	"github.com/spf13/cobra"
+)
+
+// rootCmd represents the base command when called without any subcommands
+var rootCmd = &cobra.Command{
+	Use:   "enrollment_key",
+	Short: "Manage Enrollment Keys",
+	Long:  `Manage Enrollment Keys`,
+}
+
+// GetRoot returns the root subcommand
+func GetRoot() *cobra.Command {
+	return rootCmd
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the rootCmd.
+func Execute() {
+	err := rootCmd.Execute()
+	if err != nil {
+		os.Exit(1)
+	}
+}

+ 2 - 0
cli/cmd/root.go

@@ -6,6 +6,7 @@ import (
 	"github.com/gravitl/netmaker/cli/cmd/acl"
 	"github.com/gravitl/netmaker/cli/cmd/context"
 	"github.com/gravitl/netmaker/cli/cmd/dns"
+	"github.com/gravitl/netmaker/cli/cmd/enrollment_key"
 	"github.com/gravitl/netmaker/cli/cmd/ext_client"
 	"github.com/gravitl/netmaker/cli/cmd/host"
 	"github.com/gravitl/netmaker/cli/cmd/keys"
@@ -55,4 +56,5 @@ func init() {
 	rootCmd.AddCommand(metrics.GetRoot())
 	rootCmd.AddCommand(network_user.GetRoot())
 	rootCmd.AddCommand(host.GetRoot())
+	rootCmd.AddCommand(enrollment_key.GetRoot())
 }

+ 22 - 0
cli/functions/enrollment_keys.go

@@ -0,0 +1,22 @@
+package functions
+
+import (
+	"net/http"
+
+	"github.com/gravitl/netmaker/models"
+)
+
+// CreateEnrollmentKey - create an enrollment key
+func CreateEnrollmentKey(key *models.APIEnrollmentKey) *models.EnrollmentKey {
+	return request[models.EnrollmentKey](http.MethodPost, "/api/v1/enrollment-keys", key)
+}
+
+// GetEnrollmentKeys - gets all enrollment keys
+func GetEnrollmentKeys() *[]models.EnrollmentKey {
+	return request[[]models.EnrollmentKey](http.MethodGet, "/api/v1/enrollment-keys", nil)
+}
+
+// DeleteEnrollmentKey - delete an enrollment key
+func DeleteEnrollmentKey(keyID string) {
+	request[any](http.MethodDelete, "/api/v1/enrollment-keys/"+keyID, nil)
+}

+ 2 - 2
go.mod

@@ -13,7 +13,7 @@ require (
 	github.com/mattn/go-sqlite3 v1.14.16
 	github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
-	github.com/stretchr/testify v1.8.1
+	github.com/stretchr/testify v1.8.2
 	github.com/txn2/txeh v1.3.0
 	golang.org/x/crypto v0.6.0
 	golang.org/x/net v0.6.0 // indirect
@@ -42,7 +42,7 @@ require (
 
 require (
 	github.com/guumaster/tablewriter v0.0.10
-	github.com/matryer/is v1.4.0
+	github.com/matryer/is v1.4.1
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/spf13/cobra v1.6.1
 )

+ 4 - 4
go.sum

@@ -77,8 +77,8 @@ github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ic
 github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
 github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
-github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
+github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
 github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
@@ -134,8 +134,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/txn2/txeh v1.3.0 h1:vnbv63htVMZCaQgLqVBxKvj2+HHHFUzNW7I183zjg3E=
 github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw8=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=

+ 15 - 0
logic/hosts.go

@@ -395,6 +395,21 @@ func HostExists(h *models.Host) bool {
 	return (err != nil && !database.IsEmptyRecord(err)) || (err == nil)
 }
 
+// GetHostByNodeID - returns a host if found to have a node's ID, else nil
+func GetHostByNodeID(id string) *models.Host {
+	hosts, err := GetAllHosts()
+	if err != nil {
+		return nil
+	}
+	for i := range hosts {
+		h := hosts[i]
+		if StringSliceContains(h.Nodes, id) {
+			return &h
+		}
+	}
+	return nil
+}
+
 func updatePort(p *int) {
 	*p++
 	if *p > maxPort {

+ 9 - 1
logic/nodes.go

@@ -83,8 +83,9 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
 
 // DeleteNode - marks node for deletion (and adds to zombie list) if called by UI or deletes node if called by node
 func DeleteNode(node *models.Node, purge bool) error {
+	alreadyDeleted := node.PendingDelete || node.Action == models.NODE_DELETE
 	node.Action = models.NODE_DELETE
-	if !purge {
+	if !purge && !alreadyDeleted {
 		newnode := *node
 		newnode.PendingDelete = true
 		if err := UpdateNode(node, &newnode); err != nil {
@@ -93,8 +94,15 @@ func DeleteNode(node *models.Node, purge bool) error {
 		newZombie <- node.ID
 		return nil
 	}
+	if alreadyDeleted {
+		logger.Log(1, "forcibly deleting node", node.ID.String())
+	}
 	host, err := GetHost(node.HostID.String())
 	if err != nil {
+		logger.Log(1, "no host found for node", node.ID.String(), "deleting..")
+		if delErr := deleteNodeByID(node); delErr != nil {
+			logger.Log(0, "failed to delete node", node.ID.String(), delErr.Error())
+		}
 		return err
 	}
 	if err := DissasociateNodeFromHost(node, host); err != nil {

+ 41 - 2
mq/handlers.go

@@ -6,6 +6,7 @@ import (
 	"time"
 
 	mqtt "github.com/eclipse/paho.mqtt.golang"
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
@@ -30,9 +31,47 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
 	node, err := logic.GetNodeByID(id)
 	if err != nil {
 		logger.Log(3, "mq-ping error getting node: ", err.Error())
-		_, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
+		node, err := logic.GetNodeByID(id)
 		if err != nil {
-			logger.Log(3, "error reading database", err.Error())
+			logger.Log(3, "mq-ping error getting node: ", err.Error())
+			if database.IsEmptyRecord(err) {
+				h := logic.GetHostByNodeID(id) // check if a host is still associated
+				if h != nil {                  // inform host that node should be removed
+					fakeNode := models.Node{}
+					fakeNode.ID, _ = uuid.Parse(id)
+					fakeNode.Action = models.NODE_DELETE
+					fakeNode.PendingDelete = true
+					if err := NodeUpdate(&fakeNode); err != nil {
+						logger.Log(0, "failed to inform host", h.Name, h.ID.String(), "to remove node", id, err.Error())
+					}
+				}
+			}
+			return
+		}
+		decrypted, decryptErr := decryptMsg(&node, msg.Payload())
+		if decryptErr != nil {
+			logger.Log(0, "error decrypting when updating node ", node.ID.String(), decryptErr.Error())
+			return
+		}
+		var checkin models.NodeCheckin
+		if err := json.Unmarshal(decrypted, &checkin); err != nil {
+			logger.Log(1, "error unmarshaling payload ", err.Error())
+			return
+		}
+		host, err := logic.GetHost(node.HostID.String())
+		if err != nil {
+			logger.Log(0, "error retrieving host for node ", node.ID.String(), err.Error())
+			return
+		}
+		node.SetLastCheckIn()
+		host.Version = checkin.Version
+		node.Connected = checkin.Connected
+		host.Interfaces = checkin.Ifaces
+		for i := range host.Interfaces {
+			host.Interfaces[i].AddressString = host.Interfaces[i].Address.String()
+		}
+		if err := logic.UpdateNode(&node, &node); err != nil {
+			logger.Log(0, "error updating node", node.ID.String(), " on checkin", err.Error())
 			return
 		}
 

+ 22 - 2
release.md

@@ -1,7 +1,27 @@
-# Netmaker v0.18.1
+# Netmaker v0.18.2
 
-## whats new
+## **Do not attempt upgrade from 0.17.x quite yet**
 
+## whats new
+- Enrollment Keys, give the ability for an admin to enroll clients into multiple networks, can be unlimited, time, or usage based
+- EMQX broker support and better MQTT support in general
+  - Now you must specify BROKER_ENDPOINT
+  - Also specify SERVER_BROKER_ENDPOINT, if not provided server will connect to broker over BROKER_ENDPOINT
+  - Thsi gives ability for user to specify any broker endpoint and use any protocal on clients desired, such as, `mqtts://mybroker.com:8083`
+    (we will still default to wss)
+    
 ## whats fixed
+- Fixed default ACL behavior, should work as expected
+- Peer calculations enhancement
+- main routines share a context and docker stop/ctrl+c give expected results now
+- Github workflow edits
+- Removed Deprecated Local Network Range from client + server
 
 ## known issues
+- EnrollmentKeys may not function as intended in an HA setup
+- If a host does not receive a message to delete a node, it could become orphaned and un-deletable
+- Network interface routes may be removed after sometime/unintended network update
+- Upgrade script does not handle clients
+- Caddy does not handle netmaker exporter well for EE
+- Incorrect latency on metrics (EE)
+- Swagger docs not up to date