Jelajahi Sumber

made mq functions a little easier to read and re-use

0xdcarns 2 tahun lalu
induk
melakukan
8c92308ccf
7 mengubah file dengan 187 tambahan dan 123 penghapusan
  1. 10 1
      controllers/hosts.go
  2. 7 27
      controllers/network.go
  3. 27 92
      controllers/node.go
  4. 17 0
      logic/hosts.go
  5. 2 2
      mq/dynsec.go
  6. 89 0
      mq/dynsec_clients.go
  7. 35 1
      mq/dynsec_helper.go

+ 10 - 1
controllers/hosts.go

@@ -8,6 +8,7 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/mq"
 	"github.com/gravitl/netmaker/servercfg"
 )
 
@@ -154,12 +155,20 @@ func updateHostNetworks(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if err = logic.UpdateHostNetworks(currHost, servercfg.GetServer(), payload.Networks); err != nil {
+	if err = logic.UpdateHostNetworks(currHost, servercfg.GetServer(), payload.Networks[:]); err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to update host networks:", err.Error())
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 
+	if err = mq.ModifyClient(&mq.MqClient{
+		ID:       currHost.ID.String(),
+		Text:     currHost.Name,
+		Networks: payload.Networks,
+	}); err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to update host networks roles in DynSec:", err.Error())
+	}
+
 	logger.Log(2, r.Header.Get("user"), "updated host networks", currHost.Name)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(payload)

+ 7 - 27
controllers/network.go

@@ -370,20 +370,11 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, errtype))
 		return
 	}
-	// Deletes the network role from MQ
-	event := mq.MqDynsecPayload{
-		Commands: []mq.MqDynSecCmd{
-			{
-				Command:  mq.DeleteRoleCmd,
-				RoleName: network,
-			},
-		},
-	}
 
-	if err := mq.PublishEventToDynSecTopic(event); err != nil {
-		logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
-			event.Commands, err.Error()))
+	if err := mq.DeleteNetworkRole(network); err != nil {
+		logger.Log(0, fmt.Sprintf("failed to remove network DynSec role: %v", err.Error()))
 	}
+
 	logger.Log(1, r.Header.Get("user"), "deleted network", network)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode("success")
@@ -430,21 +421,10 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-	// Create Role with acls for the network
-	event := mq.MqDynsecPayload{
-		Commands: []mq.MqDynSecCmd{
-			{
-				Command:  mq.CreateRoleCmd,
-				RoleName: network.NetID,
-				Textname: "Network wide role with Acls for nodes",
-				Acls:     mq.FetchNetworkAcls(network.NetID),
-			},
-		},
-	}
-
-	if err := mq.PublishEventToDynSecTopic(event); err != nil {
-		logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
-			event.Commands, err.Error()))
+
+	if err = mq.CreateNetworkRole(network.NetID); err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to create network DynSec role:",
+			err.Error())
 	}
 
 	if err = logic.AddDefaultHostsToNetwork(network.NetID, servercfg.GetServer()); err != nil {

+ 27 - 92
controllers/node.go

@@ -7,6 +7,7 @@ import (
 	"net/http"
 	"strings"
 
+	"github.com/google/uuid"
 	"github.com/gorilla/mux"
 	proxy_models "github.com/gravitl/netclient/nmproxy/models"
 	"github.com/gravitl/netmaker/database"
@@ -113,43 +114,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 		logic.ReturnErrorResponse(response, request, errorResponse)
 		return
 	}
-	// creates network role,node client (added here to resolve any missing configuration in MQ)
-	event := mq.MqDynsecPayload{
-		Commands: []mq.MqDynSecCmd{
-
-			{
-				Command:  mq.CreateRoleCmd,
-				RoleName: result.Network,
-				Textname: "Network wide role with Acls for nodes",
-				Acls:     mq.FetchNetworkAcls(result.Network),
-			},
-			{
-				Command:  mq.CreateClientCmd,
-				Username: result.HostID.String(),
-				Password: authRequest.Password,
-				Textname: host.Name,
-				Roles: []mq.MqDynSecRole{
-					{
-						Rolename: mq.NodeRole,
-						Priority: -1,
-					},
-					{
-						Rolename: result.Network,
-						Priority: -1,
-					},
-				},
-				Groups: make([]mq.MqDynSecGroup, 0),
-			},
-		},
-	}
-
-	if err := mq.PublishEventToDynSecTopic(event); err != nil {
-		logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
-			event.Commands, err.Error()))
-		errorResponse.Code = http.StatusInternalServerError
-		errorResponse.Message = fmt.Sprintf("could not create mq client for node [%s]: %v", result.ID, err)
-		return
-	}
 
 	tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, result.Network)
 	if tokenString == "" {
@@ -182,7 +146,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 	response.WriteHeader(http.StatusOK)
 	response.Header().Set("Content-Type", "application/json")
 	response.Write(successJSONResponse)
-
 }
 
 // auth middleware for api calls from nodes where node is has not yet joined the server (register, join)
