Compare commits
294 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
8f4c56b24a | ||
|
|
5eb0f65934 | ||
|
|
4ed4f165ac | ||
|
|
eb8419fda0 | ||
|
|
b4a7ee0e89 | ||
|
|
83ad1bc529 | ||
|
|
56948d3035 | ||
|
|
e71e5ad57e | ||
|
|
e06d1fa5b0 | ||
|
|
460439f6bd | ||
|
|
4b4072a47e | ||
|
|
65d19d92e9 | ||
|
|
79e52d1c6e | ||
|
|
59963ee7b9 | ||
|
|
88273b1c9b | ||
|
|
bc1eb994f9 | ||
|
|
136f0fd4bd | ||
|
|
021dc13ce9 | ||
|
|
925b71489d | ||
|
|
580ce9f8f5 | ||
|
|
2b3d8c062d | ||
|
|
41858e091a | ||
|
|
5b7eaf08ae | ||
|
|
7362722adb | ||
|
|
8198ea8819 | ||
|
|
cb615f4cbc | ||
|
|
6623fd8362 | ||
|
|
7f8be85116 | ||
|
|
c61381441c | ||
|
|
b3cecdfea2 | ||
|
|
66f582df58 | ||
|
|
7f6f7e11ce | ||
|
|
0bdda313da | ||
|
|
d5e851cff7 | ||
|
|
92f1ec13f9 | ||
|
|
5376006754 | ||
|
|
361979411e | ||
|
|
3981308083 | ||
|
|
facd5e14cc | ||
|
|
ecce92c528 | ||
|
|
7696940989 | ||
|
|
941ff46c2c | ||
|
|
94036073de | ||
|
|
13216f481c | ||
|
|
eb35df8720 | ||
|
|
bf500fe1a4 | ||
|
|
c173e86e62 | ||
|
|
d4cb148272 | ||
|
|
ffc3f8544e | ||
|
|
b326bfe63a | ||
|
|
12f3f47ef9 | ||
|
|
45734747c1 | ||
|
|
37933d814c | ||
|
|
5b26287264 | ||
|
|
bac20b1d1f | ||
|
|
904c641992 | ||
|
|
36004bfd94 | ||
|
|
0fcba7e90c | ||
|
|
2e9182933e | ||
|
|
e3674fa2c1 | ||
|
|
a14cbe1319 | ||
|
|
c03c35de88 | ||
|
|
dc6c649af8 | ||
|
|
b0d2bdb0ba | ||
|
|
9239dd9a8b | ||
|
|
07a368a0bd | ||
|
|
b8d6d1c249 | ||
|
|
0f1d6a1ad2 | ||
|
|
37c6928ffc | ||
|
|
7478b6dbe0 | ||
|
|
e3cd6e1441 | ||
|
|
8081d968b6 | ||
|
|
a226eee6ef | ||
|
|
8b5a21e593 | ||
|
|
2c71f6c6be | ||
|
|
1a50b01edf | ||
|
|
05f08eeb4c | ||
|
|
fdc3ebb5c5 | ||
|
|
8f06bccd48 | ||
|
|
16b4eb67d4 | ||
|
|
ffa545cb41 | ||
|
|
f67454d51c | ||
|
|
8ae54c56db | ||
|
|
9a17adcc6f | ||
|
|
4dd6903025 | ||
|
|
085770d0ad | ||
|
|
fbaba7c37d | ||
|
|
d5cea208d2 | ||
|
|
36397adca4 | ||
|
|
4971e25d44 | ||
|
|
150357441d | ||
|
|
c4ee663285 | ||
|
|
8c95b4a9b9 | ||
|
|
32ba919851 | ||
|
|
eb37345e85 | ||
|
|
681e454917 | ||
|
|
7c7b82dee4 | ||
|
|
2ae47af8f0 | ||
|
|
b72d91d0d4 | ||
|
|
56010e7203 | ||
|
|
f658698f7b | ||
|
|
b708b9c6df | ||
|
|
c2908e17fa | ||
|
|
302daab824 | ||
|
|
ec49f238d6 | ||
|
|
3e43a5d866 | ||
|
|
a99d5e68e9 | ||
|
|
28514276ec | ||
|
|
b611427c17 | ||
|
|
ce7a4ead04 | ||
|
|
5fe15a85fd | ||
|
|
ae412909f6 | ||
|
|
c6ed579797 | ||
|
|
b2a525268e | ||
|
|
eb78b4881c | ||
|
|
4ce6e5a9f6 | ||
|
|
15d7e75555 | ||
|
|
6453cc6ccc | ||
|
|
d882a2eb63 | ||
|
|
065ac4aa25 | ||
|
|
dea54fc55e | ||
|
|
8f425bd9c7 | ||
|
|
9d909d73b8 | ||
|
|
b417d50a28 | ||
|
|
aa93a2f702 | ||
|
|
ba7125e773 | ||
|
|
46a7eaa4bb | ||
|
|
887439a6fe | ||
|
|
0e2b07d06d | ||
|
|
b7d4bde11b | ||
|
|
9707360948 | ||
|
|
103a8eb092 | ||
|
|
dcba4f9376 | ||
|
|
12aaa6fcb1 | ||
|
|
d8393481a4 | ||
|
|
70d3202a2c | ||
|
|
c7f1bbc03d | ||
|
|
61a55cb3f4 | ||
|
|
6a484af775 | ||
|
|
3074d41cf2 | ||
|
|
54199058e3 | ||
|
|
87a533791b | ||
|
|
c3109bb2c6 |
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/) 提供国内源代码托管平台
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
function build() {
|
||||
ROOT=$(dirname $0)
|
||||
JS_ROOT=$ROOT/../web/public/js
|
||||
NAME="edge-admin"
|
||||
DIST=$ROOT/"../dist/${NAME}"
|
||||
OS=${1}
|
||||
@@ -20,6 +21,18 @@ function build() {
|
||||
TAG="community"
|
||||
fi
|
||||
|
||||
# checking environment
|
||||
echo "checking required commands ..."
|
||||
commands=("zip" "unzip" "go" "find" "sed")
|
||||
for cmd in "${commands[@]}"; do
|
||||
if [ `which ${cmd}` ]; then
|
||||
echo "checking ${cmd}: ok"
|
||||
else
|
||||
echo "checking ${cmd}: not found"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION=$(lookup-version $ROOT/../internal/const/const.go)
|
||||
ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
|
||||
|
||||
@@ -38,6 +51,17 @@ function build() {
|
||||
echo "=============================="
|
||||
cd -
|
||||
|
||||
# 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 ..."
|
||||
if [ ! -d $DIST ]; then
|
||||
@@ -49,8 +73,23 @@ 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]
|
||||
if [ "${TAG}" = "plus" ]; then
|
||||
echo "converting filenames ..."
|
||||
exts=("html" "js" "css")
|
||||
for ext in "${exts[@]}"; do
|
||||
pattern="*_plus."${ext}
|
||||
find $DIST/web/views -type f -name $pattern | \
|
||||
while read filename; do
|
||||
mv ${filename} "${filename/_plus."${ext}"/."${ext}"}"
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
EDGE_API_ZIP_FILE=$ROOT"/../../EdgeAPI/dist/edge-api-${OS}-${ARCH}-${TAG}-v${APINodeVersion}.zip"
|
||||
cp $EDGE_API_ZIP_FILE $DIST/
|
||||
cd $DIST/
|
||||
|
||||
16
build/generate.sh
Executable file
16
build/generate.sh
Executable file
@@ -0,0 +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"
|
||||
@@ -5,9 +5,11 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/apps"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/gen"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
)
|
||||
|
||||
@@ -63,12 +65,24 @@ func main() {
|
||||
fmt.Println("[ERROR]the service not started yet, you should start the service first")
|
||||
return
|
||||
}
|
||||
_, err := sock.Send(&gosock.Command{Code: "demo"})
|
||||
reply, err := sock.Send(&gosock.Command{Code: "demo"})
|
||||
if err != nil {
|
||||
fmt.Println("[ERROR]change demo mode failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println("change demo mode successfully")
|
||||
var isDemo = maps.NewMap(reply.Params).GetBool("isDemo")
|
||||
if isDemo {
|
||||
fmt.Println("change demo mode to: on")
|
||||
} else {
|
||||
fmt.Println("change demo mode to: off")
|
||||
}
|
||||
})
|
||||
app.On("generate", func() {
|
||||
err := gen.Generate()
|
||||
if err != nil {
|
||||
fmt.Println("generate failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
app.Run(func() {
|
||||
adminNode := nodes.NewAdminNode()
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 225 KiB |
12
go.mod
12
go.mod
@@ -8,9 +8,8 @@ require (
|
||||
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
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
|
||||
@@ -18,9 +17,8 @@ require (
|
||||
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/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
|
||||
google.golang.org/grpc v1.45.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
|
||||
88
go.sum
88
go.sum
@@ -1,10 +1,12 @@
|
||||
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=
|
||||
@@ -14,6 +16,10 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
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/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 +27,18 @@ 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/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-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 +51,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=
|
||||
@@ -60,17 +67,17 @@ 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/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-20220304042834-d8b5103e9027 h1:4knh28YgldmEtu8QG8pgQhUaI3i//qRjOdEyj9OVqXA=
|
||||
github.com/iwind/TeaGo v0.0.0-20220304042834-d8b5103e9027/go.mod h1:IyKPaIhjbjsTctPguMWJZDHuBHu+XiYcV5ZEDxQpq94=
|
||||
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=
|
||||
@@ -81,11 +88,9 @@ 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/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=
|
||||
@@ -118,17 +123,19 @@ 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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/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/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=
|
||||
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 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
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 +144,28 @@ 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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
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=
|
||||
@@ -175,30 +183,29 @@ 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-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-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/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=
|
||||
@@ -208,17 +215,23 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
||||
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-20220303160752-862486edd9cc h1:fb/ViRpv3ln/LvbqZtTpoOd1YQDNH12gaGZreoSFovE=
|
||||
google.golang.org/genproto v0.0.0-20220303160752-862486edd9cc/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
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.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
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,8 +242,9 @@ 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=
|
||||
@@ -239,13 +253,15 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
|
||||
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 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
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=
|
||||
|
||||
@@ -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,18 +3,16 @@ 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
|
||||
|
||||
const (
|
||||
AdminUISettingName = "adminUIConfig"
|
||||
)
|
||||
|
||||
func LoadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
@@ -41,7 +39,7 @@ func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
|
||||
return err
|
||||
}
|
||||
_, err = rpcClient.SysSettingRPC().UpdateSysSetting(rpcClient.Context(0), &pb.UpdateSysSettingRequest{
|
||||
Code: AdminUISettingName,
|
||||
Code: systemconfigs.SettingCodeAdminUIConfig,
|
||||
ValueJSON: valueJSON,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -49,10 +47,13 @@ func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
|
||||
}
|
||||
sharedAdminUIConfig = uiConfig
|
||||
|
||||
// timezone
|
||||
updateTimeZone(uiConfig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 是否显示财务信息
|
||||
// ShowFinance 是否显示财务信息
|
||||
func ShowFinance() bool {
|
||||
config, _ := LoadAdminUIConfig()
|
||||
if config != nil && !config.ShowFinance {
|
||||
@@ -70,7 +71,7 @@ func loadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{
|
||||
Code: AdminUISettingName,
|
||||
Code: systemconfigs.SettingCodeAdminUIConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -80,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
|
||||
}
|
||||
@@ -98,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"
|
||||
|
||||
@@ -11,7 +11,9 @@ import (
|
||||
var plusConfigFile = "plus.cache.json"
|
||||
|
||||
type PlusConfig struct {
|
||||
IsPlus bool `json:"isPlus"`
|
||||
IsPlus bool `json:"isPlus"`
|
||||
Components []string `json:"components"`
|
||||
DayTo string `json:"dayTo"`
|
||||
}
|
||||
|
||||
func ReadPlusConfig() *PlusConfig {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.3.5"
|
||||
Version = "0.4.7.1"
|
||||
|
||||
APINodeVersion = "0.3.5"
|
||||
APINodeVersion = "0.4.7"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
@@ -18,4 +18,5 @@ const (
|
||||
CookieSID = "edgesid"
|
||||
|
||||
SystemdServiceName = "edge-admin"
|
||||
UpdatesURL = "https://goedge.cn/api/boot/versions?os=${os}&arch=${arch}"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build community
|
||||
// +build community
|
||||
|
||||
package teaconst
|
||||
|
||||
// IsPlus 是否为企业版
|
||||
var IsPlus = false
|
||||
|
||||
@@ -4,9 +4,10 @@ package teaconst
|
||||
|
||||
var (
|
||||
IsRecoverMode = false
|
||||
)
|
||||
|
||||
var (
|
||||
IsDemoMode = false
|
||||
ErrorDemoOperation = "DEMO模式下无法进行创建、修改、删除等操作"
|
||||
|
||||
NewVersionCode = "" // 有新的版本
|
||||
NewVersionDownloadURL = "" // 新版本下载地址
|
||||
)
|
||||
|
||||
129
internal/gen/generate.go
Normal file
129
internal/gen/generate.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package gen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/files"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func Generate() error {
|
||||
err := generateComponentsJSFile()
|
||||
if err != nil {
|
||||
return errors.New("generate 'components.src.js' failed: " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 生成Javascript文件
|
||||
func generateComponentsJSFile() error {
|
||||
var buffer = bytes.NewBuffer([]byte{})
|
||||
|
||||
var webRoot string
|
||||
if Tea.IsTesting() {
|
||||
webRoot = Tea.Root + "/../web/public/js/components/"
|
||||
} else {
|
||||
webRoot = Tea.Root + "/web/public/js/components/"
|
||||
}
|
||||
f := files.NewFile(webRoot)
|
||||
|
||||
f.Range(func(file *files.File) {
|
||||
if !file.IsFile() {
|
||||
return
|
||||
}
|
||||
if file.Ext() != ".js" {
|
||||
return
|
||||
}
|
||||
data, err := file.ReadAll()
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
buffer.Write(data)
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
})
|
||||
|
||||
// 条件组件
|
||||
typesJSON, err := json.Marshal(condutils.ReadAllAvailableCondTypes())
|
||||
if err != nil {
|
||||
logs.Println("ComponentsAction marshal request cond types failed: " + err.Error())
|
||||
} else {
|
||||
buffer.WriteString("window.REQUEST_COND_COMPONENTS = ")
|
||||
buffer.Write(typesJSON)
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
}
|
||||
|
||||
// 条件操作符
|
||||
requestOperatorsJSON, err := json.Marshal(shared.AllRequestOperators())
|
||||
if err != nil {
|
||||
logs.Println("ComponentsAction marshal request operators failed: " + err.Error())
|
||||
} else {
|
||||
buffer.WriteString("window.REQUEST_COND_OPERATORS = ")
|
||||
buffer.Write(requestOperatorsJSON)
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
}
|
||||
|
||||
// 请求变量
|
||||
requestVariablesJSON, err := json.Marshal(shared.DefaultRequestVariables())
|
||||
if err != nil {
|
||||
logs.Println("ComponentsAction marshal request variables failed: " + err.Error())
|
||||
} else {
|
||||
buffer.WriteString("window.REQUEST_VARIABLES = ")
|
||||
buffer.Write(requestVariablesJSON)
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
}
|
||||
|
||||
// 指标
|
||||
metricHTTPKeysJSON, err := json.Marshal(serverconfigs.FindAllMetricKeyDefinitions(serverconfigs.MetricItemCategoryHTTP))
|
||||
if err != nil {
|
||||
logs.Println("ComponentsAction marshal metric http keys failed: " + err.Error())
|
||||
} else {
|
||||
buffer.WriteString("window.METRIC_HTTP_KEYS = ")
|
||||
buffer.Write(metricHTTPKeysJSON)
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
}
|
||||
|
||||
// IP地址阈值项目
|
||||
ipAddrThresholdItemsJSON, err := json.Marshal(nodeconfigs.FindAllIPAddressThresholdItems())
|
||||
if err != nil {
|
||||
logs.Println("ComponentsAction marshal ip addr threshold items failed: " + err.Error())
|
||||
} else {
|
||||
buffer.WriteString("window.IP_ADDR_THRESHOLD_ITEMS = ")
|
||||
buffer.Write(ipAddrThresholdItemsJSON)
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
}
|
||||
|
||||
// IP地址阈值动作
|
||||
ipAddrThresholdActionsJSON, err := json.Marshal(nodeconfigs.FindAllIPAddressThresholdActions())
|
||||
if err != nil {
|
||||
logs.Println("ComponentsAction marshal ip addr threshold actions failed: " + err.Error())
|
||||
} else {
|
||||
buffer.WriteString("window.IP_ADDR_THRESHOLD_ACTIONS = ")
|
||||
buffer.Write(ipAddrThresholdActionsJSON)
|
||||
buffer.Write([]byte{'\n', '\n'})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
_, err = io.Copy(fp, buffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
13
internal/gen/generate_test.go
Normal file
13
internal/gen/generate_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package gen
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
err := Generate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
12
internal/goman/instance.go
Normal file
12
internal/goman/instance.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package goman
|
||||
|
||||
import "time"
|
||||
|
||||
type Instance struct {
|
||||
Id uint64
|
||||
CreatedTime time.Time
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
81
internal/goman/lib.go
Normal file
81
internal/goman/lib.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package goman
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var locker = &sync.Mutex{}
|
||||
var instanceMap = map[uint64]*Instance{} // id => *Instance
|
||||
var instanceId = uint64(0)
|
||||
|
||||
// New 新创建goroutine
|
||||
func New(f func()) {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
|
||||
go func() {
|
||||
locker.Lock()
|
||||
instanceId++
|
||||
|
||||
var instance = &Instance{
|
||||
Id: instanceId,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
|
||||
instance.File = file
|
||||
instance.Line = line
|
||||
|
||||
instanceMap[instanceId] = instance
|
||||
locker.Unlock()
|
||||
|
||||
// run function
|
||||
f()
|
||||
|
||||
locker.Lock()
|
||||
delete(instanceMap, instanceId)
|
||||
locker.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
// NewWithArgs 创建带有参数的goroutine
|
||||
func NewWithArgs(f func(args ...interface{}), args ...interface{}) {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
|
||||
go func() {
|
||||
locker.Lock()
|
||||
instanceId++
|
||||
|
||||
var instance = &Instance{
|
||||
Id: instanceId,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
|
||||
instance.File = file
|
||||
instance.Line = line
|
||||
|
||||
instanceMap[instanceId] = instance
|
||||
locker.Unlock()
|
||||
|
||||
// run function
|
||||
f(args...)
|
||||
|
||||
locker.Lock()
|
||||
delete(instanceMap, instanceId)
|
||||
locker.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
// List 列出所有正在运行goroutine
|
||||
func List() []*Instance {
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
|
||||
var result = []*Instance{}
|
||||
for _, instance := range instanceMap {
|
||||
result = append(result, instance)
|
||||
}
|
||||
return result
|
||||
}
|
||||
28
internal/goman/lib_test.go
Normal file
28
internal/goman/lib_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package goman
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
New(func() {
|
||||
t.Log("Hello")
|
||||
|
||||
t.Log(List())
|
||||
})
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
t.Log(List())
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
func TestNewWithArgs(t *testing.T) {
|
||||
NewWithArgs(func(args ...interface{}) {
|
||||
t.Log(args[0], args[1])
|
||||
}, 1, 2)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -325,7 +369,9 @@ func (this *AdminNode) listenSock() error {
|
||||
_ = cmd.ReplyOk()
|
||||
case "demo":
|
||||
teaconst.IsDemoMode = !teaconst.IsDemoMode
|
||||
_ = cmd.ReplyOk()
|
||||
_ = cmd.Reply(&gosock.Command{
|
||||
Params: map[string]interface{}{"isDemo": teaconst.IsDemoMode},
|
||||
})
|
||||
case "info":
|
||||
exePath, _ := os.Executable()
|
||||
_ = cmd.Reply(&gosock.Command{
|
||||
|
||||
@@ -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"
|
||||
@@ -161,6 +163,10 @@ func (this *RPCClient) APINodeRPC() pb.APINodeServiceClient {
|
||||
return pb.NewAPINodeServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) APIMethodStatRPC() pb.APIMethodStatServiceClient {
|
||||
return pb.NewAPIMethodStatServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) UserNodeRPC() pb.UserNodeServiceClient {
|
||||
return pb.NewUserNodeServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -382,6 +388,10 @@ func (this *RPCClient) UserBillRPC() pb.UserBillServiceClient {
|
||||
return pb.NewUserBillServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) ServerBillRPC() pb.ServerBillServiceClient {
|
||||
return pb.NewServerBillServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) UserAccountRPC() pb.UserAccountServiceClient {
|
||||
return pb.NewUserAccountServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -474,6 +484,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())
|
||||
}
|
||||
@@ -486,6 +500,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()
|
||||
@@ -552,12 +570,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 + "'")
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ func TestRPCClient_NodeRPC(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rpc, err := NewRPCClient(config)
|
||||
rpc, err := NewRPCClient(config, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -41,7 +41,7 @@ func TestRPC_Dial_HTTP(t *testing.T) {
|
||||
},
|
||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||
})
|
||||
}, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
|
||||
},
|
||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||
})
|
||||
}, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func TestRPC_Dial_HTTPS(t *testing.T) {
|
||||
},
|
||||
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
|
||||
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
|
||||
})
|
||||
}, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
131
internal/tasks/task_check_updates.go
Normal file
131
internal/tasks/task_check_updates.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
events.On(events.EventStart, func() {
|
||||
var task = NewCheckUpdatesTask()
|
||||
goman.New(func() {
|
||||
task.Start()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type CheckUpdatesTask struct {
|
||||
ticker *time.Ticker
|
||||
}
|
||||
|
||||
func NewCheckUpdatesTask() *CheckUpdatesTask {
|
||||
return &CheckUpdatesTask{}
|
||||
}
|
||||
|
||||
func (this *CheckUpdatesTask) Start() {
|
||||
this.ticker = time.NewTicker(12 * time.Hour)
|
||||
for range this.ticker.C {
|
||||
err := this.Loop()
|
||||
if err != nil {
|
||||
logs.Println("[TASK][CHECK_UPDATES_TASK]" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *CheckUpdatesTask) Loop() error {
|
||||
// 检查是否开启
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valueResp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeCheckUpdates})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var valueJSON = valueResp.ValueJSON
|
||||
var config = &systemconfigs.CheckUpdatesConfig{AutoCheck: false}
|
||||
if len(valueJSON) > 0 {
|
||||
err = json.Unmarshal(valueJSON, config)
|
||||
if err != nil {
|
||||
return errors.New("decode config failed: " + err.Error())
|
||||
}
|
||||
if !config.AutoCheck {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 开始检查
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// 目前支持Linux
|
||||
if runtime.GOOS != "linux" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var apiURL = teaconst.UpdatesURL
|
||||
apiURL = strings.ReplaceAll(apiURL, "${os}", runtime.GOOS)
|
||||
apiURL = strings.ReplaceAll(apiURL, "${arch}", runtime.GOARCH)
|
||||
resp, err := http.Get(apiURL)
|
||||
if err != nil {
|
||||
return errors.New("read api failed: " + err.Error())
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return errors.New("read api failed: " + err.Error())
|
||||
}
|
||||
|
||||
var apiResponse = &Response{}
|
||||
err = json.Unmarshal(data, apiResponse)
|
||||
if err != nil {
|
||||
return errors.New("decode version data failed: " + err.Error())
|
||||
}
|
||||
|
||||
if apiResponse.Code != 200 {
|
||||
return errors.New("invalid response: " + apiResponse.Message)
|
||||
}
|
||||
|
||||
var m = maps.NewMap(apiResponse.Data)
|
||||
var dlHost = m.GetString("host")
|
||||
var versions = m.GetSlice("versions")
|
||||
if len(versions) > 0 {
|
||||
for _, version := range versions {
|
||||
var vMap = maps.NewMap(version)
|
||||
if vMap.GetString("code") == "admin" {
|
||||
var latestVersion = vMap.GetString("version")
|
||||
if stringutil.VersionCompare(teaconst.Version, latestVersion) < 0 {
|
||||
teaconst.NewVersionCode = latestVersion
|
||||
teaconst.NewVersionDownloadURL = dlHost + vMap.GetString("url")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
@@ -23,7 +24,9 @@ import (
|
||||
func init() {
|
||||
events.On(events.EventStart, func() {
|
||||
task := NewSyncAPINodesTask()
|
||||
go task.Start()
|
||||
goman.New(func() {
|
||||
task.Start()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package tasks
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
|
||||
@@ -17,7 +18,9 @@ import (
|
||||
func init() {
|
||||
events.On(events.EventStart, func() {
|
||||
task := NewSyncClusterTask()
|
||||
go task.Start()
|
||||
goman.New(func() {
|
||||
task.Start()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,7 +54,7 @@ func (this *SyncClusterTask) loop() error {
|
||||
}
|
||||
ctx := rpcClient.Context(0)
|
||||
|
||||
tasksResp, err := rpcClient.NodeTaskRPC().FindNotifyingNodeTasks(ctx, &pb.FindNotifyingNodeTasksRequest{Size: 100})
|
||||
tasksResp, err := rpcClient.NodeTaskRPC().FindNotifyingNodeTasks(ctx, &pb.FindNotifyingNodeTasksRequest{Size: 500})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"math/big"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 将IP转换为整型
|
||||
// IP2Long 将IP转换为整型
|
||||
func IP2Long(ip string) uint64 {
|
||||
s := net.ParseIP(ip)
|
||||
if len(s) != 16 {
|
||||
@@ -23,7 +26,7 @@ func IP2Long(ip string) uint64 {
|
||||
return uint64(binary.BigEndian.Uint32(s.To4()))
|
||||
}
|
||||
|
||||
// 判断是否为IPv4
|
||||
// IsIPv4 判断是否为IPv4
|
||||
func IsIPv4(ip string) bool {
|
||||
if !regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`).MatchString(ip) {
|
||||
return false
|
||||
@@ -34,10 +37,100 @@ func IsIPv4(ip string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// 判断是否为IPv6
|
||||
// IsIPv6 判断是否为IPv6
|
||||
func IsIPv6(ip string) bool {
|
||||
if !strings.Contains(ip, ":") {
|
||||
return false
|
||||
}
|
||||
return len(net.ParseIP(ip)) == net.IPv6len
|
||||
}
|
||||
|
||||
// ExtractIP 分解IP
|
||||
// 只支持D段掩码的CIDR
|
||||
// 最多只记录255个值
|
||||
func ExtractIP(ipStrings string) ([]string, error) {
|
||||
ipStrings = strings.ReplaceAll(ipStrings, " ", "")
|
||||
|
||||
// CIDR
|
||||
if strings.Contains(ipStrings, "/") {
|
||||
_, cidrNet, err := net.ParseCIDR(ipStrings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var index = strings.Index(ipStrings, "/")
|
||||
var ipFrom = ipStrings[:index]
|
||||
var bits = types.Int(ipStrings[index+1:])
|
||||
if bits < 24 {
|
||||
return nil, errors.New("CIDR bits should be greater than 24")
|
||||
}
|
||||
|
||||
var ipv4 = net.ParseIP(ipFrom).To4()
|
||||
if len(ipv4) == 0 {
|
||||
return nil, errors.New("support IPv4 only")
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
ipv4[3] = 0 // 从0开始
|
||||
for i := 0; i <= 255; i++ {
|
||||
if cidrNet.Contains(ipv4) {
|
||||
result = append(result, ipv4.String())
|
||||
}
|
||||
ipv4 = NextIP(ipv4)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// IP Range
|
||||
if strings.Contains(ipStrings, "-") {
|
||||
var index = strings.Index(ipStrings, "-")
|
||||
var ipFromString = ipStrings[:index]
|
||||
var ipToString = ipStrings[index+1:]
|
||||
|
||||
var ipFrom = net.ParseIP(ipFromString).To4()
|
||||
if len(ipFrom) == 0 {
|
||||
return nil, errors.New("invalid ip '" + ipFromString + "'")
|
||||
}
|
||||
|
||||
var ipTo = net.ParseIP(ipToString).To4()
|
||||
if len(ipTo) == 0 {
|
||||
return nil, errors.New("invalid ip '" + ipToString + "'")
|
||||
}
|
||||
|
||||
if bytes.Compare(ipFrom, ipTo) > 0 {
|
||||
ipFrom, ipTo = ipTo, ipFrom
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
for i := 0; i < 255; i++ {
|
||||
if bytes.Compare(ipFrom, ipTo) > 0 {
|
||||
break
|
||||
}
|
||||
result = append(result, ipFrom.String())
|
||||
ipFrom = NextIP(ipFrom)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return []string{ipStrings}, nil
|
||||
}
|
||||
|
||||
// NextIP IP增加1
|
||||
func NextIP(prevIP net.IP) net.IP {
|
||||
var ip = make(net.IP, len(prevIP))
|
||||
copy(ip, prevIP)
|
||||
var index = len(ip) - 1
|
||||
for {
|
||||
if ip[index] == 255 {
|
||||
ip[index] = 0
|
||||
index--
|
||||
if index < 0 {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
ip[index]++
|
||||
break
|
||||
}
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -83,3 +84,27 @@ func TestIsIPv6(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractIP(t *testing.T) {
|
||||
t.Log(ExtractIP("192.168.1.100"))
|
||||
}
|
||||
|
||||
func TestExtractIP_CIDR(t *testing.T) {
|
||||
t.Log(ExtractIP("192.168.2.100/24"))
|
||||
}
|
||||
|
||||
func TestExtractIP_Range(t *testing.T) {
|
||||
t.Log(ExtractIP("192.168.2.100 - 192.168.4.2"))
|
||||
}
|
||||
|
||||
func TestNextIP(t *testing.T) {
|
||||
for _, ip := range []string{"192.168.1.1", "0.0.0.0", "255.255.255.255", "192.168.2.255", "192.168.255.255"} {
|
||||
t.Log(ip+":", NextIP(net.ParseIP(ip).To4()))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextIP_Copy(t *testing.T) {
|
||||
var ip = net.ParseIP("192.168.1.100")
|
||||
var nextIP = NextIP(ip)
|
||||
t.Log(ip, nextIP)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
27
internal/utils/nodelogutils/utils.go
Normal file
27
internal/utils/nodelogutils/utils.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build community
|
||||
// +build community
|
||||
|
||||
package nodelogutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// FindCommonTags 查找常用的标签
|
||||
func FindNodeCommonTags() []maps.Map {
|
||||
return []maps.Map{
|
||||
{
|
||||
"name": "端口监听",
|
||||
"code": "LISTENER",
|
||||
},
|
||||
{
|
||||
"name": "WAF",
|
||||
"code": "WAF",
|
||||
},
|
||||
{
|
||||
"name": "访问日志",
|
||||
"code": "ACCESS_LOG",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package numberutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -13,38 +14,63 @@ func FormatInt(value int) string {
|
||||
return strconv.Itoa(value)
|
||||
}
|
||||
|
||||
func Pow1024(n int) int64 {
|
||||
if n <= 0 {
|
||||
return 1
|
||||
}
|
||||
if n == 1 {
|
||||
return 1024
|
||||
}
|
||||
return Pow1024(n-1) * 1024
|
||||
}
|
||||
|
||||
func FormatBytes(bytes int64) string {
|
||||
if bytes < 1024 {
|
||||
if bytes < Pow1024(1) {
|
||||
return FormatInt64(bytes) + "B"
|
||||
} else if bytes < 1024*1024 {
|
||||
return fmt.Sprintf("%.2fKB", float64(bytes)/1024)
|
||||
} else if bytes < 1024*1024*1024 {
|
||||
return fmt.Sprintf("%.2fMB", float64(bytes)/1024/1024)
|
||||
} else if bytes < 1024*1024*1024*1024 {
|
||||
return fmt.Sprintf("%.2fGB", float64(bytes)/1024/1024/1024)
|
||||
} else if bytes < 1024*1024*1024*1024*1024 {
|
||||
return fmt.Sprintf("%.2fTB", float64(bytes)/1024/1024/1024/1024)
|
||||
} else if bytes < 1024*1024*1024*1024*1024*1024 {
|
||||
return fmt.Sprintf("%.2fPB", float64(bytes)/1024/1024/1024/1024/1024)
|
||||
} else if bytes < Pow1024(2) {
|
||||
return fmt.Sprintf("%.2fKB", float64(bytes)/float64(Pow1024(1)))
|
||||
} else if bytes < Pow1024(3) {
|
||||
return fmt.Sprintf("%.2fMB", float64(bytes)/float64(Pow1024(2)))
|
||||
} else if bytes < Pow1024(4) {
|
||||
return fmt.Sprintf("%.2fGB", float64(bytes)/float64(Pow1024(3)))
|
||||
} else if bytes < Pow1024(5) {
|
||||
return fmt.Sprintf("%.2fTB", float64(bytes)/float64(Pow1024(4)))
|
||||
} else if bytes < Pow1024(6) {
|
||||
return fmt.Sprintf("%.2fPB", float64(bytes)/float64(Pow1024(5)))
|
||||
} else {
|
||||
return fmt.Sprintf("%.2fEB", float64(bytes)/1024/1024/1024/1024/1024/1024)
|
||||
return fmt.Sprintf("%.2fEB", float64(bytes)/float64(Pow1024(6)))
|
||||
}
|
||||
}
|
||||
|
||||
func FormatBits(bits int64) string {
|
||||
if bits < 1000 {
|
||||
return FormatInt64(bits) + "B"
|
||||
} else if bits < 1000*1000 {
|
||||
return fmt.Sprintf("%.2fKB", float64(bits)/1000)
|
||||
} else if bits < 1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fMB", float64(bits)/1000/1000)
|
||||
} else if bits < 1000*1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fGB", float64(bits)/1000/1000/1000)
|
||||
} else if bits < 1000*1000*1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fTB", float64(bits)/1000/1000/1000/1000)
|
||||
} else if bits < 1000*1000*1000*1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fPB", float64(bits)/1000/1000/1000/1000/1000)
|
||||
} else {
|
||||
return fmt.Sprintf("%.2fEB", float64(bits)/1000/1000/1000/1000/1000/1000)
|
||||
func FormatCount(count int64) string {
|
||||
if count < 1000 {
|
||||
return types.String(count)
|
||||
}
|
||||
if count < 1000*1000 {
|
||||
return fmt.Sprintf("%.1fK", float32(count)/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)
|
||||
}
|
||||
|
||||
36
internal/utils/numberutils/utils_test.go
Normal file
36
internal/utils/numberutils/utils_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package numberutils_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFormatBytes(t *testing.T) {
|
||||
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(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/EdgeNode/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)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -26,11 +27,11 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
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()
|
||||
|
||||
nodeMaps := []maps.Map{}
|
||||
var nodeMaps = []maps.Map{}
|
||||
if count > 0 {
|
||||
nodesResp, err := this.RPC().APINodeRPC().ListEnabledAPINodes(this.AdminContext(), &pb.ListEnabledAPINodesRequest{
|
||||
Offset: page.Offset,
|
||||
@@ -91,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,
|
||||
@@ -106,5 +108,13 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
// 检查是否有调试数据
|
||||
countMethodStatsResp, err := this.RPC().APIMethodStatRPC().CountAPIMethodStatsWithDay(this.AdminContext(), &pb.CountAPIMethodStatsWithDayRequest{Day: timeutil.Format("Ymd")})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["hasMethodStats"] = countMethodStatsResp.Count > 0
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ func init() {
|
||||
Helper(settingutils.NewAdvancedHelper("apiNodes")).
|
||||
Prefix("/api").
|
||||
Get("", new(IndexAction)).
|
||||
Get("/methodStats", new(MethodStatsAction)).
|
||||
GetPost("/node/createPopup", new(node.CreatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
EndAll()
|
||||
|
||||
78
internal/web/actions/default/api/methodStats.go
Normal file
78
internal/web/actions/default/api/methodStats.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MethodStatsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *MethodStatsAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *MethodStatsAction) RunGet(params struct {
|
||||
Order string
|
||||
Method string
|
||||
Tag string
|
||||
}) {
|
||||
this.Data["order"] = params.Order
|
||||
this.Data["method"] = params.Method
|
||||
this.Data["tag"] = params.Tag
|
||||
|
||||
statsResp, err := this.RPC().APIMethodStatRPC().FindAPIMethodStatsWithDay(this.AdminContext(), &pb.FindAPIMethodStatsWithDayRequest{Day: timeutil.Format("Ymd")})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var pbStats = statsResp.ApiMethodStats
|
||||
|
||||
switch params.Order {
|
||||
case "method":
|
||||
sort.Slice(pbStats, func(i, j int) bool {
|
||||
return pbStats[i].Method < pbStats[j].Method
|
||||
})
|
||||
case "costMs.desc":
|
||||
sort.Slice(pbStats, func(i, j int) bool {
|
||||
return pbStats[i].CostMs > pbStats[j].CostMs
|
||||
})
|
||||
case "peekMs.desc":
|
||||
sort.Slice(pbStats, func(i, j int) bool {
|
||||
return pbStats[i].PeekMs > pbStats[j].PeekMs
|
||||
})
|
||||
case "calls.desc":
|
||||
sort.Slice(pbStats, func(i, j int) bool {
|
||||
return pbStats[i].CountCalls > pbStats[j].CountCalls
|
||||
})
|
||||
}
|
||||
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range pbStats {
|
||||
if len(params.Method) > 0 && !strings.Contains(strings.ToLower(stat.Method), strings.ToLower(params.Method)) {
|
||||
continue
|
||||
}
|
||||
if len(params.Tag) > 0 && !strings.Contains(strings.ToLower(stat.Tag), strings.ToLower(params.Tag)) {
|
||||
continue
|
||||
}
|
||||
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"id": stat.Id,
|
||||
"method": stat.Method,
|
||||
"tag": stat.Tag,
|
||||
"costMs": stat.CostMs,
|
||||
"peekMs": stat.PeekMs,
|
||||
"countCalls": stat.CountCalls,
|
||||
})
|
||||
}
|
||||
this.Data["stats"] = statMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -3,6 +3,7 @@ package cluster
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"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"
|
||||
@@ -167,9 +168,13 @@ func (this *CreateNodeAction) RunPost(params struct {
|
||||
nodeId := createResp.NodeId
|
||||
|
||||
// IP地址
|
||||
var resultIPAddresses = []string{}
|
||||
for _, addr := range ipAddresses {
|
||||
var resultAddrIds = []int64{}
|
||||
|
||||
addrId := addr.GetInt64("id")
|
||||
if addrId > 0 {
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeId: nodeId,
|
||||
@@ -178,20 +183,50 @@ func (this *CreateNodeAction) RunPost(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
resultIPAddresses = append(resultIPAddresses, addr.GetString("ip"))
|
||||
} else {
|
||||
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: addr.GetString("name"),
|
||||
Ip: addr.GetString("ip"),
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
})
|
||||
var ipStrings = addr.GetString("ip")
|
||||
result, err := utils.ExtractIP(ipStrings)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
this.Fail("节点创建成功,但是保存IP失败:" + err.Error())
|
||||
}
|
||||
|
||||
resultIPAddresses = append(resultIPAddresses, result...)
|
||||
|
||||
if len(result) == 1 {
|
||||
// 单个创建
|
||||
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: addr.GetString("name"),
|
||||
Ip: result[0],
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
addrId = createResp.NodeIPAddressId
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
} else if len(result) > 1 {
|
||||
// 批量创建
|
||||
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(this.AdminContext(), &pb.CreateNodeIPAddressesRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: addr.GetString("name"),
|
||||
IpList: result,
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
GroupValue: ipStrings,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
|
||||
}
|
||||
addrId = createResp.NodeIPAddressId
|
||||
}
|
||||
|
||||
// 阈值
|
||||
@@ -202,13 +237,16 @@ func (this *CreateNodeAction) RunPost(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeIPAddressThresholdsJSON: thresholdsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
|
||||
for _, addrId := range resultAddrIds {
|
||||
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeIPAddressThresholdsJSON: thresholdsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,11 +262,6 @@ func (this *CreateNodeAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
if nodeResp.Node != nil {
|
||||
var addresses = []string{}
|
||||
for _, addrMap := range ipAddresses {
|
||||
addresses = append(addresses, addrMap.GetString("ip"))
|
||||
}
|
||||
|
||||
var grantMap maps.Map = nil
|
||||
grantId := params.GrantId
|
||||
if grantId > 0 {
|
||||
@@ -253,7 +286,7 @@ func (this *CreateNodeAction) RunPost(params struct {
|
||||
"name": nodeResp.Node.Name,
|
||||
"uniqueId": nodeResp.Node.UniqueId,
|
||||
"secret": nodeResp.Node.Secret,
|
||||
"addresses": addresses,
|
||||
"addresses": resultIPAddresses,
|
||||
"login": maps.Map{
|
||||
"id": 0,
|
||||
"name": "SSH",
|
||||
|
||||
@@ -54,6 +54,7 @@ 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)).
|
||||
|
||||
// 分组相关
|
||||
|
||||
@@ -33,7 +33,7 @@ func (this *DetailAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("找不到要操作的节点")
|
||||
return
|
||||
@@ -86,9 +86,16 @@ func (this *DetailAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// 是否有备用IP
|
||||
var originIP = addr.Ip
|
||||
if len(addr.BackupIP) > 0 {
|
||||
addr.Ip = addr.BackupIP
|
||||
}
|
||||
|
||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||
"id": addr.Id,
|
||||
"name": addr.Name,
|
||||
"originIP": originIP,
|
||||
"ip": addr.Ip,
|
||||
"canAccess": addr.CanAccess,
|
||||
"isOn": addr.IsOn,
|
||||
@@ -190,7 +197,7 @@ func (this *DetailAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 运行状态
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
var status = &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
@@ -278,6 +285,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,
|
||||
@@ -291,9 +300,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),
|
||||
},
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package node
|
||||
|
||||
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"
|
||||
@@ -23,6 +25,7 @@ func (this *LogsAction) RunGet(params struct {
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
Tag string
|
||||
}) {
|
||||
// 初始化节点信息(用于菜单)
|
||||
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
|
||||
@@ -31,19 +34,23 @@ func (this *LogsAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["tags"] = nodelogutils.FindNodeCommonTags()
|
||||
|
||||
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
|
||||
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,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
Tag: params.Tag,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -59,6 +66,7 @@ func (this *LogsAction) RunGet(params struct {
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
Tag: params.Tag,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
@@ -38,6 +38,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,11 +61,15 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
|
||||
"name": "DNS设置",
|
||||
"url": prefix + "/settings/dns?" + query,
|
||||
"isActive": menuItem == "dns",
|
||||
"isOn": len(node.DnsRoutes) > 0,
|
||||
},
|
||||
{
|
||||
"name": "缓存设置",
|
||||
"url": prefix + "/settings/cache?" + query,
|
||||
"isActive": menuItem == "cache",
|
||||
"isOn": len(node.CacheDiskDir) > 0 ||
|
||||
(node.MaxCacheDiskCapacity != nil && node.MaxCacheDiskCapacity.Count > 0) ||
|
||||
(node.MaxCacheMemoryCapacity != nil && node.MaxCacheMemoryCapacity.Count > 0),
|
||||
},
|
||||
}
|
||||
if teaconst.IsPlus {
|
||||
@@ -81,11 +86,13 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
|
||||
"name": "SSH设置",
|
||||
"url": prefix + "/settings/ssh?" + query,
|
||||
"isActive": menuItem == "ssh",
|
||||
"isOn": node.NodeLogin != nil,
|
||||
},
|
||||
{
|
||||
"name": "系统设置",
|
||||
"url": prefix + "/settings/system?" + query,
|
||||
"isActive": menuItem == "system",
|
||||
"isOn": node.MaxCPU > 0,
|
||||
},
|
||||
}...)
|
||||
parentAction.Data["leftMenuItems"] = menuItems
|
||||
|
||||
@@ -17,7 +17,7 @@ type IndexAction struct {
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("cache")
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -16,7 +16,7 @@ type IndexAction struct {
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("dns")
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
@@ -17,7 +19,7 @@ type IndexAction struct {
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("ssh")
|
||||
}
|
||||
|
||||
@@ -33,7 +35,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
// 登录信息
|
||||
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 +44,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 +72,45 @@ 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 {
|
||||
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 {
|
||||
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 +130,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()
|
||||
}
|
||||
@@ -15,7 +15,7 @@ type IndexAction struct {
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("system")
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ type IndexAction struct {
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
this.Nav("", "node", "update")
|
||||
this.SecondMenu("threshold")
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +3,8 @@ 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"
|
||||
@@ -29,17 +31,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 +69,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 +79,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 +88,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 +109,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 +211,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 +223,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,12 +238,12 @@ 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().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{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) + ")"
|
||||
@@ -248,7 +262,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 +271,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,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,
|
||||
}
|
||||
|
||||
@@ -8,6 +8,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 IndexAction struct {
|
||||
@@ -65,22 +66,34 @@ 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,
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"installDir": cluster.InstallDir,
|
||||
"timeZone": cluster.TimeZone,
|
||||
"nodeMaxThreads": cluster.NodeMaxThreads,
|
||||
"nodeTCPMaxConnections": cluster.NodeTCPMaxConnections,
|
||||
"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
|
||||
ClusterId int64
|
||||
Name string
|
||||
GrantId int64
|
||||
InstallDir string
|
||||
TimeZone string
|
||||
NodeMaxThreads int32
|
||||
NodeTCPMaxConnections int32
|
||||
AutoOpenPorts bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -91,12 +104,22 @@ func (this *IndexAction) RunPost(params struct {
|
||||
Field("name", params.Name).
|
||||
Require("请输入集群名称")
|
||||
|
||||
if params.NodeMaxThreads > 0 {
|
||||
params.Must.
|
||||
Field("nodeMaxThreads", params.NodeMaxThreads).
|
||||
Gte(int64(nodeconfigs.DefaultMaxThreadsMin), "单节点最大线程数最小值不能小于"+types.String(nodeconfigs.DefaultMaxThreadsMin)).
|
||||
Lte(int64(nodeconfigs.DefaultMaxThreadsMax), "单节点最大线程数最大值不能大于"+types.String(nodeconfigs.DefaultMaxThreadsMax))
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeCluster(this.AdminContext(), &pb.UpdateNodeClusterRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
NodeGrantId: params.GrantId,
|
||||
InstallDir: params.InstallDir,
|
||||
TimeZone: params.TimeZone,
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
NodeGrantId: params.GrantId,
|
||||
InstallDir: params.InstallDir,
|
||||
TimeZone: params.TimeZone,
|
||||
NodeMaxThreads: params.NodeMaxThreads,
|
||||
NodeTCPMaxConnections: params.NodeTCPMaxConnections,
|
||||
AutoOpenPorts: params.AutoOpenPorts,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -12,6 +12,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 +39,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 +76,9 @@ func init() {
|
||||
GetPost("/createPopup", new(metrics.CreatePopupAction)).
|
||||
Post("/delete", new(metrics.DeleteAction)).
|
||||
|
||||
// WebP
|
||||
Prefix("/clusters/cluster/settings/webp").
|
||||
GetPost("", new(webp.IndexAction)).
|
||||
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": "缓存设置",
|
||||
@@ -124,6 +130,12 @@ 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": "统计指标",
|
||||
"url": "/clusters/cluster/settings/metrics?clusterId=" + clusterId,
|
||||
@@ -157,6 +169,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()
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
PrivateKey string
|
||||
Passphrase string
|
||||
Description string
|
||||
Su bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -61,6 +62,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
PrivateKey: params.PrivateKey,
|
||||
Passphrase: params.Passphrase,
|
||||
Description: params.Description,
|
||||
Su: params.Su,
|
||||
NodeId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -31,6 +31,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
PrivateKey string
|
||||
Passphrase string
|
||||
Description string
|
||||
Su bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -62,6 +63,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
PrivateKey: params.PrivateKey,
|
||||
Passphrase: params.Passphrase,
|
||||
Description: params.Description,
|
||||
Su: params.Su,
|
||||
NodeId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -74,6 +76,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
"name": params.Name,
|
||||
"method": params.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(params.Method),
|
||||
"username": params.Username,
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
|
||||
@@ -60,6 +60,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
PrivateKey string
|
||||
Passphrase string
|
||||
Description string
|
||||
Su bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -97,6 +98,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
PrivateKey: params.PrivateKey,
|
||||
Passphrase: params.Passphrase,
|
||||
Description: params.Description,
|
||||
Su: params.Su,
|
||||
NodeId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -44,6 +44,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
||||
"description": grant.Description,
|
||||
"privateKey": grant.PrivateKey,
|
||||
"passphrase": grant.Passphrase,
|
||||
"su": grant.Su,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
@@ -59,6 +60,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
PrivateKey string
|
||||
Passphrase string
|
||||
Description string
|
||||
Su bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -96,6 +98,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
Passphrase: params.Passphrase,
|
||||
Description: params.Description,
|
||||
NodeId: params.NodeId,
|
||||
Su: params.Su,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -108,6 +111,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
"name": params.Name,
|
||||
"method": params.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(params.Method),
|
||||
"username": params.Username,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
|
||||
@@ -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,13 +16,15 @@ func init() {
|
||||
Prefix("/clusters").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/create", new(CreateAction)).
|
||||
Post("/pin", new(PinAction)).
|
||||
Get("/nodes", new(NodesAction)).
|
||||
|
||||
// 只要登录即可访问的Action
|
||||
EndHelpers().
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
||||
Post("/options", new(OptionsAction)).
|
||||
Post("/nodeOptions", new(NodeOptionsAction)).
|
||||
GetPost("/selectPopup", new(SelectPopupAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
33
internal/web/actions/default/clusters/logs/fix.go
Normal file
33
internal/web/actions/default/clusters/logs/fix.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
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 FixAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
type FixLogAction struct {
|
||||
type FixAllAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *FixLogAction) RunPost(params struct {
|
||||
LogId int64
|
||||
func (this *FixAllAction) RunPost(params struct {
|
||||
}) {
|
||||
_, err := this.RPC().NodeLogRPC().FixNodeLog(this.AdminContext(), &pb.FixNodeLogRequest{NodeLogId: params.LogId})
|
||||
defer this.CreateLogInfo("设置所有日志为已修复")
|
||||
|
||||
_, err := this.RPC().NodeLogRPC().FixAllNodeLogs(this.AdminContext(), &pb.FixAllNodeLogsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -1,9 +1,12 @@
|
||||
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"
|
||||
)
|
||||
@@ -13,25 +16,44 @@ 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")
|
||||
}
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
DayFrom string
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
Type string
|
||||
DayFrom string
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
Type string // unread, needFix
|
||||
Tag string
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["dayFrom"] = params.DayFrom
|
||||
this.Data["dayTo"] = params.DayTo
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["tag"] = params.Tag
|
||||
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()
|
||||
|
||||
// 未读数量
|
||||
countUnreadResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
@@ -44,48 +66,68 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["countUnreadLogs"] = countUnreadResp.Count
|
||||
|
||||
// 日志数量
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
NodeId: 0,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
IsUnread: params.Type == "unread",
|
||||
// 需要修复数量
|
||||
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
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["countNeedFixLogs"] = countNeedFixResp.Count
|
||||
|
||||
// 日志数量
|
||||
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
IsUnread: params.Type == "unread",
|
||||
Tag: params.Tag,
|
||||
FixedState: int32(fixedState),
|
||||
AllServers: allServers,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||
NodeId: 0,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
IsUnread: params.Type == "unread",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
DayFrom: params.DayFrom,
|
||||
DayTo: params.DayTo,
|
||||
Keyword: params.Keyword,
|
||||
Level: params.Level,
|
||||
IsUnread: params.Type == "unread",
|
||||
Tag: params.Tag,
|
||||
FixedState: int32(fixedState),
|
||||
AllServers: allServers,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
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
|
||||
}
|
||||
@@ -104,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,
|
||||
@@ -113,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()
|
||||
})
|
||||
}
|
||||
|
||||
34
internal/web/actions/default/clusters/nodeOptions.go
Normal file
34
internal/web/actions/default/clusters/nodeOptions.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"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type NodeOptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *NodeOptionsAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
resp, err := this.RPC().NodeRPC().FindAllEnabledNodesWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodesWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range resp.Nodes {
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
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{
|
||||
|
||||
@@ -10,7 +10,9 @@ type CheckAction struct {
|
||||
}
|
||||
|
||||
func (this *CheckAction) RunPost(params struct{}) {
|
||||
resp, err := this.RPC().NodeTaskRPC().ExistsNodeTasks(this.AdminContext(), &pb.ExistsNodeTasksRequest{})
|
||||
resp, err := this.RPC().NodeTaskRPC().ExistsNodeTasks(this.AdminContext(), &pb.ExistsNodeTasksRequest{
|
||||
ExcludeTypes: []string{"ipItemChanged"},
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
|
||||
@@ -40,6 +40,11 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// 版本更新
|
||||
this.Data["currentVersionCode"] = teaconst.Version
|
||||
this.Data["newVersionCode"] = teaconst.NewVersionCode
|
||||
this.Data["newVersionDownloadURL"] = teaconst.NewVersionDownloadURL
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ func ValidateDomainFormat(domain string) bool {
|
||||
if piece == "-" ||
|
||||
strings.HasPrefix(piece, "-") ||
|
||||
strings.HasSuffix(piece, "-") ||
|
||||
strings.Contains(piece, "--") ||
|
||||
//strings.Contains(piece, "--") ||
|
||||
len(piece) > 63 ||
|
||||
!regexp.MustCompile(`^[a-z0-9-]+$`).MatchString(piece) {
|
||||
return false
|
||||
@@ -75,7 +75,7 @@ func ValidateRecordName(name string) bool {
|
||||
if piece == "-" ||
|
||||
strings.HasPrefix(piece, "-") ||
|
||||
strings.HasSuffix(piece, "-") ||
|
||||
strings.Contains(piece, "--") ||
|
||||
//strings.Contains(piece, "--") ||
|
||||
len(piece) > 63 ||
|
||||
!regexp.MustCompile(`^[_a-z0-9-]+$`).MatchString(piece) {
|
||||
return false
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package providers
|
||||
|
||||
import (
|
||||
@@ -60,8 +65,9 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Type string
|
||||
|
||||
// DNSPod
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamRegion string
|
||||
|
||||
// AliDNS
|
||||
ParamAccessKeyId string
|
||||
@@ -76,8 +82,8 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
ParamApiSecret string
|
||||
|
||||
// CloudFlare
|
||||
CloudFlareAPIKey string
|
||||
CloudFlareEmail string
|
||||
ParamCloudFlareAPIKey string
|
||||
ParamCloudFlareEmail string
|
||||
|
||||
// Local EdgeDNS
|
||||
ParamLocalEdgeDNSClusterId int64
|
||||
@@ -106,6 +112,7 @@ 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).
|
||||
@@ -135,12 +142,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 {
|
||||
@@ -17,12 +19,20 @@ func (this *IndexAction) Init() {
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
Domain string
|
||||
}) {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["domain"] = params.Domain
|
||||
|
||||
// 格式化域名
|
||||
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,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -35,6 +45,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
providersResp, err := this.RPC().DNSProviderRPC().ListEnabledDNSProviders(this.AdminContext(), &pb.ListEnabledDNSProvidersRequest{
|
||||
AdminId: this.AdminId(),
|
||||
Keyword: params.Keyword,
|
||||
Domain: domain,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package providers
|
||||
|
||||
import (
|
||||
@@ -89,8 +92,9 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
Type string
|
||||
|
||||
// DNSPod
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamId string
|
||||
ParamToken string
|
||||
ParamRegion string
|
||||
|
||||
// AliDNS
|
||||
ParamAccessKeyId string
|
||||
@@ -105,8 +109,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
ParamApiSecret string
|
||||
|
||||
// CloudFlare
|
||||
CloudFlareAPIKey string
|
||||
CloudFlareEmail string
|
||||
ParamCloudFlareAPIKey string
|
||||
ParamCloudFlareEmail string
|
||||
|
||||
// Local EdgeDNS
|
||||
ParamLocalEdgeDNSClusterId int64
|
||||
@@ -137,6 +141,7 @@ 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).
|
||||
@@ -166,12 +171,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)
|
||||
|
||||
@@ -3,6 +3,7 @@ package ipAddresses
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
@@ -39,9 +40,15 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Field("ip", params.IP).
|
||||
Require("请输入IP地址")
|
||||
|
||||
ip := net.ParseIP(params.IP)
|
||||
if len(ip) == 0 {
|
||||
this.FailField("ip", "请输入正确的IP")
|
||||
result, err := utils.ExtractIP(params.IP)
|
||||
if err != nil {
|
||||
this.Fail("IP格式错误'" + params.IP + "'")
|
||||
}
|
||||
|
||||
for _, ip := range result {
|
||||
if len(net.ParseIP(ip)) == 0 {
|
||||
this.FailField("ip", "请输入正确的IP")
|
||||
}
|
||||
}
|
||||
|
||||
// 阈值设置
|
||||
|
||||
@@ -2,6 +2,7 @@ package ipaddressutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
@@ -16,8 +17,11 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
|
||||
return err
|
||||
}
|
||||
for _, addr := range addresses {
|
||||
var resultAddrIds = []int64{}
|
||||
addrId := addr.GetInt64("id")
|
||||
if addrId > 0 {
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
|
||||
var isOn = false
|
||||
if !addr.Has("isOn") { // 兼容老版本
|
||||
isOn = true
|
||||
@@ -37,18 +41,40 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: role,
|
||||
Name: addr.GetString("name"),
|
||||
Ip: addr.GetString("ip"),
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
var ipStrings = addr.GetString("ip")
|
||||
result, _ := utils.ExtractIP(ipStrings)
|
||||
|
||||
if len(result) == 1 {
|
||||
// 单个创建
|
||||
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: role,
|
||||
Name: addr.GetString("name"),
|
||||
Ip: result[0],
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addrId = createResp.NodeIPAddressId
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
} else if len(result) > 1 {
|
||||
// 批量创建
|
||||
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(parentAction.AdminContext(), &pb.CreateNodeIPAddressesRequest{
|
||||
NodeId: nodeId,
|
||||
Role: role,
|
||||
Name: addr.GetString("name"),
|
||||
IpList: result,
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
GroupValue: ipStrings,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
|
||||
}
|
||||
addrId = createResp.NodeIPAddressId
|
||||
}
|
||||
|
||||
// 保存阈值
|
||||
@@ -58,12 +84,25 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeIPAddressThresholdsJSON: thresholdsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
for _, addrId := range resultAddrIds {
|
||||
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeIPAddressThresholdsJSON: thresholdsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, addrId := range resultAddrIds {
|
||||
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeIPAddressThresholdsJSON: []byte("[]"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package ipAddresses
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
@@ -57,9 +58,22 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
ip := net.ParseIP(params.IP)
|
||||
if len(ip) == 0 {
|
||||
this.Fail("请输入正确的IP")
|
||||
if params.AddressId > 0 {
|
||||
ip := net.ParseIP(params.IP)
|
||||
if len(ip) == 0 {
|
||||
this.Fail("请输入正确的IP")
|
||||
}
|
||||
} else {
|
||||
result, err := utils.ExtractIP(params.IP)
|
||||
if err != nil {
|
||||
this.Fail("IP格式错误'" + params.IP + "'")
|
||||
}
|
||||
|
||||
for _, ip := range result {
|
||||
if len(net.ParseIP(ip)) == 0 {
|
||||
this.FailField("ip", "请输入正确的IP")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var thresholds = []*nodeconfigs.IPAddressThresholdConfig{}
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
RequestId string
|
||||
Keyword string
|
||||
Day string
|
||||
}) {
|
||||
day := strings.ReplaceAll(params.Day, "-", "")
|
||||
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
|
||||
day = timeutil.Format("Ymd")
|
||||
}
|
||||
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["day"] = day[:4] + "-" + day[4:6] + "-" + day[6:]
|
||||
this.Data["path"] = this.Request.URL.Path
|
||||
|
||||
var size = int64(10)
|
||||
|
||||
resp, err := this.RPC().NSAccessLogRPC().ListNSAccessLogs(this.AdminContext(), &pb.ListNSAccessLogsRequest{
|
||||
RequestId: params.RequestId,
|
||||
NsNodeId: 0,
|
||||
NsDomainId: 0,
|
||||
NsRecordId: 0,
|
||||
Size: size,
|
||||
Day: day,
|
||||
Keyword: params.Keyword,
|
||||
Reverse: false,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
ipList := []string{}
|
||||
nodeIds := []int64{}
|
||||
domainIds := []int64{}
|
||||
if len(resp.NsAccessLogs) == 0 {
|
||||
this.Data["accessLogs"] = []interface{}{}
|
||||
} else {
|
||||
this.Data["accessLogs"] = resp.NsAccessLogs
|
||||
for _, accessLog := range resp.NsAccessLogs {
|
||||
// IP
|
||||
if len(accessLog.RemoteAddr) > 0 {
|
||||
// 去掉端口
|
||||
ip, _, err := net.SplitHostPort(accessLog.RemoteAddr)
|
||||
if err == nil {
|
||||
accessLog.RemoteAddr = ip
|
||||
if !lists.ContainsString(ipList, ip) {
|
||||
ipList = append(ipList, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 节点
|
||||
if !lists.ContainsInt64(nodeIds, accessLog.NsNodeId) {
|
||||
nodeIds = append(nodeIds, accessLog.NsNodeId)
|
||||
}
|
||||
|
||||
// 域名
|
||||
if !lists.ContainsInt64(domainIds, accessLog.NsDomainId) {
|
||||
domainIds = append(domainIds, accessLog.NsDomainId)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["hasMore"] = resp.HasMore
|
||||
this.Data["nextRequestId"] = resp.RequestId
|
||||
|
||||
// 上一个requestId
|
||||
this.Data["hasPrev"] = false
|
||||
this.Data["lastRequestId"] = ""
|
||||
if len(params.RequestId) > 0 {
|
||||
this.Data["hasPrev"] = true
|
||||
prevResp, err := this.RPC().NSAccessLogRPC().ListNSAccessLogs(this.AdminContext(), &pb.ListNSAccessLogsRequest{
|
||||
RequestId: params.RequestId,
|
||||
NsNodeId: 0,
|
||||
NsDomainId: 0,
|
||||
NsRecordId: 0,
|
||||
Day: day,
|
||||
Keyword: params.Keyword,
|
||||
Size: size,
|
||||
Reverse: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if int64(len(prevResp.NsAccessLogs)) == size {
|
||||
this.Data["lastRequestId"] = prevResp.RequestId
|
||||
}
|
||||
}
|
||||
|
||||
// 根据IP查询区域
|
||||
regionMap := map[string]string{} // ip => region
|
||||
if len(ipList) > 0 {
|
||||
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IpRegionMap != nil {
|
||||
for ip, region := range resp.IpRegionMap {
|
||||
if len(region.Isp) > 0 {
|
||||
region.Summary += " | " + region.Isp
|
||||
}
|
||||
regionMap[ip] = region.Summary
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["regions"] = regionMap
|
||||
|
||||
// 节点信息
|
||||
nodeMap := map[int64]interface{}{} // node id => { ... }
|
||||
for _, nodeId := range nodeIds {
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: nodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.NsNode
|
||||
if node != nil {
|
||||
nodeMap[node.Id] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"cluster": maps.Map{
|
||||
"id": node.NsCluster.Id,
|
||||
"name": node.NsCluster.Name,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["nodes"] = nodeMap
|
||||
|
||||
// 域名信息
|
||||
domainMap := map[int64]interface{}{} // domain id => { ... }
|
||||
for _, domainId := range domainIds {
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: domainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domain := domainResp.NsDomain
|
||||
if domain != nil {
|
||||
domainMap[domain.Id] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["domains"] = domainMap
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// CreateNodeAction 创建节点
|
||||
type CreateNodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) Init() {
|
||||
this.Nav("", "node", "create")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunPost(params struct {
|
||||
Name string
|
||||
IpAddressesJSON []byte
|
||||
ClusterId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入节点名称")
|
||||
|
||||
if len(params.IpAddressesJSON) == 0 {
|
||||
this.Fail("请至少添加一个IP地址")
|
||||
}
|
||||
|
||||
// 检查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地址")
|
||||
}
|
||||
|
||||
// 保存
|
||||
createResp, err := this.RPC().NSNodeRPC().CreateNSNode(this.AdminContext(), &pb.CreateNSNodeRequest{
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
nodeId := createResp.NsNodeId
|
||||
|
||||
// IP地址
|
||||
for _, addrMap := range ipAddresses {
|
||||
addressId := addrMap.GetInt64("id")
|
||||
if addressId > 0 {
|
||||
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
|
||||
NodeIPAddressId: addressId,
|
||||
NodeId: nodeId,
|
||||
})
|
||||
} else {
|
||||
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
Name: addrMap.GetString("name"),
|
||||
Ip: addrMap.GetString("ip"),
|
||||
CanAccess: addrMap.GetBool("canAccess"),
|
||||
IsUp: addrMap.GetBool("isUp"),
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "创建域名服务节点 %d", nodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) Init() {
|
||||
this.Nav("", "delete", "index")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "删除域名服务集群 %d", params.ClusterId)
|
||||
|
||||
// TODO 如果有用户在使用此集群,就不能删除
|
||||
|
||||
// 删除
|
||||
_, err := this.RPC().NSClusterRPC().DeleteNSCluster(this.AdminContext(), &pb.DeleteNSCluster{NsClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,26 +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"
|
||||
)
|
||||
|
||||
type DeleteNodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteNodeAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除域名服务节点 %d", params.NodeId)
|
||||
|
||||
_, err := this.RPC().NSNodeRPC().DeleteNSNode(this.AdminContext(), &pb.DeleteNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"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"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
InstalledState int
|
||||
ActiveState int
|
||||
Keyword string
|
||||
}) {
|
||||
this.Data["installState"] = params.InstalledState
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
countAllResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countAll"] = countAllResp.Count
|
||||
|
||||
countResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
page := this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
nodesResp, err := this.RPC().NSNodeRPC().ListEnabledNSNodesMatch(this.AdminContext(), &pb.ListEnabledNSNodesMatchRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
NsClusterId: params.ClusterId,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
nodeMaps := []maps.Map{}
|
||||
for _, node := range nodesResp.NsNodes {
|
||||
// 状态
|
||||
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秒之内认为活跃
|
||||
}
|
||||
|
||||
// IP
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||
NodeId: node.Id,
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
})
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
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": node.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),
|
||||
},
|
||||
"ipAddresses": ipAddresses,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
// 记录最近访问
|
||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "nsCluster",
|
||||
ItemId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package cluster
|
||||
|
||||
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/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdateNodeSSHAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateNodeSSHAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdateNodeSSHAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if nodeResp.NsNode == nil {
|
||||
this.NotFound("node", params.NodeId)
|
||||
return
|
||||
}
|
||||
|
||||
node := nodeResp.NsNode
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
}
|
||||
|
||||
if nodeResp.NsNode.NsCluster != nil {
|
||||
this.Data["clusterId"] = nodeResp.NsNode.NsCluster.Id
|
||||
} else {
|
||||
this.Data["clusterId"] = 0
|
||||
}
|
||||
|
||||
// SSH
|
||||
loginParams := maps.Map{
|
||||
"host": "",
|
||||
"port": "",
|
||||
"grantId": 0,
|
||||
}
|
||||
this.Data["loginId"] = 0
|
||||
if node.NodeLogin != nil {
|
||||
this.Data["loginId"] = node.NodeLogin.Id
|
||||
if len(node.NodeLogin.Params) > 0 {
|
||||
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["params"] = loginParams
|
||||
|
||||
// 认证信息
|
||||
grantId := loginParams.GetInt64("grantId")
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
var grantMap maps.Map = nil
|
||||
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),
|
||||
}
|
||||
}
|
||||
this.Data["grant"] = grantMap
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateNodeSSHAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
LoginId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
GrantId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("sshHost", params.SshHost).
|
||||
Require("请输入SSH主机地址").
|
||||
Field("sshPort", params.SshPort).
|
||||
Gt(0, "SSH主机端口需要大于0").
|
||||
Lt(65535, "SSH主机端口需要小于65535")
|
||||
|
||||
if params.GrantId <= 0 {
|
||||
this.Fail("需要选择或填写至少一个认证信息")
|
||||
}
|
||||
|
||||
login := &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().UpdateNSNodeLogin(this.AdminContext(), &pb.UpdateNSNodeLoginRequest{
|
||||
NsNodeId: params.NodeId,
|
||||
NodeLogin: login,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 配置", params.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cluster
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type UpgradeRemoteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpgradeRemoteAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpgradeRemoteAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package clusterutils
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ClusterHelper 单个集群的帮助
|
||||
type ClusterHelper struct {
|
||||
}
|
||||
|
||||
func NewClusterHelper() *ClusterHelper {
|
||||
return &ClusterHelper{}
|
||||
}
|
||||
|
||||
func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||
action := actionPtr.Object()
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return true
|
||||
}
|
||||
|
||||
action.Data["teaMenu"] = "ns"
|
||||
|
||||
selectedTabbar := action.Data.GetString("mainTab")
|
||||
clusterId := action.ParamInt64("clusterId")
|
||||
clusterIdString := strconv.FormatInt(clusterId, 10)
|
||||
action.Data["clusterId"] = clusterId
|
||||
|
||||
if clusterId > 0 {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
clusterResp, err := rpcClient.NSClusterRPC().FindEnabledNSCluster(actionPtr.(actionutils.ActionInterface).AdminContext(), &pb.FindEnabledNSClusterRequest{
|
||||
NsClusterId: clusterId,
|
||||
})
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
cluster := clusterResp.NsCluster
|
||||
if cluster == nil {
|
||||
action.WriteString("can not find ns cluster")
|
||||
return
|
||||
}
|
||||
|
||||
tabbar := actionutils.NewTabbar()
|
||||
tabbar.Add("集群列表", "", "/ns/clusters", "", false)
|
||||
tabbar.Add("集群节点", "", "/ns/clusters/cluster?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
||||
tabbar.Add("集群设置", "", "/ns/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
|
||||
tabbar.Add("删除集群", "", "/ns/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete")
|
||||
|
||||
{
|
||||
m := tabbar.Add("当前集群:"+cluster.Name, "", "/ns/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, secondMenuItem)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 设置菜单
|
||||
func (this *ClusterHelper) createSettingMenu(cluster *pb.NSCluster, selectedItem string) (items []maps.Map) {
|
||||
clusterId := numberutils.FormatInt64(cluster.Id)
|
||||
return []maps.Map{
|
||||
{
|
||||
"name": "基础设置",
|
||||
"url": "/ns/clusters/cluster/settings?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "basic",
|
||||
},
|
||||
{
|
||||
"name": "访问日志",
|
||||
"url": "/ns/clusters/cluster/settings/accessLog?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "accessLog",
|
||||
},
|
||||
{
|
||||
"name": "递归DNS",
|
||||
"url": "/ns/clusters/cluster/settings/recursion?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "recursion",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
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 CreateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateAction) Init() {
|
||||
this.Nav("", "", "create")
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunGet(params struct{}) {
|
||||
// 默认的访问日志设置
|
||||
this.Data["accessLogRef"] = &dnsconfigs.NSAccessLogRef{
|
||||
IsOn: true,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunPost(params struct {
|
||||
Name string
|
||||
AccessLogJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var clusterId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo("创建域名服务集群 %d", clusterId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入集群名称")
|
||||
|
||||
// 校验访问日志设置
|
||||
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())
|
||||
}
|
||||
|
||||
resp, err := this.RPC().NSClusterRPC().CreateNSCluster(this.AdminContext(), &pb.CreateNSClusterRequest{
|
||||
Name: params.Name,
|
||||
AccessLogJSON: params.AccessLogJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterId = resp.NsClusterId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
clustersResp, err := this.RPC().NSClusterRPC().ListEnabledNSClusters(this.AdminContext(), &pb.ListEnabledNSClustersRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range clustersResp.NsClusters {
|
||||
// 全部节点数量
|
||||
countNodesResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{NsClusterId: cluster.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 在线节点
|
||||
countActiveNodesResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
|
||||
NsClusterId: cluster.Id,
|
||||
ActiveState: types.Int32(configutils.BoolStateYes),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 需要升级的节点
|
||||
countUpgradeNodesResp, err := this.RPC().NSNodeRPC().CountAllUpgradeNSNodesWithNSClusterId(this.AdminContext(), &pb.CountAllUpgradeNSNodesWithNSClusterIdRequest{NsClusterId: cluster.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"isOn": cluster.IsOn,
|
||||
"countAllNodes": countNodesResp.Count,
|
||||
"countActiveNodes": countActiveNodesResp.Count,
|
||||
"countUpgradeNodes": countUpgradeNodesResp.Count,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package logs
|
||||
|
||||
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 IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
DayFrom string
|
||||
DayTo string
|
||||
Keyword string
|
||||
Level string
|
||||
}) {
|
||||
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{
|
||||
NodeId: 0,
|
||||
Role: nodeconfigs.NodeRoleDNS,
|
||||
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)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||
NodeId: 0,
|
||||
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 {
|
||||
// 节点信息
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: log.NodeId})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
node := nodeResp.NsNode
|
||||
if node == nil || node.NsCluster == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
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,
|
||||
"node": maps.Map{
|
||||
"id": node.Id,
|
||||
"cluster": maps.Map{
|
||||
"id": node.NsCluster.Id,
|
||||
"name": node.NsCluster.Name,
|
||||
},
|
||||
"name": node.Name,
|
||||
},
|
||||
})
|
||||
}
|
||||
this.Data["logs"] = logs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user