diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index 4688fd84..0ffb74b2 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -388,6 +388,14 @@ func (this *RPCClient) NSAccessLogRPC() pb.NSAccessLogServiceClient { return pb.NewNSAccessLogServiceClient(this.pickConn()) } +func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient { + return pb.NewMetricItemServiceClient(this.pickConn()) +} + +func (this *RPCClient) NodeClusterMetricItemRPC() pb.NodeClusterMetricItemServiceClient { + return pb.NewNodeClusterMetricItemServiceClient(this.pickConn()) +} + // Context 构造Admin上下文 func (this *RPCClient) Context(adminId int64) context.Context { ctx := context.Background() diff --git a/internal/web/actions/default/clusters/cluster/settings/health/runPopup.go b/internal/web/actions/default/clusters/cluster/settings/health/runPopup.go index 7084946b..69a19d83 100644 --- a/internal/web/actions/default/clusters/cluster/settings/health/runPopup.go +++ b/internal/web/actions/default/clusters/cluster/settings/health/runPopup.go @@ -32,6 +32,9 @@ func (this *RunPopupAction) RunPost(params struct { this.Fail(err.Error()) } + if resp.Results == nil { + resp.Results = []*pb.ExecuteNodeClusterHealthCheckResponse_Result{} + } this.Data["results"] = resp.Results this.Success() } diff --git a/internal/web/actions/default/clusters/cluster/settings/init.go b/internal/web/actions/default/clusters/cluster/settings/init.go index b92fe649..55ae2c9e 100644 --- a/internal/web/actions/default/clusters/cluster/settings/init.go +++ b/internal/web/actions/default/clusters/cluster/settings/init.go @@ -7,6 +7,7 @@ import ( firewallActions "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/firewall-actions" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/message" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/metrics" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa" @@ -67,6 +68,12 @@ func init() { GetPost("/updatePopup", new(thresholds.UpdatePopupAction)). Post("/delete", new(thresholds.DeleteAction)). + // 指标 + Prefix("/clusters/cluster/settings/metrics"). + Get("", new(metrics.IndexAction)). + GetPost("/createPopup", new(metrics.CreatePopupAction)). + Post("/delete", new(metrics.DeleteAction)). + EndAll() }) } diff --git a/internal/web/actions/default/clusters/cluster/settings/metrics/createPopup.go b/internal/web/actions/default/clusters/cluster/settings/metrics/createPopup.go new file mode 100644 index 00000000..ba3144c9 --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/settings/metrics/createPopup.go @@ -0,0 +1,61 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type CreatePopupAction struct { + actionutils.ParentAction +} + +func (this *CreatePopupAction) Init() { + this.Nav("", "", "") +} + +func (this *CreatePopupAction) RunGet(params struct { + Category string +}) { + if len(params.Category) == 0 { + params.Category = "http" + } + this.Data["category"] = params.Category + + countResp, err := this.RPC().MetricItemRPC().CountAllEnabledMetricItems(this.AdminContext(), &pb.CountAllEnabledMetricItemsRequest{Category: params.Category}) + if err != nil { + this.ErrorPage(err) + return + } + var count = countResp.Count + page := this.NewPage(count) + this.Data["page"] = page.AsHTML() + + itemsResp, err := this.RPC().MetricItemRPC().ListEnabledMetricItems(this.AdminContext(), &pb.ListEnabledMetricItemsRequest{ + Category: params.Category, + Offset: page.Offset, + Size: page.Size, + }) + if err != nil { + this.ErrorPage(err) + return + } + 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, + }) + } + this.Data["items"] = itemMaps + + this.Show() +} diff --git a/internal/web/actions/default/clusters/cluster/settings/metrics/delete.go b/internal/web/actions/default/clusters/cluster/settings/metrics/delete.go new file mode 100644 index 00000000..60128ba9 --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/settings/metrics/delete.go @@ -0,0 +1,13 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + +type DeleteAction struct { + actionutils.ParentAction +} + +func (this *DeleteAction) RunPost(params struct{}) { + this.Success() +} diff --git a/internal/web/actions/default/clusters/cluster/settings/metrics/index.go b/internal/web/actions/default/clusters/cluster/settings/metrics/index.go new file mode 100644 index 00000000..6bb2e072 --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/settings/metrics/index.go @@ -0,0 +1,51 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + this.Nav("", "setting", "setting") + this.SecondMenu("metric") +} + +func (this *IndexAction) RunGet(params struct { + ClusterId int64 + Category string +}) { + if len(params.Category) == 0 { + params.Category = "http" + } + this.Data["category"] = params.Category + + itemsResp, err := this.RPC().NodeClusterMetricItemRPC().FindAllNodeClusterMetricItems(this.AdminContext(), &pb.FindAllNodeClusterMetricItemsRequest{NodeClusterId: params.ClusterId}) + if err != nil { + this.ErrorPage(err) + return + } + + 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, + }) + } + this.Data["items"] = itemMaps + + this.Show() +} diff --git a/internal/web/actions/default/clusters/clusterutils/cluster_helper.go b/internal/web/actions/default/clusters/clusterutils/cluster_helper.go index 96663951..eb6dde8e 100644 --- a/internal/web/actions/default/clusters/clusterutils/cluster_helper.go +++ b/internal/web/actions/default/clusters/clusterutils/cluster_helper.go @@ -1,15 +1,12 @@ package clusterutils import ( - "encoding/json" teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const" "github.com/TeaOSLab/EdgeAdmin/internal/rpc" "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/dao" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" - "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/maps" @@ -39,7 +36,8 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext action.Data["clusterId"] = clusterId if clusterId > 0 { - cluster, err := dao.SharedNodeClusterDAO.FindEnabledNodeCluster(actionPtr.(rpc.ContextInterface).AdminContext(), clusterId) + var ctx = actionPtr.(rpc.ContextInterface).AdminContext() + cluster, err := dao.SharedNodeClusterDAO.FindEnabledNodeCluster(ctx, clusterId) if err != nil { logs.Error(err) return @@ -49,6 +47,16 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext return } + clusterInfo, err := dao.SharedNodeClusterDAO.FindEnabledNodeClusterConfigInfo(ctx, clusterId) + if err != nil { + logs.Error(err) + return + } + if clusterInfo == nil { + action.WriteString("can not find cluster info") + return + } + tabbar := actionutils.NewTabbar() tabbar.Add("集群列表", "", "/clusters", "", false) tabbar.Add("集群节点", "", "/clusters/cluster?clusterId="+clusterIdString, "server", selectedTabbar == "node") @@ -65,7 +73,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext secondMenuItem := action.Data.GetString("secondMenuItem") switch selectedTabbar { case "setting": - action.Data["leftMenuItems"] = this.createSettingMenu(cluster, secondMenuItem) + action.Data["leftMenuItems"] = this.createSettingMenu(cluster, clusterInfo, secondMenuItem) } } @@ -73,7 +81,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext } // 设置菜单 -func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedItem string) (items []maps.Map) { +func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.FindEnabledNodeClusterConfigInfoResponse, selectedItem string) (items []maps.Map) { clusterId := numberutils.FormatInt64(cluster.Id) items = append(items, maps.Map{ "name": "基础设置", @@ -93,25 +101,19 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt "isOn": cluster.HttpFirewallPolicyId > 0, }) - { - hasActions, _ := this.checkFirewallActions(cluster.Id) - items = append(items, maps.Map{ - "name": "WAF动作", - "url": "/clusters/cluster/settings/firewall-actions?clusterId=" + clusterId, - "isActive": selectedItem == "firewallAction", - "isOn": hasActions, - }) - } + items = append(items, maps.Map{ + "name": "WAF动作", + "url": "/clusters/cluster/settings/firewall-actions?clusterId=" + clusterId, + "isActive": selectedItem == "firewallAction", + "isOn": info != nil && info.HasFirewallActions, + }) - { - healthCheckIsOn, _ := this.checkHealthCheckIsOn(cluster.Id) - items = append(items, maps.Map{ - "name": "健康检查", - "url": "/clusters/cluster/settings/health?clusterId=" + clusterId, - "isActive": selectedItem == "health", - "isOn": healthCheckIsOn, - }) - } + items = append(items, maps.Map{ + "name": "健康检查", + "url": "/clusters/cluster/settings/health?clusterId=" + clusterId, + "isActive": selectedItem == "health", + "isOn": info != nil && info.HealthCheckIsOn, + }) items = append(items, maps.Map{ "name": "DNS设置", @@ -119,22 +121,26 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt "isActive": selectedItem == "dns", "isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0, }) + /**items = append(items, maps.Map{ + "name": "统计指标", + "url": "/clusters/cluster/settings/metrics?clusterId=" + clusterId, + "isActive": selectedItem == "metric", + "isOn": info != nil && info.HasMetricItems, + })**/ + if teaconst.IsPlus { - hasThresholds, _ := this.checkThresholds(cluster.Id) items = append(items, maps.Map{ "name": "阈值设置", "url": "/clusters/cluster/settings/thresholds?clusterId=" + clusterId, "isActive": selectedItem == "threshold", - "isOn": hasThresholds, + "isOn": info != nil && info.HasThresholds, }) - } - if teaconst.IsPlus { - hasMessageReceivers, _ := this.checkMessages(cluster.Id) + items = append(items, maps.Map{ "name": "消息通知", "url": "/clusters/cluster/settings/message?clusterId=" + clusterId, "isActive": selectedItem == "message", - "isOn": hasMessageReceivers, + "isOn": info != nil && info.HasMessageReceivers, }) } @@ -150,99 +156,12 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt "isActive": selectedItem == "service", }) { - isChecked, _ := this.checkTOA(cluster.Id) items = append(items, maps.Map{ "name": "TOA设置", "url": "/clusters/cluster/settings/toa?clusterId=" + clusterId, "isActive": selectedItem == "toa", - "isOn": isChecked, + "isOn": info != nil && info.IsTOAEnabled, }) } return } - -// 检查健康检查是否开启 -func (this *ClusterHelper) checkHealthCheckIsOn(clusterId int64) (bool, error) { - rpcClient, err := rpc.SharedRPC() - if err != nil { - return false, err - } - resp, err := rpcClient.NodeClusterRPC().FindNodeClusterHealthCheckConfig(rpcClient.Context(0), &pb.FindNodeClusterHealthCheckConfigRequest{NodeClusterId: clusterId}) - if err != nil { - return false, err - } - if len(resp.HealthCheckJSON) > 0 { - healthCheckConfig := &serverconfigs.HealthCheckConfig{} - err = json.Unmarshal(resp.HealthCheckJSON, healthCheckConfig) - if err != nil { - return false, err - } - return healthCheckConfig.IsOn, nil - } - return false, nil -} - -// 检查是否有WAF动作 -func (this *ClusterHelper) checkFirewallActions(clusterId int64) (bool, error) { - rpcClient, err := rpc.SharedRPC() - if err != nil { - return false, err - } - resp, err := rpcClient.NodeClusterFirewallActionRPC().CountAllEnabledNodeClusterFirewallActions(rpcClient.Context(0), &pb.CountAllEnabledNodeClusterFirewallActionsRequest{NodeClusterId: clusterId}) - if err != nil { - return false, err - } - return resp.Count > 0, nil -} - -// 检查阈值是否已经设置 -func (this *ClusterHelper) checkThresholds(clusterId int64) (bool, error) { - rpcClient, err := rpc.SharedRPC() - if err != nil { - return false, err - } - resp, err := rpcClient.NodeThresholdRPC().CountAllEnabledNodeThresholds(rpcClient.Context(0), &pb.CountAllEnabledNodeThresholdsRequest{ - Role: "node", - NodeClusterId: clusterId, - }) - if err != nil { - return false, err - } - return resp.Count > 0, nil -} - -// 检查消息通知是否已经设置 -func (this *ClusterHelper) checkMessages(clusterId int64) (bool, error) { - rpcClient, err := rpc.SharedRPC() - if err != nil { - return false, err - } - resp, err := rpcClient.MessageReceiverRPC().CountAllEnabledMessageReceivers(rpcClient.Context(0), &pb.CountAllEnabledMessageReceiversRequest{ - NodeClusterId: clusterId, - }) - if err != nil { - return false, err - } - return resp.Count > 0, nil -} - -// 检查TOA是否设置 -func (this *ClusterHelper) checkTOA(clusterId int64) (bool, error) { - rpcClient, err := rpc.SharedRPC() - if err != nil { - return false, err - } - resp, err := rpcClient.NodeClusterRPC().FindEnabledNodeClusterTOA(rpcClient.Context(0), &pb.FindEnabledNodeClusterTOARequest{NodeClusterId: clusterId}) - if err != nil { - return false, err - } - if len(resp.ToaJSON) == 0 { - return false, nil - } - var toaConfig = &nodeconfigs.TOAConfig{} - err = json.Unmarshal(resp.ToaJSON, toaConfig) - if err != nil { - return false, err - } - return toaConfig.IsOn, nil -} diff --git a/internal/web/actions/default/servers/iplists/bindHTTPFirewallPopup.go b/internal/web/actions/default/servers/iplists/bindHTTPFirewallPopup.go index 2e8dd9b5..4ea80e30 100644 --- a/internal/web/actions/default/servers/iplists/bindHTTPFirewallPopup.go +++ b/internal/web/actions/default/servers/iplists/bindHTTPFirewallPopup.go @@ -99,6 +99,8 @@ func (this *BindHTTPFirewallPopupAction) RunPost(params struct { Must *actions.Must }) { + defer this.CreateLogInfo("绑定IP名单 %d 到WAF策略 %d", params.ListId, params.HttpFirewallPolicyId) + // List类型 listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: params.ListId}) if err != nil { diff --git a/internal/web/actions/default/servers/iplists/unbindHTTPFirewall.go b/internal/web/actions/default/servers/iplists/unbindHTTPFirewall.go index dfff9d3d..1e8656c8 100644 --- a/internal/web/actions/default/servers/iplists/unbindHTTPFirewall.go +++ b/internal/web/actions/default/servers/iplists/unbindHTTPFirewall.go @@ -18,6 +18,8 @@ func (this *UnbindHTTPFirewallAction) RunPost(params struct { HttpFirewallPolicyId int64 ListId int64 }) { + defer this.CreateLogInfo("接触绑定IP名单 %d WAF策略 %d", params.ListId, params.HttpFirewallPolicyId) + // List类型 listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: params.ListId}) if err != nil { diff --git a/internal/web/actions/default/servers/metrics/charts.go b/internal/web/actions/default/servers/metrics/charts.go new file mode 100644 index 00000000..445a3fea --- /dev/null +++ b/internal/web/actions/default/servers/metrics/charts.go @@ -0,0 +1,25 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + +type ChartsAction struct { + actionutils.ParentAction +} + +func (this *ChartsAction) Init() { + this.Nav("", "", "chart") +} + +func (this *ChartsAction) RunGet(params struct { + ItemId int64 +}) { + err := InitItem(this.Parent(), params.ItemId) + if err != nil { + this.ErrorPage(err) + return + } + + this.Show() +} diff --git a/internal/web/actions/default/servers/metrics/createPopup.go b/internal/web/actions/default/servers/metrics/createPopup.go new file mode 100644 index 00000000..40124302 --- /dev/null +++ b/internal/web/actions/default/servers/metrics/createPopup.go @@ -0,0 +1,83 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/maps" +) + +type CreatePopupAction struct { + actionutils.ParentAction +} + +func (this *CreatePopupAction) Init() { + this.Nav("", "", "") +} + +func (this *CreatePopupAction) RunGet(params struct { + Category string +}) { + this.Data["category"] = params.Category + + this.Show() +} + +func (this *CreatePopupAction) RunPost(params struct { + Name string + Category string + KeysJSON []byte + PeriodJSON []byte + Value string + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + params.Must. + Field("name", params.Name). + Require("请输入指标名称") + + if len(params.Category) == 0 { + this.Fail("请选择指标类型") + } + + // 统计对象 + if len(params.KeysJSON) == 0 { + this.FailField("keys", "请选择指标统计的对象") + } + var keys = []string{} + err := json.Unmarshal(params.KeysJSON, &keys) + if err != nil { + this.FailField("keys", "解析指标对象失败") + } + if len(keys) == 0 { + this.FailField("keys", "请选择指标统计的对象") + } + + var periodMap = maps.Map{} + err = json.Unmarshal(params.PeriodJSON, &periodMap) + if err != nil { + this.FailField("period", "解析统计周期失败") + } + var period = periodMap.GetInt32("period") + var periodUnit = periodMap.GetString("unit") + + createResp, err := this.RPC().MetricItemRPC().CreateMetricItem(this.AdminContext(), &pb.CreateMetricItemRequest{ + Code: "", // TODO 未来实现 + Category: params.Category, + Name: params.Name, + Keys: keys, + Period: period, + PeriodUnit: periodUnit, + Value: params.Value, + }) + if err != nil { + this.ErrorPage(err) + return + } + defer this.CreateLogInfo("创建统计指标 %d", createResp.MetricItemId) + this.Success() +} diff --git a/internal/web/actions/default/servers/metrics/delete.go b/internal/web/actions/default/servers/metrics/delete.go new file mode 100644 index 00000000..64c35f89 --- /dev/null +++ b/internal/web/actions/default/servers/metrics/delete.go @@ -0,0 +1,26 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type DeleteAction struct { + actionutils.ParentAction +} + +func (this *DeleteAction) RunPost(params struct { + ItemId int64 +}) { + defer this.CreateLogInfo("删除统计指标") + + _, err := this.RPC().MetricItemRPC().DeleteMetricItem(this.AdminContext(), &pb.DeleteMetricItemRequest{MetricItemId: params.ItemId}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/servers/metrics/index.go b/internal/web/actions/default/servers/metrics/index.go new file mode 100644 index 00000000..5463cc6c --- /dev/null +++ b/internal/web/actions/default/servers/metrics/index.go @@ -0,0 +1,61 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + this.Nav("", "", "") +} + +func (this *IndexAction) RunGet(params struct { + Category string +}) { + if len(params.Category) == 0 { + params.Category = "http" + } + this.Data["category"] = params.Category + + countResp, err := this.RPC().MetricItemRPC().CountAllEnabledMetricItems(this.AdminContext(), &pb.CountAllEnabledMetricItemsRequest{Category: params.Category}) + if err != nil { + this.ErrorPage(err) + return + } + var count = countResp.Count + page := this.NewPage(count) + this.Data["page"] = page.AsHTML() + + itemsResp, err := this.RPC().MetricItemRPC().ListEnabledMetricItems(this.AdminContext(), &pb.ListEnabledMetricItemsRequest{ + Category: params.Category, + Offset: page.Offset, + Size: page.Size, + }) + if err != nil { + this.ErrorPage(err) + return + } + 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, + }) + } + this.Data["items"] = itemMaps + + this.Show() +} diff --git a/internal/web/actions/default/servers/metrics/init.go b/internal/web/actions/default/servers/metrics/init.go new file mode 100644 index 00000000..8ab69e43 --- /dev/null +++ b/internal/web/actions/default/servers/metrics/init.go @@ -0,0 +1,24 @@ +package metrics + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/configloaders" + "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" + "github.com/iwind/TeaGo" +) + +func init() { + TeaGo.BeforeStart(func(server *TeaGo.Server) { + server. + Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)). + Data("teaMenu", "servers"). + Data("teaSubMenu", "metric"). + Prefix("/servers/metrics"). + Get("", new(IndexAction)). + GetPost("/createPopup", new(CreatePopupAction)). + GetPost("/update", new(UpdateAction)). + Post("/delete", new(DeleteAction)). + Get("/item", new(ItemAction)). + Get("/charts", new(ChartsAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/servers/metrics/item.go b/internal/web/actions/default/servers/metrics/item.go new file mode 100644 index 00000000..0f47eacb --- /dev/null +++ b/internal/web/actions/default/servers/metrics/item.go @@ -0,0 +1,25 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + +type ItemAction struct { + actionutils.ParentAction +} + +func (this *ItemAction) Init() { + this.Nav("", "", "item") +} + +func (this *ItemAction) RunGet(params struct { + ItemId int64 +}) { + err := InitItem(this.Parent(), params.ItemId) + if err != nil { + this.ErrorPage(err) + return + } + + this.Show() +} diff --git a/internal/web/actions/default/servers/metrics/update.go b/internal/web/actions/default/servers/metrics/update.go index 1377bcf8..4f0dae9c 100644 --- a/internal/web/actions/default/servers/metrics/update.go +++ b/internal/web/actions/default/servers/metrics/update.go @@ -2,16 +2,83 @@ package metrics -import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/maps" +) type UpdateAction struct { actionutils.ParentAction } func (this *UpdateAction) Init() { - this.Nav("", "", "") + this.Nav("", "", "update") } -func (this *UpdateAction) RunGet(params struct{}) { +func (this *UpdateAction) RunGet(params struct { + ItemId int64 +}) { + err := InitItem(this.Parent(), params.ItemId) + if err != nil { + this.ErrorPage(err) + return + } + this.Show() } + +func (this *UpdateAction) RunPost(params struct { + ItemId int64 + Name string + KeysJSON []byte + PeriodJSON []byte + Value string + IsOn bool + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + params.Must. + Field("name", params.Name). + Require("请输入指标名称") + + // 统计对象 + if len(params.KeysJSON) == 0 { + this.FailField("keys", "请选择指标统计的对象") + } + var keys = []string{} + err := json.Unmarshal(params.KeysJSON, &keys) + if err != nil { + this.FailField("keys", "解析指标对象失败") + } + if len(keys) == 0 { + this.FailField("keys", "请选择指标统计的对象") + } + + var periodMap = maps.Map{} + err = json.Unmarshal(params.PeriodJSON, &periodMap) + if err != nil { + this.FailField("period", "解析统计周期失败") + } + var period = periodMap.GetInt32("period") + var periodUnit = periodMap.GetString("unit") + + _, err = this.RPC().MetricItemRPC().UpdateMetricItem(this.AdminContext(), &pb.UpdateMetricItemRequest{ + MetricItemId: params.ItemId, + Name: params.Name, + Keys: keys, + Period: period, + PeriodUnit: periodUnit, + Value: params.Value, + IsOn: params.IsOn, + }) + if err != nil { + this.ErrorPage(err) + return + } + defer this.CreateLogInfo("修改统计指标 %d", params.ItemId) + this.Success() +} diff --git a/internal/web/actions/default/servers/metrics/utils.go b/internal/web/actions/default/servers/metrics/utils.go new file mode 100644 index 00000000..37e12dcf --- /dev/null +++ b/internal/web/actions/default/servers/metrics/utils.go @@ -0,0 +1,37 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package metrics + +import ( + "errors" + "github.com/TeaOSLab/EdgeAdmin/internal/rpc" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +func InitItem(parent *actionutils.ParentAction, itemId int64) error { + client, err := rpc.SharedRPC() + if err != nil { + return err + } + resp, err := client.MetricItemRPC().FindEnabledMetricItem(parent.AdminContext(), &pb.FindEnabledMetricItemRequest{MetricItemId: itemId}) + if err != nil { + return err + } + var item = resp.MetricItem + if item == nil { + return errors.New("not found") + } + parent.Data["item"] = maps.Map{ + "id": item.Id, + "name": item.Name, + "isOn": item.IsOn, + "keys": item.Keys, + "value": item.Value, + "period": item.Period, + "periodUnit": item.PeriodUnit, + "category": item.Category, + } + return nil +} diff --git a/internal/web/actions/default/ui/components.go b/internal/web/actions/default/ui/components.go index f11d6928..eb174363 100644 --- a/internal/web/actions/default/ui/components.go +++ b/internal/web/actions/default/ui/components.go @@ -2,22 +2,33 @@ package ui import ( "bytes" + "crypto/md5" "encoding/json" + "fmt" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/files" "github.com/iwind/TeaGo/logs" + "net/http" ) type ComponentsAction actions.Action var componentsData = []byte{} +var componentsDataSum string func (this *ComponentsAction) RunGet(params struct{}) { this.AddHeader("Content-Type", "text/javascript; charset=utf-8") + // etag + var requestETag = this.Header("If-None-Match") + if len(requestETag) > 0 && requestETag == "\""+componentsDataSum+"\"" { + this.ResponseWriter.WriteHeader(http.StatusNotModified) + return + } + if !Tea.IsTesting() && len(componentsData) > 0 { this.AddHeader("Last-Modified", "Fri, 06 Sep 2019 08:29:50 GMT") this.Write(componentsData) @@ -81,5 +92,12 @@ func (this *ComponentsAction) RunGet(params struct{}) { } componentsData = buffer.Bytes() + + // ETag + var h = md5.New() + h.Write(buffer.Bytes()) + componentsDataSum = fmt.Sprintf("%x", h.Sum(nil)) + this.AddHeader("ETag", "\""+componentsDataSum+"\"") + this.Write(componentsData) } diff --git a/internal/web/helpers/user_must_auth.go b/internal/web/helpers/user_must_auth.go index 0fe92b5c..16d4710d 100644 --- a/internal/web/helpers/user_must_auth.go +++ b/internal/web/helpers/user_must_auth.go @@ -177,6 +177,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map { "url": "/servers/certs", "code": "cert", }, + /**{ + "name": "统计指标", + "url": "/servers/metrics", + "code": "metric", + },**/ }, }, { diff --git a/internal/web/import.go b/internal/web/import.go index 5ae82605..0e67319e 100644 --- a/internal/web/import.go +++ b/internal/web/import.go @@ -110,6 +110,7 @@ import ( _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/stat" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/iplists" + _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics" // 设置相关 _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings" diff --git a/web/public/js/components/common/health-check-config-box.js b/web/public/js/components/common/health-check-config-box.js index f361036f..ae9cfc28 100644 --- a/web/public/js/components/common/health-check-config-box.js +++ b/web/public/js/components/common/health-check-config-box.js @@ -176,6 +176,7 @@ Vue.component("health-check-config-box", {
在此集群上可以访问到的一个域名。