mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 05:00:25 +08:00 
			
		
		
		
	实现集群看板(暂时只对企业版开放)
This commit is contained in:
		
							
								
								
									
										132
									
								
								internal/web/actions/default/clusters/cluster/boards/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								internal/web/actions/default/clusters/cluster/boards/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
			
		||||
 | 
			
		||||
package boards
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	timeutil "github.com/iwind/TeaGo/utils/time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.Nav("", "board", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
	ClusterId int64
 | 
			
		||||
}) {
 | 
			
		||||
	resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeClusterBoard(this.AdminContext(), &pb.ComposeServerStatNodeClusterBoardRequest{NodeClusterId: params.ClusterId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["board"] = maps.Map{
 | 
			
		||||
		"countUsers":         resp.CountUsers,
 | 
			
		||||
		"countActiveNodes":   resp.CountActiveNodes,
 | 
			
		||||
		"countInactiveNodes": resp.CountInactiveNodes,
 | 
			
		||||
		"countServers":       resp.CountServers,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 24小时流量趋势
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.HourlyTrafficStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"bytes":               stat.Bytes,
 | 
			
		||||
				"cachedBytes":         stat.CachedBytes,
 | 
			
		||||
				"countRequests":       stat.CountRequests,
 | 
			
		||||
				"countCachedRequests": stat.CountCachedRequests,
 | 
			
		||||
				"day":                 stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
 | 
			
		||||
				"hour":                stat.Hour[8:],
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["hourlyStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 15天流量趋势
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.DailyTrafficStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"bytes":               stat.Bytes,
 | 
			
		||||
				"cachedBytes":         stat.CachedBytes,
 | 
			
		||||
				"countRequests":       stat.CountRequests,
 | 
			
		||||
				"countCachedRequests": stat.CountCachedRequests,
 | 
			
		||||
				"day":                 stat.Day[4:6] + "月" + stat.Day[6:] + "日",
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["dailyStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 节点排行
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.TopNodeStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"nodeId":        stat.NodeId,
 | 
			
		||||
				"nodeName":      stat.NodeName,
 | 
			
		||||
				"countRequests": stat.CountRequests,
 | 
			
		||||
				"bytes":         stat.Bytes,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["topNodeStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 域名排行
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.TopDomainStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"serverId":      stat.ServerId,
 | 
			
		||||
				"domain":        stat.Domain,
 | 
			
		||||
				"countRequests": stat.CountRequests,
 | 
			
		||||
				"bytes":         stat.Bytes,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["topDomainStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// CPU
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.CpuNodeValues {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"time":  timeutil.FormatTime("H:i", stat.CreatedAt),
 | 
			
		||||
				"value": types.Float32(string(stat.ValueJSON)),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["cpuValues"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Memory
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.MemoryNodeValues {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"time":  timeutil.FormatTime("H:i", stat.CreatedAt),
 | 
			
		||||
				"value": types.Float32(string(stat.ValueJSON)),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["memoryValues"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Load
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.LoadNodeValues {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"time":  timeutil.FormatTime("H:i", stat.CreatedAt),
 | 
			
		||||
				"value": types.Float32(string(stat.ValueJSON)),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["loadValues"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +1,11 @@
 | 
			
		||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
			
		||||
 | 
			
		||||
package cluster
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/logs"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
@@ -18,207 +13,15 @@ type IndexAction struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.Nav("", "node", "index")
 | 
			
		||||
	this.SecondMenu("nodes")
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
	ClusterId      int64
 | 
			
		||||
	GroupId        int64
 | 
			
		||||
	RegionId       int64
 | 
			
		||||
	InstalledState int
 | 
			
		||||
	ActiveState    int
 | 
			
		||||
	Keyword        string
 | 
			
		||||
	ClusterId int64
 | 
			
		||||
}) {
 | 
			
		||||
	this.Data["groupId"] = params.GroupId
 | 
			
		||||
	this.Data["regionId"] = params.RegionId
 | 
			
		||||
	this.Data["installState"] = params.InstalledState
 | 
			
		||||
	this.Data["activeState"] = params.ActiveState
 | 
			
		||||
	this.Data["keyword"] = params.Keyword
 | 
			
		||||
 | 
			
		||||
	countAllResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	if teaconst.IsPlus {
 | 
			
		||||
		this.RedirectURL("/clusters/cluster/boards?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
 | 
			
		||||
	} else {
 | 
			
		||||
		this.RedirectURL("/clusters/cluster/nodes?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["countAll"] = countAllResp.Count
 | 
			
		||||
 | 
			
		||||
	countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
		NodeGroupId:   params.GroupId,
 | 
			
		||||
		NodeRegionId:  params.RegionId,
 | 
			
		||||
		InstallState:  types.Int32(params.InstalledState),
 | 
			
		||||
		ActiveState:   types.Int32(params.ActiveState),
 | 
			
		||||
		Keyword:       params.Keyword,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page := this.NewPage(countResp.Count)
 | 
			
		||||
	this.Data["page"] = page.AsHTML()
 | 
			
		||||
 | 
			
		||||
	nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), &pb.ListEnabledNodesMatchRequest{
 | 
			
		||||
		Offset:        page.Offset,
 | 
			
		||||
		Size:          page.Size,
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
		NodeGroupId:   params.GroupId,
 | 
			
		||||
		NodeRegionId:  params.RegionId,
 | 
			
		||||
		InstallState:  types.Int32(params.InstalledState),
 | 
			
		||||
		ActiveState:   types.Int32(params.ActiveState),
 | 
			
		||||
		Keyword:       params.Keyword,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	nodeMaps := []maps.Map{}
 | 
			
		||||
	for _, node := range nodesResp.Nodes {
 | 
			
		||||
		// 状态
 | 
			
		||||
		isSynced := false
 | 
			
		||||
		status := &nodeconfigs.NodeStatus{}
 | 
			
		||||
		if len(node.StatusJSON) > 0 {
 | 
			
		||||
			err = json.Unmarshal(node.StatusJSON, &status)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logs.Error(err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
 | 
			
		||||
			isSynced = status.ConfigVersion == node.Version
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// IP
 | 
			
		||||
		ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
 | 
			
		||||
			NodeId: node.Id,
 | 
			
		||||
			Role:   nodeconfigs.NodeRoleNode,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		ipAddresses := []maps.Map{}
 | 
			
		||||
		for _, addr := range ipAddressesResp.Addresses {
 | 
			
		||||
			ipAddresses = append(ipAddresses, maps.Map{
 | 
			
		||||
				"id":        addr.Id,
 | 
			
		||||
				"name":      addr.Name,
 | 
			
		||||
				"ip":        addr.Ip,
 | 
			
		||||
				"canAccess": addr.CanAccess,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 分组
 | 
			
		||||
		var groupMap maps.Map = nil
 | 
			
		||||
		if node.NodeGroup != nil {
 | 
			
		||||
			groupMap = maps.Map{
 | 
			
		||||
				"id":   node.NodeGroup.Id,
 | 
			
		||||
				"name": node.NodeGroup.Name,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 区域
 | 
			
		||||
		var regionMap maps.Map = nil
 | 
			
		||||
		if node.NodeRegion != nil {
 | 
			
		||||
			regionMap = maps.Map{
 | 
			
		||||
				"id":   node.NodeRegion.Id,
 | 
			
		||||
				"name": node.NodeRegion.Name,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// DNS
 | 
			
		||||
		dnsRouteNames := []string{}
 | 
			
		||||
		for _, route := range node.DnsRoutes {
 | 
			
		||||
			dnsRouteNames = append(dnsRouteNames, route.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		nodeMaps = append(nodeMaps, maps.Map{
 | 
			
		||||
			"id":          node.Id,
 | 
			
		||||
			"name":        node.Name,
 | 
			
		||||
			"isInstalled": node.IsInstalled,
 | 
			
		||||
			"isOn":        node.IsOn,
 | 
			
		||||
			"isUp":        node.IsUp,
 | 
			
		||||
			"installStatus": maps.Map{
 | 
			
		||||
				"isRunning":  node.InstallStatus.IsRunning,
 | 
			
		||||
				"isFinished": node.InstallStatus.IsFinished,
 | 
			
		||||
				"isOk":       node.InstallStatus.IsOk,
 | 
			
		||||
				"error":      node.InstallStatus.Error,
 | 
			
		||||
			},
 | 
			
		||||
			"status": maps.Map{
 | 
			
		||||
				"isActive":     status.IsActive,
 | 
			
		||||
				"updatedAt":    status.UpdatedAt,
 | 
			
		||||
				"hostname":     status.Hostname,
 | 
			
		||||
				"cpuUsage":     status.CPUUsage,
 | 
			
		||||
				"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
 | 
			
		||||
				"memUsage":     status.MemoryUsage,
 | 
			
		||||
				"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
 | 
			
		||||
			},
 | 
			
		||||
			"cluster": maps.Map{
 | 
			
		||||
				"id":   node.NodeCluster.Id,
 | 
			
		||||
				"name": node.NodeCluster.Name,
 | 
			
		||||
			},
 | 
			
		||||
			"isSynced":      isSynced,
 | 
			
		||||
			"ipAddresses":   ipAddresses,
 | 
			
		||||
			"group":         groupMap,
 | 
			
		||||
			"region":        regionMap,
 | 
			
		||||
			"dnsRouteNames": dnsRouteNames,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["nodes"] = nodeMaps
 | 
			
		||||
 | 
			
		||||
	// 所有分组
 | 
			
		||||
	groupMaps := []maps.Map{}
 | 
			
		||||
	groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for _, group := range groupsResp.NodeGroups {
 | 
			
		||||
		countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		countNodes := countResp.Count
 | 
			
		||||
		groupName := group.Name
 | 
			
		||||
		if countNodes > 0 {
 | 
			
		||||
			groupName += "(" + strconv.FormatInt(countNodes, 10) + ")"
 | 
			
		||||
		}
 | 
			
		||||
		groupMaps = append(groupMaps, maps.Map{
 | 
			
		||||
			"id":         group.Id,
 | 
			
		||||
			"name":       groupName,
 | 
			
		||||
			"countNodes": countNodes,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["groups"] = groupMaps
 | 
			
		||||
 | 
			
		||||
	// 所有区域
 | 
			
		||||
	regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	regionMaps := []maps.Map{}
 | 
			
		||||
	for _, region := range regionsResp.NodeRegions {
 | 
			
		||||
		regionMaps = append(regionMaps, maps.Map{
 | 
			
		||||
			"id":   region.Id,
 | 
			
		||||
			"name": region.Name,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["regions"] = regionMaps
 | 
			
		||||
 | 
			
		||||
	// 记录最近访问
 | 
			
		||||
	_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
 | 
			
		||||
		ItemType: "cluster",
 | 
			
		||||
		ItemId:   params.ClusterId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package cluster
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/boards"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/monitor"
 | 
			
		||||
@@ -18,6 +19,7 @@ func init() {
 | 
			
		||||
			Helper(clusters.NewClusterHelper()).
 | 
			
		||||
			Prefix("/clusters/cluster").
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			Get("/nodes", new(NodesAction)).
 | 
			
		||||
			GetPost("/installNodes", new(InstallNodesAction)).
 | 
			
		||||
			GetPost("/installRemote", new(InstallRemoteAction)).
 | 
			
		||||
			Post("/installStatus", new(InstallStatusAction)).
 | 
			
		||||
@@ -56,6 +58,9 @@ func init() {
 | 
			
		||||
			Post("/groups/sort", new(groups.SortAction)).
 | 
			
		||||
			GetPost("/groups/selectPopup", new(groups.SelectPopupAction)).
 | 
			
		||||
 | 
			
		||||
			// 看板相关
 | 
			
		||||
			Get("/boards", new(boards.IndexAction)).
 | 
			
		||||
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										224
									
								
								internal/web/actions/default/clusters/cluster/nodes.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								internal/web/actions/default/clusters/cluster/nodes.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,224 @@
 | 
			
		||||
package cluster
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/logs"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type NodesAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *NodesAction) Init() {
 | 
			
		||||
	this.Nav("", "node", "index")
 | 
			
		||||
	this.SecondMenu("nodes")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *NodesAction) RunGet(params struct {
 | 
			
		||||
	ClusterId      int64
 | 
			
		||||
	GroupId        int64
 | 
			
		||||
	RegionId       int64
 | 
			
		||||
	InstalledState int
 | 
			
		||||
	ActiveState    int
 | 
			
		||||
	Keyword        string
 | 
			
		||||
}) {
 | 
			
		||||
	this.Data["groupId"] = params.GroupId
 | 
			
		||||
	this.Data["regionId"] = params.RegionId
 | 
			
		||||
	this.Data["installState"] = params.InstalledState
 | 
			
		||||
	this.Data["activeState"] = params.ActiveState
 | 
			
		||||
	this.Data["keyword"] = params.Keyword
 | 
			
		||||
 | 
			
		||||
	countAllResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["countAll"] = countAllResp.Count
 | 
			
		||||
 | 
			
		||||
	countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
		NodeGroupId:   params.GroupId,
 | 
			
		||||
		NodeRegionId:  params.RegionId,
 | 
			
		||||
		InstallState:  types.Int32(params.InstalledState),
 | 
			
		||||
		ActiveState:   types.Int32(params.ActiveState),
 | 
			
		||||
		Keyword:       params.Keyword,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page := this.NewPage(countResp.Count)
 | 
			
		||||
	this.Data["page"] = page.AsHTML()
 | 
			
		||||
 | 
			
		||||
	nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), &pb.ListEnabledNodesMatchRequest{
 | 
			
		||||
		Offset:        page.Offset,
 | 
			
		||||
		Size:          page.Size,
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
		NodeGroupId:   params.GroupId,
 | 
			
		||||
		NodeRegionId:  params.RegionId,
 | 
			
		||||
		InstallState:  types.Int32(params.InstalledState),
 | 
			
		||||
		ActiveState:   types.Int32(params.ActiveState),
 | 
			
		||||
		Keyword:       params.Keyword,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	nodeMaps := []maps.Map{}
 | 
			
		||||
	for _, node := range nodesResp.Nodes {
 | 
			
		||||
		// 状态
 | 
			
		||||
		isSynced := false
 | 
			
		||||
		status := &nodeconfigs.NodeStatus{}
 | 
			
		||||
		if len(node.StatusJSON) > 0 {
 | 
			
		||||
			err = json.Unmarshal(node.StatusJSON, &status)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logs.Error(err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
 | 
			
		||||
			isSynced = status.ConfigVersion == node.Version
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// IP
 | 
			
		||||
		ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
 | 
			
		||||
			NodeId: node.Id,
 | 
			
		||||
			Role:   nodeconfigs.NodeRoleNode,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		ipAddresses := []maps.Map{}
 | 
			
		||||
		for _, addr := range ipAddressesResp.Addresses {
 | 
			
		||||
			ipAddresses = append(ipAddresses, maps.Map{
 | 
			
		||||
				"id":        addr.Id,
 | 
			
		||||
				"name":      addr.Name,
 | 
			
		||||
				"ip":        addr.Ip,
 | 
			
		||||
				"canAccess": addr.CanAccess,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 分组
 | 
			
		||||
		var groupMap maps.Map = nil
 | 
			
		||||
		if node.NodeGroup != nil {
 | 
			
		||||
			groupMap = maps.Map{
 | 
			
		||||
				"id":   node.NodeGroup.Id,
 | 
			
		||||
				"name": node.NodeGroup.Name,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 区域
 | 
			
		||||
		var regionMap maps.Map = nil
 | 
			
		||||
		if node.NodeRegion != nil {
 | 
			
		||||
			regionMap = maps.Map{
 | 
			
		||||
				"id":   node.NodeRegion.Id,
 | 
			
		||||
				"name": node.NodeRegion.Name,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// DNS
 | 
			
		||||
		dnsRouteNames := []string{}
 | 
			
		||||
		for _, route := range node.DnsRoutes {
 | 
			
		||||
			dnsRouteNames = append(dnsRouteNames, route.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		nodeMaps = append(nodeMaps, maps.Map{
 | 
			
		||||
			"id":          node.Id,
 | 
			
		||||
			"name":        node.Name,
 | 
			
		||||
			"isInstalled": node.IsInstalled,
 | 
			
		||||
			"isOn":        node.IsOn,
 | 
			
		||||
			"isUp":        node.IsUp,
 | 
			
		||||
			"installStatus": maps.Map{
 | 
			
		||||
				"isRunning":  node.InstallStatus.IsRunning,
 | 
			
		||||
				"isFinished": node.InstallStatus.IsFinished,
 | 
			
		||||
				"isOk":       node.InstallStatus.IsOk,
 | 
			
		||||
				"error":      node.InstallStatus.Error,
 | 
			
		||||
			},
 | 
			
		||||
			"status": maps.Map{
 | 
			
		||||
				"isActive":     status.IsActive,
 | 
			
		||||
				"updatedAt":    status.UpdatedAt,
 | 
			
		||||
				"hostname":     status.Hostname,
 | 
			
		||||
				"cpuUsage":     status.CPUUsage,
 | 
			
		||||
				"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
 | 
			
		||||
				"memUsage":     status.MemoryUsage,
 | 
			
		||||
				"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
 | 
			
		||||
			},
 | 
			
		||||
			"cluster": maps.Map{
 | 
			
		||||
				"id":   node.NodeCluster.Id,
 | 
			
		||||
				"name": node.NodeCluster.Name,
 | 
			
		||||
			},
 | 
			
		||||
			"isSynced":      isSynced,
 | 
			
		||||
			"ipAddresses":   ipAddresses,
 | 
			
		||||
			"group":         groupMap,
 | 
			
		||||
			"region":        regionMap,
 | 
			
		||||
			"dnsRouteNames": dnsRouteNames,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["nodes"] = nodeMaps
 | 
			
		||||
 | 
			
		||||
	// 所有分组
 | 
			
		||||
	groupMaps := []maps.Map{}
 | 
			
		||||
	groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
 | 
			
		||||
		NodeClusterId: params.ClusterId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for _, group := range groupsResp.NodeGroups {
 | 
			
		||||
		countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		countNodes := countResp.Count
 | 
			
		||||
		groupName := group.Name
 | 
			
		||||
		if countNodes > 0 {
 | 
			
		||||
			groupName += "(" + strconv.FormatInt(countNodes, 10) + ")"
 | 
			
		||||
		}
 | 
			
		||||
		groupMaps = append(groupMaps, maps.Map{
 | 
			
		||||
			"id":         group.Id,
 | 
			
		||||
			"name":       groupName,
 | 
			
		||||
			"countNodes": countNodes,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["groups"] = groupMaps
 | 
			
		||||
 | 
			
		||||
	// 所有区域
 | 
			
		||||
	regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	regionMaps := []maps.Map{}
 | 
			
		||||
	for _, region := range regionsResp.NodeRegions {
 | 
			
		||||
		regionMaps = append(regionMaps, maps.Map{
 | 
			
		||||
			"id":   region.Id,
 | 
			
		||||
			"name": region.Name,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["regions"] = regionMaps
 | 
			
		||||
 | 
			
		||||
	// 记录最近访问
 | 
			
		||||
	_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
 | 
			
		||||
		ItemType: "cluster",
 | 
			
		||||
		ItemId:   params.ClusterId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ package metrics
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
@@ -59,15 +60,17 @@ func (this *CreatePopupAction) RunGet(params struct {
 | 
			
		||||
		var exists = existsResp.Exists
 | 
			
		||||
 | 
			
		||||
		itemMaps = append(itemMaps, maps.Map{
 | 
			
		||||
			"id":         item.Id,
 | 
			
		||||
			"name":       item.Name,
 | 
			
		||||
			"isOn":       item.IsOn,
 | 
			
		||||
			"period":     item.Period,
 | 
			
		||||
			"periodUnit": item.PeriodUnit,
 | 
			
		||||
			"keys":       item.Keys,
 | 
			
		||||
			"value":      item.Value,
 | 
			
		||||
			"category":   item.Category,
 | 
			
		||||
			"isChecked":  exists,
 | 
			
		||||
			"id":             item.Id,
 | 
			
		||||
			"name":           item.Name,
 | 
			
		||||
			"isOn":           item.IsOn,
 | 
			
		||||
			"period":         item.Period,
 | 
			
		||||
			"periodUnit":     item.PeriodUnit,
 | 
			
		||||
			"periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit),
 | 
			
		||||
			"keys":           item.Keys,
 | 
			
		||||
			"value":          item.Value,
 | 
			
		||||
			"valueName":      serverconfigs.FindMetricValueName(item.Category, item.Value),
 | 
			
		||||
			"category":       item.Category,
 | 
			
		||||
			"isChecked":      exists,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["items"] = itemMaps
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ package metrics
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -38,14 +39,16 @@ func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
	var itemMaps = []maps.Map{}
 | 
			
		||||
	for _, item := range itemsResp.MetricItems {
 | 
			
		||||
		itemMaps = append(itemMaps, maps.Map{
 | 
			
		||||
			"id":         item.Id,
 | 
			
		||||
			"name":       item.Name,
 | 
			
		||||
			"isOn":       item.IsOn,
 | 
			
		||||
			"period":     item.Period,
 | 
			
		||||
			"periodUnit": item.PeriodUnit,
 | 
			
		||||
			"keys":       item.Keys,
 | 
			
		||||
			"value":      item.Value,
 | 
			
		||||
			"category":   item.Category,
 | 
			
		||||
			"id":             item.Id,
 | 
			
		||||
			"name":           item.Name,
 | 
			
		||||
			"isOn":           item.IsOn,
 | 
			
		||||
			"period":         item.Period,
 | 
			
		||||
			"periodUnit":     item.PeriodUnit,
 | 
			
		||||
			"periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit),
 | 
			
		||||
			"keys":           item.Keys,
 | 
			
		||||
			"value":          item.Value,
 | 
			
		||||
			"valueName":      serverconfigs.FindMetricValueName(item.Category, item.Value),
 | 
			
		||||
			"category":       item.Category,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["items"] = itemMaps
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user