mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-06 05:04:27 +08:00
NET-1956: Async Node Status API (#3341)
* add node status api * upsate node status api to return map data * resolve merge conflicts
This commit is contained in:
parent
a805901a73
commit
48535f7ef1
5 changed files with 90 additions and 8 deletions
|
@ -31,6 +31,7 @@ func nodeHandlers(r *mux.Router) {
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createGateway)))).Methods(http.MethodPost)
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createGateway)))).Methods(http.MethodPost)
|
||||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteGateway))).Methods(http.MethodDelete)
|
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteGateway))).Methods(http.MethodDelete)
|
||||||
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
|
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
|
||||||
|
r.HandleFunc("/api/v1/nodes/{network}/status", logic.SecurityCheck(true, http.HandlerFunc(getNetworkNodeStatus))).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
|
r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +329,7 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = logic.AddStaticNodestoList(nodes)
|
nodes = logic.AddStaticNodestoList(nodes)
|
||||||
nodes = logic.AddStatusToNodes(nodes)
|
nodes = logic.AddStatusToNodes(nodes, false)
|
||||||
// returns all the nodes in JSON/API format
|
// returns all the nodes in JSON/API format
|
||||||
apiNodes := logic.GetAllNodesAPI(nodes[:])
|
apiNodes := logic.GetAllNodesAPI(nodes[:])
|
||||||
logger.Log(2, r.Header.Get("user"), "fetched nodes on network", networkName)
|
logger.Log(2, r.Header.Get("user"), "fetched nodes on network", networkName)
|
||||||
|
@ -368,7 +369,7 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
}
|
}
|
||||||
nodes = logic.AddStaticNodestoList(nodes)
|
nodes = logic.AddStaticNodestoList(nodes)
|
||||||
nodes = logic.AddStatusToNodes(nodes)
|
nodes = logic.AddStatusToNodes(nodes, false)
|
||||||
// return all the nodes in JSON/API format
|
// return all the nodes in JSON/API format
|
||||||
apiNodes := logic.GetAllNodesAPI(nodes[:])
|
apiNodes := logic.GetAllNodesAPI(nodes[:])
|
||||||
logger.Log(3, r.Header.Get("user"), "fetched all nodes they have access to")
|
logger.Log(3, r.Header.Get("user"), "fetched all nodes they have access to")
|
||||||
|
@ -377,6 +378,52 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
||||||
json.NewEncoder(w).Encode(apiNodes)
|
json.NewEncoder(w).Encode(apiNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Get all nodes status on the network
|
||||||
|
// @Router /api/v1/nodes/{network}/status [get]
|
||||||
|
// @Tags Nodes
|
||||||
|
// @Securitydefinitions.oauth2.application OAuth2Application
|
||||||
|
// @Success 200 {array} models.ApiNode
|
||||||
|
// @Failure 500 {object} models.ErrorResponse
|
||||||
|
// 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 getNetworkNodeStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var params = mux.Vars(r)
|
||||||
|
netID := params["network"]
|
||||||
|
// validate network
|
||||||
|
_, err := logic.GetNetwork(netID)
|
||||||
|
if err != nil {
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to get network %v", err), "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var nodes []models.Node
|
||||||
|
nodes, err = logic.GetNetworkNodes(netID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log(0, "error fetching all nodes info: ", err.Error())
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
username := r.Header.Get("user")
|
||||||
|
if r.Header.Get("ismaster") == "no" {
|
||||||
|
user, err := logic.GetUser(username)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !userPlatformRole.FullAccess {
|
||||||
|
nodes = logic.GetFilteredNodesByUserAccess(*user, nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
nodes = logic.AddStaticNodestoList(nodes)
|
||||||
|
nodes = logic.AddStatusToNodes(nodes, false)
|
||||||
|
// return all the nodes in JSON/API format
|
||||||
|
apiNodesStatusMap := logic.GetNodesStatusAPI(nodes[:])
|
||||||
|
logger.Log(3, r.Header.Get("user"), "fetched all nodes they have access to")
|
||||||
|
logic.ReturnSuccessResponseWithJson(w, r, apiNodesStatusMap, "fetched nodes with metric status")
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Get an individual node
|
// @Summary Get an individual node
|
||||||
// @Router /api/nodes/{network}/{nodeid} [get]
|
// @Router /api/nodes/{network}/{nodeid} [get]
|
||||||
// @Tags Nodes
|
// @Tags Nodes
|
||||||
|
|
|
@ -443,7 +443,7 @@ func AddStaticNodestoList(nodes []models.Node) []models.Node {
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddStatusToNodes(nodes []models.Node) (nodesWithStatus []models.Node) {
|
func AddStatusToNodes(nodes []models.Node, statusCall bool) (nodesWithStatus []models.Node) {
|
||||||
aclDefaultPolicyStatusMap := make(map[string]bool)
|
aclDefaultPolicyStatusMap := make(map[string]bool)
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
if _, ok := aclDefaultPolicyStatusMap[node.Network]; !ok {
|
if _, ok := aclDefaultPolicyStatusMap[node.Network]; !ok {
|
||||||
|
@ -451,7 +451,12 @@ func AddStatusToNodes(nodes []models.Node) (nodesWithStatus []models.Node) {
|
||||||
defaultPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
|
defaultPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
|
||||||
aclDefaultPolicyStatusMap[node.Network] = defaultPolicy.Enabled
|
aclDefaultPolicyStatusMap[node.Network] = defaultPolicy.Enabled
|
||||||
}
|
}
|
||||||
GetNodeStatus(&node, aclDefaultPolicyStatusMap[node.Network])
|
if statusCall {
|
||||||
|
GetNodeStatus(&node, aclDefaultPolicyStatusMap[node.Network])
|
||||||
|
} else {
|
||||||
|
GetNodeCheckInStatus(&node, true)
|
||||||
|
}
|
||||||
|
|
||||||
nodesWithStatus = append(nodesWithStatus, node)
|
nodesWithStatus = append(nodesWithStatus, node)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -572,6 +577,16 @@ func GetAllNodesAPI(nodes []models.Node) []models.ApiNode {
|
||||||
return apiNodes[:]
|
return apiNodes[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodesStatusAPI - gets nodes status
|
||||||
|
func GetNodesStatusAPI(nodes []models.Node) map[string]models.ApiNodeStatus {
|
||||||
|
apiStatusNodesMap := make(map[string]models.ApiNodeStatus)
|
||||||
|
for i := range nodes {
|
||||||
|
newApiNode := nodes[i].ConvertToStatusNode()
|
||||||
|
apiStatusNodesMap[newApiNode.ID] = *newApiNode
|
||||||
|
}
|
||||||
|
return apiStatusNodesMap
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteExpiredNodes - goroutine which deletes nodes which are expired
|
// DeleteExpiredNodes - goroutine which deletes nodes which are expired
|
||||||
func DeleteExpiredNodes(ctx context.Context, peerUpdate chan *models.Node) {
|
func DeleteExpiredNodes(ctx context.Context, peerUpdate chan *models.Node) {
|
||||||
// Delete Expired Nodes Every Hour
|
// Delete Expired Nodes Every Hour
|
||||||
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
"github.com/gravitl/netmaker/models"
|
"github.com/gravitl/netmaker/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
var GetNodeStatus = getNodeStatus
|
var GetNodeStatus = GetNodeCheckInStatus
|
||||||
|
|
||||||
func getNodeStatus(node *models.Node, t bool) {
|
func GetNodeCheckInStatus(node *models.Node, t bool) {
|
||||||
// On CE check only last check-in time
|
// On CE check only last check-in time
|
||||||
if node.IsStatic {
|
if node.IsStatic {
|
||||||
if !node.StaticNode.Enabled {
|
if !node.StaticNode.Enabled {
|
||||||
|
|
|
@ -8,6 +8,13 @@ import (
|
||||||
"golang.org/x/exp/slog"
|
"golang.org/x/exp/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ApiNodeStatus struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
IsStatic bool `json:"is_static"`
|
||||||
|
IsUserNode bool `json:"is_user_node"`
|
||||||
|
Status NodeStatus `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
// ApiNode is a stripped down Node DTO that exposes only required fields to external systems
|
// ApiNode is a stripped down Node DTO that exposes only required fields to external systems
|
||||||
type ApiNode struct {
|
type ApiNode struct {
|
||||||
ID string `json:"id,omitempty" validate:"required,min=5,id_unique"`
|
ID string `json:"id,omitempty" validate:"required,min=5,id_unique"`
|
||||||
|
@ -132,6 +139,19 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
|
||||||
return &convertedNode
|
return &convertedNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nm *Node) ConvertToStatusNode() *ApiNodeStatus {
|
||||||
|
apiNode := ApiNodeStatus{}
|
||||||
|
if nm.IsStatic {
|
||||||
|
apiNode.ID = nm.StaticNode.ClientID
|
||||||
|
} else {
|
||||||
|
apiNode.ID = nm.ID.String()
|
||||||
|
}
|
||||||
|
apiNode.IsStatic = nm.IsStatic
|
||||||
|
apiNode.IsUserNode = nm.IsUserNode
|
||||||
|
apiNode.Status = nm.Status
|
||||||
|
return &apiNode
|
||||||
|
}
|
||||||
|
|
||||||
// Node.ConvertToAPINode - converts a node to an API node
|
// Node.ConvertToAPINode - converts a node to an API node
|
||||||
func (nm *Node) ConvertToAPINode() *ApiNode {
|
func (nm *Node) ConvertToAPINode() *ApiNode {
|
||||||
apiNode := ApiNode{}
|
apiNode := ApiNode{}
|
||||||
|
|
|
@ -1102,7 +1102,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
|
||||||
slog.Error("failed to get node network", "error", err)
|
slog.Error("failed to get node network", "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nodesWithStatus := logic.AddStatusToNodes([]models.Node{node})
|
nodesWithStatus := logic.AddStatusToNodes([]models.Node{node}, false)
|
||||||
if len(nodesWithStatus) > 0 {
|
if len(nodesWithStatus) > 0 {
|
||||||
node = nodesWithStatus[0]
|
node = nodesWithStatus[0]
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1143,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nodesWithStatus := logic.AddStatusToNodes([]models.Node{node})
|
nodesWithStatus := logic.AddStatusToNodes([]models.Node{node}, false)
|
||||||
if len(nodesWithStatus) > 0 {
|
if len(nodesWithStatus) > 0 {
|
||||||
node = nodesWithStatus[0]
|
node = nodesWithStatus[0]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue