diff --git a/internal/const/build.go b/internal/const/build.go index 71c71807..c12973fe 100644 --- a/internal/const/build.go +++ b/internal/const/build.go @@ -1,5 +1,5 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -// +build community +// +build !plus package teaconst diff --git a/internal/const/plus.go b/internal/const/plus.go index 4b50970d..e3f7d0aa 100644 --- a/internal/const/plus.go +++ b/internal/const/plus.go @@ -1,6 +1,6 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -//go:build community -// +build community +//go:build !plus +// +build !plus package teaconst diff --git a/internal/utils/nodelogutils/utils.go b/internal/utils/nodelogutils/utils.go index 813a8072..5c076901 100644 --- a/internal/utils/nodelogutils/utils.go +++ b/internal/utils/nodelogutils/utils.go @@ -1,6 +1,6 @@ // Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -//go:build community -// +build community +//go:build !plus +// +build !plus package nodelogutils diff --git a/internal/web/actions/default/settings/settingutils/advanced_helper.go b/internal/web/actions/default/settings/settingutils/advanced_helper.go index b5130541..5e0066a1 100644 --- a/internal/web/actions/default/settings/settingutils/advanced_helper.go +++ b/internal/web/actions/default/settings/settingutils/advanced_helper.go @@ -1,5 +1,5 @@ -//go:build community -// +build community +//go:build !plus +// +build !plus package settingutils diff --git a/internal/web/helpers/menu.go b/internal/web/helpers/menu.go index ec84c61a..283a54a7 100644 --- a/internal/web/helpers/menu.go +++ b/internal/web/helpers/menu.go @@ -1,6 +1,6 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -//go:build community -// +build community +//go:build !plus +// +build !plus package helpers diff --git a/web/public/js/components.js b/web/public/js/components.js index db13ce90..73ade29a 100644 --- a/web/public/js/components.js +++ b/web/public/js/components.js @@ -44,7 +44,37 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio - `}),Vue.component("node-clusters-labels",{props:["v-primary-cluster","v-secondary-clusters","size"],data:function(){var e=this.vPrimaryCluster;let t=this.vSecondaryClusters,i=(null==t&&(t=[]),this.size);return null==i&&(i="small"),{cluster:e,secondaryClusters:t,labelSize:i}},template:`
+
`}),Vue.component("ddos-protection-ports-config-box",{props:["v-ports"],data:function(){let e=this.vPorts;return{ports:e=null==e?[]:e,isAdding:!1,addingPort:{port:"",description:""}}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingPortInput.focus()})},confirm:function(){var e=this.addingPort.port;if(0==e.length)this.warn("请输入端口号");else if(/^\d+$/.test(e)){let i=parseInt(e,10);if(i<=0)this.warn("请输入正确的端口号");else if(65535 +
+
+ {{portConfig.port}} ({{portConfig.description}}) +
+
+
+
+
+
+
+ 端口 + +
+
+
+
+ 备注 + +
+
+
+ +  取消 +
+
+
+
+ +
+`}),Vue.component("node-clusters-labels",{props:["v-primary-cluster","v-secondary-clusters","size"],data:function(){var e=this.vPrimaryCluster;let t=this.vSecondaryClusters,i=(null==t&&(t=[]),this.size);return null==i&&(i="small"),{cluster:e,secondaryClusters:t,labelSize:i}},template:`
{{cluster.name}} {{cluster.name}} @@ -58,6 +88,96 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio +
`}),Vue.component("node-ddos-protection-config-box",{props:["v-ddos-protection-config","v-default-configs","v-is-node","v-cluster-is-on"],data:function(){let e=this.vDdosProtectionConfig;return null==(e=null==e?{tcp:{isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,allowIPList:[],ports:[]}}:e).tcp&&(e.tcp={isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,allowIPList:[],ports:[]}),{config:e,defaultConfigs:this.vDefaultConfigs,isNode:this.vIsNode,isAddingPort:!1}},methods:{changeTCPPorts:function(e){this.config.tcp.ports=e},changeTCPAllowIPList:function(e){this.config.tcp.allowIPList=e}},template:`
+ + +

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

+ +
当前节点所在集群已设置DDoS防护。
+ +

TCP设置

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用 + +
单节点TCP最大连接数 + +

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

+
单IP TCP最大连接数 + +

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

+
单IP TCP新连接速率 +
+ + 个新连接/每分钟 +
+

单个IP可以创建TCP新连接的速率。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinRate}}。

+
TCP端口列表 + +

默认为80和443两个端口。

+
IP白名单 + +

在白名单中的IP不受当前设置的限制。

+
+
+
`}),Vue.component("ddos-protection-ip-list-config-box",{props:["v-ip-list"],data:function(){let e=this.vIpList;return{list:e=null==e?[]:e,isAdding:!1,addingIP:{ip:"",description:""}}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingIPInput.focus()})},confirm:function(){let i=this.addingIP.ip;if(0==i.length)this.warn("请输入IP");else{let t=!1;if(this.list.forEach(function(e){e.ip==i&&(t=!0)}),t)this.warn("IP '"+i+"'已经存在");else{let e=this;Tea.Vue.$post("/ui/validateIPs").params({ips:[i]}).success(function(){e.list.push({ip:i,description:e.addingIP.description}),e.notifyChange(),e.cancel()}).fail(function(){e.warn("请输入正确的IP")})}}},cancel:function(){this.isAdding=!1,this.addingIP={ip:"",description:""}},remove:function(e){this.list.$remove(e),this.notifyChange()},warn:function(e){let t=this;teaweb.warn(e,function(){t.$refs.addingIPInput.focus()})},notifyChange:function(){this.$emit("change",this.list)}},template:`
+
+ +
+
+
+
+
+
+ IP + +
+
+
+
+ 备注 + +
+
+
+ +  取消 +
+
+
+
+ +
`}),Vue.component("node-cluster-combo-box",{props:["v-cluster-id"],data:function(){let t=this;return Tea.action("/clusters/options").post().success(function(e){t.clusters=e.data.clusters}),{clusters:[]}},methods:{change:function(e){null==e?this.$emit("change",0):this.$emit("change",e.value)}},template:`
`}),Vue.component("node-clusters-selector",{props:["v-primary-cluster","v-secondary-clusters"],data:function(){var e=this.vPrimaryCluster;let t=this.vSecondaryClusters;return null==t&&(t=[]),{primaryClusterId:null==e?0:e.id,secondaryClusterIds:t.map(function(e){return e.id}),primaryCluster:e,secondaryClusters:t}},methods:{addPrimary:function(){let t=this,e=[this.primaryClusterId].concat(this.secondaryClusterIds);teaweb.popup("/clusters/selectPopup?selectedClusterIds="+e.join(",")+"&mode=single",{height:"30em",width:"50em",callback:function(e){null!=e.data.cluster&&(t.primaryCluster=e.data.cluster,t.primaryClusterId=t.primaryCluster.id,t.notifyChange())}})},removePrimary:function(){this.primaryClusterId=0,this.primaryCluster=null,this.notifyChange()},addSecondary:function(){let t=this,e=[this.primaryClusterId].concat(this.secondaryClusterIds);teaweb.popup("/clusters/selectPopup?selectedClusterIds="+e.join(",")+"&mode=multiple",{height:"30em",width:"50em",callback:function(e){null!=e.data.cluster&&(t.secondaryClusterIds.push(e.data.cluster.id),t.secondaryClusters.push(e.data.cluster),t.notifyChange())}})},removeSecondary:function(e){this.secondaryClusterIds.$remove(e),this.secondaryClusters.$remove(e),this.notifyChange()},notifyChange:function(){this.$emit("change",{clusterId:this.primaryClusterId})}},template:`
@@ -2372,7 +2492,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio

{{description}}

-
`}),Vue.component("prior-checkbox",{props:["v-config"],data:function(){return{isPrior:this.vConfig.isPrior}},watch:{isPrior:function(e){this.vConfig.isPrior=e}},template:` +`}),Vue.component("prior-checkbox",{props:["v-config","description"],data:function(){let e=this.description;return null==e&&(e="打开后可以覆盖父级或子级配置"),{isPrior:this.vConfig.isPrior,realDescription:e}},watch:{isPrior:function(e){this.vConfig.isPrior=e}},template:` 打开独立配置 @@ -2380,7 +2500,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio -

[已打开] 打开后可以覆盖父级或子级配置。

+

[已打开] {{realDescription}}。

`}),Vue.component("http-charsets-box",{props:["v-usual-charsets","v-all-charsets","v-charset-config","v-is-location","v-is-group"],data:function(){let e=this.vCharsetConfig;return{charsetConfig:e=null==e?{isPrior:!1,isOn:!1,charset:"",isUpper:!1}:e,advancedVisible:!1}},methods:{changeAdvancedVisible:function(e){this.advancedVisible=e}},template:`
@@ -3872,12 +3992,12 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio `}),Vue.component("second-menu",{template:' \t\t
\t\t\t \t\t\t
\t\t
'}),Vue.component("loading-message",{template:`
  -
`}),Vue.component("more-options-angle",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:'更多选项收起选项'}),Vue.component("inner-menu-item",{props:["href","active","code"],data:function(){var e,t=this.active;return void 0===t&&(e="",t=(e=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:e)==this.code),{vHref:null==this.href?"":this.href,vActive:t}},template:'\t\t[] \t\t'}),Vue.component("health-check-config-box",{props:["v-health-check-config"],data:function(){let t=this.vHealthCheckConfig,i="http",s="",n="/",o="";if(null==t){t={isOn:!1,url:"",interval:{count:60,unit:"second"},statusCodes:[200],timeout:{count:10,unit:"second"},countTries:3,tryDelay:{count:100,unit:"ms"},autoDown:!0,countUp:1,countDown:3,userAgent:"",onlyBasicRequest:!0};let e=this;setTimeout(function(){e.changeURL()},500)}else{try{let e=new URL(t.url);i=e.protocol.substring(0,e.protocol.length-1);var a=(o="%24%7Bhost%7D"==(o=e.host)?"${host}":o).indexOf(":");0 +
`}),Vue.component("more-options-angle",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:'更多选项收起选项'}),Vue.component("inner-menu-item",{props:["href","active","code"],data:function(){var e,t=this.active;return void 0===t&&(e="",t=(e=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:e)==this.code),{vHref:null==this.href?"":this.href,vActive:t}},template:'\t\t[] \t\t'}),Vue.component("health-check-config-box",{props:["v-health-check-config"],data:function(){let t=this.vHealthCheckConfig,i="http",s="",n="/",o="";if(null==t){t={isOn:!1,url:"",interval:{count:60,unit:"second"},statusCodes:[200],timeout:{count:10,unit:"second"},countTries:3,tryDelay:{count:100,unit:"ms"},autoDown:!0,countUp:1,countDown:3,userAgent:"",onlyBasicRequest:!0,accessLogIsOn:!0};let e=this;setTimeout(function(){e.changeURL()},500)}else{try{let e=new URL(t.url);i=e.protocol.substring(0,e.protocol.length-1);var a=(o="%24%7Bhost%7D"==(o=e.host)?"${host}":o).indexOf(":");0 - + - + - +
是否启用启用
@@ -3888,7 +4008,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
URL *检测URL *
{{healthCheck.url}}   修改
@@ -3906,22 +4026,25 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
域名 -

在此集群上可以访问到的一个域名。

+

已经绑定到此集群的一个域名;如果为空则使用节点IP作为域名。

端口 +

域名或者IP的端口,可选项,默认为80/443。

RequestURI +

请求的路径,可以带参数,可选项。

+
-

拼接后的URL:{{healthCheck.url}},其中\${host}指的是域名。

+

拼接后的检测URL:{{healthCheck.url}},其中\${host}指的是域名。

@@ -3929,6 +4052,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio 检测时间间隔 +

两次检查之间的间隔。

@@ -3945,14 +4069,14 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio 连续上线次数 -

连续N次检查成功后自动恢复上线。

+

连续{{healthCheck.countUp}}次检查成功后自动恢复上线。

连续下线次数 -

连续N次检查失败后自动下线。

+

连续{{healthCheck.countDown}}次检查失败后自动下线。

@@ -4000,6 +4124,13 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio

只做基础的请求,不处理反向代理(不检查源站)、WAF等。

+ + 记录访问日志 + + +

是否记录健康检查的访问日志。

+ +
@@ -4059,7 +4190,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
-`}),Vue.component("keyword",{props:["v-word"],data:function(){let e=this.vWord;e=null==e?"":(e=(e=(e=(e=(e=(e=(e=(e=(e=e.replace(/\)/g,"\\)")).replace(/\(/g,"\\(")).replace(/\+/g,"\\+")).replace(/\^/g,"\\^")).replace(/\$/g,"\\$")).replace(/\?/,"\\?")).replace(/\*/,"\\*")).replace(/\[/,"\\[")).replace(/{/,"\\{")).replace(/\./,"\\.");let t=this.$slots.default[0].text;if(0",t="$TMP__KEY__"+n.toString()+"$";return s.push([t,e]),t}),t=this.encodeHTML(t),s.forEach(function(e){t=t.replace(e[0],e[1])})}else t=this.encodeHTML(t);return{word:e,text:t}},methods:{encodeHTML:function(e){return e=(e=(e=(e=e.replace(/&/g,"&")).replace(//g,">")).replace(/"/g,""")}},template:''}),Vue.component("node-log-row",{props:["v-log","v-keyword"],data:function(){return{log:this.vLog,keyword:this.vKeyword}},template:`
+
`}),Vue.component("digit-input",{props:["value","maxlength","size","min","max","required","placeholder"],mounted:function(){let e=this;setTimeout(function(){e.check()})},data:function(){let e=this.maxlength,t=(null==e&&(e=20),this.size);return null==t&&(t=6),{realValue:this.value,realMaxLength:e,realSize:t,isValid:!0}},watch:{realValue:function(e){this.notifyChange()}},methods:{notifyChange:function(){let e=parseInt(this.realValue.toString(),10);isNaN(e)&&(e=0),this.check(),this.$emit("input",e)},check:function(){var e;null!=this.realValue&&(e=this.realValue.toString(),/^\d+$/.test(e)?(e=parseInt(e,10),isNaN(e)?this.isValid=!1:this.required?this.isValid=(null==this.min||this.min<=e)&&(null==this.max||this.max>=e):this.isValid=0==e||(null==this.min||this.min<=e)&&(null==this.max||this.max>=e)):this.isValid=!1)}},template:''}),Vue.component("keyword",{props:["v-word"],data:function(){let e=this.vWord;e=null==e?"":(e=(e=(e=(e=(e=(e=(e=(e=(e=e.replace(/\)/g,"\\)")).replace(/\(/g,"\\(")).replace(/\+/g,"\\+")).replace(/\^/g,"\\^")).replace(/\$/g,"\\$")).replace(/\?/,"\\?")).replace(/\*/,"\\*")).replace(/\[/,"\\[")).replace(/{/,"\\{")).replace(/\./,"\\.");let t=this.$slots.default[0].text;if(0",t="$TMP__KEY__"+n.toString()+"$";return s.push([t,e]),t}),t=this.encodeHTML(t),s.forEach(function(e){t=t.replace(e[0],e[1])})}else t=this.encodeHTML(t);return{word:e,text:t}},methods:{encodeHTML:function(e){return e=(e=(e=(e=e.replace(/&/g,"&")).replace(//g,">")).replace(/"/g,""")}},template:''}),Vue.component("node-log-row",{props:["v-log","v-keyword"],data:function(){return{log:this.vLog,keyword:this.vKeyword}},template:`
[{{log.createdTime}}][{{log.createdTime}}][{{log.tag}}]{{log.description}}   共{{log.count}}条 {{log.server.name}}
`}),Vue.component("provinces-selector",{props:["v-provinces"],data:function(){let e=this.vProvinces;var t=(e=null==e?[]:e).$map(function(e,t){return t.id});return{provinces:e,provinceIds:t}},methods:{add:function(){let e=this.provinceIds.map(function(e){return e.toString()}),t=this;teaweb.popup("/ui/selectProvincesPopup?provinceIds="+e.join(","),{width:"48em",height:"23em",callback:function(e){t.provinces=e.data.provinces,t.change()}})},remove:function(e){this.provinces.$remove(e),this.change()},change:function(){this.provinceIds=this.provinces.$map(function(e,t){return t.id})}},template:`
@@ -4467,7 +4598,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio -

修改此项配置后,需要重启节点进程才会生效。

+

边缘节点使用的DNS解析库。修改此项配置后,需要重启节点进程才会生效。

diff --git a/web/public/js/components.src.js b/web/public/js/components.src.js index cbee772c..208f8057 100755 --- a/web/public/js/components.src.js +++ b/web/public/js/components.src.js @@ -259,6 +259,122 @@ Vue.component("traffic-map-box-table", {
` }) +Vue.component("ddos-protection-ports-config-box", { + props: ["v-ports"], + data: function () { + let ports = this.vPorts + if (ports == null) { + ports = [] + } + return { + ports: ports, + isAdding: false, + addingPort: { + port: "", + description: "" + } + } + }, + methods: { + add: function () { + this.isAdding = true + let that = this + setTimeout(function () { + that.$refs.addingPortInput.focus() + }) + }, + confirm: function () { + let portString = this.addingPort.port + if (portString.length == 0) { + this.warn("请输入端口号") + return + } + if (!/^\d+$/.test(portString)) { + this.warn("请输入正确的端口号") + return + } + let port = parseInt(portString, 10) + if (port <= 0) { + this.warn("请输入正确的端口号") + return + } + if (port > 65535) { + this.warn("请输入正确的端口号") + return + } + + let exists = false + this.ports.forEach(function (v) { + if (v.port == port) { + exists = true + } + }) + if (exists) { + this.warn("端口号已经存在") + return + } + + this.ports.push({ + port: port, + description: this.addingPort.description + }) + this.notifyChange() + this.cancel() + }, + cancel: function () { + this.isAdding = false + this.addingPort = { + port: "", + description: "" + } + }, + remove: function (index) { + this.ports.$remove(index) + this.notifyChange() + }, + warn: function (message) { + let that = this + teaweb.warn(message, function () { + that.$refs.addingPortInput.focus() + }) + }, + notifyChange: function () { + this.$emit("change", this.ports) + } + }, + template: `
+
+
+ {{portConfig.port}} ({{portConfig.description}}) +
+
+
+
+
+
+
+ 端口 + +
+
+
+
+ 备注 + +
+
+
+ +  取消 +
+
+
+
+ +
+
` +}) + // 显示节点的多个集群 Vue.component("node-clusters-labels", { props: ["v-primary-cluster", "v-secondary-clusters", "size"], @@ -321,6 +437,230 @@ Vue.component("cluster-selector", { ` }) +Vue.component("node-ddos-protection-config-box", { + props: ["v-ddos-protection-config", "v-default-configs", "v-is-node", "v-cluster-is-on"], + data: function () { + let config = this.vDdosProtectionConfig + if (config == null) { + config = { + tcp: { + isPrior: false, + isOn: false, + maxConnections: 0, + maxConnectionsPerIP: 0, + newConnectionsRate: 0, + allowIPList: [], + ports: [] + } + } + } + + // initialize + if (config.tcp == null) { + config.tcp = { + isPrior: false, + isOn: false, + maxConnections: 0, + maxConnectionsPerIP: 0, + newConnectionsRate: 0, + allowIPList: [], + ports: [] + } + } + + + return { + config: config, + defaultConfigs: this.vDefaultConfigs, + isNode: this.vIsNode, + + isAddingPort: false + } + }, + methods: { + changeTCPPorts: function (ports) { + this.config.tcp.ports = ports + }, + changeTCPAllowIPList: function (ipList) { + this.config.tcp.allowIPList = ipList + } + }, + template: `
+ + +

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

+ +
当前节点所在集群已设置DDoS防护。
+ +

TCP设置

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用 + +
单节点TCP最大连接数 + +

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

+
单IP TCP最大连接数 + +

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

+
单IP TCP新连接速率 +
+ + 个新连接/每分钟 +
+

单个IP可以创建TCP新连接的速率。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinRate}}。

+
TCP端口列表 + +

默认为80和443两个端口。

+
IP白名单 + +

在白名单中的IP不受当前设置的限制。

+
+
+
` +}) + +Vue.component("ddos-protection-ip-list-config-box", { + props: ["v-ip-list"], + data: function () { + let list = this.vIpList + if (list == null) { + list = [] + } + return { + list: list, + isAdding: false, + addingIP: { + ip: "", + description: "" + } + } + }, + methods: { + add: function () { + this.isAdding = true + let that = this + setTimeout(function () { + that.$refs.addingIPInput.focus() + }) + }, + confirm: function () { + let ip = this.addingIP.ip + if (ip.length == 0) { + this.warn("请输入IP") + return + } + + let exists = false + this.list.forEach(function (v) { + if (v.ip == ip) { + exists = true + } + }) + if (exists) { + this.warn("IP '" + ip + "'已经存在") + return + } + + let that = this + Tea.Vue.$post("/ui/validateIPs") + .params({ + ips: [ip] + }) + .success(function () { + that.list.push({ + ip: ip, + description: that.addingIP.description + }) + that.notifyChange() + that.cancel() + }) + .fail(function () { + that.warn("请输入正确的IP") + }) + }, + cancel: function () { + this.isAdding = false + this.addingIP = { + ip: "", + description: "" + } + }, + remove: function (index) { + this.list.$remove(index) + this.notifyChange() + }, + warn: function (message) { + let that = this + teaweb.warn(message, function () { + that.$refs.addingIPInput.focus() + }) + }, + notifyChange: function () { + this.$emit("change", this.list) + } + }, + template: `
+
+
+ {{ipConfig.ip}} ({{ipConfig.description}}) +
+
+
+
+
+
+
+ IP + +
+
+
+
+ 备注 + +
+
+
+ +  取消 +
+
+
+
+ +
+
` +}) + Vue.component("node-cluster-combo-box", { props: ["v-cluster-id"], data: function () { @@ -7065,10 +7405,15 @@ Vue.component("firewall-event-level-options", { }) Vue.component("prior-checkbox", { - props: ["v-config"], + props: ["v-config", "description"], data: function () { + let description = this.description + if (description == null) { + description = "打开后可以覆盖父级或子级配置" + } return { - isPrior: this.vConfig.isPrior + isPrior: this.vConfig.isPrior, + realDescription: description } }, watch: { @@ -7084,7 +7429,7 @@ Vue.component("prior-checkbox", { -

[已打开] 打开后可以覆盖父级或子级配置。

+

[已打开] {{realDescription}}。

` @@ -11814,7 +12159,8 @@ Vue.component("health-check-config-box", { countUp: 1, countDown: 3, userAgent: "", - onlyBasicRequest: true + onlyBasicRequest: true, + accessLogIsOn: true } let that = this setTimeout(function () { @@ -11949,7 +12295,7 @@ Vue.component("health-check-config-box", { - + - + - +
是否启用启用
@@ -11960,7 +12306,7 @@ Vue.component("health-check-config-box", {
URL *检测URL *
{{healthCheck.url}}   修改
@@ -11978,22 +12324,25 @@ Vue.component("health-check-config-box", {
域名 -

在此集群上可以访问到的一个域名。

+

已经绑定到此集群的一个域名;如果为空则使用节点IP作为域名。

端口 +

域名或者IP的端口,可选项,默认为80/443。

RequestURI +

请求的路径,可以带参数,可选项。

+
-

拼接后的URL:{{healthCheck.url}},其中\${host}指的是域名。

+

拼接后的检测URL:{{healthCheck.url}},其中\${host}指的是域名。

@@ -12001,6 +12350,7 @@ Vue.component("health-check-config-box", { 检测时间间隔 +

两次检查之间的间隔。

@@ -12017,14 +12367,14 @@ Vue.component("health-check-config-box", { 连续上线次数 -

连续N次检查成功后自动恢复上线。

+

连续{{healthCheck.countUp}}次检查成功后自动恢复上线。

连续下线次数 -

连续N次检查失败后自动下线。

+

连续{{healthCheck.countDown}}次检查失败后自动下线。

@@ -12072,6 +12422,13 @@ Vue.component("health-check-config-box", {

只做基础的请求,不处理反向代理(不检查源站)、WAF等。

+ + 记录访问日志 + + +

是否记录健康检查的访问日志。

+ +
@@ -12452,6 +12809,70 @@ Vue.component("tip-message-box", { ` }) +Vue.component("digit-input", { + props: ["value", "maxlength", "size", "min", "max", "required", "placeholder"], + mounted: function () { + let that = this + setTimeout(function () { + that.check() + }) + }, + data: function () { + let realMaxLength = this.maxlength + if (realMaxLength == null) { + realMaxLength = 20 + } + + let realSize = this.size + if (realSize == null) { + realSize = 6 + } + + return { + realValue: this.value, + realMaxLength: realMaxLength, + realSize: realSize, + isValid: true + } + }, + watch: { + realValue: function (v) { + this.notifyChange() + } + }, + methods: { + notifyChange: function () { + let v = parseInt(this.realValue.toString(), 10) + if (isNaN(v)) { + v = 0 + } + this.check() + this.$emit("input", v) + }, + check: function () { + if (this.realValue == null) { + return + } + let s = this.realValue.toString() + if (!/^\d+$/.test(s)) { + this.isValid = false + return + } + let v = parseInt(s, 10) + if (isNaN(v)) { + this.isValid = false + } else { + if (this.required) { + this.isValid = (this.min == null || this.min <= v) && (this.max == null || this.max >= v) + } else { + this.isValid = (v == 0 || (this.min == null || this.min <= v) && (this.max == null || this.max >= v)) + } + } + } + }, + template: `` +}) + Vue.component("keyword", { props: ["v-word"], data: function () { @@ -14293,7 +14714,7 @@ Vue.component("dns-resolver-config-box", { -

修改此项配置后,需要重启节点进程才会生效。

+

边缘节点使用的DNS解析库。修改此项配置后,需要重启节点进程才会生效。

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 a41a4bff..d76e77fa 100644 --- a/web/public/js/components/common/health-check-config-box.js +++ b/web/public/js/components/common/health-check-config-box.js @@ -20,7 +20,8 @@ Vue.component("health-check-config-box", { countUp: 1, countDown: 3, userAgent: "", - onlyBasicRequest: true + onlyBasicRequest: true, + accessLogIsOn: true } let that = this setTimeout(function () { @@ -155,7 +156,7 @@ Vue.component("health-check-config-box", { - + - + - +
是否启用启用
@@ -166,7 +167,7 @@ Vue.component("health-check-config-box", {
URL *检测URL *
{{healthCheck.url}}   修改
@@ -184,22 +185,25 @@ Vue.component("health-check-config-box", {
域名 -

在此集群上可以访问到的一个域名。

+

已经绑定到此集群的一个域名;如果为空则使用节点IP作为域名。

端口 +

域名或者IP的端口,可选项,默认为80/443。

RequestURI +

请求的路径,可以带参数,可选项。

+
-

拼接后的URL:{{healthCheck.url}},其中\${host}指的是域名。

+

拼接后的检测URL:{{healthCheck.url}},其中\${host}指的是域名。

@@ -207,6 +211,7 @@ Vue.component("health-check-config-box", { 检测时间间隔 +

两次检查之间的间隔。

@@ -223,14 +228,14 @@ Vue.component("health-check-config-box", { 连续上线次数 -

连续N次检查成功后自动恢复上线。

+

连续{{healthCheck.countUp}}次检查成功后自动恢复上线。

连续下线次数 -

连续N次检查失败后自动下线。

+

连续{{healthCheck.countDown}}次检查失败后自动下线。

@@ -278,6 +283,13 @@ Vue.component("health-check-config-box", {

只做基础的请求,不处理反向代理(不检查源站)、WAF等。

+ + 记录访问日志 + + +

是否记录健康检查的访问日志。

+ +