节点IP地址可以设置阈值

This commit is contained in:
刘祥超
2021-08-18 16:19:07 +08:00
parent fd203ed436
commit 4b200762a5
11 changed files with 359 additions and 65 deletions

View File

@@ -175,12 +175,19 @@ func (this *CreateNodeAction) RunPost(params struct {
NodeId: nodeId, NodeId: nodeId,
}) })
} else { } else {
var thresholdsJSON = []byte{}
var thresholds = address.GetSlice("thresholds")
if len(thresholds) > 0 {
thresholdsJSON, _ = json.Marshal(thresholds)
}
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{ _, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId, NodeId: nodeId,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
Name: address.GetString("name"), Name: address.GetString("name"),
Ip: address.GetString("ip"), Ip: address.GetString("ip"),
CanAccess: address.GetBool("canAccess"), CanAccess: address.GetBool("canAccess"),
ThresholdsJSON: thresholdsJSON,
}) })
} }
if err != nil { if err != nil {

View File

@@ -79,6 +79,14 @@ func (this *DetailAction) RunGet(params struct {
var ipAddresses = ipAddressesResp.Addresses var ipAddresses = ipAddressesResp.Addresses
ipAddressMaps := []maps.Map{} ipAddressMaps := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.Addresses {
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{}
if len(addr.ThresholdsJSON) > 0 {
err = json.Unmarshal(addr.ThresholdsJSON, &thresholds)
if err != nil {
this.ErrorPage(err)
return
}
}
ipAddressMaps = append(ipAddressMaps, maps.Map{ ipAddressMaps = append(ipAddressMaps, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,
@@ -86,6 +94,7 @@ func (this *DetailAction) RunGet(params struct {
"canAccess": addr.CanAccess, "canAccess": addr.CanAccess,
"isOn": addr.IsOn, "isOn": addr.IsOn,
"isUp": addr.IsUp, "isUp": addr.IsUp,
"thresholds": thresholds,
}) })
} }

View File

@@ -57,6 +57,15 @@ func (this *UpdateAction) RunGet(params struct {
} }
ipAddressMaps := []maps.Map{} ipAddressMaps := []maps.Map{}
for _, addr := range ipAddressesResp.Addresses { for _, addr := range ipAddressesResp.Addresses {
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{}
if len(addr.ThresholdsJSON) > 0 {
err = json.Unmarshal(addr.ThresholdsJSON, &thresholds)
if err != nil {
this.ErrorPage(err)
return
}
}
ipAddressMaps = append(ipAddressMaps, maps.Map{ ipAddressMaps = append(ipAddressMaps, maps.Map{
"id": addr.Id, "id": addr.Id,
"name": addr.Name, "name": addr.Name,
@@ -64,6 +73,7 @@ func (this *UpdateAction) RunGet(params struct {
"canAccess": addr.CanAccess, "canAccess": addr.CanAccess,
"isOn": addr.IsOn, "isOn": addr.IsOn,
"isUp": addr.IsUp, "isUp": addr.IsUp,
"thresholds": thresholds,
}) })
} }

View File

@@ -1,7 +1,10 @@
package ipAddresses package ipAddresses
import ( import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"net" "net"
@@ -16,6 +19,7 @@ func (this *CreatePopupAction) Init() {
} }
func (this *CreatePopupAction) RunGet(params struct{}) { func (this *CreatePopupAction) RunGet(params struct{}) {
this.Show() this.Show()
} }
@@ -23,11 +27,10 @@ func (this *CreatePopupAction) RunPost(params struct {
IP string `alias:"ip"` IP string `alias:"ip"`
CanAccess bool CanAccess bool
Name string Name string
ThresholdsJSON []byte
Must *actions.Must Must *actions.Must
}) { }) {
// TODO 严格校验IP地址
ip := net.ParseIP(params.IP) ip := net.ParseIP(params.IP)
if len(ip) == 0 { if len(ip) == 0 {
this.Fail("请输入正确的IP") this.Fail("请输入正确的IP")
@@ -37,6 +40,11 @@ func (this *CreatePopupAction) RunPost(params struct {
Field("ip", params.IP). Field("ip", params.IP).
Require("请输入IP地址") Require("请输入IP地址")
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{}
if teaconst.IsPlus && len(params.ThresholdsJSON) > 0 {
_ = json.Unmarshal(params.ThresholdsJSON, &thresholds)
}
this.Data["ipAddress"] = maps.Map{ this.Data["ipAddress"] = maps.Map{
"name": params.Name, "name": params.Name,
"canAccess": params.CanAccess, "canAccess": params.CanAccess,
@@ -44,6 +52,7 @@ func (this *CreatePopupAction) RunPost(params struct {
"id": 0, "id": 0,
"isOn": true, "isOn": true,
"isUp": true, "isUp": true,
"thresholds": thresholds,
} }
this.Success() this.Success()
} }

View File

@@ -16,6 +16,12 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
return err return err
} }
for _, addr := range addresses { for _, addr := range addresses {
var thresholdsJSON = []byte{}
var thresholds = addr.GetSlice("thresholds")
if len(thresholds) > 0 {
thresholdsJSON, _ = json.Marshal(thresholds)
}
addrId := addr.GetInt64("id") addrId := addr.GetInt64("id")
if addrId > 0 { if addrId > 0 {
var isOn = false var isOn = false
@@ -24,12 +30,14 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
} else { } else {
isOn = addr.GetBool("isOn") isOn = addr.GetBool("isOn")
} }
_, err = parentAction.RPC().NodeIPAddressRPC().UpdateNodeIPAddress(parentAction.AdminContext(), &pb.UpdateNodeIPAddressRequest{ _, err = parentAction.RPC().NodeIPAddressRPC().UpdateNodeIPAddress(parentAction.AdminContext(), &pb.UpdateNodeIPAddressRequest{
AddressId: addrId, AddressId: addrId,
Ip: addr.GetString("ip"), Ip: addr.GetString("ip"),
Name: addr.GetString("name"), Name: addr.GetString("name"),
CanAccess: addr.GetBool("canAccess"), CanAccess: addr.GetBool("canAccess"),
IsOn: isOn, IsOn: isOn,
ThresholdsJSON: thresholdsJSON,
}) })
if err != nil { if err != nil {
return err return err
@@ -41,6 +49,7 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
Name: addr.GetString("name"), Name: addr.GetString("name"),
Ip: addr.GetString("ip"), Ip: addr.GetString("ip"),
CanAccess: addr.GetBool("canAccess"), CanAccess: addr.GetBool("canAccess"),
ThresholdsJSON: thresholdsJSON,
}) })
if err != nil { if err != nil {
return err return err

View File

@@ -1,7 +1,10 @@
package ipAddresses package ipAddresses
import ( import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
@@ -28,6 +31,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
Name string Name string
CanAccess bool CanAccess bool
IsOn bool IsOn bool
ThresholdsJSON []byte
Must *actions.Must Must *actions.Must
}) { }) {
@@ -36,6 +40,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
Require("请输入IP地址") Require("请输入IP地址")
// 获取IP地址信息 // 获取IP地址信息
var isUp = true
if params.AddressId > 0 {
addressResp, err := this.RPC().NodeIPAddressRPC().FindEnabledNodeIPAddress(this.AdminContext(), &pb.FindEnabledNodeIPAddressRequest{AddressId: params.AddressId}) addressResp, err := this.RPC().NodeIPAddressRPC().FindEnabledNodeIPAddress(this.AdminContext(), &pb.FindEnabledNodeIPAddressRequest{AddressId: params.AddressId})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -45,19 +51,27 @@ func (this *UpdatePopupAction) RunPost(params struct {
if address == nil { if address == nil {
this.Fail("找不到要修改的地址") this.Fail("找不到要修改的地址")
} }
isUp = address.IsUp
}
ip := net.ParseIP(params.IP) ip := net.ParseIP(params.IP)
if len(ip) == 0 { if len(ip) == 0 {
this.Fail("请输入正确的IP") this.Fail("请输入正确的IP")
} }
var thresholds = []*nodeconfigs.NodeValueThresholdConfig{}
if teaconst.IsPlus && len(params.ThresholdsJSON) > 0 {
_ = json.Unmarshal(params.ThresholdsJSON, &thresholds)
}
this.Data["ipAddress"] = maps.Map{ this.Data["ipAddress"] = maps.Map{
"name": params.Name, "name": params.Name,
"ip": params.IP, "ip": params.IP,
"id": params.AddressId, "id": params.AddressId,
"canAccess": params.CanAccess, "canAccess": params.CanAccess,
"isOn": params.IsOn, "isOn": params.IsOn,
"isUp": address.IsUp, "isUp": isUp,
"thresholds": thresholds,
} }
this.Success() this.Success()

View File

@@ -0,0 +1,213 @@
// 节点IP阈值
Vue.component("node-ip-address-thresholds-box", {
props: ["v-thresholds"],
data: function () {
let thresholds = this.vThresholds
if (thresholds == null) {
thresholds = []
}
let avgRequests = {
duration: "",
operator: "lt",
value: ""
}
let avgTrafficOut = {
duration: "",
operator: "lt",
value: ""
}
let avgTrafficIn = {
duration: "",
operator: "lt",
value: ""
}
thresholds.forEach(function (v) {
switch (v.item) {
case "avgRequests":
avgRequests.duration = v.duration
avgRequests.operator = v.operator
avgRequests.value = v.value.toString()
break
case "avgTrafficOut":
avgTrafficOut.duration = v.duration
avgTrafficOut.operator = v.operator
avgTrafficOut.value = v.value.toString()
break
case "avgTrafficIn":
avgTrafficIn.duration = v.duration
avgTrafficIn.operator = v.operator
avgTrafficIn.value = v.value.toString()
break
}
})
return {
thresholds: thresholds,
avgRequests: avgRequests,
avgTrafficOut: avgTrafficOut,
avgTrafficIn: avgTrafficIn
}
},
watch: {
"avgRequests.duration": function () {
this.compose()
},
"avgRequests.operator": function () {
this.compose()
},
"avgRequests.value": function () {
this.compose()
},
"avgTrafficOut.duration": function () {
this.compose()
},
"avgTrafficOut.operator": function () {
this.compose()
},
"avgTrafficOut.value": function () {
this.compose()
},
"avgTrafficIn.duration": function () {
this.compose()
},
"avgTrafficIn.operator": function () {
this.compose()
},
"avgTrafficIn.value": function () {
this.compose()
}
},
methods: {
compose: function () {
let thresholds = []
// avg requests
{
let duration = parseInt(this.avgRequests.duration)
let value = parseInt(this.avgRequests.value)
if (!isNaN(duration) && duration > 0 && !isNaN(value) && value > 0) {
thresholds.push({
item: "avgRequests",
operator: this.avgRequests.operator,
duration: duration,
durationUnit: "minute",
value: value
})
}
}
// avg traffic out
{
let duration = parseInt(this.avgTrafficOut.duration)
let value = parseInt(this.avgTrafficOut.value)
if (!isNaN(duration) && duration > 0 && !isNaN(value) && value > 0) {
thresholds.push({
item: "avgTrafficOut",
operator: this.avgTrafficOut.operator,
duration: duration,
durationUnit: "minute",
value: value
})
}
}
// avg requests
{
let duration = parseInt(this.avgTrafficIn.duration)
let value = parseInt(this.avgTrafficIn.value)
if (!isNaN(duration) && duration > 0 && !isNaN(value) && value > 0) {
thresholds.push({
item: "avgTrafficIn",
operator: this.avgTrafficIn.operator,
duration: duration,
durationUnit: "minute",
value: value
})
}
}
this.thresholds = thresholds
}
},
template: `<div>
<input type="hidden" name="thresholdsJSON" :value="JSON.stringify(thresholds)"/>
<table class="ui table celled">
<thead>
<tr>
<td>统计项目</td>
<th>统计周期</th>
<th>操作符</th>
<th>对比值</th>
</tr>
</thead>
<tr>
<td>平均请求数/秒</td>
<td>
<div class="ui input right labeled">
<input type="text" style="width: 5em" v-model="avgRequests.duration"/>
<span class="ui label">分钟</span>
</div>
</td>
<td>
<select class="ui dropdown auto-width" v-model="avgRequests.operator">
<option value="lt">小于</option>
<option value="gt">大于</option>
</select>
</td>
<td>
<div class="ui input right labeled">
<input type="text" style="width: 6em" v-model="avgRequests.value"/>
<span class="ui label">个</span>
</div>
</td>
</tr>
<tr>
<td class="title">平均下行流量/秒</td>
<td>
<div class="ui input right labeled">
<input type="text" style="width: 5em" v-model="avgTrafficOut.duration"/>
<span class="ui label">分钟</span>
</div>
</td>
<td>
<select class="ui dropdown auto-width" v-model="avgTrafficOut.operator">
<option value="lt">小于</option>
<option value="gt">大于</option>
</select>
</td>
<td>
<div class="ui input right labeled">
<input type="text" style="width: 6em" v-model="avgTrafficOut.value"/>
<span class="ui label">MB</span>
</div>
</td>
</tr>
<tr>
<td>平均上行流量/秒</td>
<td>
<div class="ui input right labeled">
<input type="text" style="width: 5em" v-model="avgTrafficIn.duration"/>
<span class="ui label">分钟</span>
</div>
</td>
<td>
<select class="ui dropdown auto-width" v-model="avgTrafficIn.operator">
<option value="lt">小于</option>
<option value="gt">大于</option>
</select>
</td>
<td>
<div class="ui input right labeled">
<input type="text" style="width: 6em" v-model="avgTrafficIn.value"/>
<span class="ui label">MB</span>
</div>
</td>
</tr>
</table>
<p class="comment">满足所有阈值条件时IP才会上线否则下线。统计周期和对比值设置为0表示没有限制。各个输入项只支持整数数字。</p>
</div>`
})

View File

@@ -15,7 +15,9 @@ Vue.component("node-ip-addresses-box", {
teaweb.popup("/nodes/ipAddresses/createPopup", { teaweb.popup("/nodes/ipAddresses/createPopup", {
callback: function (resp) { callback: function (resp) {
that.ipAddresses.push(resp.data.ipAddress); that.ipAddresses.push(resp.data.ipAddress);
} },
height: "24em",
width: "44em"
}) })
}, },
@@ -27,7 +29,9 @@ Vue.component("node-ip-addresses-box", {
teaweb.popup("/nodes/ipAddresses/updatePopup", { teaweb.popup("/nodes/ipAddresses/updatePopup", {
callback: function (resp) { callback: function (resp) {
Vue.set(that.ipAddresses, index, resp.data.ipAddress); Vue.set(that.ipAddresses, index, resp.data.ipAddress);
} },
height: "24em",
width: "44em"
}) })
}, },
@@ -51,6 +55,7 @@ Vue.component("node-ip-addresses-box", {
<span class="small grey" v-if="address.name.length == 0 && !address.canAccess">(不可访问)</span> <span class="small grey" v-if="address.name.length == 0 && !address.canAccess">(不可访问)</span>
<span class="small red" v-if="!address.isOn">[off]</span> <span class="small red" v-if="!address.isOn">[off]</span>
<span class="small red" v-if="!address.isUp">[down]</span> <span class="small red" v-if="!address.isUp">[down]</span>
<span class="small" v-if="address.thresholds != null && address.thresholds.length > 0">[阈值]</span>
&nbsp; &nbsp;
<a href="" title="修改" @click.prevent="updateIPAddress(index, address)"><i class="icon pencil small"></i></a> <a href="" title="修改" @click.prevent="updateIPAddress(index, address)"><i class="icon pencil small"></i></a>
<a href="" title="删除" @click.prevent="removeIPAddress(index)"><i class="icon remove"></i></a> <a href="" title="删除" @click.prevent="removeIPAddress(index)"><i class="icon remove"></i></a>

View File

@@ -29,6 +29,7 @@
<span class="small grey" v-if="address.name.length == 0 && !address.canAccess">(不可访问)</span> <span class="small grey" v-if="address.name.length == 0 && !address.canAccess">(不可访问)</span>
<span class="small red" v-if="!address.isOn">[off]</span> <span class="small red" v-if="!address.isOn">[off]</span>
<span class="small red" v-if="!address.isUp">[down]</span> <span class="small red" v-if="!address.isUp">[down]</span>
<span class="small" v-if="address.thresholds != null && address.thresholds.length > 0">[阈值]</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -20,12 +20,23 @@
<p class="comment">是否为可以公开访问的IP如果选中也会作为DNS解析记录的值使用。</p> <p class="comment">是否为可以公开访问的IP如果选中也会作为DNS解析记录的值使用。</p>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
<tbody v-show="moreOptionsVisible">
<tr> <tr>
<td class="title">备注</td> <td class="title">备注</td>
<td> <td>
<input type="text" name="name" maxlength="50"/> <input type="text" name="name" maxlength="50"/>
</td> </td>
</tr> </tr>
<tr v-if="teaIsPlus">
<td>上线阈值</td>
<td>
<node-ip-address-thresholds-box></node-ip-address-thresholds-box>
</td>
</tr>
</tbody>
</table> </table>
<submit-btn></submit-btn> <submit-btn></submit-btn>
</form> </form>

View File

@@ -41,6 +41,12 @@
<input type="text" name="name" maxlength="50" v-model="address.name"/> <input type="text" name="name" maxlength="50" v-model="address.name"/>
</td> </td>
</tr> </tr>
<tr v-if="teaIsPlus">
<td>上线阈值</td>
<td>
<node-ip-address-thresholds-box :v-thresholds="address.thresholds"></node-ip-address-thresholds-box>
</td>
</tr>
</tbody> </tbody>
</table> </table>
<submit-btn></submit-btn> <submit-btn></submit-btn>