实现基础的阈值设置

This commit is contained in:
GoEdgeLab
2021-05-04 21:02:25 +08:00
parent 4b44768f2a
commit 7cbabe51c0
14 changed files with 615 additions and 1 deletions

View File

@@ -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())
}

View File

@@ -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()
})
}

View File

@@ -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,

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -0,0 +1,67 @@
{$layout "layout_popup"}
<h3>添加阈值</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="clusterId" :value="clusterId" />
<input type="hidden" name="sumMethod" value="avg"/>
<table class="ui table definition selectable">
<tr>
<td class="title">监控项 *</td>
<td>
<select class="ui dropdown auto-width" name="item" v-model="threshold.item" @change="changeItem">
<option v-for="item in items" :value="item.code">{{item.name}}</option>
</select>
<p class="comment">{{itemDescription}}</p>
</td>
</tr>
<tr>
<td>参数 *</td>
<td>
<select class="ui dropdown auto-width" name="param" v-model="threshold.param" @change="changeParam">
<option v-for="param in itemParams" :value="param.code">{{param.name}}</option>
</select>
<p class="comment">{{paramDescription}}</p>
</td>
</tr>
<tr>
<td>操作符 *</td>
<td>
<select class="ui dropdown auto-width" name="operator" v-model="threshold.operator">
<option v-for="operator in operators" :value="operator.code">{{operator.name}}</option>
</select>
</td>
</tr>
<tr>
<td>对比值</td>
<td>
<input type="text" name="value" style="width: 6em" maxlength="10"/>
</td>
</tr>
<tr>
<td>统计时间段 *</td>
<td>
<div class="ui fields inline">
<div class="ui field">
<input type="text" name="duration" value="5" style="width: 5em"/>
</div>
<div class="ui field">
分钟
<!-- TODO 将来支持更多时间范围 -->
<input type="hidden" name="durationUnit" value="minute"/>
</div>
</div>
</td>
</tr>
<tr>
<td>消息</td>
<td>
<textarea rows="2" maxlength="100" name="message"></textarea>
<p class="comment">触发阈值时的消息提示。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -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
}
})
}
})
}
})

View File

@@ -0,0 +1,37 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
<first-menu>
<menu-item @click.prevent="createThreshold">添加阈值</menu-item>
</first-menu>
<p class="comment" v-if="thresholds.length == 0">暂时还没有设置阈值。</p>
<table class="ui table selectable" v-if="thresholds.length > 0">
<thead>
<tr>
<th>监控项</th>
<th>参数</th>
<th>操作符</th>
<th>对比值</th>
<th>统计时间段</th>
<th class="two wide">状态</th>
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="threshold in thresholds">
<td>{{threshold.itemName}}</td>
<td>{{threshold.paramName}}</td>
<td>{{threshold.operatorName}}</td>
<td>{{threshold.itemName}}</td>
<td>{{threshold.duration}}{{threshold.durationUnitName}}</td>
<td>
<label-on :v-is-on="threshold.isOn"></label-on>
</td>
<td>
<a href="" @click.prevent="updateThreshold(threshold.id)">修改</a> &nbsp;
<a href="" @click.prevent="deleteThreshold(threshold.id)">删除</a>
</td>
</tr>
</table>
</div>

View File

@@ -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()
})
})
})
}
})

View File

@@ -0,0 +1,73 @@
{$layout "layout_popup"}
<h3>修改阈值</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="thresholdId" :value="threshold.id"/>
<input type="hidden" name="sumMethod" value="avg"/>
<table class="ui table definition selectable">
<tr>
<td class="title">监控项 *</td>
<td>
<select class="ui dropdown auto-width" name="item" v-model="threshold.item" @change="changeItem">
<option v-for="item in items" :value="item.code">{{item.name}}</option>
</select>
<p class="comment">{{itemDescription}}</p>
</td>
</tr>
<tr>
<td>参数 *</td>
<td>
<select class="ui dropdown auto-width" name="param" v-model="threshold.param" @change="changeParam">
<option v-for="param in itemParams" :value="param.code">{{param.name}}</option>
</select>
<p class="comment">{{paramDescription}}</p>
</td>
</tr>
<tr>
<td>操作符 *</td>
<td>
<select class="ui dropdown auto-width" name="operator" v-model="threshold.operator">
<option v-for="operator in operators" :value="operator.code">{{operator.name}}</option>
</select>
</td>
</tr>
<tr>
<td>对比值</td>
<td>
<input type="text" name="value" style="width: 6em" maxlength="10" v-model="threshold.value"/>
</td>
</tr>
<tr>
<td>统计时间段 *</td>
<td>
<div class="ui fields inline">
<div class="ui field">
<input type="text" name="duration" value="5" style="width: 5em" v-model="threshold.duration"/>
</div>
<div class="ui field">
分钟
<!-- TODO 将来支持更多时间范围 -->
<input type="hidden" name="durationUnit" value="minute" v-model="threshold.durationUnit"/>
</div>
</div>
</td>
</tr>
<tr>
<td>消息</td>
<td>
<textarea rows="2" maxlength="100" name="message" v-model="threshold.message"></textarea>
<p class="comment">触发阈值时的消息提示。</p>
</td>
</tr>
<tr>
<td>是否启用</td>
<td>
<checkbox name="isOn" value="1" v-model="threshold.isOn"></checkbox>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -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
}
})
}
})
}
})