@@ -606,7 +569,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	server := servercfg.GetServerInfo()
 	server.TrafficKey = key
 	// consume password before hashing for mq client creation
-	nodePassword := data.Host.HostPass
+	hostPassword := data.Host.HostPass
 	data.Node.Server = servercfg.GetServer()
 	if err := logic.CreateHost(&data.Host); err != nil {
 		if errors.Is(err, logic.ErrHostExists) {
@@ -616,6 +579,18 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 			return
 		}
+	} else {
+		// Create client for this host in Mq
+		if err := mq.CreateMqClient(&mq.MqClient{
+			ID:       data.Host.ID.String(),
+			Text:     data.Host.Name,
+			Password: hostPassword,
+			Networks: []string{networkName},
+		}); err != nil {
+			logger.Log(0, fmt.Sprintf("failed to create DynSec client: %v", err.Error()))
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
 	}
 	host, err := logic.GetHost(data.Host.ID.String())
 	if err != nil {
@@ -657,43 +632,6 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	data.Node.Peers = peerUpdate.Peers
-	// Create client for this host in Mq
-	event := mq.MqDynsecPayload{
-		Commands: []mq.MqDynSecCmd{
-			{ // delete if any client exists already
-				Command:  mq.DeleteClientCmd,
-				Username: data.Host.ID.String(),
-			},
-			{
-				Command:  mq.CreateRoleCmd,
-				RoleName: networkName,
-				Textname: "Network wide role with Acls for nodes",
-				Acls:     mq.FetchNetworkAcls(networkName),
-			},
-			{
-				Command:  mq.CreateClientCmd,
-				Username: data.Host.ID.String(),
-				Password: nodePassword,
-				Textname: data.Host.Name,
-				Roles: []mq.MqDynSecRole{
-					{
-						Rolename: mq.NodeRole,
-						Priority: -1,
-					},
-					{
-						Rolename: networkName,
-						Priority: -1,
-					},
-				},
-				Groups: make([]mq.MqDynSecGroup, 0),
-			},
-		},
-	}
-
-	if err := mq.PublishEventToDynSecTopic(event); err != nil {
-		logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
-			event.Commands, err.Error()))
-	}
 
 	response := models.NodeJoinResponse{
 		Node:         data.Node,
@@ -1110,30 +1048,27 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 		}, &node)
 	}
 	if fromNode {
-		//check if server should be removed from mq
-		found := false
+		// check if server should be removed from mq
 		// err is irrelevent
 		nodes, _ := logic.GetAllNodes()
+		var foundNode models.Node
 		for _, nodetocheck := range nodes {
 			if nodetocheck.HostID == node.HostID {
-				found = true
+				foundNode = nodetocheck
 				break
 			}
 		}
 		// TODO: Address how to remove host
-		if !found {
-			// deletes node related role and client
-			event := mq.MqDynsecPayload{
-				Commands: []mq.MqDynSecCmd{
-					{
-						Command:  mq.DeleteClientCmd,
-						Username: node.HostID.String(),
-					},
-				},
-			}
-			if err := mq.PublishEventToDynSecTopic(event); err != nil {
-				logger.Log(0, fmt.Sprintf("failed to send DynSec command [%v]: %v",
-					event.Commands, err.Error()))
+		if foundNode.HostID != uuid.Nil {
+			if err = logic.DissasociateNodeFromHost(&foundNode, host); err == nil {
+				currNets := logic.GetHostNetworks(host.ID.String())
+				if len(currNets) > 0 {
+					mq.ModifyClient(&mq.MqClient{
+						ID:       host.ID.String(),
+						Text:     host.Name,
+						Networks: currNets,
+					})
+				}
 			}
 		}
 	}

+ 17 - 0
logic/hosts.go

@@ -278,3 +278,20 @@ func AddDefaultHostsToNetwork(network, server string) error {
 	}
 	return nil
 }
+
+// GetHostNetworks - fetches all the networks
+func GetHostNetworks(hostID string) []string {
+	currHost, err := GetHost(hostID)
+	if err != nil {
+		return nil
+	}
+	nets := []string{}
+	for i := range currHost.Nodes {
+		n, err := GetNodeByID(currHost.Nodes[i])
+		if err != nil {
+			return nil
+		}
+		nets = append(nets, n.Network)
+	}
+	return nets
+}

+ 2 - 2
mq/dynsec.go

@@ -189,8 +189,8 @@ func Configure() error {
 	return os.WriteFile(path, data, 0755)
 }
 
-// PublishEventToDynSecTopic - publishes the message to dynamic security topic
-func PublishEventToDynSecTopic(payload MqDynsecPayload) error {
+// publishes the message to dynamic security topic
+func publishEventToDynSecTopic(payload MqDynsecPayload) error {
 
 	d, err := json.Marshal(payload)
 	if err != nil {

+ 89 - 0
mq/dynsec_clients.go

@@ -0,0 +1,89 @@
+package mq
+
+// MqClient - type for taking in an MQ client's data
+type MqClient struct {
+	ID       string
+	Text     string
+	Password string
+	Networks []string
+}
+
+// ModifyClient - modifies an existing client's network roles
+func ModifyClient(client *MqClient) error {
+
+	roles := []MqDynSecRole{
+		{
+			Rolename: HostRole,
+			Priority: -1,
+		},
+	}
+
+	for i := range client.Networks {
+		roles = append(roles, MqDynSecRole{
+			Rolename: client.Networks[i],
+			Priority: -1,
+		},
+		)
+	}
+
+	event := MqDynsecPayload{
+		Commands: []MqDynSecCmd{
+			{
+				Command:  ModifyClientCmd,
+				Username: client.ID,
+				Textname: client.Text,
+				Roles:    roles,
+				Groups:   make([]MqDynSecGroup, 0),
+			},
+		},
+	}
+
+	return publishEventToDynSecTopic(event)
+}
+
+// DeleteMqClient - removes a client from the DynSec system
+func DeleteMqClient(hostID string) error {
+	event := MqDynsecPayload{
+		Commands: []MqDynSecCmd{
+			{
+				Command:  DeleteClientCmd,
+				Username: hostID,
+			},
+		},
+	}
+	return publishEventToDynSecTopic(event)
+}
+
+// CreateMqClient - creates an MQ DynSec client
+func CreateMqClient(client *MqClient) error {
+
+	roles := []MqDynSecRole{
+		{
+			Rolename: HostRole,
+			Priority: -1,
+		},
+	}
+
+	for i := range client.Networks {
+		roles = append(roles, MqDynSecRole{
+			Rolename: client.Networks[i],
+			Priority: -1,
+		},
+		)
+	}
+
+	event := MqDynsecPayload{
+		Commands: []MqDynSecCmd{
+			{
+				Command:  CreateClientCmd,
+				Username: client.ID,
+				Password: client.Password,
+				Textname: client.Text,
+				Roles:    roles,
+				Groups:   make([]MqDynSecGroup, 0),
+			},
+		},
+	}
+
+	return publishEventToDynSecTopic(event)
+}

+ 35 - 1
mq/dynsec_helper.go

@@ -19,6 +19,8 @@ const (
 	exporterRole = "exporter"
 	// constant for node role
 	NodeRole = "node"
+	// HostRole constant for host role
+	HostRole = "host"
 
 	// const for dynamic security file
 	dynamicSecurityFile = "dynamic-security.json"
@@ -64,7 +66,7 @@ var (
 				Acls:     fetchServerAcls(),
 			},
 			{
-				Rolename: NodeRole,
+				Rolename: HostRole,
 				Acls:     fetchNodeAcls(),
 			},
 			exporterMQRole,
@@ -203,6 +205,38 @@ func FetchNetworkAcls(network string) []Acl {
 	}
 }
 
+// DeleteNetworkRole - deletes a network role from DynSec system
+func DeleteNetworkRole(network string) error {
+	// Deletes the network role from MQ
+	event := MqDynsecPayload{
+		Commands: []MqDynSecCmd{
+			{
+				Command:  DeleteRoleCmd,
+				RoleName: network,
+			},
+		},
+	}
+
+	return publishEventToDynSecTopic(event)
+}
+
+// CreateNetworkRole - createss a network role from DynSec system
+func CreateNetworkRole(network string) error {
+	// Create Role with acls for the network
+	event := MqDynsecPayload{
+		Commands: []MqDynSecCmd{
+			{
+				Command:  CreateRoleCmd,
+				RoleName: network,
+				Textname: "Network wide role with Acls for nodes",
+				Acls:     FetchNetworkAcls(network),
+			},
+		},
+	}
+
+	return publishEventToDynSecTopic(event)
+}
+
 // serverAcls - fetches server role related acls
 func fetchServerAcls() []Acl {
 	return []Acl{