diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index e53ea683..b0f42b27 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -95,6 +95,10 @@ func (this *RPCClient) NodeValueRPC() pb.NodeValueServiceClient { return pb.NewNodeValueServiceClient(this.pickConn()) } +func (this *RPCClient) NodeThresholdRPC() pb.NodeThresholdServiceClient { + return pb.NewNodeThresholdServiceClient(this.pickConn()) +} + func (this *RPCClient) ServerRPC() pb.ServerServiceClient { return pb.NewServerServiceClient(this.pickConn()) } diff --git a/internal/web/actions/default/clusters/cluster/settings/init.go b/internal/web/actions/default/clusters/cluster/settings/init.go index 3b2ce45a..b92fe649 100644 --- a/internal/web/actions/default/clusters/cluster/settings/init.go +++ b/internal/web/actions/default/clusters/cluster/settings/init.go @@ -8,6 +8,7 @@ import ( "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/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" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/waf" clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils" @@ -59,6 +60,13 @@ func init() { GetPost("/updatePopup", new(firewallActions.UpdatePopupAction)). Post("/delete", new(firewallActions.DeleteAction)). + // 阈值 + Prefix("/clusters/cluster/settings/thresholds"). + Get("", new(thresholds.IndexAction)). + GetPost("/createPopup", new(thresholds.CreatePopupAction)). + GetPost("/updatePopup", new(thresholds.UpdatePopupAction)). + Post("/delete", new(thresholds.DeleteAction)). + EndAll() }) } diff --git a/internal/web/actions/default/clusters/cluster/settings/message/selectedReceivers.go b/internal/web/actions/default/clusters/cluster/settings/message/selectedReceivers.go index 6f14e004..b975b58f 100644 --- a/internal/web/actions/default/clusters/cluster/settings/message/selectedReceivers.go +++ b/internal/web/actions/default/clusters/cluster/settings/message/selectedReceivers.go @@ -21,7 +21,7 @@ func (this *SelectedReceiversAction) RunPost(params struct { NodeId int64 ServerId int64 }) { - receiversResp, err := this.RPC().MessageReceiverRPC().FindAllMessageReceivers(this.AdminContext(), &pb.FindAllMessageReceiversRequest{ + receiversResp, err := this.RPC().MessageReceiverRPC().FindAllEnabledMessageReceivers(this.AdminContext(), &pb.FindAllEnabledMessageReceiversRequest{ NodeClusterId: params.ClusterId, NodeId: params.NodeId, ServerId: params.ServerId, diff --git a/internal/web/actions/default/clusters/cluster/settings/thresholds/createPopup.go b/internal/web/actions/default/clusters/cluster/settings/thresholds/createPopup.go new file mode 100644 index 00000000..251be750 --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/settings/thresholds/createPopup.go @@ -0,0 +1,74 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package thresholds + +import ( + "encoding/json" + "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/actions" +) + +type CreatePopupAction struct { + actionutils.ParentAction +} + +func (this *CreatePopupAction) Init() { + this.Nav("", "", "") +} + +func (this *CreatePopupAction) RunGet(params struct { + ClusterId int64 +}) { + this.Data["clusterId"] = params.ClusterId + this.Data["items"] = nodeconfigs.FindAllNodeValueItemDefinitions() + this.Data["operators"] = nodeconfigs.FindAllNodeValueOperatorDefinitions() + + this.Show() +} + +func (this *CreatePopupAction) RunPost(params struct { + ClusterId int64 + NodeId int64 + Item string + Param string + SumMethod string + Operator string + Value string + Duration int32 + DurationUnit string + Message string + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + if params.ClusterId <= 0 && params.NodeId >= 0 { + this.Fail("集群或者节点至少需要填写其中一个参数") + } + + valueJSON, err := json.Marshal(params.Value) + if err != nil { + this.ErrorPage(err) + return + } + resp, err := this.RPC().NodeThresholdRPC().CreateNodeThreshold(this.AdminContext(), &pb.CreateNodeThresholdRequest{ + NodeClusterId: params.ClusterId, + NodeId: params.NodeId, + Item: params.Item, + Param: params.Param, + Operator: params.Operator, + ValueJSON: valueJSON, + Message: params.Message, + Duration: params.Duration, + DurationUnit: params.DurationUnit, + SumMethod: params.SumMethod, + }) + if err != nil { + this.ErrorPage(err) + return + } + defer this.CreateLogInfo("创建节点阈值 %d", resp.NodeThresholdId) + + this.Success() +} diff --git a/internal/web/actions/default/clusters/cluster/settings/thresholds/delete.go b/internal/web/actions/default/clusters/cluster/settings/thresholds/delete.go new file mode 100644 index 00000000..48c9b293 --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/settings/thresholds/delete.go @@ -0,0 +1,27 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package thresholds + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +// DeleteAction 删除阈值 +type DeleteAction struct { + actionutils.ParentAction +} + +func (this *DeleteAction) RunPost(params struct { + ThresholdId int64 +}) { + defer this.CreateLogInfo("删除阈值 %d", params.ThresholdId) + + _, err := this.RPC().NodeThresholdRPC().DeleteNodeThreshold(this.AdminContext(), &pb.DeleteNodeThresholdRequest{NodeThresholdId: params.ThresholdId}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/clusters/cluster/settings/thresholds/index.go b/internal/web/actions/default/clusters/cluster/settings/thresholds/index.go new file mode 100644 index 00000000..d1fca8eb --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/settings/thresholds/index.go @@ -0,0 +1,51 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package thresholds + +import ( + "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" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + this.Nav("", "setting", "setting") + this.SecondMenu("threshold") +} + +func (this *IndexAction) RunGet(params struct { + ClusterId int64 +}) { + // 列出所有阈值 + thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{ + NodeClusterId: params.ClusterId, + NodeId: 0, + }) + if err != nil { + this.ErrorPage(err) + return + } + + thresholdMaps := []maps.Map{} + for _, threshold := range thresholdsResp.NodeThresholds { + thresholdMaps = append(thresholdMaps, maps.Map{ + "id": threshold.Id, + "itemName": nodeconfigs.FindNodeValueItemName(threshold.Item), + "paramName": nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param), + "operatorName": nodeconfigs.FindNodeValueOperatorName(threshold.Operator), + "value": string(threshold.ValueJSON), + "sumMethodName": nodeconfigs.FindNodeValueSumMethodName(threshold.SumMethod), + "duration": threshold.Duration, + "durationUnitName": nodeconfigs.FindNodeValueDurationUnitName(threshold.DurationUnit), + "isOn": threshold.IsOn, + }) + } + this.Data["thresholds"] = thresholdMaps + + this.Show() +} diff --git a/internal/web/actions/default/clusters/cluster/settings/thresholds/updatePopup.go b/internal/web/actions/default/clusters/cluster/settings/thresholds/updatePopup.go new file mode 100644 index 00000000..23e31b02 --- /dev/null +++ b/internal/web/actions/default/clusters/cluster/settings/thresholds/updatePopup.go @@ -0,0 +1,103 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package thresholds + +import ( + "encoding/json" + "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/actions" + "github.com/iwind/TeaGo/maps" +) + +type UpdatePopupAction struct { + actionutils.ParentAction +} + +func (this *UpdatePopupAction) Init() { + this.Nav("", "", "") +} + +func (this *UpdatePopupAction) RunGet(params struct { + ThresholdId int64 +}) { + // 通用参数 + this.Data["items"] = nodeconfigs.FindAllNodeValueItemDefinitions() + this.Data["operators"] = nodeconfigs.FindAllNodeValueOperatorDefinitions() + + // 阈值详情 + thresholdResp, err := this.RPC().NodeThresholdRPC().FindEnabledNodeThreshold(this.AdminContext(), &pb.FindEnabledNodeThresholdRequest{NodeThresholdId: params.ThresholdId}) + if err != nil { + this.ErrorPage(err) + return + } + threshold := thresholdResp.NodeThreshold + if threshold == nil { + this.NotFound("nodeThreshold", params.ThresholdId) + return + } + + valueInterface := new(interface{}) + err = json.Unmarshal(threshold.ValueJSON, valueInterface) + if err != nil { + this.ErrorPage(err) + return + } + + this.Data["threshold"] = maps.Map{ + "id": threshold.Id, + "item": threshold.Item, + "param": threshold.Param, + "message": threshold.Message, + "value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON), + "operator": threshold.Operator, + "duration": threshold.Duration, + "durationUnit": threshold.DurationUnit, + "isOn": threshold.IsOn, + } + + this.Show() +} + +func (this *UpdatePopupAction) RunPost(params struct { + ThresholdId int64 + Item string + Param string + SumMethod string + Operator string + Value string + Duration int32 + DurationUnit string + Message string + IsOn bool + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + defer this.CreateLogInfo("修改节点阈值 %d", params.ThresholdId) + + valueJSON, err := json.Marshal(params.Value) + if err != nil { + this.ErrorPage(err) + return + } + _, err = this.RPC().NodeThresholdRPC().UpdateNodeThreshold(this.AdminContext(), &pb.UpdateNodeThresholdRequest{ + NodeThresholdId: params.ThresholdId, + Item: params.Item, + Param: params.Param, + Operator: params.Operator, + ValueJSON: valueJSON, + Message: params.Message, + Duration: params.Duration, + DurationUnit: params.DurationUnit, + SumMethod: params.SumMethod, + IsOn: params.IsOn, + }) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/clusters/clusterutils/cluster_helper.go b/internal/web/actions/default/clusters/clusterutils/cluster_helper.go index 7d8826ed..a32cabf9 100644 --- a/internal/web/actions/default/clusters/clusterutils/cluster_helper.go +++ b/internal/web/actions/default/clusters/clusterutils/cluster_helper.go @@ -119,10 +119,21 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt "isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0, }) 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, + }) + } + 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, }) } @@ -178,3 +189,33 @@ func (this *ClusterHelper) checkFirewallActions(clusterId int64) (bool, error) { } 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{ + 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 +} diff --git a/web/views/@default/clusters/cluster/settings/thresholds/createPopup.html b/web/views/@default/clusters/cluster/settings/thresholds/createPopup.html new file mode 100644 index 00000000..abd7ecd4 --- /dev/null +++ b/web/views/@default/clusters/cluster/settings/thresholds/createPopup.html @@ -0,0 +1,67 @@ +{$layout "layout_popup"} + +

添加阈值

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
监控项 * + +

{{itemDescription}}

+
参数 * + +

{{paramDescription}}

+
操作符 * + +
对比值 + +
统计时间段 * +
+
+ +
+
+ 分钟 + + +
+
+
消息 + +

触发阈值时的消息提示。

+
+ + +
\ No newline at end of file diff --git a/web/views/@default/clusters/cluster/settings/thresholds/createPopup.js b/web/views/@default/clusters/cluster/settings/thresholds/createPopup.js new file mode 100644 index 00000000..4268c0bf --- /dev/null +++ b/web/views/@default/clusters/cluster/settings/thresholds/createPopup.js @@ -0,0 +1,42 @@ +Tea.context(function () { + this.success = NotifyPopup + this.threshold = { + item: this.items[0].code, + param: "", + operator: this.operators[0].code + } + this.$delay(function () { + this.changeItem() + this.changeParam() + }) + + this.itemDescription = "" + this.itemParams = [] + + this.changeItem = function () { + let that = this + this.threshold.param = "" + this.items.forEach(function (v) { + if (v.code == that.threshold.item) { + that.itemDescription = v.description + that.itemParams = v.params + that.threshold.param = v.params[0].code + } + }) + } + + this.paramDescription = "" + + this.changeParam = function () { + let that = this + this.items.forEach(function (v) { + if (v.code == that.threshold.item) { + v.params.forEach(function (param) { + if (param.code == that.threshold.param) { + that.paramDescription = param.description + } + }) + } + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/settings/thresholds/index.html b/web/views/@default/clusters/cluster/settings/thresholds/index.html new file mode 100644 index 00000000..7b4cdde9 --- /dev/null +++ b/web/views/@default/clusters/cluster/settings/thresholds/index.html @@ -0,0 +1,37 @@ +{$layout} +{$template "/left_menu"} + +
+ + 添加阈值 + + +

暂时还没有设置阈值。

+ + + + + + + + + + + + + + + + + + + + + +
监控项参数操作符对比值统计时间段状态操作
{{threshold.itemName}}{{threshold.paramName}}{{threshold.operatorName}}{{threshold.itemName}}{{threshold.duration}}{{threshold.durationUnitName}} + + + 修改   + 删除 +
+
\ No newline at end of file diff --git a/web/views/@default/clusters/cluster/settings/thresholds/index.js b/web/views/@default/clusters/cluster/settings/thresholds/index.js new file mode 100644 index 00000000..7af445f4 --- /dev/null +++ b/web/views/@default/clusters/cluster/settings/thresholds/index.js @@ -0,0 +1,40 @@ +Tea.context(function () { + this.createThreshold = function () { + teaweb.popup(Tea.url(".createPopup", { + clusterId: this.clusterId + }), { + callback: function () { + teaweb.success("保存成功", function () { + teaweb.reload() + }) + } + }) + } + + this.updateThreshold = function (thresholdId) { + teaweb.popup(Tea.url(".updatePopup", { + thresholdId: thresholdId + }), { + callback: function () { + teaweb.success("保存成功", function () { + teaweb.reload() + }) + } + }) + } + + this.deleteThreshold = function (thresholdId) { + let that = this + teaweb.confirm("确定要删除这个阈值吗?", function () { + that.$post(".delete") + .params({ + thresholdId: thresholdId + }) + .success(function () { + teaweb.success("删除成功", function () { + teaweb.reload() + }) + }) + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/clusters/cluster/settings/thresholds/updatePopup.html b/web/views/@default/clusters/cluster/settings/thresholds/updatePopup.html new file mode 100644 index 00000000..16ee9e0b --- /dev/null +++ b/web/views/@default/clusters/cluster/settings/thresholds/updatePopup.html @@ -0,0 +1,73 @@ +{$layout "layout_popup"} + +

修改阈值

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
监控项 * + +

{{itemDescription}}

+
参数 * + +

{{paramDescription}}

+
操作符 * + +
对比值 + +
统计时间段 * +
+
+ +
+
+ 分钟 + + +
+
+
消息 + +

触发阈值时的消息提示。

+
是否启用 + +
+ + +
\ No newline at end of file diff --git a/web/views/@default/clusters/cluster/settings/thresholds/updatePopup.js b/web/views/@default/clusters/cluster/settings/thresholds/updatePopup.js new file mode 100644 index 00000000..0683221b --- /dev/null +++ b/web/views/@default/clusters/cluster/settings/thresholds/updatePopup.js @@ -0,0 +1,47 @@ +Tea.context(function () { + this.success = NotifyPopup + this.$delay(function () { + this.initItem() + this.changeParam() + }) + + this.itemDescription = "" + this.itemParams = [] + + this.initItem = function () { + let that = this + this.items.forEach(function (v) { + if (v.code == that.threshold.item) { + that.itemDescription = v.description + that.itemParams = v.params + } + }) + } + + this.changeItem = function () { + let that = this + this.threshold.param = "" + this.items.forEach(function (v) { + if (v.code == that.threshold.item) { + that.itemDescription = v.description + that.itemParams = v.params + that.threshold.param = v.params[0].code + } + }) + } + + this.paramDescription = "" + + this.changeParam = function () { + let that = this + this.items.forEach(function (v) { + if (v.code == that.threshold.item) { + v.params.forEach(function (param) { + if (param.code == that.threshold.param) { + that.paramDescription = param.description + } + }) + } + }) + } +}) \ No newline at end of file