diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go
index 75d55a5b..9f10808f 100644
--- a/internal/rpc/rpc_client.go
+++ b/internal/rpc/rpc_client.go
@@ -91,6 +91,10 @@ func (this *RPCClient) NodeIPAddressRPC() pb.NodeIPAddressServiceClient {
return pb.NewNodeIPAddressServiceClient(this.pickConn())
}
+func (this *RPCClient) NodeValueRPC() pb.NodeValueServiceClient {
+ return pb.NewNodeValueServiceClient(this.pickConn())
+}
+
func (this *RPCClient) ServerRPC() pb.ServerServiceClient {
return pb.NewServerServiceClient(this.pickConn())
}
diff --git a/internal/web/actions/default/clusters/cluster/init.go b/internal/web/actions/default/clusters/cluster/init.go
index bf7915ea..49237a30 100644
--- a/internal/web/actions/default/clusters/cluster/init.go
+++ b/internal/web/actions/default/clusters/cluster/init.go
@@ -4,6 +4,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"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"
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
@@ -37,6 +38,12 @@ func init() {
Post("/node/start", new(node.StartAction)).
Post("/node/stop", new(node.StopAction)).
Post("/node/up", new(node.UpAction)).
+ Get("/node/monitor", new(monitor.IndexAction)).
+ Post("/node/monitor/cpu", new(monitor.CpuAction)).
+ Post("/node/monitor/memory", new(monitor.MemoryAction)).
+ Post("/node/monitor/load", new(monitor.LoadAction)).
+ Post("/node/monitor/trafficIn", new(monitor.TrafficInAction)).
+ Post("/node/monitor/trafficOut", new(monitor.TrafficOutAction)).
// 分组相关
Get("/groups", new(groups.IndexAction)).
diff --git a/internal/web/actions/default/clusters/cluster/node/monitor/cpu.go b/internal/web/actions/default/clusters/cluster/node/monitor/cpu.go
new file mode 100644
index 00000000..c0964918
--- /dev/null
+++ b/internal/web/actions/default/clusters/cluster/node/monitor/cpu.go
@@ -0,0 +1,73 @@
+// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
+
+package monitor
+
+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/maps"
+ timeutil "github.com/iwind/TeaGo/utils/time"
+ "time"
+)
+
+type CpuAction struct {
+ actionutils.ParentAction
+}
+
+func (this *CpuAction) RunPost(params struct {
+ NodeId int64
+}) {
+ resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
+ Role: "node",
+ NodeId: params.NodeId,
+ Item: nodeconfigs.NodeValueItemCPU,
+ Range: nodeconfigs.NodeValueRangeMinute,
+ })
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+ valuesMap := map[string]float32{} // YmdHi => usage
+ for _, v := range resp.NodeValues {
+ if len(v.ValueJSON) == 0 {
+ continue
+ }
+
+ valueMap := maps.Map{}
+ err = json.Unmarshal(v.ValueJSON, &valueMap)
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+
+ valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("usage") * 100
+ }
+
+ // 过去一个小时
+ result := []maps.Map{}
+ for i := 60; i >= 1; i-- {
+ timestamp := time.Now().Unix() - int64(i)*60
+ minute := timeutil.FormatTime("YmdHi", timestamp)
+ total, ok := valuesMap[minute]
+ if ok {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": total,
+ "text": fmt.Sprintf("%.2f%%", total),
+ })
+ } else {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": 0,
+ "text": "0.0%",
+ })
+ }
+ }
+
+ this.Data["values"] = result
+
+ this.Success()
+}
diff --git a/internal/web/actions/default/clusters/cluster/node/monitor/index.go b/internal/web/actions/default/clusters/cluster/node/monitor/index.go
new file mode 100644
index 00000000..cdef3fd6
--- /dev/null
+++ b/internal/web/actions/default/clusters/cluster/node/monitor/index.go
@@ -0,0 +1,21 @@
+// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
+
+package monitor
+
+import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
+
+type IndexAction struct {
+ actionutils.ParentAction
+}
+
+func (this *IndexAction) Init() {
+ this.Nav("", "node", "monitor")
+}
+
+func (this *IndexAction) RunGet(params struct {
+ NodeId int64
+}) {
+ this.Data["nodeId"] = params.NodeId
+
+ this.Show()
+}
diff --git a/internal/web/actions/default/clusters/cluster/node/monitor/load.go b/internal/web/actions/default/clusters/cluster/node/monitor/load.go
new file mode 100644
index 00000000..b31c3663
--- /dev/null
+++ b/internal/web/actions/default/clusters/cluster/node/monitor/load.go
@@ -0,0 +1,73 @@
+// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
+
+package monitor
+
+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/maps"
+ timeutil "github.com/iwind/TeaGo/utils/time"
+ "time"
+)
+
+type LoadAction struct {
+ actionutils.ParentAction
+}
+
+func (this *LoadAction) RunPost(params struct {
+ NodeId int64
+}) {
+ resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
+ Role: "node",
+ NodeId: params.NodeId,
+ Item: nodeconfigs.NodeValueItemLoad,
+ Range: nodeconfigs.NodeValueRangeMinute,
+ })
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+ valuesMap := map[string]float32{} // YmdHi => load5m
+ for _, v := range resp.NodeValues {
+ if len(v.ValueJSON) == 0 {
+ continue
+ }
+
+ valueMap := maps.Map{}
+ err = json.Unmarshal(v.ValueJSON, &valueMap)
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+
+ valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("load5m")
+ }
+
+ // 过去一个小时
+ result := []maps.Map{}
+ for i := 60; i >= 1; i-- {
+ timestamp := time.Now().Unix() - int64(i)*60
+ minute := timeutil.FormatTime("YmdHi", timestamp)
+ total, ok := valuesMap[minute]
+ if ok {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": total,
+ "text": fmt.Sprintf("5分钟: %.2f", total),
+ })
+ } else {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": 0,
+ "text": "5分钟: 0.0",
+ })
+ }
+ }
+
+ this.Data["values"] = result
+
+ this.Success()
+}
diff --git a/internal/web/actions/default/clusters/cluster/node/monitor/memory.go b/internal/web/actions/default/clusters/cluster/node/monitor/memory.go
new file mode 100644
index 00000000..4b4e7255
--- /dev/null
+++ b/internal/web/actions/default/clusters/cluster/node/monitor/memory.go
@@ -0,0 +1,73 @@
+// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
+
+package monitor
+
+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/maps"
+ timeutil "github.com/iwind/TeaGo/utils/time"
+ "time"
+)
+
+type MemoryAction struct {
+ actionutils.ParentAction
+}
+
+func (this *MemoryAction) RunPost(params struct {
+ NodeId int64
+}) {
+ resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
+ Role: "node",
+ NodeId: params.NodeId,
+ Item: nodeconfigs.NodeValueItemMemory,
+ Range: nodeconfigs.NodeValueRangeMinute,
+ })
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+ valuesMap := map[string]float32{} // YmdHi => usage
+ for _, v := range resp.NodeValues {
+ if len(v.ValueJSON) == 0 {
+ continue
+ }
+
+ valueMap := maps.Map{}
+ err = json.Unmarshal(v.ValueJSON, &valueMap)
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+
+ valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetFloat32("usage") * 100
+ }
+
+ // 过去一个小时
+ result := []maps.Map{}
+ for i := 60; i >= 1; i-- {
+ timestamp := time.Now().Unix() - int64(i)*60
+ minute := timeutil.FormatTime("YmdHi", timestamp)
+ total, ok := valuesMap[minute]
+ if ok {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": total,
+ "text": fmt.Sprintf("%.2f%%", total),
+ })
+ } else {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": 0,
+ "text": "0.0%",
+ })
+ }
+ }
+
+ this.Data["values"] = result
+
+ this.Success()
+}
diff --git a/internal/web/actions/default/clusters/cluster/node/monitor/trafficIn.go b/internal/web/actions/default/clusters/cluster/node/monitor/trafficIn.go
new file mode 100644
index 00000000..bad2a865
--- /dev/null
+++ b/internal/web/actions/default/clusters/cluster/node/monitor/trafficIn.go
@@ -0,0 +1,73 @@
+// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
+
+package monitor
+
+import (
+ "encoding/json"
+ "github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
+ "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/maps"
+ timeutil "github.com/iwind/TeaGo/utils/time"
+ "time"
+)
+
+type TrafficInAction struct {
+ actionutils.ParentAction
+}
+
+func (this *TrafficInAction) RunPost(params struct {
+ NodeId int64
+}) {
+ resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
+ Role: "node",
+ NodeId: params.NodeId,
+ Item: nodeconfigs.NodeValueItemTrafficIn,
+ Range: nodeconfigs.NodeValueRangeMinute,
+ })
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+ valuesMap := map[string]int64{} // YmdHi => bytes
+ for _, v := range resp.NodeValues {
+ if len(v.ValueJSON) == 0 {
+ continue
+ }
+
+ valueMap := maps.Map{}
+ err = json.Unmarshal(v.ValueJSON, &valueMap)
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+
+ valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
+ }
+
+ // 过去一个小时
+ result := []maps.Map{}
+ for i := 60; i >= 1; i-- {
+ timestamp := time.Now().Unix() - int64(i)*60
+ minute := timeutil.FormatTime("YmdHi", timestamp)
+ total, ok := valuesMap[minute]
+ if ok {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": total,
+ "text": numberutils.FormatBytes(total),
+ })
+ } else {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": 0,
+ "text": numberutils.FormatBytes(0),
+ })
+ }
+ }
+
+ this.Data["values"] = result
+
+ this.Success()
+}
diff --git a/internal/web/actions/default/clusters/cluster/node/monitor/trafficOut.go b/internal/web/actions/default/clusters/cluster/node/monitor/trafficOut.go
new file mode 100644
index 00000000..4f1a975b
--- /dev/null
+++ b/internal/web/actions/default/clusters/cluster/node/monitor/trafficOut.go
@@ -0,0 +1,73 @@
+// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
+
+package monitor
+
+import (
+ "encoding/json"
+ "github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
+ "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/maps"
+ timeutil "github.com/iwind/TeaGo/utils/time"
+ "time"
+)
+
+type TrafficOutAction struct {
+ actionutils.ParentAction
+}
+
+func (this *TrafficOutAction) RunPost(params struct {
+ NodeId int64
+}) {
+ resp, err := this.RPC().NodeValueRPC().ListNodeValues(this.AdminContext(), &pb.ListNodeValuesRequest{
+ Role: "node",
+ NodeId: params.NodeId,
+ Item: nodeconfigs.NodeValueItemTrafficOut,
+ Range: nodeconfigs.NodeValueRangeMinute,
+ })
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+ valuesMap := map[string]int64{} // YmdHi => bytes
+ for _, v := range resp.NodeValues {
+ if len(v.ValueJSON) == 0 {
+ continue
+ }
+
+ valueMap := maps.Map{}
+ err = json.Unmarshal(v.ValueJSON, &valueMap)
+ if err != nil {
+ this.ErrorPage(err)
+ return
+ }
+
+ valuesMap[timeutil.FormatTime("YmdHi", v.CreatedAt)] = valueMap.GetInt64("total")
+ }
+
+ // 过去一个小时
+ result := []maps.Map{}
+ for i := 60; i >= 1; i-- {
+ timestamp := time.Now().Unix() - int64(i)*60
+ minute := timeutil.FormatTime("YmdHi", timestamp)
+ total, ok := valuesMap[minute]
+ if ok {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": total,
+ "text": numberutils.FormatBytes(total),
+ })
+ } else {
+ result = append(result, maps.Map{
+ "label": timeutil.FormatTime("H:i", timestamp),
+ "value": 0,
+ "text": numberutils.FormatBytes(0),
+ })
+ }
+ }
+
+ this.Data["values"] = result
+
+ this.Success()
+}
diff --git a/internal/web/helpers/user_must_auth.go b/internal/web/helpers/user_must_auth.go
index 945218a5..71031de4 100644
--- a/internal/web/helpers/user_must_auth.go
+++ b/internal/web/helpers/user_must_auth.go
@@ -107,6 +107,7 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
}
action.Data["teaShowOpenSourceInfo"] = config.ShowOpenSourceInfo
action.Data["teaIsSuper"] = false
+ action.Data["teaIsPlus"] = teaconst.IsPlus
action.Data["teaDemoEnabled"] = teaconst.IsDemo
action.Data["teaShowFinance"] = configloaders.ShowFinance()
if !action.Data.Has("teaSubMenu") {
diff --git a/web/views/@default/clusters/cluster/node/@node_menu.html b/web/views/@default/clusters/cluster/node/@node_menu.html
index ec4f1176..eed3b382 100644
--- a/web/views/@default/clusters/cluster/node/@node_menu.html
+++ b/web/views/@default/clusters/cluster/node/@node_menu.html
@@ -2,7 +2,8 @@