Compare commits
203 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23899e196e | ||
|
|
ecbc87265e | ||
|
|
9f8731d668 | ||
|
|
12d545138a | ||
|
|
0c054581ac | ||
|
|
c8c2f83763 | ||
|
|
9056d591c3 | ||
|
|
191f58074e | ||
|
|
92d3af3d2b | ||
|
|
2ddc4d62a2 | ||
|
|
81a2967683 | ||
|
|
29e3c55df0 | ||
|
|
27e3cdffb1 | ||
|
|
a1ad56aebb | ||
|
|
2573b3b827 | ||
|
|
bcd9a8fcd2 | ||
|
|
8dbc83fd27 | ||
|
|
275280d24e | ||
|
|
c82fa4709d | ||
|
|
c8e826014b | ||
|
|
75b2e93678 | ||
|
|
b0573df9d8 | ||
|
|
e6c14590f1 | ||
|
|
248ac43f28 | ||
|
|
9361a27dca | ||
|
|
700836903f | ||
|
|
039ce26f58 | ||
|
|
95bfb7f0b6 | ||
|
|
9a181556ca | ||
|
|
9554b6f3ec | ||
|
|
45089437ef | ||
|
|
f47a3b0586 | ||
|
|
1a19c7520a | ||
|
|
6266af66f7 | ||
|
|
d3cdc24ebf | ||
|
|
f37d2fc4d7 | ||
|
|
6cd182b858 | ||
|
|
d46bf37726 | ||
|
|
363295e0ea | ||
|
|
611d5daf27 | ||
|
|
0c1e42078e | ||
|
|
c9acafd3ad | ||
|
|
75dd760148 | ||
|
|
28bfbbfa68 | ||
|
|
36326697d7 | ||
|
|
34b7cfec6f | ||
|
|
f65b725b27 | ||
|
|
d7bceb8f2d | ||
|
|
549f418b69 | ||
|
|
8a95f49f8f | ||
|
|
2c269a87a6 | ||
|
|
c17a27b7bf | ||
|
|
3eaecf2ca0 | ||
|
|
07182639f3 | ||
|
|
046628eda4 | ||
|
|
8f0054b2b0 | ||
|
|
33f86a7730 | ||
|
|
2487c69136 | ||
|
|
492d24f28a | ||
|
|
9a355da75c | ||
|
|
8bae065572 | ||
|
|
efebb5a869 | ||
|
|
32cc745a85 | ||
|
|
42bfe3ffac | ||
|
|
de3a5f87cf | ||
|
|
bd1add6dea | ||
|
|
d275cc6a8b | ||
|
|
556b5bd2e9 | ||
|
|
e26cf2a19d | ||
|
|
94f5f1faf6 | ||
|
|
fb3c58bd60 | ||
|
|
e50c918e4d | ||
|
|
eb3ff3369c | ||
|
|
a07a08991f | ||
|
|
6fcc8f3401 | ||
|
|
36b38c6da4 | ||
|
|
7f2f86b7ea | ||
|
|
68514bc7ed | ||
|
|
f0dfab536c | ||
|
|
3b75c9999e | ||
|
|
084ddf4f5d | ||
|
|
6770b1fa72 | ||
|
|
118d39ed83 | ||
|
|
c24df4f876 | ||
|
|
0ae9c25d6f | ||
|
|
f99b2a9def | ||
|
|
caf9eeae2e | ||
|
|
6afecb5708 | ||
|
|
739d32e2e0 | ||
|
|
4e601298b0 | ||
|
|
74cffced3f | ||
|
|
f8cc76be35 | ||
|
|
dced2dd418 | ||
|
|
418fe97c67 | ||
|
|
1440f9b721 | ||
|
|
9504c086ea | ||
|
|
3a15d6475c | ||
|
|
18f3a00c0f | ||
|
|
5138bbe947 | ||
|
|
a309feb516 | ||
|
|
e9c172c261 | ||
|
|
6ac6842a8d | ||
|
|
71dc53ac1f | ||
|
|
4450fa1379 | ||
|
|
af0f9489c7 | ||
|
|
75b2b2bdb2 | ||
|
|
2d8224fd12 | ||
|
|
c3aea3ba72 | ||
|
|
ad1ff29ed2 | ||
|
|
9887bd99c7 | ||
|
|
9af9d0192d | ||
|
|
62933cf637 | ||
|
|
ee0837571d | ||
|
|
c2b12419c7 | ||
|
|
991aed7e8c | ||
|
|
528d5fc5a9 | ||
|
|
93569227f3 | ||
|
|
46812f9e42 | ||
|
|
61f043319d | ||
|
|
77140d01a0 | ||
|
|
beff326001 | ||
|
|
f2841b7328 | ||
|
|
2ba63b2484 | ||
|
|
f054241a73 | ||
|
|
b5007b9195 | ||
|
|
9deea64097 | ||
|
|
105777da21 | ||
|
|
e13743dfa8 | ||
|
|
35bdd3a41a | ||
|
|
464d757800 | ||
|
|
8076fcd148 | ||
|
|
53b1f07601 | ||
|
|
2626d78835 | ||
|
|
3442ddfae2 | ||
|
|
5ed863c5ec | ||
|
|
00f6387182 | ||
|
|
ca70e8f0c8 | ||
|
|
081e95b293 | ||
|
|
1282e610ba | ||
|
|
287c52cef4 | ||
|
|
dd421fec80 | ||
|
|
9b10bdaf0d | ||
|
|
4b916829a4 | ||
|
|
b33e9d9187 | ||
|
|
9d0d323b50 | ||
|
|
2872569ce0 | ||
|
|
cd2212b754 | ||
|
|
eb6525b8d9 | ||
|
|
10319a1e3d | ||
|
|
6bcfea9372 | ||
|
|
4699d1c2ee | ||
|
|
68f0b2efc3 | ||
|
|
b2af8e196b | ||
|
|
2e626a915f | ||
|
|
0127050d89 | ||
|
|
a25938022f | ||
|
|
c47b2973b0 | ||
|
|
efd3934470 | ||
|
|
fb7da4e07e | ||
|
|
d7d209f694 | ||
|
|
83a88299c2 | ||
|
|
bfae3b86cc | ||
|
|
027ee4d336 | ||
|
|
b07a65c879 | ||
|
|
284b2762f5 | ||
|
|
5ba6e3b332 | ||
|
|
8b0e3d960a | ||
|
|
fba2953974 | ||
|
|
a36b843eff | ||
|
|
0735bc2d8a | ||
|
|
69d6fd645b | ||
|
|
039b11d434 | ||
|
|
485581f680 | ||
|
|
a0c2006e24 | ||
|
|
7a288c360d | ||
|
|
597d39f651 | ||
|
|
7d27f64b8a | ||
|
|
bd280bdc53 | ||
|
|
018429866e | ||
|
|
78ad6526b8 | ||
|
|
8c6e960db7 | ||
|
|
46d38ff8c0 | ||
|
|
db6fe469ad | ||
|
|
5a7630bcd1 | ||
|
|
099b57169d | ||
|
|
e22dfd3314 | ||
|
|
be71992930 | ||
|
|
37433178cb | ||
|
|
14499a4564 | ||
|
|
0355777f59 | ||
|
|
a55834c78d | ||
|
|
79bbb47459 | ||
|
|
d3bcf0605b | ||
|
|
19a02f3a40 | ||
|
|
db20e9308a | ||
|
|
b3f9f28554 | ||
|
|
ea5bd3f346 | ||
|
|
5c13797639 | ||
|
|
f147905532 | ||
|
|
a73314c12a | ||
|
|
619934a275 | ||
|
|
5fe1384e55 | ||
|
|
9af2c4a18a |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -2,4 +2,7 @@
|
||||
*-plus.sh
|
||||
*_plus.html
|
||||
*_plus.js
|
||||
*@plus.js
|
||||
*@plus.js
|
||||
*_plus.less
|
||||
*_plus.css
|
||||
*_plus.css.map
|
||||
40
README.md
40
README.md
@@ -8,13 +8,42 @@
|
||||
* `简单` - 架构简单清晰,安装简单,使用简单,运维简单
|
||||
* `高扩展性` - 可以自由扩展新的节点,支持亿级数据
|
||||
|
||||
## 功能介绍
|
||||
* 多用户
|
||||
* 日志审计
|
||||
* 集群管理
|
||||
* HTTP/HTTPS/TCP/UDP等协议支持
|
||||
* WAF
|
||||
* 缓存
|
||||
* DNS自动解析
|
||||
* 多域名绑定
|
||||
* 免费证书申请
|
||||
* IP黑白名单
|
||||
* 访问日志
|
||||
* 统计
|
||||
* 内容压缩
|
||||
* Protocol Proxy协议
|
||||
* 本地静态文件
|
||||
* URL跳转
|
||||
* 路由规则
|
||||
* 重写规则
|
||||
* 访问控制
|
||||
* 字符编码
|
||||
* 自定义页面
|
||||
* 自定义HTTP Header
|
||||
* Websocket
|
||||
* WebP自动转换
|
||||
* Fastcgi
|
||||
* 请求限制
|
||||
* 流量限制
|
||||
|
||||
## 在线演示
|
||||
* [http://demo.goedge.cn](http://demo.goedge.cn)
|
||||
|
||||
## 文档
|
||||
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md)
|
||||
* [完整文档](https://edge.teaos.cn/docs)
|
||||
* [开发者指南](https://edge.teaos.cn/docs/Developer/Build.md)
|
||||
* [新手指南](https://goedge.cn/docs/QuickStart/Index.md)
|
||||
* [完整文档](https://goedge.cn/docs)
|
||||
* [开发者指南](https://goedge.cn/docs/Developer/Build.md)
|
||||
|
||||
## 架构
|
||||

|
||||
@@ -25,8 +54,7 @@
|
||||
* [管理平台](https://github.com/TeaOSLab/EdgeAdmin)
|
||||
|
||||
## 联系我们
|
||||
有什么问题和建议都可以加入QQ群 `659832182`。
|
||||
有什么问题和建议都可以加入QQ群 `659832182` 或者 [Telegram群](https://t.me/+5kVCMGxQhZxiODY9) 。
|
||||
|
||||
## 感谢
|
||||
* 感谢[JetBrains公司](https://www.jetbrains.com/)提供免费的IDE开发Licence。
|
||||
* 感谢[Gitee](https://gitee.com/)提供国内源代码托管平台
|
||||
* 感谢 [Gitee](https://gitee.com/) 提供国内源代码托管平台
|
||||
3
build/.gitignore
vendored
3
build/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
edge-api/
|
||||
edge-api/
|
||||
build-all-test.sh
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
function build() {
|
||||
ROOT=$(dirname $0)
|
||||
JS_ROOT=$ROOT/../web/public/js
|
||||
NAME="edge-admin"
|
||||
DIST=$ROOT/"../dist/${NAME}"
|
||||
OS=${1}
|
||||
@@ -53,6 +54,13 @@ function build() {
|
||||
# generate files
|
||||
echo "generating files ..."
|
||||
go run -tags $TAG $ROOT/../cmd/edge-admin/main.go generate
|
||||
if [ `which uglifyjs` ]; then
|
||||
echo "compress to component.js ..."
|
||||
uglifyjs --compress --mangle -- ${JS_ROOT}/components.src.js > ${JS_ROOT}/components.js
|
||||
else
|
||||
echo "copy to component.js ..."
|
||||
cp ${JS_ROOT}/components.src.js ${JS_ROOT}/components.js
|
||||
fi
|
||||
|
||||
# create dir & copy files
|
||||
echo "copying ..."
|
||||
@@ -65,6 +73,8 @@ function build() {
|
||||
|
||||
cp -R $ROOT/../web $DIST/
|
||||
rm -f $DIST/web/tmp/*
|
||||
rm -rf $DIST/web/public/js/components
|
||||
rm -f $DIST/web/public/js/components.src.js
|
||||
cp $ROOT/configs/server.template.yaml $DIST/configs/
|
||||
|
||||
# change _plus.[ext] to .[ext]
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
JS_ROOT=../web/public/js
|
||||
|
||||
echo "generate component.src.js ..."
|
||||
go run -tags=community ../cmd/edge-admin/main.go generate
|
||||
|
||||
if [ `which uglifyjs` ]; then
|
||||
echo "compress to component.js ..."
|
||||
uglifyjs --compress --mangle -- ${JS_ROOT}/components.src.js > ${JS_ROOT}/components.js
|
||||
else
|
||||
echo "copy to component.js ..."
|
||||
cp ${JS_ROOT}/components.src.js ${JS_ROOT}/components.js
|
||||
fi
|
||||
|
||||
echo "ok"
|
||||
@@ -18,14 +18,19 @@ func main() {
|
||||
Version(teaconst.Version).
|
||||
Product(teaconst.ProductName).
|
||||
Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset|recover|demo]").
|
||||
Usage(teaconst.ProcessName+" [dev|prod]").
|
||||
Option("-h", "show this help").
|
||||
Option("-v", "show version").
|
||||
Option("start", "start the service").
|
||||
Option("stop", "stop the service").
|
||||
Option("restart", "restart the service").
|
||||
Option("service", "register service into systemd").
|
||||
Option("daemon", "start the service with daemon").
|
||||
Option("reset", "reset configs").
|
||||
Option("recover", "enter recovery mode")
|
||||
Option("recover", "enter recovery mode").
|
||||
Option("demo", "switch to demo mode").
|
||||
Option("dev", "switch to 'dev' mode").
|
||||
Option("prod", "switch to 'prod' mode")
|
||||
|
||||
app.On("daemon", func() {
|
||||
nodes.NewAdminNode().Daemon()
|
||||
@@ -84,6 +89,32 @@ func main() {
|
||||
return
|
||||
}
|
||||
})
|
||||
app.On("dev", func() {
|
||||
var env = "dev"
|
||||
var sock = gosock.NewTmpSock(teaconst.ProcessName)
|
||||
_, err := sock.Send(&gosock.Command{
|
||||
Code: env,
|
||||
Params: nil,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("failed to switch to '" + env + "': " + err.Error())
|
||||
} else {
|
||||
fmt.Println("switch to '" + env + "' ok")
|
||||
}
|
||||
})
|
||||
app.On("prod", func() {
|
||||
var env = "prod"
|
||||
var sock = gosock.NewTmpSock(teaconst.ProcessName)
|
||||
_, err := sock.Send(&gosock.Command{
|
||||
Code: env,
|
||||
Params: nil,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("failed to switch to '" + env + "': " + err.Error())
|
||||
} else {
|
||||
fmt.Println("switch to '" + env + "' ok")
|
||||
}
|
||||
})
|
||||
app.Run(func() {
|
||||
adminNode := nodes.NewAdminNode()
|
||||
adminNode.Run()
|
||||
|
||||
19
go.mod
19
go.mod
@@ -7,20 +7,21 @@ replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
|
||||
require (
|
||||
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/frankban/quicktest v1.11.3 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24
|
||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475
|
||||
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/miekg/dns v1.1.35
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/miekg/dns v1.1.43
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.22.5
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/tealeg/xlsx/v3 v3.2.3
|
||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
|
||||
google.golang.org/grpc v1.38.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
|
||||
google.golang.org/grpc v1.45.0
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
|
||||
125
go.sum
125
go.sum
@@ -1,19 +1,27 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -21,18 +29,21 @@ github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cu
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/frankban/quicktest v1.5.0 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
|
||||
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -45,6 +56,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
@@ -55,41 +67,38 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/TeaGo v0.0.0-20210831140440-a2a442471b13 h1:HuEJ5xJfujW1Q6rNDhOu5LQXEBB2qLPah3jYslT8Gz4=
|
||||
github.com/iwind/TeaGo v0.0.0-20210831140440-a2a442471b13/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24 h1:1cGulkD2SNJJRok5OKwyhP/Ddm+PgSWKOupn0cR36/A=
|
||||
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 h1:EseyfFaQOjWanGiby9KMw7PjDBMg/95tLDgIw/ns0Cw=
|
||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
|
||||
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
|
||||
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@@ -106,11 +115,15 @@ github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug=
|
||||
github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa h1:2cO3RojjYl3hVTbEvJVqrMaFmORhL6O06qdW42toftk=
|
||||
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa/go.mod h1:Yjr3bdWaVWyME1kha7X0jsz3k2DgXNa1Pj3XGyUAbx8=
|
||||
github.com/shirou/gopsutil/v3 v3.22.5 h1:atX36I/IXgFiB81687vSiBI5zrMsxcIBkP9cQMJQoJA=
|
||||
github.com/shirou/gopsutil/v3 v3.22.5/go.mod h1:so9G9VzeHt/hsd0YwqprnjHnfARAUktauykSbr+y2gA=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
@@ -118,17 +131,23 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tealeg/xlsx/v3 v3.2.3 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ=
|
||||
github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
|
||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
@@ -137,27 +156,29 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -167,7 +188,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -175,50 +196,51 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg=
|
||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -229,23 +251,24 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
type AppCmd struct {
|
||||
product string
|
||||
version string
|
||||
usage string
|
||||
usages []string
|
||||
options []*CommandHelpOption
|
||||
appendStrings []string
|
||||
|
||||
@@ -52,7 +52,7 @@ func (this *AppCmd) Version(version string) *AppCmd {
|
||||
|
||||
// Usage 使用方法
|
||||
func (this *AppCmd) Usage(usage string) *AppCmd {
|
||||
this.usage = usage
|
||||
this.usages = append(this.usages, usage)
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -75,8 +75,10 @@ func (this *AppCmd) Append(appendString string) *AppCmd {
|
||||
func (this *AppCmd) Print() {
|
||||
fmt.Println(this.product + " v" + this.version)
|
||||
|
||||
usage := this.usage
|
||||
fmt.Println("Usage:", "\n "+usage)
|
||||
fmt.Println("Usage:")
|
||||
for _, usage := range this.usages {
|
||||
fmt.Println(" " + usage)
|
||||
}
|
||||
|
||||
if len(this.options) > 0 {
|
||||
fmt.Println("")
|
||||
|
||||
@@ -1,51 +1,108 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/sizes"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/files"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/utils/time"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LogWriter struct {
|
||||
fileAppender *files.Appender
|
||||
fp *os.File
|
||||
c chan string
|
||||
}
|
||||
|
||||
func (this *LogWriter) Init() {
|
||||
// 创建目录
|
||||
dir := files.NewFile(Tea.LogDir())
|
||||
var dir = files.NewFile(Tea.LogDir())
|
||||
if !dir.Exists() {
|
||||
err := dir.Mkdir()
|
||||
if err != nil {
|
||||
log.Println("[error]" + err.Error())
|
||||
log.Println("[LOG]create log dir failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
logFile := files.NewFile(Tea.LogFile("run.log"))
|
||||
|
||||
// 打开要写入的日志文件
|
||||
appender, err := logFile.Appender()
|
||||
var logPath = Tea.LogFile("run.log")
|
||||
fp, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
log.Println("[LOG]open log file failed: " + err.Error())
|
||||
} else {
|
||||
this.fileAppender = appender
|
||||
this.fp = fp
|
||||
}
|
||||
|
||||
this.c = make(chan string, 1024)
|
||||
|
||||
// 异步写入文件
|
||||
var maxFileSize = 2 * sizes.G // 文件最大尺寸,超出此尺寸则清空
|
||||
if fp != nil {
|
||||
goman.New(func() {
|
||||
var totalSize int64 = 0
|
||||
stat, err := fp.Stat()
|
||||
if err == nil {
|
||||
totalSize = stat.Size()
|
||||
}
|
||||
|
||||
for message := range this.c {
|
||||
totalSize += int64(len(message))
|
||||
_, err := fp.WriteString(timeutil.Format("Y/m/d H:i:s ") + message + "\n")
|
||||
if err != nil {
|
||||
log.Println("[LOG]write log failed: " + err.Error())
|
||||
} else {
|
||||
// 如果太大则Truncate
|
||||
if totalSize > maxFileSize {
|
||||
_ = fp.Truncate(0)
|
||||
totalSize = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (this *LogWriter) Write(message string) {
|
||||
log.Println(message)
|
||||
backgroundEnv, _ := os.LookupEnv("EdgeBackground")
|
||||
if backgroundEnv != "on" {
|
||||
// 文件和行号
|
||||
var file string
|
||||
var line int
|
||||
if Tea.IsTesting() {
|
||||
var callDepth = 3
|
||||
var ok bool
|
||||
_, file, line, ok = runtime.Caller(callDepth)
|
||||
if ok {
|
||||
file = this.packagePath(file)
|
||||
}
|
||||
}
|
||||
|
||||
if this.fileAppender != nil {
|
||||
_, err := this.fileAppender.AppendString(timeutil.Format("Y/m/d H:i:s ") + message + "\n")
|
||||
if err != nil {
|
||||
log.Println("[error]" + err.Error())
|
||||
if len(file) > 0 {
|
||||
log.Println(message + " (" + file + ":" + strconv.Itoa(line) + ")")
|
||||
} else {
|
||||
log.Println(message)
|
||||
}
|
||||
}
|
||||
|
||||
this.c <- message
|
||||
}
|
||||
|
||||
func (this *LogWriter) Close() {
|
||||
if this.fileAppender != nil {
|
||||
_ = this.fileAppender.Close()
|
||||
if this.fp != nil {
|
||||
_ = this.fp.Close()
|
||||
}
|
||||
|
||||
close(this.c)
|
||||
}
|
||||
|
||||
func (this *LogWriter) packagePath(path string) string {
|
||||
var pieces = strings.Split(path, "/")
|
||||
if len(pieces) >= 2 {
|
||||
return strings.Join(pieces[len(pieces)-2:], "/")
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package configloaders
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var sharedAdminUIConfig *systemconfigs.AdminUIConfig = nil
|
||||
@@ -45,6 +47,9 @@ func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
|
||||
}
|
||||
sharedAdminUIConfig = uiConfig
|
||||
|
||||
// timezone
|
||||
updateTimeZone(uiConfig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -76,13 +81,17 @@ func loadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
|
||||
return sharedAdminUIConfig, nil
|
||||
}
|
||||
|
||||
config := &systemconfigs.AdminUIConfig{}
|
||||
var config = &systemconfigs.AdminUIConfig{}
|
||||
err = json.Unmarshal(resp.ValueJSON, config)
|
||||
if err != nil {
|
||||
logs.Println("[UI_MANAGER]" + err.Error())
|
||||
sharedAdminUIConfig = defaultAdminUIConfig()
|
||||
return sharedAdminUIConfig, nil
|
||||
}
|
||||
|
||||
// timezone
|
||||
updateTimeZone(config)
|
||||
|
||||
sharedAdminUIConfig = config
|
||||
return sharedAdminUIConfig, nil
|
||||
}
|
||||
@@ -94,5 +103,17 @@ func defaultAdminUIConfig() *systemconfigs.AdminUIConfig {
|
||||
ShowOpenSourceInfo: true,
|
||||
ShowVersion: true,
|
||||
ShowFinance: true,
|
||||
DefaultPageSize: 10,
|
||||
TimeZone: nodeconfigs.DefaultTimeZoneLocation,
|
||||
}
|
||||
}
|
||||
|
||||
// 修改时区
|
||||
func updateTimeZone(config *systemconfigs.AdminUIConfig) {
|
||||
if len(config.TimeZone) > 0 {
|
||||
location, err := time.LoadLocation(config.TimeZone)
|
||||
if err == nil && time.Local != location {
|
||||
time.Local = location
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package configs
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
// +build community
|
||||
// +build !plus
|
||||
|
||||
package teaconst
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.4.2"
|
||||
Version = "0.4.8"
|
||||
|
||||
APINodeVersion = "0.4.2"
|
||||
APINodeVersion = "0.4.8"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
func Generate() error {
|
||||
err := generateComponentsJSFile()
|
||||
if err != nil {
|
||||
return errors.New("generate 'components.js' failed: " + err.Error())
|
||||
return errors.New("generate 'components.src.js' failed: " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -115,7 +115,7 @@ func generateComponentsJSFile() error {
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
}
|
||||
|
||||
fp, err := os.OpenFile(filepath.Clean(Tea.PublicFile("/js/components.js")), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
|
||||
fp, err := os.OpenFile(filepath.Clean(Tea.PublicFile("/js/components.src.js")), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,9 +13,12 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"github.com/iwind/TeaGo/sessions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
@@ -38,7 +41,7 @@ func (this *AdminNode) Run() {
|
||||
SharedAdminNode = this
|
||||
|
||||
// 启动管理界面
|
||||
secret := this.genSecret()
|
||||
var secret = this.genSecret()
|
||||
configs.Secret = secret
|
||||
|
||||
// 本地Sock
|
||||
@@ -58,6 +61,9 @@ func (this *AdminNode) Run() {
|
||||
return
|
||||
}
|
||||
|
||||
// 添加端口到防火墙
|
||||
this.addPortsToFirewall()
|
||||
|
||||
// 监听信号
|
||||
sigQueue := make(chan os.Signal)
|
||||
signal.Notify(sigQueue, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT)
|
||||
@@ -201,6 +207,44 @@ https:
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加端口到防火墙
|
||||
func (this *AdminNode) addPortsToFirewall() {
|
||||
var configFile = Tea.ConfigFile("server.yaml")
|
||||
data, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var config = &TeaGo.ServerConfig{}
|
||||
err = yaml.Unmarshal(data, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var ports = []int{}
|
||||
if config.Http.On {
|
||||
for _, listen := range config.Http.Listen {
|
||||
_, portString, _ := net.SplitHostPort(listen)
|
||||
var port = types.Int(portString)
|
||||
if port > 0 && !lists.ContainsInt(ports, port) {
|
||||
ports = append(ports, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if config.Https.On {
|
||||
for _, listen := range config.Https.Listen {
|
||||
_, portString, _ := net.SplitHostPort(listen)
|
||||
var port = types.Int(portString)
|
||||
if port > 0 && !lists.ContainsInt(ports, port) {
|
||||
ports = append(ports, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
utils.AddPortsToFirewall(ports)
|
||||
}
|
||||
|
||||
// 启动API节点
|
||||
func (this *AdminNode) startAPINode() {
|
||||
configPath := Tea.Root + "/edge-api/configs/api.yaml"
|
||||
@@ -338,6 +382,12 @@ func (this *AdminNode) listenSock() error {
|
||||
"path": exePath,
|
||||
},
|
||||
})
|
||||
case "dev": // 切换到dev
|
||||
Tea.Env = Tea.EnvDev
|
||||
_ = cmd.ReplyOk()
|
||||
case "prod": // 切换到prod
|
||||
Tea.Env = Tea.EnvProd
|
||||
_ = cmd.ReplyOk()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/encoding/gzip"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"net/url"
|
||||
"sync"
|
||||
@@ -217,6 +219,14 @@ func (this *RPCClient) HTTPCachePolicyRPC() pb.HTTPCachePolicyServiceClient {
|
||||
return pb.NewHTTPCachePolicyServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) HTTPCacheTaskRPC() pb.HTTPCacheTaskServiceClient {
|
||||
return pb.NewHTTPCacheTaskServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) HTTPCacheTaskKeyRPC() pb.HTTPCacheTaskKeyServiceClient {
|
||||
return pb.NewHTTPCacheTaskKeyServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) HTTPFirewallPolicyRPC() pb.HTTPFirewallPolicyServiceClient {
|
||||
return pb.NewHTTPFirewallPolicyServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -342,6 +352,14 @@ func (this *RPCClient) RegionProvinceRPC() pb.RegionProvinceServiceClient {
|
||||
return pb.NewRegionProvinceServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) RegionCityRPC() pb.RegionCityServiceClient {
|
||||
return pb.NewRegionCityServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) RegionProviderRPC() pb.RegionProviderServiceClient {
|
||||
return pb.NewRegionProviderServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) LogRPC() pb.LogServiceClient {
|
||||
return pb.NewLogServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -482,6 +500,10 @@ func (this *RPCClient) ServerStatBoardRPC() pb.ServerStatBoardServiceClient {
|
||||
return pb.NewServerStatBoardServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) ServerDomainHourlyStatRPC() pb.ServerDomainHourlyStatServiceClient {
|
||||
return pb.NewServerDomainHourlyStatServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) ServerStatBoardChartRPC() pb.ServerStatBoardChartServiceClient {
|
||||
return pb.NewServerStatBoardChartServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -494,6 +516,10 @@ func (this *RPCClient) UserPlanRPC() pb.UserPlanServiceClient {
|
||||
return pb.NewUserPlanServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) TrafficDailyStatRPC() pb.TrafficDailyStatServiceClient {
|
||||
return pb.NewTrafficDailyStatServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
// Context 构造Admin上下文
|
||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||
ctx := context.Background()
|
||||
@@ -560,12 +586,14 @@ func (this *RPCClient) init() error {
|
||||
return errors.New("parse endpoint failed: " + err.Error())
|
||||
}
|
||||
var conn *grpc.ClientConn
|
||||
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
|
||||
grpc.UseCompressor(gzip.Name))
|
||||
if u.Scheme == "http" {
|
||||
conn, err = grpc.Dial(u.Host, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024)))
|
||||
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
|
||||
} else if u.Scheme == "https" {
|
||||
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
})), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024)))
|
||||
})), callOptions)
|
||||
} else {
|
||||
return errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'")
|
||||
}
|
||||
|
||||
28
internal/utils/firewall.go
Normal file
28
internal/utils/firewall.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func AddPortsToFirewall(ports []int) {
|
||||
for _, port := range ports {
|
||||
// Linux
|
||||
if runtime.GOOS == "linux" {
|
||||
// firewalld
|
||||
firewallCmd, _ := exec.LookPath("firewall-cmd")
|
||||
if len(firewallCmd) > 0 {
|
||||
err := exec.Command(firewallCmd, "--add-port="+types.String(port)+"/tcp").Run()
|
||||
if err == nil {
|
||||
logs.Println("ADMIN_NODE", "add port '"+types.String(port)+"' to firewalld")
|
||||
|
||||
_ = exec.Command(firewallCmd, "--add-port="+types.String(port)+"/tcp", "--permanent").Run()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,3 +134,23 @@ func NextIP(prevIP net.IP) net.IP {
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
// IsLocalIP 判断是否为本地IP
|
||||
// ip 是To4()或者To16()的结果
|
||||
func IsLocalIP(ip net.IP) bool {
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if ip[0] == 127 ||
|
||||
ip[0] == 10 ||
|
||||
(ip[0] == 172 && ip[1]&0xf0 == 16) ||
|
||||
(ip[0] == 192 && ip[1] == 168) {
|
||||
return true
|
||||
}
|
||||
|
||||
if ip.String() == "::1" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
24
internal/utils/json.go
Normal file
24
internal/utils/json.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// JSONClone 使用JSON克隆对象
|
||||
func JSONClone(v interface{}) (interface{}, error) {
|
||||
data, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nv = reflect.New(reflect.TypeOf(v).Elem()).Interface()
|
||||
err = json.Unmarshal(data, nv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nv, nil
|
||||
}
|
||||
25
internal/utils/json_test.go
Normal file
25
internal/utils/json_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package utils_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJSONClone(t *testing.T) {
|
||||
type A struct {
|
||||
B int `json:"b"`
|
||||
C string `json:"c"`
|
||||
}
|
||||
|
||||
var a = &A{B: 123, C: "456"}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
c, err := utils.JSONClone(a)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%p, %#v", c, c)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -46,11 +46,31 @@ func FormatCount(count int64) string {
|
||||
if count < 1000 {
|
||||
return types.String(count)
|
||||
}
|
||||
if count < 1000 * 1000 {
|
||||
if count < 1000*1000 {
|
||||
return fmt.Sprintf("%.1fK", float32(count)/1000)
|
||||
}
|
||||
if count < 1000 * 1000 * 1000{
|
||||
if count < 1000*1000*1000 {
|
||||
return fmt.Sprintf("%.1fM", float32(count)/1000/1000)
|
||||
}
|
||||
return fmt.Sprintf("%.1fB", float32(count)/1000/1000/1000)
|
||||
}
|
||||
|
||||
func FormatFloat(f interface{}, decimal int) string {
|
||||
if f == nil {
|
||||
return ""
|
||||
}
|
||||
switch x := f.(type) {
|
||||
case float32, float64:
|
||||
var s = fmt.Sprintf("%."+types.String(decimal)+"f", x)
|
||||
return s
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
return types.String(x)
|
||||
case string:
|
||||
return x
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func FormatFloat2(f interface{}) string {
|
||||
return FormatFloat(f, 2)
|
||||
}
|
||||
|
||||
@@ -1,26 +1,36 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package numberutils
|
||||
package numberutils_test
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFormatBytes(t *testing.T) {
|
||||
t.Log(FormatBytes(1))
|
||||
t.Log(FormatBytes(1000))
|
||||
t.Log(FormatBytes(1_000_000))
|
||||
t.Log(FormatBytes(1_000_000_000))
|
||||
t.Log(FormatBytes(1_000_000_000_000))
|
||||
t.Log(FormatBytes(1_000_000_000_000_000))
|
||||
t.Log(FormatBytes(1_000_000_000_000_000_000))
|
||||
t.Log(FormatBytes(9_000_000_000_000_000_000))
|
||||
t.Log(numberutils.FormatBytes(1))
|
||||
t.Log(numberutils.FormatBytes(1000))
|
||||
t.Log(numberutils.FormatBytes(1_000_000))
|
||||
t.Log(numberutils.FormatBytes(1_000_000_000))
|
||||
t.Log(numberutils.FormatBytes(1_000_000_000_000))
|
||||
t.Log(numberutils.FormatBytes(1_000_000_000_000_000))
|
||||
t.Log(numberutils.FormatBytes(1_000_000_000_000_000_000))
|
||||
t.Log(numberutils.FormatBytes(9_000_000_000_000_000_000))
|
||||
}
|
||||
|
||||
func TestFormatCount(t *testing.T) {
|
||||
t.Log(FormatCount(1))
|
||||
t.Log(FormatCount(1000))
|
||||
t.Log(FormatCount(1500))
|
||||
t.Log(FormatCount(1_000_000))
|
||||
t.Log(FormatCount(1_500_000))
|
||||
t.Log(FormatCount(1_000_000_000))
|
||||
t.Log(FormatCount(1_500_000_000))
|
||||
}
|
||||
t.Log(numberutils.FormatCount(1))
|
||||
t.Log(numberutils.FormatCount(1000))
|
||||
t.Log(numberutils.FormatCount(1500))
|
||||
t.Log(numberutils.FormatCount(1_000_000))
|
||||
t.Log(numberutils.FormatCount(1_500_000))
|
||||
t.Log(numberutils.FormatCount(1_000_000_000))
|
||||
t.Log(numberutils.FormatCount(1_500_000_000))
|
||||
}
|
||||
|
||||
func TestFormatFloat(t *testing.T) {
|
||||
t.Log(numberutils.FormatFloat(1, 2))
|
||||
t.Log(numberutils.FormatFloat(100.23456, 2))
|
||||
t.Log(numberutils.FormatFloat(100.000023, 2))
|
||||
t.Log(numberutils.FormatFloat(100.012, 2))
|
||||
}
|
||||
|
||||
10
internal/utils/sizes/sizes.go
Normal file
10
internal/utils/sizes/sizes.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package sizes
|
||||
|
||||
const (
|
||||
K int64 = 1024
|
||||
M = 1024 * K
|
||||
G = 1024 * M
|
||||
T = 1024 * G
|
||||
)
|
||||
17
internal/utils/sizes/sizes_test.go
Normal file
17
internal/utils/sizes/sizes_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package sizes_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/sizes"
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSizes(t *testing.T) {
|
||||
var a = assert.NewAssertion(t)
|
||||
a.IsTrue(sizes.K == 1024)
|
||||
a.IsTrue(sizes.M == 1024*1024)
|
||||
a.IsTrue(sizes.G == 1024*1024*1024)
|
||||
a.IsTrue(sizes.T == 1024*1024*1024*1024)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package actionutils
|
||||
|
||||
// 子菜单定义
|
||||
// Menu 子菜单定义
|
||||
type Menu struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -11,14 +11,14 @@ type Menu struct {
|
||||
CountNormalItems int `json:"countNormalItems"`
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
// NewMenu 获取新对象
|
||||
func NewMenu() *Menu {
|
||||
return &Menu{
|
||||
Items: []*MenuItem{},
|
||||
}
|
||||
}
|
||||
|
||||
// 添加菜单项
|
||||
// Add 添加菜单项
|
||||
func (this *Menu) Add(name string, subName string, url string, isActive bool) *MenuItem {
|
||||
item := &MenuItem{
|
||||
Name: name,
|
||||
@@ -36,7 +36,7 @@ func (this *Menu) Add(name string, subName string, url string, isActive bool) *M
|
||||
return item
|
||||
}
|
||||
|
||||
// 添加特殊菜单项,不计数
|
||||
// AddSpecial 添加特殊菜单项,不计数
|
||||
func (this *Menu) AddSpecial(name string, subName string, url string, isActive bool) *MenuItem {
|
||||
item := this.Add(name, subName, url, isActive)
|
||||
this.CountNormalItems--
|
||||
|
||||
@@ -5,20 +5,20 @@ import (
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
)
|
||||
|
||||
// 菜单分组
|
||||
// MenuGroup 菜单分组
|
||||
type MenuGroup struct {
|
||||
Menus []*Menu `json:"menus"`
|
||||
AlwaysMenu *Menu `json:"alwaysMenu"`
|
||||
}
|
||||
|
||||
// 获取新菜单分组对象
|
||||
// NewMenuGroup 获取新菜单分组对象
|
||||
func NewMenuGroup() *MenuGroup {
|
||||
return &MenuGroup{
|
||||
Menus: []*Menu{},
|
||||
}
|
||||
}
|
||||
|
||||
// 查找菜单,如果找不到则自动创建
|
||||
// FindMenu 查找菜单,如果找不到则自动创建
|
||||
func (this *MenuGroup) FindMenu(menuId string, menuName string) *Menu {
|
||||
for _, m := range this.Menus {
|
||||
if m.Id == menuId {
|
||||
@@ -33,7 +33,7 @@ func (this *MenuGroup) FindMenu(menuId string, menuName string) *Menu {
|
||||
return menu
|
||||
}
|
||||
|
||||
// 排序
|
||||
// Sort 排序
|
||||
func (this *MenuGroup) Sort() {
|
||||
lists.Sort(this.Menus, func(i int, j int) bool {
|
||||
menu1 := this.Menus[i]
|
||||
@@ -42,7 +42,7 @@ func (this *MenuGroup) Sort() {
|
||||
})
|
||||
}
|
||||
|
||||
// 设置子菜单
|
||||
// SetSubMenu 设置子菜单
|
||||
func SetSubMenu(action actions.ActionWrapper, menu *MenuGroup) {
|
||||
action.Object().Data["teaSubMenus"] = menu
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package actionutils
|
||||
|
||||
// 菜单项
|
||||
// MenuItem 菜单项
|
||||
type MenuItem struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -127,7 +127,7 @@ func (this *Page) AsHTML() string {
|
||||
return `<div class="page">` + strings.Join(result, "") + `</div>`
|
||||
}
|
||||
|
||||
// 判断是否为最后一页
|
||||
// IsLastPage 判断是否为最后一页
|
||||
func (this *Page) IsLastPage() bool {
|
||||
return this.Current == this.Max
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
@@ -55,7 +56,14 @@ func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
|
||||
if len(size) > 0 {
|
||||
return NewActionPage(this, total, size[0])
|
||||
}
|
||||
return NewActionPage(this, total, 10)
|
||||
|
||||
var pageSize int64 = 10
|
||||
adminConfig, err := configloaders.LoadAdminUIConfig()
|
||||
if err == nil && adminConfig.DefaultPageSize > 0 {
|
||||
pageSize = int64(adminConfig.DefaultPageSize)
|
||||
}
|
||||
|
||||
return NewActionPage(this, total, pageSize)
|
||||
}
|
||||
|
||||
func (this *ParentAction) Nav(mainMenu string, tab string, firstMenu string) {
|
||||
|
||||
@@ -5,19 +5,19 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// Tabbar定义
|
||||
// Tabbar Tabbar定义
|
||||
type Tabbar struct {
|
||||
items []maps.Map
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
// NewTabbar 获取新对象
|
||||
func NewTabbar() *Tabbar {
|
||||
return &Tabbar{
|
||||
items: []maps.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// 添加菜单项
|
||||
// Add 添加菜单项
|
||||
func (this *Tabbar) Add(name string, subName string, url string, icon string, active bool) maps.Map {
|
||||
m := maps.Map{
|
||||
"name": name,
|
||||
@@ -31,12 +31,12 @@ func (this *Tabbar) Add(name string, subName string, url string, icon string, ac
|
||||
return m
|
||||
}
|
||||
|
||||
// 取得所有的Items
|
||||
// Items 取得所有的Items
|
||||
func (this *Tabbar) Items() []maps.Map {
|
||||
return this.items
|
||||
}
|
||||
|
||||
// 设置子菜单
|
||||
// SetTabbar 设置子菜单
|
||||
func SetTabbar(action actions.ActionWrapper, tabbar *Tabbar) {
|
||||
action.Object().Data["teaTabbar"] = tabbar.Items()
|
||||
}
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
rpcerrors "github.com/TeaOSLab/EdgeCommon/pkg/rpc/errors"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -24,24 +31,78 @@ func Fail(action actions.ActionWrapper, err error) {
|
||||
|
||||
// FailPage 提示页面错误信息
|
||||
func FailPage(action actions.ActionWrapper, err error) {
|
||||
if err != nil {
|
||||
logs.Println("[" + reflect.TypeOf(action).String() + "]" + findStack(err.Error()))
|
||||
if err == nil {
|
||||
err = errors.New("unknown error")
|
||||
}
|
||||
err = rpcerrors.HumanError(err)
|
||||
|
||||
logs.Println("[" + reflect.TypeOf(action).String() + "]" + findStack(err.Error()))
|
||||
|
||||
// 当前API终端地址
|
||||
var apiEndpoints = []string{}
|
||||
apiConfig, apiConfigErr := configs.LoadAPIConfig()
|
||||
if apiConfigErr == nil && apiConfig != nil {
|
||||
apiEndpoints = append(apiEndpoints, apiConfig.RPC.Endpoints...)
|
||||
}
|
||||
|
||||
var isRPCConnError bool
|
||||
err, isRPCConnError = rpcerrors.HumanError(err, apiEndpoints, Tea.ConfigFile("api.yaml"))
|
||||
|
||||
action.Object().ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||
if len(action.Object().Request.Header.Get("X-Requested-With")) > 0 {
|
||||
action.Object().WriteString(teaconst.ErrServer)
|
||||
} else {
|
||||
action.Object().WriteString(`<!DOCTYPE html>
|
||||
// 本地的一些错误提示
|
||||
var isLocalAPI = false
|
||||
if isRPCConnError {
|
||||
host, _, hostErr := net.SplitHostPort(action.Object().Request.Host)
|
||||
if hostErr == nil {
|
||||
for _, endpoint := range apiEndpoints {
|
||||
if strings.HasPrefix(endpoint, "http://"+host) || strings.HasPrefix(endpoint, "https://"+host) || strings.HasPrefix(endpoint, host) {
|
||||
isLocalAPI = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var issuesHTML = ""
|
||||
if isLocalAPI {
|
||||
// 读取本地API节点的issues
|
||||
issuesData, issuesErr := ioutil.ReadFile(Tea.Root + "/edge-api/logs/issues.log")
|
||||
if issuesErr == nil {
|
||||
var issueMaps = []maps.Map{}
|
||||
issuesErr = json.Unmarshal(issuesData, &issueMaps)
|
||||
if issuesErr == nil && len(issueMaps) > 0 {
|
||||
var issueMap = issueMaps[0]
|
||||
issuesHTML = "本地API节点启动错误:" + issueMap.GetString("message") + ",处理建议:" + issueMap.GetString("suggestion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var html = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head></head>
|
||||
<head>
|
||||
<title>有系统错误需要处理</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<style type="text/css">
|
||||
hr { border-top: 1px #ccc solid; }
|
||||
.red { color: red; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="background: #eee; border: 1px #ccc solid; padding: 10px; font-size: 12px; line-height: 1.8">
|
||||
` + teaconst.ErrServer + `
|
||||
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
||||
<hr style="border-top: 1px #ccc solid"/>
|
||||
<div style="color: red">Error: ` + err.Error() + `</pre>
|
||||
</div>
|
||||
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
||||
<hr/>
|
||||
<div class="red">Error: ` + err.Error() + `</div>`
|
||||
|
||||
if len(issuesHTML) > 0 {
|
||||
html += ` <hr/>
|
||||
<div class="red">` + issuesHTML + `</div>`
|
||||
}
|
||||
|
||||
action.Object().WriteString(html + `
|
||||
</div>
|
||||
</body>
|
||||
</html>`)
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
"name": node.Name,
|
||||
"accessAddrs": node.AccessAddrs,
|
||||
"restAccessAddrs": restAccessAddrs,
|
||||
"isPrimary": node.IsPrimary,
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
|
||||
@@ -129,6 +129,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
"restAccessAddrs": restAccessAddrs,
|
||||
"hasHTTPS": hasHTTPS,
|
||||
"certs": certs,
|
||||
"isPrimary": node.IsPrimary,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
|
||||
@@ -29,13 +29,13 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.ApiNode
|
||||
var node = nodeResp.ApiNode
|
||||
if node == nil {
|
||||
this.WriteString("要操作的节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||
if len(node.HttpJSON) > 0 {
|
||||
err = json.Unmarshal(node.HttpJSON, httpConfig)
|
||||
if err != nil {
|
||||
@@ -43,7 +43,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
}
|
||||
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||
if len(node.HttpsJSON) > 0 {
|
||||
err = json.Unmarshal(node.HttpsJSON, httpsConfig)
|
||||
if err != nil {
|
||||
@@ -53,11 +53,11 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 监听地址
|
||||
listens := []*serverconfigs.NetworkAddressConfig{}
|
||||
var listens = []*serverconfigs.NetworkAddressConfig{}
|
||||
listens = append(listens, httpConfig.Listen...)
|
||||
listens = append(listens, httpsConfig.Listen...)
|
||||
|
||||
restHTTPConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||
if len(node.RestHTTPJSON) > 0 {
|
||||
err = json.Unmarshal(node.RestHTTPJSON, restHTTPConfig)
|
||||
if err != nil {
|
||||
@@ -65,7 +65,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
}
|
||||
restHTTPSConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||
if len(node.RestHTTPSJSON) > 0 {
|
||||
err = json.Unmarshal(node.RestHTTPSJSON, restHTTPSConfig)
|
||||
if err != nil {
|
||||
@@ -75,20 +75,20 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 监听地址
|
||||
restListens := []*serverconfigs.NetworkAddressConfig{}
|
||||
var restListens = []*serverconfigs.NetworkAddressConfig{}
|
||||
restListens = append(restListens, restHTTPConfig.Listen...)
|
||||
restListens = append(restListens, restHTTPSConfig.Listen...)
|
||||
|
||||
// 证书信息
|
||||
certs := []*sslconfigs.SSLCertConfig{}
|
||||
sslPolicyId := int64(0)
|
||||
var certs = []*sslconfigs.SSLCertConfig{}
|
||||
var sslPolicyId = int64(0)
|
||||
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
|
||||
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON
|
||||
var sslPolicyConfigJSON = sslPolicyConfigResp.SslPolicyJSON
|
||||
if len(sslPolicyConfigJSON) > 0 {
|
||||
sslPolicyId = httpsConfig.SSLPolicyRef.SSLPolicyId
|
||||
|
||||
@@ -102,7 +102,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
accessAddrs := []*serverconfigs.NetworkAddressConfig{}
|
||||
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(node.AccessAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(node.AccessAddrsJSON, &accessAddrs)
|
||||
if err != nil {
|
||||
@@ -122,6 +122,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
"certs": certs,
|
||||
"sslPolicyId": sslPolicyId,
|
||||
"accessAddrs": accessAddrs,
|
||||
"isPrimary": node.IsPrimary,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
@@ -139,6 +140,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
AccessAddrsJSON []byte
|
||||
Description string
|
||||
IsOn bool
|
||||
IsPrimary bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -146,11 +148,11 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
Field("name", params.Name).
|
||||
Require("请输入API节点名称")
|
||||
|
||||
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||
|
||||
// 监听地址
|
||||
listens := []*serverconfigs.NetworkAddressConfig{}
|
||||
var listens = []*serverconfigs.NetworkAddressConfig{}
|
||||
err := json.Unmarshal(params.ListensJSON, &listens)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -170,8 +172,8 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// Rest监听地址
|
||||
restHTTPConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||
restHTTPSConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||
if params.RestIsOn {
|
||||
restListens := []*serverconfigs.NetworkAddressConfig{}
|
||||
err = json.Unmarshal(params.RestListensJSON, &restListens)
|
||||
@@ -191,7 +193,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 证书
|
||||
certIds := []int64{}
|
||||
var certIds = []int64{}
|
||||
if len(params.CertIdsJSON) > 0 {
|
||||
err = json.Unmarshal(params.CertIdsJSON, &certIds)
|
||||
if err != nil {
|
||||
@@ -203,7 +205,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
this.Fail("请添加至少一个证书")
|
||||
}
|
||||
|
||||
certRefs := []*sslconfigs.SSLCertRef{}
|
||||
var certRefs = []*sslconfigs.SSLCertRef{}
|
||||
for _, certId := range certIds {
|
||||
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
|
||||
IsOn: true,
|
||||
@@ -217,7 +219,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 创建策略
|
||||
sslPolicyId := params.SslPolicyId
|
||||
var sslPolicyId = params.SslPolicyId
|
||||
if sslPolicyId == 0 {
|
||||
if len(certIds) > 0 {
|
||||
sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{
|
||||
@@ -249,7 +251,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 访问地址
|
||||
accessAddrs := []*serverconfigs.NetworkAddressConfig{}
|
||||
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -291,6 +293,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
RestHTTPSJSON: restHTTPSJSON,
|
||||
AccessAddrsJSON: params.AccessAddrsJSON,
|
||||
IsOn: params.IsOn,
|
||||
IsPrimary: params.IsPrimary,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/groups"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/cache"
|
||||
ddosProtection "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/ddos-protection"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/dns"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/ssh"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/system"
|
||||
@@ -54,7 +55,10 @@ func init() {
|
||||
GetPost("/settings/dns", new(dns.IndexAction)).
|
||||
GetPost("/settings/system", new(system.IndexAction)).
|
||||
GetPost("/settings/ssh", new(ssh.IndexAction)).
|
||||
GetPost("/settings/ssh/test", new(ssh.TestAction)).
|
||||
GetPost("/settings/thresholds", new(thresholds.IndexAction)).
|
||||
GetPost("/settings/ddos-protection", new(ddosProtection.IndexAction)).
|
||||
Post("/settings/ddos-protection/status", new(ddosProtection.StatusAction)).
|
||||
|
||||
// 分组相关
|
||||
Prefix("/clusters/cluster/groups").
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -33,7 +34,7 @@ func (this *DetailAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
@@ -197,7 +198,9 @@ func (this *DetailAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 运行状态
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
var status = &nodeconfigs.NodeStatus{}
|
||||
this.Data["nodeDatetime"] = ""
|
||||
this.Data["nodeTimeDiff"] = 0
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
@@ -205,6 +208,19 @@ func (this *DetailAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
|
||||
if status.Timestamp > 0 {
|
||||
this.Data["nodeDatetime"] = timeutil.FormatTime("Y-m-d H:i:s", status.Timestamp)
|
||||
if status.UpdatedAt > 0 {
|
||||
var diff = status.UpdatedAt - status.Timestamp
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
}
|
||||
this.Data["nodeTimeDiff"] = diff
|
||||
}
|
||||
} else if status.UpdatedAt > 0 {
|
||||
this.Data["nodeDatetime"] = timeutil.FormatTime("Y-m-d H:i:s", status.UpdatedAt)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有新版本
|
||||
@@ -285,6 +301,8 @@ func (this *DetailAction) RunGet(params struct {
|
||||
"isOn": node.IsOn,
|
||||
"records": recordMaps,
|
||||
"routes": routeMaps,
|
||||
"level": node.Level,
|
||||
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
||||
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
@@ -298,9 +316,9 @@ func (this *DetailAction) RunGet(params struct {
|
||||
"buildVersion": status.BuildVersion,
|
||||
"cpuPhysicalCount": status.CPUPhysicalCount,
|
||||
"cpuLogicalCount": status.CPULogicalCount,
|
||||
"load1m": fmt.Sprintf("%.2f", status.Load1m),
|
||||
"load5m": fmt.Sprintf("%.2f", status.Load5m),
|
||||
"load15m": fmt.Sprintf("%.2f", status.Load15m),
|
||||
"load1m": numberutils.FormatFloat2(status.Load1m),
|
||||
"load5m": numberutils.FormatFloat2(status.Load5m),
|
||||
"load15m": numberutils.FormatFloat2(status.Load15m),
|
||||
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
||||
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
@@ -43,7 +44,7 @@ func (this *LogsAction) RunGet(params struct {
|
||||
this.Data["tag"] = params.Tag
|
||||
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
Role: "node",
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
NodeId: params.NodeId,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
|
||||
@@ -4,7 +4,6 @@ package nodeutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -24,6 +23,11 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
|
||||
}
|
||||
var node = nodeResp.Node
|
||||
|
||||
info, err := parentAction.RPC().NodeRPC().FindEnabledNodeConfigInfo(parentAction.AdminContext(), &pb.FindEnabledNodeConfigInfoRequest{NodeId: nodeId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var groupMap maps.Map
|
||||
if node.NodeGroup != nil {
|
||||
groupMap = maps.Map{
|
||||
@@ -38,6 +42,7 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
|
||||
"isOn": node.IsOn,
|
||||
"isUp": node.IsUp,
|
||||
"group": groupMap,
|
||||
"level": node.Level,
|
||||
}
|
||||
var clusterId int64 = 0
|
||||
if node.NodeCluster != nil {
|
||||
@@ -60,32 +65,38 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
|
||||
"name": "DNS设置",
|
||||
"url": prefix + "/settings/dns?" + query,
|
||||
"isActive": menuItem == "dns",
|
||||
"isOn": info.HasDNSInfo,
|
||||
},
|
||||
{
|
||||
"name": "缓存设置",
|
||||
"url": prefix + "/settings/cache?" + query,
|
||||
"isActive": menuItem == "cache",
|
||||
"isOn": info.HasCacheInfo,
|
||||
},
|
||||
{
|
||||
"name": "DDoS防护",
|
||||
"url": prefix + "/settings/ddos-protection?" + query,
|
||||
"isActive": menuItem == "ddosProtection",
|
||||
"isOn": info.HasDDoSProtection,
|
||||
},
|
||||
{
|
||||
"name": "-",
|
||||
"url": "",
|
||||
},
|
||||
}
|
||||
if teaconst.IsPlus {
|
||||
menuItems = append(menuItems, []maps.Map{
|
||||
{
|
||||
"name": "阈值设置",
|
||||
"url": prefix + "/settings/thresholds?" + query,
|
||||
"isActive": menuItem == "threshold",
|
||||
},
|
||||
}...)
|
||||
}
|
||||
menuItems = filterMenuItems(menuItems, menuItem, prefix, query, info)
|
||||
menuItems = append(menuItems, []maps.Map{
|
||||
{
|
||||
"name": "SSH设置",
|
||||
"url": prefix + "/settings/ssh?" + query,
|
||||
"isActive": menuItem == "ssh",
|
||||
"isOn": info.HasSSH,
|
||||
},
|
||||
{
|
||||
"name": "系统设置",
|
||||
"url": prefix + "/settings/system?" + query,
|
||||
"isActive": menuItem == "system",
|
||||
"isOn": info.HasSystemSettings,
|
||||
},
|
||||
}...)
|
||||
parentAction.Data["leftMenuItems"] = menuItems
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package nodeutils
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
func filterMenuItems(menuItems []maps.Map, menuItem string, prefix string, query string, info *pb.FindEnabledNodeConfigInfoResponse) []maps.Map {
|
||||
return menuItems
|
||||
}
|
||||
@@ -59,6 +59,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
|
||||
nodeMap["cacheDiskDir"] = node.CacheDiskDir
|
||||
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
|
||||
|
||||
this.Show()
|
||||
@@ -67,6 +68,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
MaxCacheDiskCapacityJSON []byte
|
||||
CacheDiskDir string
|
||||
MaxCacheMemoryCapacityJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
@@ -106,6 +108,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
|
||||
NodeId: params.NodeId,
|
||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||
CacheDiskDir: params.CacheDiskDir,
|
||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("ddosProtection")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 集群设置
|
||||
clusterProtectionResp, err := this.RPC().NodeClusterRPC().FindNodeClusterDDoSProtection(this.AdminContext(), &pb.FindNodeClusterDDoSProtectionRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var clusterDDoSProtectionIsOn = false
|
||||
if len(clusterProtectionResp.DdosProtectionJSON) > 0 {
|
||||
var clusterDDoSProtection = &ddosconfigs.ProtectionConfig{}
|
||||
err = json.Unmarshal(clusterProtectionResp.DdosProtectionJSON, clusterDDoSProtection)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterDDoSProtectionIsOn = clusterDDoSProtection.IsOn()
|
||||
}
|
||||
|
||||
this.Data["clusterDDoSProtectionIsOn"] = clusterDDoSProtectionIsOn
|
||||
|
||||
// 节点设置
|
||||
ddosProtectionResp, err := this.RPC().NodeRPC().FindNodeDDoSProtection(this.AdminContext(), &pb.FindNodeDDoSProtectionRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ddosProtectionConfig = ddosconfigs.DefaultProtectionConfig()
|
||||
if len(ddosProtectionResp.DdosProtectionJSON) > 0 {
|
||||
err = json.Unmarshal(ddosProtectionResp.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["config"] = ddosProtectionConfig
|
||||
this.Data["defaultConfigs"] = nodeconfigs.DefaultConfigs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
DdosProtectionJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改节点 %d 的DDOS防护设置", params.NodeId)
|
||||
|
||||
var ddosProtectionConfig = &ddosconfigs.ProtectionConfig{}
|
||||
err := json.Unmarshal(params.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = ddosProtectionConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 校验参数
|
||||
if ddosProtectionConfig.TCP != nil {
|
||||
var tcpConfig = ddosProtectionConfig.TCP
|
||||
if tcpConfig.MaxConnectionsPerIP > 0 && tcpConfig.MaxConnectionsPerIP < nodeconfigs.DefaultTCPMinConnectionsPerIP {
|
||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||
}
|
||||
|
||||
if tcpConfig.NewConnectionsRate > 0 && tcpConfig.NewConnectionsRate < nodeconfigs.DefaultTCPNewConnectionsMinRate {
|
||||
this.FailField("tcpNewConnectionsRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinRate))
|
||||
}
|
||||
|
||||
// Port
|
||||
for _, portConfig := range tcpConfig.Ports {
|
||||
if portConfig.Port > 65535 {
|
||||
this.Fail("端口号" + types.String(portConfig.Port) + "不能大于65535")
|
||||
}
|
||||
}
|
||||
|
||||
// IP
|
||||
for _, ipConfig := range tcpConfig.AllowIPList {
|
||||
if net.ParseIP(ipConfig.IP) == nil {
|
||||
this.Fail("白名单IP '" + ipConfig.IP + "' 格式错误")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeDDoSProtection(this.AdminContext(), &pb.UpdateNodeDDoSProtectionRequest{
|
||||
NodeId: params.NodeId,
|
||||
DdosProtectionJSON: params.DdosProtectionJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
)
|
||||
|
||||
type StatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
results, err := nodeutils.SendMessageToNodeIds(this.AdminContext(), []int64{params.NodeId}, messageconfigs.MessageCodeCheckLocalFirewall, &messageconfigs.CheckLocalFirewallMessage{
|
||||
Name: "nftables",
|
||||
}, 10)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["results"] = results
|
||||
this.Success()
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -30,10 +32,12 @@ func (this *IndexAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["hostIsAutoFilled"] = false
|
||||
|
||||
// 登录信息
|
||||
var loginMap maps.Map = nil
|
||||
if node.NodeLogin != nil {
|
||||
loginParams := maps.Map{}
|
||||
var loginParams = maps.Map{}
|
||||
if len(node.NodeLogin.Params) > 0 {
|
||||
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
@@ -42,7 +46,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
grantMap := maps.Map{}
|
||||
var grantMap = maps.Map{}
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
@@ -70,6 +74,47 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
if loginMap == nil {
|
||||
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{NodeId: node.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(addressesResp.NodeIPAddresses) > 0 {
|
||||
this.Data["hostIsAutoFilled"] = true
|
||||
loginMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
"type": "ssh",
|
||||
"params": maps.Map{
|
||||
"host": addressesResp.NodeIPAddresses[0].Ip,
|
||||
"port": 22,
|
||||
"grantId": 0,
|
||||
},
|
||||
"grant": nil,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var loginParams = loginMap.GetMap("params")
|
||||
if len(loginParams.GetString("host")) == 0 {
|
||||
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{NodeId: node.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(addressesResp.NodeIPAddresses) > 0 {
|
||||
this.Data["hostIsAutoFilled"] = true
|
||||
loginParams["host"] = addressesResp.NodeIPAddresses[0].Ip
|
||||
}
|
||||
}
|
||||
|
||||
if loginParams.GetInt("port") == 0 {
|
||||
loginParams["port"] = 22
|
||||
}
|
||||
|
||||
loginMap["params"] = loginParams
|
||||
}
|
||||
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["login"] = loginMap
|
||||
|
||||
@@ -89,8 +134,13 @@ func (this *IndexAction) RunPost(params struct {
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改节点 %d SSH登录信息", params.NodeId)
|
||||
|
||||
// 检查IP地址
|
||||
if regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+$`).MatchString(params.SshHost) && net.ParseIP(params.SshHost) == nil {
|
||||
this.Fail("SSH主机地址 '" + params.SshHost + "' IP格式错误")
|
||||
}
|
||||
|
||||
// TODO 检查登录授权
|
||||
loginInfo := &pb.NodeLogin{
|
||||
var loginInfo = &pb.NodeLogin{
|
||||
Id: params.LoginId,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
GrantId int64
|
||||
Host string
|
||||
Port int32
|
||||
}) {
|
||||
resp, err := this.RPC().NodeGrantRPC().TestNodeGrant(this.AdminContext(), &pb.TestNodeGrantRequest{
|
||||
NodeGrantId: params.GrantId,
|
||||
Host: params.Host,
|
||||
Port: params.Port,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["isOk"] = resp.IsOk
|
||||
this.Data["error"] = resp.Error
|
||||
this.Success()
|
||||
}
|
||||
@@ -3,8 +3,10 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -32,6 +34,22 @@ func (this *IndexAction) RunGet(params struct {
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["maxCPU"] = node.MaxCPU
|
||||
|
||||
// DNS
|
||||
dnsResolverResp, err := this.RPC().NodeRPC().FindNodeDNSResolver(this.AdminContext(), &pb.FindNodeDNSResolverRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||
if len(dnsResolverResp.DnsResolverJSON) > 0 {
|
||||
err = json.Unmarshal(dnsResolverResp.DnsResolverJSON, dnsResolverConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["dnsResolverConfig"] = dnsResolverConfig
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -39,6 +57,8 @@ func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
MaxCPU int32
|
||||
|
||||
DnsResolverJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
@@ -57,5 +77,26 @@ func (this *IndexAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||
err = json.Unmarshal(params.DnsResolverJSON, dnsResolverConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = dnsResolverConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验DNS解析配置失败:" + err.Error())
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeDNSResolver(this.AdminContext(), &pb.UpdateNodeDNSResolverRequest{
|
||||
NodeId: params.NodeId,
|
||||
DnsResolverJSON: params.DnsResolverJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type UpdateAction struct {
|
||||
@@ -37,7 +38,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
@@ -97,7 +98,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
var m = maps.Map{
|
||||
var nodeMap = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
@@ -105,15 +106,16 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
"isOn": node.IsOn,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"level": node.Level,
|
||||
}
|
||||
|
||||
if node.NodeCluster != nil {
|
||||
m["primaryCluster"] = maps.Map{
|
||||
nodeMap["primaryCluster"] = maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
}
|
||||
} else {
|
||||
m["primaryCluster"] = nil
|
||||
nodeMap["primaryCluster"] = nil
|
||||
}
|
||||
|
||||
if len(node.SecondaryNodeClusters) > 0 {
|
||||
@@ -124,12 +126,14 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
m["secondaryClusters"] = secondaryClusterMaps
|
||||
nodeMap["secondaryClusters"] = secondaryClusterMaps
|
||||
} else {
|
||||
m["secondaryClusters"] = []interface{}{}
|
||||
nodeMap["secondaryClusters"] = []interface{}{}
|
||||
}
|
||||
|
||||
this.Data["node"] = m
|
||||
this.Data["node"] = nodeMap
|
||||
|
||||
this.Data["canUpdateLevel"] = this.CanUpdateLevel(2)
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -144,11 +148,12 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
PrimaryClusterId int64
|
||||
SecondaryClusterIds []byte
|
||||
IsOn bool
|
||||
Level int32
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d", params.NodeId)
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 基本信息", params.NodeId)
|
||||
|
||||
if params.NodeId <= 0 {
|
||||
this.Fail("要操作的节点不存在")
|
||||
@@ -186,6 +191,10 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 保存
|
||||
if !this.CanUpdateLevel(params.Level) {
|
||||
this.Fail("没有权限修改节点级别:" + types.String(params.Level))
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeGroupId: params.GroupId,
|
||||
@@ -194,6 +203,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
NodeClusterId: params.PrimaryClusterId,
|
||||
SecondaryNodeClusterIds: secondaryClusterIds,
|
||||
IsOn: params.IsOn,
|
||||
Level: params.Level,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package node
|
||||
|
||||
func (this *UpdateAction) CanUpdateLevel(level int32) bool {
|
||||
return level <= 1
|
||||
}
|
||||
@@ -3,13 +3,14 @@ package cluster
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"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/pb"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -29,17 +30,21 @@ func (this *NodesAction) RunGet(params struct {
|
||||
InstalledState int
|
||||
ActiveState int
|
||||
Keyword string
|
||||
Level int32
|
||||
|
||||
CpuOrder string
|
||||
MemoryOrder string
|
||||
TrafficInOrder string
|
||||
TrafficOutOrder string
|
||||
LoadOrder string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["regionId"] = params.RegionId
|
||||
this.Data["installState"] = params.InstalledState
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
this.Data["hasOrder"] = len(params.CpuOrder) > 0 || len(params.MemoryOrder) > 0 || len(params.TrafficInOrder) > 0 || len(params.TrafficOutOrder) > 0 || len(params.LoadOrder) > 0
|
||||
|
||||
// 集群是否已经设置了线路
|
||||
clusterDNSResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
@@ -63,6 +68,7 @@ func (this *NodesAction) RunGet(params struct {
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Level: params.Level,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
@@ -72,7 +78,7 @@ func (this *NodesAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
page := this.NewPage(countResp.Count)
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
var req = &pb.ListEnabledNodesMatchRequest{
|
||||
@@ -81,6 +87,7 @@ func (this *NodesAction) RunGet(params struct {
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Level: params.Level,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
@@ -101,13 +108,17 @@ func (this *NodesAction) RunGet(params struct {
|
||||
req.TrafficOutAsc = true
|
||||
} else if params.TrafficOutOrder == "desc" {
|
||||
req.TrafficOutDesc = true
|
||||
} else if params.LoadOrder == "asc" {
|
||||
req.LoadAsc = true
|
||||
} else if params.LoadOrder == "desc" {
|
||||
req.LoadDesc = true
|
||||
}
|
||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), req)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
nodeMaps := []maps.Map{}
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
isSynced := false
|
||||
@@ -199,6 +210,7 @@ func (this *NodesAction) RunGet(params struct {
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"trafficInBytes": status.TrafficInBytes,
|
||||
"trafficOutBytes": status.TrafficOutBytes,
|
||||
"load1m": numberutils.FormatFloat2(status.Load1m),
|
||||
},
|
||||
"cluster": maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
@@ -210,12 +222,13 @@ func (this *NodesAction) RunGet(params struct {
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
"level": node.Level,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
// 所有分组
|
||||
groupMaps := []maps.Map{}
|
||||
var groupMaps = []maps.Map{}
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
@@ -224,15 +237,18 @@ func (this *NodesAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
for _, group := range groupsResp.NodeGroups {
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
|
||||
countNodesInGroupResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: group.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countNodes := countResp.Count
|
||||
countNodes := countNodesInGroupResp.Count
|
||||
groupName := group.Name
|
||||
if countNodes > 0 {
|
||||
groupName += "(" + strconv.FormatInt(countNodes, 10) + ")"
|
||||
groupName += "(" + types.String(countNodes) + ")"
|
||||
}
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
@@ -240,6 +256,29 @@ func (this *NodesAction) RunGet(params struct {
|
||||
"countNodes": countNodes,
|
||||
})
|
||||
}
|
||||
|
||||
// 是否有未分组
|
||||
if len(groupMaps) > 0 {
|
||||
countNodesInGroupResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: -1,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countUngroupNodes = countNodesInGroupResp.Count
|
||||
if countUngroupNodes > 0 {
|
||||
groupMaps = append([]maps.Map{
|
||||
{
|
||||
"id": -1,
|
||||
"name": "[未分组](" + types.String(countUngroupNodes) + ")",
|
||||
"countNodes": countUngroupNodes,
|
||||
},
|
||||
}, groupMaps...)
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
// 所有区域
|
||||
@@ -248,7 +287,7 @@ func (this *NodesAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
regionMaps := []maps.Map{}
|
||||
var regionMaps = []maps.Map{}
|
||||
for _, region := range regionsResp.NodeRegions {
|
||||
regionMaps = append(regionMaps, maps.Map{
|
||||
"id": region.Id,
|
||||
@@ -257,6 +296,12 @@ func (this *NodesAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["regions"] = regionMaps
|
||||
|
||||
// 级别
|
||||
this.Data["levels"] = []maps.Map{}
|
||||
if teaconst.IsPlus {
|
||||
this.Data["levels"] = nodeconfigs.FindAllNodeLevels()
|
||||
}
|
||||
|
||||
// 记录最近访问
|
||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "cluster",
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
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/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"net"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("ddosProtection")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
protectionResp, err := this.RPC().NodeClusterRPC().FindNodeClusterDDoSProtection(this.AdminContext(), &pb.FindNodeClusterDDoSProtectionRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var ddosProtectionConfig = ddosconfigs.DefaultProtectionConfig()
|
||||
if len(protectionResp.DdosProtectionJSON) > 0 {
|
||||
err = json.Unmarshal(protectionResp.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["config"] = ddosProtectionConfig
|
||||
this.Data["defaultConfigs"] = nodeconfigs.DefaultConfigs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
DdosProtectionJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改集群 %d 的DDOS防护设置", params.ClusterId)
|
||||
|
||||
var ddosProtectionConfig = &ddosconfigs.ProtectionConfig{}
|
||||
err := json.Unmarshal(params.DdosProtectionJSON, ddosProtectionConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = ddosProtectionConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 校验参数
|
||||
if ddosProtectionConfig.TCP != nil {
|
||||
var tcpConfig = ddosProtectionConfig.TCP
|
||||
if tcpConfig.MaxConnectionsPerIP > 0 && tcpConfig.MaxConnectionsPerIP < nodeconfigs.DefaultTCPMinConnectionsPerIP {
|
||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||
}
|
||||
|
||||
if tcpConfig.NewConnectionsRate > 0 && tcpConfig.NewConnectionsRate < nodeconfigs.DefaultTCPNewConnectionsMinRate {
|
||||
this.FailField("tcpNewConnectionsRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinRate))
|
||||
}
|
||||
|
||||
// Port
|
||||
for _, portConfig := range tcpConfig.Ports {
|
||||
if portConfig.Port > 65535 {
|
||||
this.Fail("端口号" + types.String(portConfig.Port) + "不能大于65535")
|
||||
}
|
||||
}
|
||||
|
||||
// IP
|
||||
for _, ipConfig := range tcpConfig.AllowIPList {
|
||||
if net.ParseIP(ipConfig.IP) == nil {
|
||||
this.Fail("白名单IP '" + ipConfig.IP + "' 格式错误")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterDDoSProtection(this.AdminContext(), &pb.UpdateNodeClusterDDoSProtectionRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
DdosProtectionJSON: params.DdosProtectionJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ddosProtection
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type StatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatusAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("ddosProtection")
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeCheckLocalFirewall, &messageconfigs.CheckLocalFirewallMessage{
|
||||
Name: "nftables",
|
||||
}, 10)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var resultMaps = []maps.Map{}
|
||||
for _, result := range results {
|
||||
var resultMap = maps.Map{
|
||||
"isOk": result.IsOK,
|
||||
"message": result.Message,
|
||||
"nodeId": result.NodeId,
|
||||
"nodeName": result.NodeName,
|
||||
}
|
||||
|
||||
nodeResp, err := this.RPC().NodeRPC().FindNodeDDoSProtection(this.AdminContext(), &pb.FindNodeDDoSProtectionRequest{NodeId: result.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(nodeResp.DdosProtectionJSON) > 0 {
|
||||
var ddosProtection = ddosconfigs.DefaultProtectionConfig()
|
||||
err = json.Unmarshal(nodeResp.DdosProtectionJSON, ddosProtection)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resultMap["isPrior"] = !ddosProtection.IsPriorEmpty()
|
||||
}
|
||||
resultMaps = append(resultMaps, resultMap)
|
||||
}
|
||||
|
||||
this.Data["results"] = resultMaps
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
)
|
||||
|
||||
type RandomNameAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RandomNameAction) RunPost(params struct{}) {
|
||||
this.Data["name"] = "cluster" + rands.HexString(8)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -34,6 +34,8 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
// ipset
|
||||
IpsetWhiteName string
|
||||
IpsetBlackName string
|
||||
IpsetWhiteNameIPv6 string
|
||||
IpsetBlackNameIPv6 string
|
||||
IpsetAutoAddToIPTables bool
|
||||
IpsetAutoAddToFirewalld bool
|
||||
|
||||
@@ -49,7 +51,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("创建WAF动作")
|
||||
defer this.CreateLogInfo("创建集群 %d 的WAF动作", params.ClusterId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
@@ -66,11 +68,19 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
|
||||
Field("ipsetBlackName", params.IpsetBlackName).
|
||||
Require("请输入IPSet黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet黑名单名称")
|
||||
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
|
||||
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
|
||||
Require("请输入IPSet IPv6白名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
|
||||
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
|
||||
Require("请输入IPSet IPv6黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
|
||||
|
||||
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
|
||||
WhiteName: params.IpsetWhiteName,
|
||||
BlackName: params.IpsetBlackName,
|
||||
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
|
||||
BlackNameIPv6: params.IpsetBlackNameIPv6,
|
||||
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
|
||||
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
// ipset
|
||||
IpsetWhiteName string
|
||||
IpsetBlackName string
|
||||
IpsetWhiteNameIPv6 string
|
||||
IpsetBlackNameIPv6 string
|
||||
IpsetAutoAddToIPTables bool
|
||||
IpsetAutoAddToFirewalld bool
|
||||
|
||||
@@ -95,11 +97,19 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
|
||||
Field("ipsetBlackName", params.IpsetBlackName).
|
||||
Require("请输入IPSet黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet黑名单名称")
|
||||
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
|
||||
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
|
||||
Require("请输入IPSet IPv6白名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
|
||||
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
|
||||
Require("请输入IPSet IPv6黑名单名称").
|
||||
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
|
||||
|
||||
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
|
||||
WhiteName: params.IpsetWhiteName,
|
||||
BlackName: params.IpsetBlackName,
|
||||
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
|
||||
BlackNameIPv6: params.IpsetBlackNameIPv6,
|
||||
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
|
||||
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
|
||||
}
|
||||
|
||||
@@ -66,34 +66,31 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Data["timeZoneLocation"] = nodeconfigs.FindTimeZoneLocation(cluster.TimeZone)
|
||||
|
||||
this.Data["cluster"] = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
"timeZone": cluster.TimeZone,
|
||||
"nodeMaxThreads": cluster.NodeMaxThreads,
|
||||
"nodeTCPMaxConnections": cluster.NodeTCPMaxConnections,
|
||||
"autoOpenPorts": cluster.AutoOpenPorts,
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
"timeZone": cluster.TimeZone,
|
||||
"nodeMaxThreads": cluster.NodeMaxThreads,
|
||||
"autoOpenPorts": cluster.AutoOpenPorts,
|
||||
}
|
||||
|
||||
// 默认值
|
||||
this.Data["defaultNodeMaxThreads"] = nodeconfigs.DefaultMaxThreads
|
||||
this.Data["defaultNodeMaxThreadsMin"] = nodeconfigs.DefaultMaxThreadsMin
|
||||
this.Data["defaultNodeMaxThreadsMax"] = nodeconfigs.DefaultMaxThreadsMax
|
||||
this.Data["defaultNodeTCPMaxConnections"] = nodeconfigs.DefaultTCPMaxConnections
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// RunPost 保存设置
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
GrantId int64
|
||||
InstallDir string
|
||||
TimeZone string
|
||||
NodeMaxThreads int32
|
||||
NodeTCPMaxConnections int32
|
||||
AutoOpenPorts bool
|
||||
ClusterId int64
|
||||
Name string
|
||||
GrantId int64
|
||||
InstallDir string
|
||||
TimeZone string
|
||||
NodeMaxThreads int32
|
||||
AutoOpenPorts bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -112,14 +109,13 @@ func (this *IndexAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeCluster(this.AdminContext(), &pb.UpdateNodeClusterRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
NodeGrantId: params.GrantId,
|
||||
InstallDir: params.InstallDir,
|
||||
TimeZone: params.TimeZone,
|
||||
NodeMaxThreads: params.NodeMaxThreads,
|
||||
NodeTCPMaxConnections: params.NodeTCPMaxConnections,
|
||||
AutoOpenPorts: params.AutoOpenPorts,
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
NodeGrantId: params.GrantId,
|
||||
InstallDir: params.InstallDir,
|
||||
TimeZone: params.TimeZone,
|
||||
NodeMaxThreads: params.NodeMaxThreads,
|
||||
AutoOpenPorts: params.AutoOpenPorts,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -3,6 +3,7 @@ package settings
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/cache"
|
||||
ddosProtection "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/ddos-protection"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/dns"
|
||||
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"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"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"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/webp"
|
||||
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
@@ -38,6 +40,7 @@ func init() {
|
||||
// DNS
|
||||
Prefix("/clusters/cluster/settings/dns").
|
||||
GetPost("", new(dns.IndexAction)).
|
||||
Post("/randomName", new(dns.RandomNameAction)).
|
||||
|
||||
// 消息
|
||||
Prefix("/clusters/cluster/settings/message").
|
||||
@@ -74,6 +77,16 @@ func init() {
|
||||
GetPost("/createPopup", new(metrics.CreatePopupAction)).
|
||||
Post("/delete", new(metrics.DeleteAction)).
|
||||
|
||||
// WebP
|
||||
Prefix("/clusters/cluster/settings/webp").
|
||||
GetPost("", new(webp.IndexAction)).
|
||||
|
||||
// DDOS Protection
|
||||
Prefix("/clusters/cluster/settings/ddos-protection").
|
||||
GetPost("", new(ddosProtection.IndexAction)).
|
||||
GetPost("/status", new(ddosProtection.StatusAction)).
|
||||
|
||||
//
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package webp
|
||||
|
||||
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/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("webp")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
webpResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterWebPPolicy(this.AdminContext(), &pb.FindEnabledNodeClusterWebPPolicyRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(webpResp.WebpPolicyJSON) == 0 {
|
||||
this.Data["webpPolicy"] = nodeconfigs.DefaultWebPImagePolicy
|
||||
} else {
|
||||
var config = &nodeconfigs.WebPImagePolicy{}
|
||||
err = json.Unmarshal(webpResp.WebpPolicyJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["webpPolicy"] = config
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
RequireCache bool
|
||||
MinLengthJSON []byte
|
||||
MaxLengthJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改集群 %d 的WebP设置", params.ClusterId)
|
||||
|
||||
var config = &nodeconfigs.WebPImagePolicy{
|
||||
IsOn: params.IsOn,
|
||||
RequireCache: params.RequireCache,
|
||||
}
|
||||
|
||||
if len(params.MinLengthJSON) > 0 {
|
||||
var minLength = &shared.SizeCapacity{}
|
||||
err := json.Unmarshal(params.MinLengthJSON, minLength)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
config.MinLength = minLength
|
||||
}
|
||||
|
||||
if len(params.MaxLengthJSON) > 0 {
|
||||
var maxLength = &shared.SizeCapacity{}
|
||||
err := json.Unmarshal(params.MaxLengthJSON, maxLength)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
config.MaxLength = maxLength
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterWebPPolicy(this.AdminContext(), &pb.UpdateNodeClusterWebPPolicyRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
WebpPolicyJSON: configJSON,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type UpdateNodeSSHAction struct {
|
||||
@@ -31,7 +33,7 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
node := nodeResp.Node
|
||||
var node = nodeResp.Node
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -43,7 +45,7 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// SSH
|
||||
loginParams := maps.Map{
|
||||
var loginParams = maps.Map{
|
||||
"host": "",
|
||||
"port": "",
|
||||
"grantId": 0,
|
||||
@@ -59,10 +61,22 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(loginParams.GetString("host")) == 0 {
|
||||
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{NodeId: node.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(addressesResp.NodeIPAddresses) > 0 {
|
||||
loginParams["host"] = addressesResp.NodeIPAddresses[0].Ip
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["params"] = loginParams
|
||||
|
||||
// 认证信息
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
var grantId = loginParams.GetInt64("grantId")
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -101,7 +115,12 @@ func (this *UpdateNodeSSHAction) RunPost(params struct {
|
||||
this.Fail("需要选择或填写至少一个认证信息")
|
||||
}
|
||||
|
||||
login := &pb.NodeLogin{
|
||||
// 检查IP地址
|
||||
if regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+$`).MatchString(params.SshHost) && net.ParseIP(params.SshHost) == nil {
|
||||
this.Fail("SSH主机地址 '" + params.SshHost + "' IP格式错误")
|
||||
}
|
||||
|
||||
var login = &pb.NodeLogin{
|
||||
Id: params.LoginId,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 单个集群的帮助
|
||||
// ClusterHelper 单个集群的帮助
|
||||
type ClusterHelper struct {
|
||||
}
|
||||
|
||||
@@ -65,18 +65,23 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
||||
tabbar.Add("集群节点", "", "/clusters/cluster/nodes?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
||||
tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
|
||||
tabbar.Add("删除集群", "", "/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete")
|
||||
|
||||
{
|
||||
m := tabbar.Add("当前集群:"+cluster.Name, "", "/clusters/cluster?clusterId="+clusterIdString, "", false)
|
||||
m["right"] = true
|
||||
}
|
||||
actionutils.SetTabbar(action, tabbar)
|
||||
|
||||
// 左侧菜单
|
||||
secondMenuItem := action.Data.GetString("secondMenuItem")
|
||||
switch selectedTabbar {
|
||||
case "setting":
|
||||
action.Data["leftMenuItems"] = this.createSettingMenu(cluster, clusterInfo, secondMenuItem)
|
||||
var menuItems = this.createSettingMenu(cluster, clusterInfo, secondMenuItem)
|
||||
action.Data["leftMenuItems"] = menuItems
|
||||
|
||||
// 当前菜单
|
||||
action.Data["leftMenuActiveItem"] = nil
|
||||
for _, item := range menuItems {
|
||||
if item.GetBool("isActive") {
|
||||
action.Data["leftMenuActiveItem"] = item
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +95,7 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
|
||||
"name": "基础设置",
|
||||
"url": "/clusters/cluster/settings?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "basic",
|
||||
"isOn": true,
|
||||
})
|
||||
items = append(items, maps.Map{
|
||||
"name": "缓存设置",
|
||||
@@ -111,6 +117,13 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
|
||||
"isOn": info != nil && info.HasFirewallActions,
|
||||
})
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "DDoS防护",
|
||||
"url": "/clusters/cluster/settings/ddos-protection?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "ddosProtection",
|
||||
"isOn": info != nil && info.HasDDoSProtection,
|
||||
})
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "健康检查",
|
||||
"url": "/clusters/cluster/settings/health?clusterId=" + clusterId,
|
||||
@@ -124,6 +137,17 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
|
||||
"isActive": selectedItem == "dns",
|
||||
"isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0,
|
||||
})
|
||||
items = append(items, maps.Map{
|
||||
"name": "WebP",
|
||||
"url": "/clusters/cluster/settings/webp?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "webp",
|
||||
"isOn": info != nil && info.WebpIsOn,
|
||||
})
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "-",
|
||||
})
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "统计指标",
|
||||
"url": "/clusters/cluster/settings/metrics?clusterId=" + clusterId,
|
||||
@@ -157,6 +181,7 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
|
||||
"name": "系统服务",
|
||||
"url": "/clusters/cluster/settings/services?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "service",
|
||||
"isOn": info != nil && info.HasSystemServices,
|
||||
})
|
||||
{
|
||||
items = append(items, maps.Map{
|
||||
|
||||
@@ -27,6 +27,22 @@ func (this *CreateAction) RunGet(params struct{}) {
|
||||
}
|
||||
this.Data["hasDomains"] = hasDomainsResp.Exist
|
||||
|
||||
// 菜单:集群总数
|
||||
totalResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["totalNodeClusters"] = totalResp.Count
|
||||
|
||||
// 菜单:节点总数
|
||||
totalNodesResp, err := this.RPC().NodeRPC().CountAllEnabledNodes(this.AdminContext(), &pb.CountAllEnabledNodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["totalNodes"] = totalNodesResp.Count
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -24,11 +21,27 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
SearchType string
|
||||
}) {
|
||||
isSearching := len(params.Keyword) > 0
|
||||
var isSearching = len(params.Keyword) > 0
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["searchType"] = params.SearchType
|
||||
this.Data["isSearching"] = isSearching
|
||||
|
||||
// 集群总数
|
||||
totalClustersResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["totalNodeClusters"] = totalClustersResp.Count
|
||||
|
||||
// 节点总数
|
||||
totalNodesResp, err := this.RPC().NodeRPC().CountAllEnabledNodes(this.AdminContext(), &pb.CountAllEnabledNodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["totalNodes"] = totalNodesResp.Count
|
||||
|
||||
// 常用的集群
|
||||
latestClusterMaps := []maps.Map{}
|
||||
if !isSearching {
|
||||
@@ -46,12 +59,6 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["latestClusters"] = latestClusterMaps
|
||||
|
||||
// 搜索节点
|
||||
if params.SearchType == "node" && len(params.Keyword) > 0 {
|
||||
this.searchNodes(params.Keyword)
|
||||
return
|
||||
}
|
||||
|
||||
// 搜索集群
|
||||
countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{
|
||||
Keyword: params.Keyword,
|
||||
@@ -137,6 +144,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
"dnsDomainName": dnsDomainName,
|
||||
"countServers": countServersResp.Count,
|
||||
"timeZone": cluster.TimeZone,
|
||||
"isPinned": cluster.IsPinned,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -157,149 +165,3 @@ func (this *IndexAction) RunGet(params struct {
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) searchNodes(keyword string) {
|
||||
// 搜索节点
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
Keyword: keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
this.Data["countNodes"] = count
|
||||
|
||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), &pb.ListEnabledNodesMatchRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
nodeMaps := []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
isSynced := false
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
isSynced = status.ConfigVersion == node.Version
|
||||
}
|
||||
|
||||
// IP
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: node.Id,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
ipAddresses := []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||
ipAddresses = append(ipAddresses, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isOn": addr.IsOn,
|
||||
"isUp": addr.IsUp,
|
||||
})
|
||||
}
|
||||
|
||||
// 分组
|
||||
var groupMap maps.Map = nil
|
||||
if node.NodeGroup != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.NodeGroup.Id,
|
||||
"name": node.NodeGroup.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 区域
|
||||
var regionMap maps.Map = nil
|
||||
if node.NodeRegion != nil {
|
||||
regionMap = maps.Map{
|
||||
"id": node.NodeRegion.Id,
|
||||
"name": node.NodeRegion.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// DNS
|
||||
dnsRouteNames := []string{}
|
||||
for _, route := range node.DnsRoutes {
|
||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||
}
|
||||
|
||||
// 从集群
|
||||
var secondaryClusterMaps []maps.Map
|
||||
for _, secondaryCluster := range node.SecondaryNodeClusters {
|
||||
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||
"id": secondaryCluster.Id,
|
||||
"name": secondaryCluster.Name,
|
||||
"isOn": secondaryCluster.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"isOn": node.IsOn,
|
||||
"isUp": node.IsUp,
|
||||
"installStatus": maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"error": node.InstallStatus.Error,
|
||||
},
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
},
|
||||
"cluster": maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
},
|
||||
"secondaryClusters": secondaryClusterMaps,
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
this.Data["clusters"] = []maps.Map{}
|
||||
|
||||
// 搜索集群
|
||||
{
|
||||
countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{
|
||||
Keyword: keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countClusters"] = countResp.Count
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ func init() {
|
||||
Prefix("/clusters").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/create", new(CreateAction)).
|
||||
Post("/pin", new(PinAction)).
|
||||
Get("/nodes", new(NodesAction)).
|
||||
|
||||
// 只要登录即可访问的Action
|
||||
EndHelpers().
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package servers
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FixLogAction struct {
|
||||
type FixAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *FixLogAction) RunPost(params struct {
|
||||
func (this *FixAction) RunPost(params struct {
|
||||
LogIds []int64
|
||||
}) {
|
||||
var logIdStrings = []string{}
|
||||
for _, logId := range params.LogIds {
|
||||
logIdStrings = append(logIdStrings, types.String(logId))
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo("设置日志 %s 为已修复", strings.Join(logIdStrings, ", "))
|
||||
|
||||
_, err := this.RPC().NodeLogRPC().FixNodeLogs(this.AdminContext(), &pb.FixNodeLogsRequest{NodeLogIds: params.LogIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -1,22 +1,21 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
type FixAllAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
KeyId int64
|
||||
func (this *FixAllAction) RunPost(params struct {
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除DNS密钥 %d", params.KeyId)
|
||||
defer this.CreateLogInfo("设置所有日志为已修复")
|
||||
|
||||
_, err := this.RPC().NSKeyRPC().DeleteNSKey(this.AdminContext(), &pb.DeleteNSKeyRequest{NsKeyId: params.KeyId})
|
||||
_, err := this.RPC().NodeLogRPC().FixAllNodeLogs(this.AdminContext(), &pb.FixAllNodeLogsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -3,8 +3,10 @@ package logs
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
@@ -14,8 +16,11 @@ type IndexAction struct {
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
if this.ParamString("type") == "unread" {
|
||||
var paramType = this.ParamString("type")
|
||||
if paramType == "unread" {
|
||||
this.FirstMenu("unread")
|
||||
} else if paramType == "needFix" {
|
||||
this.FirstMenu("needFix")
|
||||
} else {
|
||||
this.FirstMenu("index")
|
||||
}
|
||||
@@ -26,7 +31,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
Type string
|
||||
Type string // unread, needFix
|
||||
Tag string
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
@@ -40,6 +45,13 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
var fixedState configutils.BoolState = 0
|
||||
var allServers = false
|
||||
if params.Type == "needFix" {
|
||||
fixedState = configutils.BoolStateNo
|
||||
allServers = true
|
||||
}
|
||||
|
||||
// 常见标签
|
||||
this.Data["tags"] = nodelogutils.FindNodeCommonTags()
|
||||
|
||||
@@ -54,6 +66,18 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["countUnreadLogs"] = countUnreadResp.Count
|
||||
|
||||
// 需要修复数量
|
||||
countNeedFixResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
AllServers: true,
|
||||
FixedState: int32(configutils.BoolStateNo),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countNeedFixLogs"] = countNeedFixResp.Count
|
||||
|
||||
// 日志数量
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
@@ -65,13 +89,15 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Level: params.Level,
|
||||
IsUnread: params.Type == "unread",
|
||||
Tag: params.Tag,
|
||||
FixedState: int32(fixedState),
|
||||
AllServers: allServers,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||
@@ -84,6 +110,8 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Level: params.Level,
|
||||
IsUnread: params.Type == "unread",
|
||||
Tag: params.Tag,
|
||||
FixedState: int32(fixedState),
|
||||
AllServers: allServers,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
@@ -92,14 +120,14 @@ func (this *IndexAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
logs := []maps.Map{}
|
||||
var logs = []maps.Map{}
|
||||
for _, log := range logsResp.NodeLogs {
|
||||
// 节点信息
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: log.NodeId})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
node := nodeResp.Node
|
||||
var node = nodeResp.Node
|
||||
if node == nil || node.NodeCluster == nil {
|
||||
continue
|
||||
}
|
||||
@@ -118,6 +146,11 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
var isFixed = true
|
||||
if !log.IsFixed && log.ServerId > 0 && lists.ContainsString([]string{"success", "warning", "error"}, log.Level) {
|
||||
isFixed = false
|
||||
}
|
||||
|
||||
logs = append(logs, maps.Map{
|
||||
"id": log.Id,
|
||||
"tag": log.Tag,
|
||||
@@ -127,6 +160,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
|
||||
"count": log.Count,
|
||||
"isRead": log.IsRead,
|
||||
"isFixed": isFixed,
|
||||
"node": maps.Map{
|
||||
"id": node.Id,
|
||||
"cluster": maps.Map{
|
||||
|
||||
@@ -16,6 +16,8 @@ func init() {
|
||||
Get("", new(IndexAction)).
|
||||
Post("/readLogs", new(ReadLogsAction)).
|
||||
Post("/readAllLogs", new(ReadAllLogsAction)).
|
||||
Post("/fix", new(FixAction)).
|
||||
Post("/fixAll", new(FixAllAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct{}) {
|
||||
resp, err := this.RPC().ReportNodeGroupRPC().FindAllEnabledReportNodeGroups(this.AdminContext(), &pb.FindAllEnabledReportNodeGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var groupMaps = []maps.Map{}
|
||||
for _, group := range resp.ReportNodeGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
293
internal/web/actions/default/clusters/nodes.go
Normal file
293
internal/web/actions/default/clusters/nodes.go
Normal file
@@ -0,0 +1,293 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"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/pb"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NodesAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *NodesAction) Init() {
|
||||
this.Nav("", "", "node")
|
||||
}
|
||||
|
||||
func (this *NodesAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
InstalledState int
|
||||
ActiveState int
|
||||
Keyword string
|
||||
Level int32
|
||||
|
||||
CpuOrder string
|
||||
MemoryOrder string
|
||||
TrafficInOrder string
|
||||
TrafficOutOrder string
|
||||
LoadOrder string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["regionId"] = params.RegionId
|
||||
this.Data["installState"] = params.InstalledState
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["hasOrder"] = len(params.CpuOrder) > 0 || len(params.MemoryOrder) > 0 || len(params.TrafficInOrder) > 0 || len(params.TrafficOutOrder) > 0 || len(params.LoadOrder) > 0
|
||||
|
||||
// 集群是否已经设置了线路
|
||||
clusterDNSResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["hasClusterDNS"] = clusterDNSResp.Domain != nil
|
||||
|
||||
// 数量
|
||||
countAllResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countAll"] = countAllResp.Count
|
||||
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Level: params.Level,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
var req = &pb.ListEnabledNodesMatchRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Level: params.Level,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
}
|
||||
if params.CpuOrder == "asc" {
|
||||
req.CpuAsc = true
|
||||
} else if params.CpuOrder == "desc" {
|
||||
req.CpuDesc = true
|
||||
} else if params.MemoryOrder == "asc" {
|
||||
req.MemoryAsc = true
|
||||
} else if params.MemoryOrder == "desc" {
|
||||
req.MemoryDesc = true
|
||||
} else if params.TrafficInOrder == "asc" {
|
||||
req.TrafficInAsc = true
|
||||
} else if params.TrafficInOrder == "desc" {
|
||||
req.TrafficInDesc = true
|
||||
} else if params.TrafficOutOrder == "asc" {
|
||||
req.TrafficOutAsc = true
|
||||
} else if params.TrafficOutOrder == "desc" {
|
||||
req.TrafficOutDesc = true
|
||||
} else if params.LoadOrder == "asc" {
|
||||
req.LoadAsc = true
|
||||
} else if params.LoadOrder == "desc" {
|
||||
req.LoadDesc = true
|
||||
}
|
||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), req)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
isSynced := false
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
continue
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
isSynced = status.ConfigVersion == node.Version
|
||||
}
|
||||
|
||||
// IP
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: node.Id,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
ipAddresses := []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||
ipAddresses = append(ipAddresses, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isUp": addr.IsUp,
|
||||
"isOn": addr.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
// 分组
|
||||
var groupMap maps.Map = nil
|
||||
if node.NodeGroup != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.NodeGroup.Id,
|
||||
"name": node.NodeGroup.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 区域
|
||||
var regionMap maps.Map = nil
|
||||
if node.NodeRegion != nil {
|
||||
regionMap = maps.Map{
|
||||
"id": node.NodeRegion.Id,
|
||||
"name": node.NodeRegion.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// DNS
|
||||
dnsRouteNames := []string{}
|
||||
for _, route := range node.DnsRoutes {
|
||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||
}
|
||||
|
||||
// 从集群
|
||||
var secondaryClusterMaps []maps.Map
|
||||
for _, secondaryCluster := range node.SecondaryNodeClusters {
|
||||
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||
"id": secondaryCluster.Id,
|
||||
"name": secondaryCluster.Name,
|
||||
"isOn": secondaryCluster.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"isOn": node.IsOn,
|
||||
"isUp": node.IsUp,
|
||||
"installStatus": maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"error": node.InstallStatus.Error,
|
||||
},
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": numberutils.FormatFloat2(status.CPUUsage * 100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": numberutils.FormatFloat2(status.MemoryUsage * 100),
|
||||
"trafficInBytes": status.TrafficInBytes,
|
||||
"trafficOutBytes": status.TrafficOutBytes,
|
||||
"load1m": numberutils.FormatFloat2(status.Load1m),
|
||||
},
|
||||
"cluster": maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
},
|
||||
"secondaryClusters": secondaryClusterMaps,
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
"level": node.Level,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
// 所有分组
|
||||
var groupMaps = []maps.Map{}
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, group := range groupsResp.NodeGroups {
|
||||
countNodesInGroupResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countNodes := countNodesInGroupResp.Count
|
||||
groupName := group.Name
|
||||
if countNodes > 0 {
|
||||
groupName += "(" + strconv.FormatInt(countNodes, 10) + ")"
|
||||
}
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": groupName,
|
||||
"countNodes": countNodes,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
// 所有区域
|
||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var regionMaps = []maps.Map{}
|
||||
for _, region := range regionsResp.NodeRegions {
|
||||
regionMaps = append(regionMaps, maps.Map{
|
||||
"id": region.Id,
|
||||
"name": region.Name,
|
||||
})
|
||||
}
|
||||
this.Data["regions"] = regionMaps
|
||||
|
||||
// 级别
|
||||
this.Data["levels"] = []maps.Map{}
|
||||
if teaconst.IsPlus {
|
||||
this.Data["levels"] = nodeconfigs.FindAllNodeLevels()
|
||||
}
|
||||
|
||||
// 集群总数
|
||||
totalClustersResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["totalNodeClusters"] = totalClustersResp.Count
|
||||
|
||||
// 节点总数
|
||||
this.Data["totalNodes"] = countResp.Count
|
||||
|
||||
this.Show()
|
||||
}
|
||||
34
internal/web/actions/default/clusters/pin.go
Normal file
34
internal/web/actions/default/clusters/pin.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type PinAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *PinAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
IsPinned bool
|
||||
}) {
|
||||
if params.IsPinned {
|
||||
defer this.CreateLogInfo("置顶集群 %d", params.ClusterId)
|
||||
} else {
|
||||
defer this.CreateLogInfo("取消置顶集群 %d", params.ClusterId)
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterPinned(this.AdminContext(), &pb.UpdateNodeClusterPinnedRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
IsPinned: params.IsPinned,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -35,11 +35,11 @@ func (this *SelectPopupAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
page.Size = 6
|
||||
var pageSize int64 = 6
|
||||
if params.PageSize > 0 {
|
||||
page.Size = params.PageSize
|
||||
pageSize = params.PageSize
|
||||
}
|
||||
var page = this.NewPage(count, pageSize)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{
|
||||
|
||||
@@ -3,14 +3,20 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/sizes"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"regexp"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -57,6 +63,14 @@ func (this *IndexAction) RunPost(params struct{}) {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查当前服务器空间
|
||||
var diskUsageWarning = ""
|
||||
diskPath, diskUsage, diskUsagePercent, shouldWarning := this.checkDiskPartitions(90)
|
||||
if shouldWarning {
|
||||
diskUsageWarning = "当前服务器磁盘空间不足,请立即扩充容量,文件路径:" + diskPath + ",已使用:" + types.String(diskUsage/1024/1024/1024) + "G,已使用比例:" + fmt.Sprintf("%.2f%%", diskUsagePercent) + ",仅剩余空间:" + fmt.Sprintf("%.2f%%", 100-diskUsagePercent) + "。"
|
||||
}
|
||||
|
||||
this.Data["dashboard"] = maps.Map{
|
||||
"defaultClusterId": resp.DefaultNodeClusterId,
|
||||
|
||||
@@ -75,6 +89,8 @@ func (this *IndexAction) RunPost(params struct{}) {
|
||||
"canGoNodes": configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeNode),
|
||||
"canGoSettings": configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeSetting),
|
||||
"canGoUsers": configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeUser),
|
||||
|
||||
"diskUsageWarning": diskUsageWarning,
|
||||
}
|
||||
|
||||
// 今日流量
|
||||
@@ -249,3 +265,47 @@ func (this *IndexAction) RunPost(params struct{}) {
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
// 检查服务器磁盘空间
|
||||
func (this *IndexAction) checkDiskPartitions(thresholdPercent float64) (path string, usage uint64, usagePercent float64, shouldWarning bool) {
|
||||
partitions, err := disk.Partitions(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !lists.ContainsString([]string{"darwin", "linux", "freebsd"}, runtime.GOOS) {
|
||||
return
|
||||
}
|
||||
|
||||
var rootFS = ""
|
||||
|
||||
for _, p := range partitions {
|
||||
if p.Mountpoint == "/" {
|
||||
rootFS = p.Fstype
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range partitions {
|
||||
if p.Mountpoint == "/boot" {
|
||||
continue
|
||||
}
|
||||
if p.Fstype != rootFS {
|
||||
continue
|
||||
}
|
||||
stat, _ := disk.Usage(p.Mountpoint)
|
||||
if stat != nil {
|
||||
if stat.Used < 2*uint64(sizes.G) {
|
||||
continue
|
||||
}
|
||||
if stat.UsedPercent > thresholdPercent {
|
||||
path = stat.Path
|
||||
usage = stat.Used
|
||||
usagePercent = stat.UsedPercent
|
||||
shouldWarning = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package providers
|
||||
|
||||
import (
|
||||
@@ -60,12 +65,14 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Type string
|
||||
|
||||
// DNSPod
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamRegion string
|
||||
|
||||
// AliDNS
|
||||
ParamAccessKeyId string
|
||||
ParamAccessKeySecret string
|
||||
ParamAliDNSAccessKeyId string
|
||||
ParamAliDNSAccessKeySecret string
|
||||
ParamAliDNSRegionId string
|
||||
|
||||
// HuaweiDNS
|
||||
ParamHuaweiAccessKeyId string
|
||||
@@ -76,8 +83,8 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
ParamApiSecret string
|
||||
|
||||
// CloudFlare
|
||||
CloudFlareAPIKey string
|
||||
CloudFlareEmail string
|
||||
ParamCloudFlareAPIKey string
|
||||
ParamCloudFlareEmail string
|
||||
|
||||
// Local EdgeDNS
|
||||
ParamLocalEdgeDNSClusterId int64
|
||||
@@ -106,15 +113,17 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
|
||||
apiParams["id"] = params.ParamId
|
||||
apiParams["token"] = params.ParamToken
|
||||
apiParams["region"] = params.ParamRegion
|
||||
case "alidns":
|
||||
params.Must.
|
||||
Field("paramAccessKeyId", params.ParamAccessKeyId).
|
||||
Field("paramAliDNSAccessKeyId", params.ParamAliDNSAccessKeyId).
|
||||
Require("请输入AccessKeyId").
|
||||
Field("paramAccessKeySecret", params.ParamAccessKeySecret).
|
||||
Field("paramAliDNSAccessKeySecret", params.ParamAliDNSAccessKeySecret).
|
||||
Require("请输入AccessKeySecret")
|
||||
|
||||
apiParams["accessKeyId"] = params.ParamAccessKeyId
|
||||
apiParams["accessKeySecret"] = params.ParamAccessKeySecret
|
||||
apiParams["accessKeyId"] = params.ParamAliDNSAccessKeyId
|
||||
apiParams["accessKeySecret"] = params.ParamAliDNSAccessKeySecret
|
||||
apiParams["regionId"] = params.ParamAliDNSRegionId
|
||||
case "huaweiDNS":
|
||||
params.Must.
|
||||
Field("paramHuaweiAccessKeyId", params.ParamHuaweiAccessKeyId).
|
||||
@@ -135,12 +144,12 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
apiParams["apiSecret"] = params.ParamApiSecret
|
||||
case "cloudFlare":
|
||||
params.Must.
|
||||
Field("cloudFlareAPIKey", params.CloudFlareAPIKey).
|
||||
Field("paramCloudFlareAPIKey", params.ParamCloudFlareAPIKey).
|
||||
Require("请输入API密钥").
|
||||
Field("cloudFlareEmail", params.CloudFlareEmail).
|
||||
Field("paramCloudFlareEmail", params.ParamCloudFlareEmail).
|
||||
Email("请输入正确格式的邮箱地址")
|
||||
apiParams["apiKey"] = params.CloudFlareAPIKey
|
||||
apiParams["email"] = params.CloudFlareEmail
|
||||
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
||||
apiParams["email"] = params.ParamCloudFlareEmail
|
||||
case "localEdgeDNS":
|
||||
params.Must.
|
||||
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -16,13 +18,24 @@ func (this *IndexAction) Init() {
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
Keyword string
|
||||
Domain string
|
||||
ProviderType string
|
||||
}) {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["domain"] = params.Domain
|
||||
this.Data["providerType"] = params.ProviderType
|
||||
|
||||
// 格式化域名
|
||||
var domain = params.Domain
|
||||
domain = regexp.MustCompile(`^(www\.)`).ReplaceAllString(params.Domain, "")
|
||||
domain = strings.ToLower(domain)
|
||||
|
||||
countResp, err := this.RPC().DNSProviderRPC().CountAllEnabledDNSProviders(this.AdminContext(), &pb.CountAllEnabledDNSProvidersRequest{
|
||||
AdminId: this.AdminId(),
|
||||
Keyword: params.Keyword,
|
||||
Domain: domain,
|
||||
Type: params.ProviderType,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -35,6 +48,8 @@ func (this *IndexAction) RunGet(params struct {
|
||||
providersResp, err := this.RPC().DNSProviderRPC().ListEnabledDNSProviders(this.AdminContext(), &pb.ListEnabledDNSProvidersRequest{
|
||||
AdminId: this.AdminId(),
|
||||
Keyword: params.Keyword,
|
||||
Domain: domain,
|
||||
Type: params.ProviderType,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
@@ -42,7 +57,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
providerMaps := []maps.Map{}
|
||||
var providerMaps = []maps.Map{}
|
||||
for _, provider := range providersResp.DnsProviders {
|
||||
dataUpdatedTime := ""
|
||||
if provider.DataUpdatedAt > 0 {
|
||||
@@ -50,7 +65,9 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 域名
|
||||
countDomainsResp, err := this.RPC().DNSDomainRPC().CountAllEnabledDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.CountAllEnabledDNSDomainsWithDNSProviderIdRequest{DnsProviderId: provider.Id})
|
||||
countDomainsResp, err := this.RPC().DNSDomainRPC().CountAllEnabledDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.CountAllEnabledDNSDomainsWithDNSProviderIdRequest{
|
||||
DnsProviderId: provider.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -68,5 +85,30 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["providers"] = providerMaps
|
||||
|
||||
// 类型
|
||||
typesResponse, err := this.RPC().DNSProviderRPC().FindAllDNSProviderTypes(this.AdminContext(), &pb.FindAllDNSProviderTypesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var providerTypeMaps = []maps.Map{}
|
||||
for _, providerType := range typesResponse.ProviderTypes {
|
||||
countProvidersWithTypeResp, err := this.RPC().DNSProviderRPC().CountAllEnabledDNSProviders(this.AdminContext(), &pb.CountAllEnabledDNSProvidersRequest{
|
||||
Type: providerType.Code,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countProvidersWithTypeResp.Count > 0 {
|
||||
providerTypeMaps = append(providerTypeMaps, maps.Map{
|
||||
"name": providerType.Name,
|
||||
"code": providerType.Code,
|
||||
"count": countProvidersWithTypeResp.Count,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["providerTypes"] = providerTypeMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package providers
|
||||
|
||||
import (
|
||||
@@ -89,12 +92,14 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
Type string
|
||||
|
||||
// DNSPod
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamRegion string
|
||||
|
||||
// AliDNS
|
||||
ParamAccessKeyId string
|
||||
ParamAccessKeySecret string
|
||||
ParamAliDNSAccessKeyId string
|
||||
ParamAliDNSAccessKeySecret string
|
||||
ParamAliDNSRegionId string
|
||||
|
||||
// HuaweiDNS
|
||||
ParamHuaweiAccessKeyId string
|
||||
@@ -105,8 +110,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
ParamApiSecret string
|
||||
|
||||
// CloudFlare
|
||||
CloudFlareAPIKey string
|
||||
CloudFlareEmail string
|
||||
ParamCloudFlareAPIKey string
|
||||
ParamCloudFlareEmail string
|
||||
|
||||
// Local EdgeDNS
|
||||
ParamLocalEdgeDNSClusterId int64
|
||||
@@ -137,15 +142,17 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
|
||||
apiParams["id"] = params.ParamId
|
||||
apiParams["token"] = params.ParamToken
|
||||
apiParams["region"] = params.ParamRegion
|
||||
case "alidns":
|
||||
params.Must.
|
||||
Field("paramAccessKeyId", params.ParamAccessKeyId).
|
||||
Field("paramAliDNSAccessKeyId", params.ParamAliDNSAccessKeyId).
|
||||
Require("请输入AccessKeyId").
|
||||
Field("paramAccessKeySecret", params.ParamAccessKeySecret).
|
||||
Field("paramAliDNSAccessKeySecret", params.ParamAliDNSAccessKeySecret).
|
||||
Require("请输入AccessKeySecret")
|
||||
|
||||
apiParams["accessKeyId"] = params.ParamAccessKeyId
|
||||
apiParams["accessKeySecret"] = params.ParamAccessKeySecret
|
||||
apiParams["accessKeyId"] = params.ParamAliDNSAccessKeyId
|
||||
apiParams["accessKeySecret"] = params.ParamAliDNSAccessKeySecret
|
||||
apiParams["regionId"] = params.ParamAliDNSRegionId
|
||||
case "huaweiDNS":
|
||||
params.Must.
|
||||
Field("paramHuaweiAccessKeyId", params.ParamHuaweiAccessKeyId).
|
||||
@@ -166,12 +173,12 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
apiParams["apiSecret"] = params.ParamApiSecret
|
||||
case "cloudFlare":
|
||||
params.Must.
|
||||
Field("cloudFlareAPIKey", params.CloudFlareAPIKey).
|
||||
Field("paramCloudFlareAPIKey", params.ParamCloudFlareAPIKey).
|
||||
Require("请输入API密钥").
|
||||
Field("cloudFlareEmail", params.CloudFlareEmail).
|
||||
Field("paramCloudFlareEmail", params.ParamCloudFlareEmail).
|
||||
Email("请输入正确格式的邮箱地址")
|
||||
apiParams["apiKey"] = params.CloudFlareAPIKey
|
||||
apiParams["email"] = params.CloudFlareEmail
|
||||
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
||||
apiParams["email"] = params.ParamCloudFlareEmail
|
||||
case "localEdgeDNS":
|
||||
params.Must.
|
||||
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).
|
||||
|
||||
@@ -27,7 +27,7 @@ func (this *ExportExcelAction) RunGet(params struct {
|
||||
}) {
|
||||
logsResp, err := this.RPC().LogRPC().ListLogs(this.AdminContext(), &pb.ListLogsRequest{
|
||||
Offset: 0,
|
||||
Size: 1000, // 日志最大导出1000条,TODO 将来可以配置
|
||||
Size: 10000, // 日志最大导出10000条,TODO 将来可以配置
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
@@ -38,7 +38,7 @@ func (this *ExportExcelAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
wb := xlsx.NewFile()
|
||||
var wb = xlsx.NewFile()
|
||||
sheet, err := wb.AddSheet("default")
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -47,7 +47,7 @@ func (this *ExportExcelAction) RunGet(params struct {
|
||||
|
||||
// 头部
|
||||
{
|
||||
row := sheet.AddRow()
|
||||
var row = sheet.AddRow()
|
||||
row.SetHeight(25)
|
||||
row.AddCell().SetString("ID")
|
||||
row.AddCell().SetString("日期")
|
||||
@@ -61,8 +61,8 @@ func (this *ExportExcelAction) RunGet(params struct {
|
||||
|
||||
// 数据
|
||||
for _, log := range logsResp.Logs {
|
||||
regionName := ""
|
||||
ispName := ""
|
||||
var regionName = ""
|
||||
var ispName = ""
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: log.Ip})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -86,7 +86,7 @@ func (this *ExportExcelAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
row := sheet.AddRow()
|
||||
var row = sheet.AddRow()
|
||||
row.SetHeight(25)
|
||||
row.AddCell().SetInt64(log.Id)
|
||||
row.AddCell().SetString(timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt))
|
||||
@@ -106,7 +106,7 @@ func (this *ExportExcelAction) RunGet(params struct {
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"LOG-"+timeutil.Format("YmdHis")+".xlsx\"")
|
||||
this.AddHeader("Cache-Control", "max-age=0")
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
var buf = bytes.NewBuffer([]byte{})
|
||||
err = wb.Write(buf)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -34,7 +34,10 @@ func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg
|
||||
}
|
||||
|
||||
// 获取所有节点
|
||||
nodesResp, err := defaultRPCClient.NodeRPC().FindAllEnabledNodesWithNodeClusterId(ctx, &pb.FindAllEnabledNodesWithNodeClusterIdRequest{NodeClusterId: clusterId})
|
||||
nodesResp, err := defaultRPCClient.NodeRPC().FindAllEnabledNodesWithNodeClusterId(ctx, &pb.FindAllEnabledNodesWithNodeClusterIdRequest{
|
||||
NodeClusterId: clusterId,
|
||||
IncludeSecondary: true,
|
||||
})
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
@@ -43,10 +46,10 @@ func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg
|
||||
return results, nil
|
||||
}
|
||||
|
||||
rpcMap := map[int64]*rpc.RPCClient{} // apiNodeId => RPCClient
|
||||
locker := &sync.Mutex{}
|
||||
var rpcMap = map[int64]*rpc.RPCClient{} // apiNodeId => RPCClient
|
||||
var locker = &sync.Mutex{}
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
var wg = &sync.WaitGroup{}
|
||||
wg.Add(len(nodes))
|
||||
|
||||
for _, node := range nodes {
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "node")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.NsNode
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
}
|
||||
|
||||
var clusterMap maps.Map = nil
|
||||
if node.NsCluster != nil {
|
||||
clusterId := node.NsCluster.Id
|
||||
clusterResp, err := this.RPC().NSClusterRPC().FindEnabledNSCluster(this.AdminContext(), &pb.FindEnabledNSClusterRequest{NsClusterId: clusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster := clusterResp.NsCluster
|
||||
if cluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IP地址
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
ipAddressMaps := []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isOn": addr.IsOn,
|
||||
"isUp": addr.IsUp,
|
||||
})
|
||||
}
|
||||
|
||||
// 运行状态
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
}
|
||||
|
||||
// 检查是否有新版本
|
||||
if len(status.OS) > 0 {
|
||||
checkVersionResp, err := this.RPC().NSNodeRPC().CheckNSNodeLatestVersion(this.AdminContext(), &pb.CheckNSNodeLatestVersionRequest{
|
||||
Os: status.OS,
|
||||
Arch: status.Arch,
|
||||
CurrentVersion: status.BuildVersion,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["shouldUpgrade"] = checkVersionResp.HasNewVersion
|
||||
this.Data["newVersion"] = checkVersionResp.NewVersion
|
||||
} else {
|
||||
this.Data["shouldUpgrade"] = false
|
||||
this.Data["newVersion"] = ""
|
||||
}
|
||||
|
||||
// 登录信息
|
||||
var loginMap maps.Map = nil
|
||||
if node.NodeLogin != nil {
|
||||
loginParams := maps.Map{}
|
||||
if len(node.NodeLogin.Params) > 0 {
|
||||
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
grantMap := maps.Map{}
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.NodeGrant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||
"username": grantResp.NodeGrant.Username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loginMap = maps.Map{
|
||||
"id": node.NodeLogin.Id,
|
||||
"name": node.NodeLogin.Name,
|
||||
"type": node.NodeLogin.Type,
|
||||
"params": loginParams,
|
||||
"grant": grantMap,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"installDir": node.InstallDir,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"uniqueId": node.UniqueId,
|
||||
"secret": node.Secret,
|
||||
"isOn": node.IsOn,
|
||||
|
||||
"status": maps.Map{
|
||||
"isActive": node.IsActive && status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"connectionCount": status.ConnectionCount,
|
||||
"buildVersion": status.BuildVersion,
|
||||
"cpuPhysicalCount": status.CPUPhysicalCount,
|
||||
"cpuLogicalCount": status.CPULogicalCount,
|
||||
"load1m": fmt.Sprintf("%.2f", status.Load1m),
|
||||
"load5m": fmt.Sprintf("%.2f", status.Load5m),
|
||||
"load15m": fmt.Sprintf("%.2f", status.Load15m),
|
||||
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
||||
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
||||
},
|
||||
|
||||
"login": loginMap,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// InstallAction 安装节点
|
||||
type InstallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallAction) Init() {
|
||||
this.Nav("", "node", "install")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *InstallAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
// 节点
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.NsNode
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
}
|
||||
|
||||
// 安装信息
|
||||
if node.InstallStatus != nil {
|
||||
this.Data["installStatus"] = maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"updatedAt": node.InstallStatus.UpdatedAt,
|
||||
"error": node.InstallStatus.Error,
|
||||
}
|
||||
} else {
|
||||
this.Data["installStatus"] = nil
|
||||
}
|
||||
|
||||
// 集群
|
||||
var clusterMap maps.Map = nil
|
||||
if node.NsCluster != nil {
|
||||
clusterId := node.NsCluster.Id
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster := clusterResp.NodeCluster
|
||||
if cluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API节点列表
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
apiNodes := apiNodesResp.ApiNodes
|
||||
apiEndpoints := []string{}
|
||||
for _, apiNode := range apiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||
}
|
||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"installDir": node.InstallDir,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"uniqueId": node.UniqueId,
|
||||
"secret": node.Secret,
|
||||
"cluster": clusterMap,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// RunPost 开始安装
|
||||
func (this *InstallAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo("安装节点 %d", params.NodeId)
|
||||
|
||||
_, err := this.RPC().NSNodeRPC().InstallNSNode(this.AdminContext(), &pb.InstallNSNodeRequest{
|
||||
NsNodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package node
|
||||
|
||||
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"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type LogsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *LogsAction) Init() {
|
||||
this.Nav("", "node", "log")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *LogsAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
DayFrom string
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["dayFrom"] = params.DayFrom
|
||||
this.Data["dayTo"] = params.DayTo
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
NodeId: params.NodeId,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count, 20)
|
||||
|
||||
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
logs := []maps.Map{}
|
||||
for _, log := range logsResp.NodeLogs {
|
||||
logs = append(logs, maps.Map{
|
||||
"tag": log.Tag,
|
||||
"description": log.Description,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
|
||||
"level": log.Level,
|
||||
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
|
||||
"count": log.Count,
|
||||
})
|
||||
}
|
||||
this.Data["logs"] = logs
|
||||
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StartAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StartAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NSNodeRPC().StartNSNode(this.AdminContext(), &pb.StartNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "远程启动节点 %d", params.NodeId)
|
||||
|
||||
if resp.IsOk {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
this.Fail("启动失败:" + resp.Error)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// StatusAction 节点状态
|
||||
type StatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
// 节点
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.NsNode
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
}
|
||||
|
||||
// 安装信息
|
||||
if node.InstallStatus != nil {
|
||||
this.Data["installStatus"] = maps.Map{
|
||||
"isRunning": node.InstallStatus.IsRunning,
|
||||
"isFinished": node.InstallStatus.IsFinished,
|
||||
"isOk": node.InstallStatus.IsOk,
|
||||
"updatedAt": node.InstallStatus.UpdatedAt,
|
||||
"error": node.InstallStatus.Error,
|
||||
"errorCode": node.InstallStatus.ErrorCode,
|
||||
}
|
||||
} else {
|
||||
this.Data["installStatus"] = nil
|
||||
}
|
||||
|
||||
this.Data["isInstalled"] = node.IsInstalled
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type StopAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StopAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NSNodeRPC().StopNSNode(this.AdminContext(), &pb.StopNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "远程停止节点 %d", params.NodeId)
|
||||
|
||||
if resp.IsOk {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
this.Fail("执行失败:" + resp.Error)
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"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("", "node", "update")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.NsNode
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
}
|
||||
|
||||
var clusterMap maps.Map = nil
|
||||
if node.NsCluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": node.NsCluster.Id,
|
||||
"name": node.NsCluster.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// IP地址
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
ipAddressMaps := []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isOn": addr.IsOn,
|
||||
"isUp": addr.IsUp,
|
||||
})
|
||||
}
|
||||
|
||||
// 登录信息
|
||||
var loginMap maps.Map = nil
|
||||
if node.NodeLogin != nil {
|
||||
loginParams := maps.Map{}
|
||||
if len(node.NodeLogin.Params) > 0 {
|
||||
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
grantMap := maps.Map{}
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.NodeGrant != nil {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
|
||||
"username": grantResp.NodeGrant.Username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loginMap = maps.Map{
|
||||
"id": node.NodeLogin.Id,
|
||||
"name": node.NodeLogin.Name,
|
||||
"type": node.NodeLogin.Type,
|
||||
"params": loginParams,
|
||||
"grant": grantMap,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"isOn": node.IsOn,
|
||||
"login": loginMap,
|
||||
}
|
||||
|
||||
// 所有集群
|
||||
resp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range resp.NsClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
LoginId int64
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
|
||||
NodeId int64
|
||||
Name string
|
||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||
ClusterId int64
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d", params.NodeId)
|
||||
|
||||
if params.NodeId <= 0 {
|
||||
this.Fail("要操作的节点不存在")
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入节点名称")
|
||||
|
||||
// 检查cluster
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择所在集群")
|
||||
}
|
||||
clusterResp, err := this.RPC().NSClusterRPC().FindEnabledNSCluster(this.AdminContext(), &pb.FindEnabledNSClusterRequest{NsClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if clusterResp.NsCluster == nil {
|
||||
this.Fail("选择的集群不存在")
|
||||
}
|
||||
|
||||
// IP地址
|
||||
ipAddresses := []maps.Map{}
|
||||
if len(params.IPAddressesJSON) > 0 {
|
||||
err := json.Unmarshal(params.IPAddressesJSON, &ipAddresses)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(ipAddresses) == 0 {
|
||||
this.Fail("请至少输入一个IP地址")
|
||||
}
|
||||
|
||||
// TODO 检查登录授权
|
||||
loginInfo := &pb.NodeLogin{
|
||||
Id: params.LoginId,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
Params: maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
}.AsJSON(),
|
||||
}
|
||||
|
||||
// 保存
|
||||
_, err = this.RPC().NSNodeRPC().UpdateNSNode(this.AdminContext(), &pb.UpdateNSNodeRequest{
|
||||
NsNodeId: params.NodeId,
|
||||
Name: params.Name,
|
||||
NsClusterId: params.ClusterId,
|
||||
IsOn: params.IsOn,
|
||||
NodeLogin: loginInfo,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 禁用老的IP地址
|
||||
_, err = this.RPC().NodeIPAddressRPC().DisableAllNodeIPAddressesWithNodeId(this.AdminContext(), &pb.DisableAllNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加新的IP地址
|
||||
err = ipaddressutils.UpdateNodeIPAddresses(this.Parent(), params.NodeId, nodeconfigs.NodeRoleDNS, params.IPAddressesJSON)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateInstallStatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateInstallStatusAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
IsInstalled bool
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改节点安装状态 %d", params.NodeId)
|
||||
|
||||
_, err := this.RPC().NSNodeRPC().UpdateNSNodeIsInstalled(this.AdminContext(), &pb.UpdateNSNodeIsInstalledRequest{
|
||||
NsNodeId: params.NodeId,
|
||||
IsInstalled: params.IsInstalled,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accessLog
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("accessLog")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
accessLogResp, err := this.RPC().NSClusterRPC().FindNSClusterAccessLog(this.AdminContext(), &pb.FindNSClusterAccessLogRequest{NsClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
accessLogRef := &dnsconfigs.NSAccessLogRef{}
|
||||
if len(accessLogResp.AccessLogJSON) > 0 {
|
||||
err = json.Unmarshal(accessLogResp.AccessLogJSON, accessLogRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["accessLogRef"] = accessLogRef
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
AccessLogJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改域名服务集群 %d 访问日志配置", params.ClusterId)
|
||||
|
||||
ref := &dnsconfigs.NSAccessLogRef{}
|
||||
err := json.Unmarshal(params.AccessLogJSON, ref)
|
||||
if err != nil {
|
||||
this.Fail("数据格式错误:" + err.Error())
|
||||
}
|
||||
err = ref.Init()
|
||||
if err != nil {
|
||||
this.Fail("数据格式错误:" + err.Error())
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSClusterRPC().UpdateNSClusterAccessLog(this.AdminContext(), &pb.UpdateNSClusterAccessLogRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
AccessLogJSON: params.AccessLogJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"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 IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("basic")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
clusterResp, err := this.RPC().NSClusterRPC().FindEnabledNSCluster(this.AdminContext(), &pb.FindEnabledNSClusterRequest{NsClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
cluster := clusterResp.NsCluster
|
||||
if cluster == nil {
|
||||
this.NotFound("nsCluster", params.ClusterId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["cluster"] = maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"isOn": cluster.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改域名服务集群基本信息 %d", params.ClusterId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入集群名称")
|
||||
|
||||
_, err := this.RPC().NSClusterRPC().UpdateNSCluster(this.AdminContext(), &pb.UpdateNSClusterRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package recursion
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("recursion")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
resp, err := this.RPC().NSClusterRPC().FindNSClusterRecursionConfig(this.AdminContext(), &pb.FindNSClusterRecursionConfigRequest{NsClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var config = &dnsconfigs.RecursionConfig{}
|
||||
if len(resp.RecursionJSON) > 0 {
|
||||
err = json.Unmarshal(resp.RecursionJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
config.UseLocalHosts = true
|
||||
}
|
||||
this.Data["config"] = config
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
RecursionJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改DNS集群 %d 的递归DNS设置", params.ClusterId)
|
||||
|
||||
// TODO 校验域名
|
||||
|
||||
_, err := this.RPC().NSClusterRPC().UpdateNSClusterRecursionConfig(this.AdminContext(), &pb.UpdateNSClusterRecursionConfigRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
RecursionJSON: params.RecursionJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateAction) Init() {
|
||||
this.Nav("", "", "create")
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunGet(params struct{}) {
|
||||
// 集群数量
|
||||
countClustersResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countClusters"] = countClustersResp.Count
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunPost(params struct {
|
||||
Name string
|
||||
ClusterId int64
|
||||
UserId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var domainId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo("创建域名 %d", domainId)
|
||||
}()
|
||||
|
||||
params.Name = strings.ToLower(params.Name)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入域名").
|
||||
Expect(func() (message string, success bool) {
|
||||
success = domainutils.ValidateDomainFormat(params.Name)
|
||||
if !success {
|
||||
message = "请输入正确的域名"
|
||||
}
|
||||
return
|
||||
}).
|
||||
Field("clusterId", params.ClusterId).
|
||||
Gt(0, "请选择所属集群")
|
||||
|
||||
createResp, err := this.RPC().NSDomainRPC().CreateNSDomain(this.AdminContext(), &pb.CreateNSDomainRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
UserId: params.UserId,
|
||||
Name: params.Name,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domainId = createResp.NsDomainId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domains
|
||||
|
||||
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 {
|
||||
DomainId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除域名 %d", params.DomainId)
|
||||
|
||||
_, err := this.RPC().NSDomainRPC().DeleteNSDomain(this.AdminContext(), &pb.DeleteNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type DomainAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DomainAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *DomainAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countRecords = this.Data.GetMap("domain").GetInt64("countRecords")
|
||||
var countKeys = this.Data.GetMap("domain").GetInt64("countKeys")
|
||||
|
||||
// 域名信息
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domain := domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", params.DomainId)
|
||||
return
|
||||
}
|
||||
|
||||
var clusterMap maps.Map
|
||||
if domain.NsCluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": domain.NsCluster.Id,
|
||||
"name": domain.NsCluster.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 用户信息
|
||||
var userMap maps.Map
|
||||
if domain.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": domain.User.Id,
|
||||
"username": domain.User.Username,
|
||||
"fullname": domain.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"isOn": domain.IsOn,
|
||||
"cluster": clusterMap,
|
||||
"user": userMap,
|
||||
"countRecords": countRecords,
|
||||
"countKeys": countKeys,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domainutils
|
||||
|
||||
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"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
// InitDomain 初始化域名信息
|
||||
func InitDomain(parent *actionutils.ParentAction, domainId int64) error {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domainResp, err := rpcClient.NSDomainRPC().FindEnabledNSDomain(parent.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: domainId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
return errors.New("InitDomain: can not find domain with id '" + types.String(domainId) + "'")
|
||||
}
|
||||
|
||||
// 记录数量
|
||||
countRecordsResp, err := rpcClient.NSRecordRPC().CountAllEnabledNSRecords(parent.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{
|
||||
NsDomainId: domainId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var countRecords = countRecordsResp.Count
|
||||
|
||||
// Key数量
|
||||
countKeysResp, err := rpcClient.NSKeyRPC().CountAllEnabledNSKeys(parent.AdminContext(), &pb.CountAllEnabledNSKeysRequest{
|
||||
NsDomainId: domainId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var countKeys = countKeysResp.Count
|
||||
|
||||
parent.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"countRecords": countRecords,
|
||||
"countKeys": countKeys,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package domains
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"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("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
UserId int64
|
||||
Keyword string
|
||||
}) {
|
||||
if !teaconst.IsPlus {
|
||||
this.RedirectURL("/")
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["userId"] = params.UserId
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
// 集群数量
|
||||
countClustersResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countClusters"] = countClustersResp.Count
|
||||
|
||||
// 分页
|
||||
countResp, err := this.RPC().NSDomainRPC().CountAllEnabledNSDomains(this.AdminContext(), &pb.CountAllEnabledNSDomainsRequest{
|
||||
UserId: params.UserId,
|
||||
NsClusterId: params.ClusterId,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
page := this.NewPage(countResp.Count)
|
||||
|
||||
// 列表
|
||||
domainsResp, err := this.RPC().NSDomainRPC().ListEnabledNSDomains(this.AdminContext(), &pb.ListEnabledNSDomainsRequest{
|
||||
UserId: params.UserId,
|
||||
NsClusterId: params.ClusterId,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domainMaps := []maps.Map{}
|
||||
for _, domain := range domainsResp.NsDomains {
|
||||
// 集群信息
|
||||
var clusterMap maps.Map
|
||||
if domain.NsCluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": domain.NsCluster.Id,
|
||||
"name": domain.NsCluster.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// 用户信息
|
||||
var userMap maps.Map
|
||||
if domain.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": domain.User.Id,
|
||||
"username": domain.User.Username,
|
||||
"fullname": domain.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
domainMaps = append(domainMaps, maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"isOn": domain.IsOn,
|
||||
"cluster": clusterMap,
|
||||
"user": userMap,
|
||||
})
|
||||
}
|
||||
this.Data["domains"] = domainMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"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 {
|
||||
DomainId int64
|
||||
}) {
|
||||
this.Data["domainId"] = params.DomainId
|
||||
|
||||
// 所有算法
|
||||
var algorithmMaps = []maps.Map{}
|
||||
for _, algo := range dnsconfigs.FindAllKeyAlgorithmTypes() {
|
||||
algorithmMaps = append(algorithmMaps, maps.Map{
|
||||
"name": algo.Name,
|
||||
"code": algo.Code,
|
||||
})
|
||||
}
|
||||
this.Data["algorithms"] = algorithmMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
Name string
|
||||
Algo string
|
||||
Secret string
|
||||
SecretType string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var keyId int64 = 0
|
||||
defer func() {
|
||||
this.CreateLogInfo("创建DNS密钥 %d", keyId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入密钥名称").
|
||||
Field("algo", params.Algo).
|
||||
Require("请选择算法").
|
||||
Field("secret", params.Secret).
|
||||
Require("请输入密码")
|
||||
|
||||
// 校验密码
|
||||
if params.SecretType == dnsconfigs.NSKeySecretTypeBase64 {
|
||||
_, err := base64.StdEncoding.DecodeString(params.Secret)
|
||||
if err != nil {
|
||||
this.FailField("secret", "请输入BASE64格式的密码或者选择明文")
|
||||
}
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().NSKeyRPC().CreateNSKey(this.AdminContext(), &pb.CreateNSKeyRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsZoneId: 0,
|
||||
Name: params.Name,
|
||||
Algo: params.Algo,
|
||||
Secret: params.Secret,
|
||||
SecretType: params.SecretType,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
keyId = createResp.NsKeyId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
)
|
||||
|
||||
type GenerateSecretAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *GenerateSecretAction) RunPost(params struct {
|
||||
SecretType string
|
||||
}) {
|
||||
switch params.SecretType {
|
||||
case dnsconfigs.NSKeySecretTypeClear:
|
||||
this.Data["secret"] = rands.HexString(128)
|
||||
case dnsconfigs.NSKeySecretTypeBase64:
|
||||
this.Data["secret"] = base64.StdEncoding.EncodeToString([]byte(rands.HexString(128)))
|
||||
default:
|
||||
this.Data["secret"] = rands.HexString(128)
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "key")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
// 初始化域名信息
|
||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 数量
|
||||
countResp, err := this.RPC().NSKeyRPC().CountAllEnabledNSKeys(this.AdminContext(), &pb.CountAllEnabledNSKeysRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsZoneId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
// 列表
|
||||
keysResp, err := this.RPC().NSKeyRPC().ListEnabledNSKeys(this.AdminContext(), &pb.ListEnabledNSKeysRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsZoneId: 0,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var keyMaps = []maps.Map{}
|
||||
for _, key := range keysResp.NsKeys {
|
||||
keyMaps = append(keyMaps, maps.Map{
|
||||
"id": key.Id,
|
||||
"name": key.Name,
|
||||
"secret": key.Secret,
|
||||
"secretTypeName": dnsconfigs.FindKeySecretTypeName(key.SecretType),
|
||||
"algoName": dnsconfigs.FindKeyAlgorithmTypeName(key.Algo),
|
||||
"isOn": key.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["keys"] = keyMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"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 {
|
||||
KeyId int64
|
||||
}) {
|
||||
keyResp, err := this.RPC().NSKeyRPC().FindEnabledNSKey(this.AdminContext(), &pb.FindEnabledNSKeyRequest{NsKeyId: params.KeyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var key = keyResp.NsKey
|
||||
if key == nil {
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["key"] = maps.Map{
|
||||
"id": key.Id,
|
||||
"name": key.Name,
|
||||
"algo": key.Algo,
|
||||
"secret": key.Secret,
|
||||
"secretType": key.SecretType,
|
||||
"isOn": key.IsOn,
|
||||
}
|
||||
|
||||
// 所有算法
|
||||
var algorithmMaps = []maps.Map{}
|
||||
for _, algo := range dnsconfigs.FindAllKeyAlgorithmTypes() {
|
||||
algorithmMaps = append(algorithmMaps, maps.Map{
|
||||
"name": algo.Name,
|
||||
"code": algo.Code,
|
||||
})
|
||||
}
|
||||
this.Data["algorithms"] = algorithmMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
KeyId int64
|
||||
Name string
|
||||
Algo string
|
||||
Secret string
|
||||
SecretType string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
this.CreateLogInfo("修改DNS密钥 %d", params.KeyId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入密钥名称").
|
||||
Field("algo", params.Algo).
|
||||
Require("请选择算法").
|
||||
Field("secret", params.Secret).
|
||||
Require("请输入密码")
|
||||
|
||||
// 校验密码
|
||||
if params.SecretType == dnsconfigs.NSKeySecretTypeBase64 {
|
||||
_, err := base64.StdEncoding.DecodeString(params.Secret)
|
||||
if err != nil {
|
||||
this.FailField("secret", "请输入BASE64格式的密码或者选择明文")
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NSKeyRPC().UpdateNSKey(this.AdminContext(), &pb.UpdateNSKeyRequest{
|
||||
NsKeyId: params.KeyId,
|
||||
Name: params.Name,
|
||||
Algo: params.Algo,
|
||||
Secret: params.Secret,
|
||||
SecretType: params.SecretType,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"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 {
|
||||
DomainId int64
|
||||
}) {
|
||||
// 域名信息
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domain := domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", params.DomainId)
|
||||
return
|
||||
}
|
||||
this.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
}
|
||||
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllRecordTypeDefinitions()
|
||||
|
||||
// TTL
|
||||
this.Data["ttlValues"] = dnsconfigs.FindAllRecordTTL()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
Name string
|
||||
Type string
|
||||
Value string
|
||||
Ttl int32
|
||||
Description string
|
||||
RouteCodes []string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var recordId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo("创建域名记录 %d", recordId)
|
||||
}()
|
||||
|
||||
// 校验记录名
|
||||
if !domainutils.ValidateRecordName(params.Name) {
|
||||
this.FailField("name", "请输入正确的记录名")
|
||||
}
|
||||
|
||||
// 校验记录值
|
||||
message, ok := domainutils.ValidateRecordValue(params.Type, params.Value)
|
||||
if !ok {
|
||||
this.FailField("value", "记录值错误:"+message)
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().NSRecordRPC().CreateNSRecord(this.AdminContext(), &pb.CreateNSRecordRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
Description: params.Description,
|
||||
Name: params.Name,
|
||||
Type: params.Type,
|
||||
Value: params.Value,
|
||||
Ttl: params.Ttl,
|
||||
NsRouteCodes: params.RouteCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recordId = createResp.NsRecordId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package records
|
||||
|
||||
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 {
|
||||
RecordId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除域名记录 %d", params.RecordId)
|
||||
|
||||
_, err := this.RPC().NSRecordRPC().DeleteNSRecord(this.AdminContext(), &pb.DeleteNSRecordRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user