Compare commits

...

148 Commits

Author SHA1 Message Date
刘祥超
8f0054b2b0 更新components.js 2022-04-24 15:24:15 +08:00
刘祥超
33f86a7730 健康检查默认只做基础的请求 2022-04-23 13:26:34 +08:00
刘祥超
2487c69136 多个API节点时选择一个作为主节点 2022-04-23 12:32:13 +08:00
刘祥超
492d24f28a 修改一个搜索示例(从http改为https) 2022-04-23 09:09:00 +08:00
刘祥超
9a355da75c 集群概要信息中增加系统服务状态 2022-04-22 22:04:36 +08:00
刘祥超
8bae065572 手动健康检查增加超时时间为60s 2022-04-22 20:56:49 +08:00
刘祥超
efebb5a869 删除不需要的文件 2022-04-22 16:52:17 +08:00
刘祥超
32cc745a85 删除不需要的文件 2022-04-22 16:49:34 +08:00
刘祥超
42bfe3ffac 删除不必要的文件 2022-04-22 16:05:37 +08:00
刘祥超
de3a5f87cf 删除不需要的文件 2022-04-22 15:58:15 +08:00
刘祥超
bd1add6dea 优化代码 2022-04-22 15:58:07 +08:00
刘祥超
d275cc6a8b 修改一处颜色显示 2022-04-22 15:15:24 +08:00
刘祥超
556b5bd2e9 优化代码 2022-04-22 10:38:03 +08:00
刘祥超
e26cf2a19d 优化代码 2022-04-22 09:58:25 +08:00
刘祥超
94f5f1faf6 节点列表页CPU和内容用量增加百分号% 2022-04-22 09:22:15 +08:00
刘祥超
fb3c58bd60 修复IPBox只能显示昨日日志的Bug 2022-04-22 09:15:08 +08:00
刘祥超
e50c918e4d 优化界面显示 2022-04-22 09:14:48 +08:00
刘祥超
eb3ff3369c 增加WAF日志配置/WAF策略中之日志中增加分表查询 2022-04-21 19:45:25 +08:00
刘祥超
a07a08991f 更新components.js 2022-04-21 18:38:47 +08:00
刘祥超
6fcc8f3401 访问日志列表显示WAF相关信息 2022-04-21 16:20:03 +08:00
刘祥超
36b38c6da4 IP列表增加名单类型筛选 2022-04-21 15:09:24 +08:00
刘祥超
7f2f86b7ea 通过IP看访问日志时优先查询IP被加入名单的时间 2022-04-21 09:42:25 +08:00
刘祥超
68514bc7ed 修复访问日志耗时可能显示NaN的Bug 2022-04-21 09:41:59 +08:00
刘祥超
f0dfab536c 修复一个日志提示标签错误 2022-04-19 19:55:03 +08:00
刘祥超
3b75c9999e 自动将端口加入到本地防火墙 2022-04-19 19:51:38 +08:00
刘祥超
084ddf4f5d 更新components.js 2022-04-19 19:51:29 +08:00
刘祥超
6770b1fa72 域名解析增加GoDaddy DNS(目前仅商业版可用) 2022-04-19 16:33:51 +08:00
刘祥超
118d39ed83 修复sendfile功能显示错误 2022-04-19 14:19:06 +08:00
刘祥超
c24df4f876 证书在上传时检查有效期 2022-04-19 11:14:40 +08:00
刘祥超
0ae9c25d6f IP名单增加区域和ISP显示 2022-04-19 10:57:47 +08:00
刘祥超
f99b2a9def 优化界面文字 2022-04-18 21:05:01 +08:00
刘祥超
caf9eeae2e 集群DNS子域名可以随机生成 2022-04-18 18:19:30 +08:00
刘祥超
6afecb5708 单个服务切换集群时可以选择是否保留节点上的配置/总是可以切换集群,不再受所属用户的影响 2022-04-18 17:18:39 +08:00
刘祥超
739d32e2e0 修复访问日志分表为-1时无法切换的问题 2022-04-18 14:32:20 +08:00
刘祥超
4e601298b0 优化界面 2022-04-17 20:49:40 +08:00
刘祥超
74cffced3f 优化访问日志弹窗中的发送字节 2022-04-17 20:22:34 +08:00
刘祥超
f8cc76be35 服务访问日志也支持分表查询 2022-04-17 17:08:39 +08:00
刘祥超
dced2dd418 修复编译脚本无法生成components.js的问题 2022-04-17 16:40:29 +08:00
刘祥超
418fe97c67 Update components.src.js 2022-04-17 16:26:53 +08:00
刘祥超
1440f9b721 优化IPBox访问日志查询 2022-04-17 16:23:52 +08:00
刘祥超
9504c086ea 访问日志可以使用分表查询 2022-04-17 16:18:43 +08:00
刘祥超
3a15d6475c 优化看板界面 2022-04-16 22:23:58 +08:00
刘祥超
18f3a00c0f 修复看板中统计数据可能不显示的问题 2022-04-16 22:22:18 +08:00
刘祥超
5138bbe947 服务列表增加下行带宽 2022-04-15 12:15:09 +08:00
刘祥超
a309feb516 修复服务列表页面中待修复的日志数量显示错误的Bug 2022-04-15 09:58:30 +08:00
刘祥超
e9c172c261 服务列表--选择分组--增加"[未分组]"选项 2022-04-14 16:59:45 +08:00
刘祥超
6ac6842a8d 优化域名设置交互 2022-04-14 16:58:57 +08:00
刘祥超
71dc53ac1f 优化界面/将“反向代理”菜单改为“源站”,将“Web设置”改为“静态分发” 2022-04-14 15:58:39 +08:00
刘祥超
4450fa1379 优化SSH地址自动填充 2022-04-10 16:56:31 +08:00
刘祥超
af0f9489c7 优化本地日志 2022-04-10 15:58:54 +08:00
刘祥超
75b2b2bdb2 修改SSH时自动填入SSH主机地址/节点设置--SSH设置增加连接测试 2022-04-09 21:44:34 +08:00
刘祥超
2d8224fd12 服务设置菜单和路由规则菜单支持拦截函数 2022-04-08 22:09:45 +08:00
刘祥超
c3aea3ba72 支持使用uglifyjs压缩js组件文件 2022-04-08 21:24:54 +08:00
刘祥超
ad1ff29ed2 Update components.js 2022-04-08 20:49:33 +08:00
刘祥超
9887bd99c7 缓存条件增加暂停/恢复功能;缓存条件修改后自动保存 2022-04-08 20:49:31 +08:00
刘祥超
9af9d0192d 判断修改节点级别权限 2022-04-07 21:37:13 +08:00
刘祥超
62933cf637 优化界面 2022-04-07 19:53:10 +08:00
刘祥超
ee0837571d 增加当日统计接口 2022-04-07 19:46:45 +08:00
刘祥超
c2b12419c7 优化代码 2022-04-07 18:53:56 +08:00
刘祥超
991aed7e8c Update components.js 2022-04-07 18:34:34 +08:00
刘祥超
528d5fc5a9 增加节点列表 2022-04-07 18:31:21 +08:00
刘祥超
93569227f3 服务分组开启访问日志设置时,在服务访问日志设置界面有对应提示 2022-04-07 16:19:44 +08:00
刘祥超
46812f9e42 优化界面/删除不需要的文件 2022-04-07 10:21:38 +08:00
刘祥超
61f043319d 对访问日志中的Cookie进行排序显示 2022-04-05 15:58:35 +08:00
刘祥超
77140d01a0 优化访问日志Header显示 2022-04-05 15:43:49 +08:00
刘祥超
beff326001 访问日志中的响应Header和请求Header排序后显示 2022-04-05 15:38:22 +08:00
刘祥超
f2841b7328 优化界面 2022-04-05 15:23:48 +08:00
刘祥超
2ba63b2484 优化界面 2022-04-05 11:33:29 +08:00
刘祥超
f054241a73 优化界面 2022-04-04 19:47:57 +08:00
刘祥超
b5007b9195 缓存文件实现Sendfile 2022-04-04 19:46:12 +08:00
刘祥超
9deea64097 商业版支持L2节点 2022-04-04 12:08:18 +08:00
刘祥超
105777da21 优化界面 2022-04-02 16:33:08 +08:00
刘祥超
e13743dfa8 优化界面 2022-04-02 16:28:22 +08:00
刘祥超
35bdd3a41a 优化界面 2022-04-02 11:09:04 +08:00
刘祥超
464d757800 README增加功能介绍 2022-04-02 10:56:14 +08:00
刘祥超
8076fcd148 集群可以单独设置WebP策略 2022-04-01 16:42:08 +08:00
刘祥超
53b1f07601 优化证书上传和修改界面 2022-04-01 11:12:42 +08:00
刘祥超
2626d78835 只有满足缓存条件的图片内容才会被转换 2022-03-31 16:22:14 +08:00
刘祥超
3442ddfae2 优化代码 2022-03-31 15:21:02 +08:00
刘祥超
5ed863c5ec 特殊页面改为自定义页面 2022-03-31 14:53:07 +08:00
刘祥超
00f6387182 更新README中链接 2022-03-30 22:27:05 +08:00
刘祥超
ca70e8f0c8 全站防护改为5秒盾(商业版可用) 2022-03-30 11:37:55 +08:00
刘祥超
081e95b293 可以用域名搜索DNS账号 2022-03-30 11:15:32 +08:00
刘祥超
1282e610ba DNSPod区域改为中国站和国际站 2022-03-30 10:59:42 +08:00
刘祥超
287c52cef4 IP列表可以使用级别筛选 2022-03-30 09:41:14 +08:00
刘祥超
dd421fec80 支持DNSPod国际版 2022-03-30 09:12:16 +08:00
刘祥超
9b10bdaf0d Update components.js 2022-03-29 21:25:33 +08:00
刘祥超
4b916829a4 商业版增加UAM功能 2022-03-29 21:25:30 +08:00
刘祥超
b33e9d9187 修复服务统计--流量统计--即时的tooltip错误 2022-03-29 10:29:49 +08:00
刘祥超
9d0d323b50 数据库清理界面显示行数 2022-03-28 17:31:37 +08:00
刘祥超
2872569ce0 可以自行设定指标数据保留时间 2022-03-28 09:37:48 +08:00
刘祥超
cd2212b754 优化界面 2022-03-27 17:23:02 +08:00
刘祥超
eb6525b8d9 优化看板打开速度/删除一些不必要的文件 2022-03-27 16:39:20 +08:00
刘祥超
10319a1e3d 优化界面 2022-03-26 22:10:34 +08:00
刘祥超
6bcfea9372 支持路由定义请求脚本 2022-03-26 22:04:26 +08:00
刘祥超
4699d1c2ee 管理界面设置和用户界面设置可以修改时区 2022-03-26 10:23:03 +08:00
刘祥超
68f0b2efc3 反向代理要求必须添加源站 2022-03-25 14:42:28 +08:00
刘祥超
b2af8e196b 优化界面 2022-03-25 14:10:40 +08:00
刘祥超
2e626a915f 优化文字提示 2022-03-25 09:32:46 +08:00
刘祥超
0127050d89 修复无法修复单个日志的Bug 2022-03-25 09:32:35 +08:00
刘祥超
a25938022f 可以修复单页或者全部服务日志 2022-03-23 17:31:53 +08:00
刘祥超
c47b2973b0 优化文字 2022-03-23 16:33:20 +08:00
刘祥超
efd3934470 优化界面 2022-03-23 16:29:56 +08:00
刘祥超
fb7da4e07e 版本号改为0.4.7 2022-03-23 14:45:10 +08:00
刘祥超
d7d209f694 更改版本为0.4.6 2022-03-23 10:03:25 +08:00
刘祥超
83a88299c2 Update components.js 2022-03-21 08:23:34 +08:00
刘祥超
bfae3b86cc Age改为在缓存中的已存活时间 2022-03-20 21:18:51 +08:00
刘祥超
027ee4d336 GRPC通讯支持gzip压缩 2022-03-20 11:28:38 +08:00
刘祥超
b07a65c879 更新相关库 2022-03-20 10:46:09 +08:00
刘祥超
284b2762f5 优化界面 2022-03-18 20:21:00 +08:00
刘祥超
5ba6e3b332 改进文字 2022-03-18 17:02:36 +08:00
刘祥超
8b0e3d960a Update components.js 2022-03-17 19:59:58 +08:00
刘祥超
fba2953974 优化界面 2022-03-17 19:57:41 +08:00
刘祥超
a36b843eff 优化指标统计图表数字展示 2022-03-17 16:01:47 +08:00
刘祥超
0735bc2d8a 源站支持自定义回源主机名 2022-03-17 15:48:08 +08:00
刘祥超
69d6fd645b 修复访问日志按小时搜索无法上翻页的Bug 2022-03-17 12:31:45 +08:00
刘祥超
039b11d434 增加置顶集群功能 2022-03-17 11:12:24 +08:00
刘祥超
485581f680 优化界面 2022-03-17 10:36:30 +08:00
刘祥超
a0c2006e24 Update components.js 2022-03-16 22:48:04 +08:00
刘祥超
7a288c360d IPSet支持IPv6 2022-03-16 20:48:35 +08:00
刘祥超
597d39f651 优化文字 2022-03-16 17:07:46 +08:00
刘祥超
7d27f64b8a 节点可以单独设置缓存目录 2022-03-16 15:24:11 +08:00
刘祥超
bd280bdc53 改进文字 2022-03-14 19:25:19 +08:00
刘祥超
018429866e 优化文字提示 2022-03-14 16:24:09 +08:00
刘祥超
78ad6526b8 缓存策略可以使用存储类型筛选 2022-03-14 15:42:10 +08:00
刘祥超
8c6e960db7 实现回源跟随功能 2022-03-14 15:07:49 +08:00
刘祥超
46d38ff8c0 格式化部分图表中的数字 2022-03-14 12:04:46 +08:00
刘祥超
db6fe469ad 访问日志慢的时候增加指定域名查询建议 2022-03-11 20:35:42 +08:00
刘祥超
5a7630bcd1 增加证书OCSP错误日志管理 2022-03-11 20:27:45 +08:00
刘祥超
099b57169d 上传js 2022-03-10 21:32:56 +08:00
刘祥超
e22dfd3314 优化界面 2022-03-10 15:47:25 +08:00
刘祥超
be71992930 增加OCSP Stapling功能 2022-03-10 11:55:09 +08:00
刘祥超
37433178cb 支持使用小时筛选访问日志 2022-03-09 11:00:49 +08:00
刘祥超
14499a4564 增加对访问日志自动分表配置 2022-03-09 10:01:52 +08:00
刘祥超
0355777f59 优化文字 2022-03-06 19:48:50 +08:00
刘祥超
a55834c78d 优化界面 2022-03-04 17:00:01 +08:00
刘祥超
79bbb47459 更新TeaGo 2022-03-04 15:01:26 +08:00
刘祥超
d3bcf0605b 升级相关依赖库 2022-03-04 12:35:28 +08:00
刘祥超
19a02f3a40 实现基础的区间内容缓存(206 partial content) 2022-03-03 19:32:11 +08:00
刘祥超
db20e9308a 修复选择集群弹窗页面可能只显示前6个集群的Bug 2022-02-28 14:41:55 +08:00
刘祥超
b3f9f28554 优化界面显示 2022-02-27 21:20:49 +08:00
刘祥超
ea5bd3f346 可以在管理界面设置里设置默认每页显示数 2022-02-24 20:52:47 +08:00
刘祥超
5c13797639 缓存可以设置是否使用系统默认设置 2022-02-24 20:39:09 +08:00
刘祥超
f147905532 增加是否同步写入压缩缓存设置 2022-02-24 20:12:15 +08:00
刘祥超
a73314c12a 修改版本为0.4.5 2022-02-24 19:25:12 +08:00
刘祥超
619934a275 修复访问日志XSS漏洞 2022-02-23 17:34:54 +08:00
刘祥超
5fe1384e55 修改版本为0.4.4 2022-02-23 14:48:33 +08:00
刘祥超
9af2c4a18a 修改版本为v0.4.3 2022-02-21 18:32:03 +08:00
496 changed files with 19990 additions and 17894 deletions

5
.gitignore vendored
View File

@@ -2,4 +2,7 @@
*-plus.sh *-plus.sh
*_plus.html *_plus.html
*_plus.js *_plus.js
*@plus.js *@plus.js
*_plus.less
*_plus.css
*_plus.css.map

View File

@@ -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) * [http://demo.goedge.cn](http://demo.goedge.cn)
## 文档 ## 文档
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md) * [新手指南](https://goedge.cn/docs/QuickStart/Index.md)
* [完整文档](https://edge.teaos.cn/docs) * [完整文档](https://goedge.cn/docs)
* [开发者指南](https://edge.teaos.cn/docs/Developer/Build.md) * [开发者指南](https://goedge.cn/docs/Developer/Build.md)
## 架构 ## 架构
![架构](doc/architect-zh.jpg) ![架构](doc/architect-zh.jpg)
@@ -25,8 +54,7 @@
* [管理平台](https://github.com/TeaOSLab/EdgeAdmin) * [管理平台](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/)提供国内源代码托管平台

View File

@@ -2,6 +2,7 @@
function build() { function build() {
ROOT=$(dirname $0) ROOT=$(dirname $0)
JS_ROOT=$ROOT/../web/public/js
NAME="edge-admin" NAME="edge-admin"
DIST=$ROOT/"../dist/${NAME}" DIST=$ROOT/"../dist/${NAME}"
OS=${1} OS=${1}
@@ -53,6 +54,13 @@ function build() {
# generate files # generate files
echo "generating files ..." echo "generating files ..."
go run -tags $TAG $ROOT/../cmd/edge-admin/main.go generate 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 # create dir & copy files
echo "copying ..." echo "copying ..."
@@ -65,6 +73,8 @@ function build() {
cp -R $ROOT/../web $DIST/ cp -R $ROOT/../web $DIST/
rm -f $DIST/web/tmp/* 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/ cp $ROOT/configs/server.template.yaml $DIST/configs/
# change _plus.[ext] to .[ext] # change _plus.[ext] to .[ext]

View File

@@ -1,3 +1,16 @@
#!/usr/bin/env bash #!/usr/bin/env bash
JS_ROOT=../web/public/js
echo "generate component.src.js ..."
go run -tags=community ../cmd/edge-admin/main.go generate 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"

12
go.mod
View File

@@ -8,9 +8,8 @@ require (
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000 github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
github.com/cespare/xxhash v1.1.0 github.com/cespare/xxhash v1.1.0
github.com/go-sql-driver/mysql v1.5.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/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/iwind/gosock v0.0.0-20211103081026-ee4652210ca4
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/miekg/dns v1.1.35 github.com/miekg/dns v1.1.35
@@ -18,9 +17,8 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tealeg/xlsx/v3 v3.2.3 github.com/tealeg/xlsx/v3 v3.2.3
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect google.golang.org/grpc v1.45.0
google.golang.org/grpc v1.38.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
) )

88
go.sum
View File

@@ -1,10 +1,12 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 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= 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/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/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/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 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 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/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0 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/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-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-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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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.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.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.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/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 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= 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.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 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-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-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 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 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/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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 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.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.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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/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/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/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/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-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 h1:1cGulkD2SNJJRok5OKwyhP/Ddm+PgSWKOupn0cR36/A=
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc= 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/TeaGo v0.0.0-20220304042834-d8b5103e9027 h1:4knh28YgldmEtu8QG8pgQhUaI3i//qRjOdEyj9OVqXA=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA= 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 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA= 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.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 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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/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 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= 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-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 h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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 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 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 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/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.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.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.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 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ=
github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA= 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 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8= 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/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-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-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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= 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-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-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-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/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.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.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-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-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-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-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-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-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-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-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-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-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-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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-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-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-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-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 h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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-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-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-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-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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-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.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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/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.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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-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-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-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-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-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-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.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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 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-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-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-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-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-20220303160752-862486edd9cc h1:fb/ViRpv3ln/LvbqZtTpoOd1YQDNH12gaGZreoSFovE=
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/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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 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.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 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.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.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 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-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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 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.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.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-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.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 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f 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/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.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.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.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.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.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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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-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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -1,51 +1,108 @@
package apps package apps
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
"github.com/TeaOSLab/EdgeAdmin/internal/utils/sizes"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files" "github.com/iwind/TeaGo/files"
"github.com/iwind/TeaGo/logs" timeutil "github.com/iwind/TeaGo/utils/time"
"github.com/iwind/TeaGo/utils/time"
"log" "log"
"os"
"runtime"
"strconv"
"strings"
) )
type LogWriter struct { type LogWriter struct {
fileAppender *files.Appender fp *os.File
c chan string
} }
func (this *LogWriter) Init() { func (this *LogWriter) Init() {
// 创建目录 // 创建目录
dir := files.NewFile(Tea.LogDir()) var dir = files.NewFile(Tea.LogDir())
if !dir.Exists() { if !dir.Exists() {
err := dir.Mkdir() err := dir.Mkdir()
if err != nil { 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 { if err != nil {
logs.Error(err) log.Println("[LOG]open log file failed: " + err.Error())
} else { } 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) { 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 { if len(file) > 0 {
_, err := this.fileAppender.AppendString(timeutil.Format("Y/m/d H:i:s ") + message + "\n") log.Println(message + " (" + file + ":" + strconv.Itoa(line) + ")")
if err != nil { } else {
log.Println("[error]" + err.Error()) log.Println(message)
} }
} }
this.c <- message
} }
func (this *LogWriter) Close() { func (this *LogWriter) Close() {
if this.fileAppender != nil { if this.fp != nil {
_ = this.fileAppender.Close() _ = 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
} }

View File

@@ -3,10 +3,12 @@ package configloaders
import ( import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc" "github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
"reflect" "reflect"
"time"
) )
var sharedAdminUIConfig *systemconfigs.AdminUIConfig = nil var sharedAdminUIConfig *systemconfigs.AdminUIConfig = nil
@@ -45,6 +47,9 @@ func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
} }
sharedAdminUIConfig = uiConfig sharedAdminUIConfig = uiConfig
// timezone
updateTimeZone(uiConfig)
return nil return nil
} }
@@ -76,13 +81,17 @@ func loadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
return sharedAdminUIConfig, nil return sharedAdminUIConfig, nil
} }
config := &systemconfigs.AdminUIConfig{} var config = &systemconfigs.AdminUIConfig{}
err = json.Unmarshal(resp.ValueJSON, config) err = json.Unmarshal(resp.ValueJSON, config)
if err != nil { if err != nil {
logs.Println("[UI_MANAGER]" + err.Error()) logs.Println("[UI_MANAGER]" + err.Error())
sharedAdminUIConfig = defaultAdminUIConfig() sharedAdminUIConfig = defaultAdminUIConfig()
return sharedAdminUIConfig, nil return sharedAdminUIConfig, nil
} }
// timezone
updateTimeZone(config)
sharedAdminUIConfig = config sharedAdminUIConfig = config
return sharedAdminUIConfig, nil return sharedAdminUIConfig, nil
} }
@@ -94,5 +103,17 @@ func defaultAdminUIConfig() *systemconfigs.AdminUIConfig {
ShowOpenSourceInfo: true, ShowOpenSourceInfo: true,
ShowVersion: true, ShowVersion: true,
ShowFinance: 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
}
} }
} }

View File

@@ -2,8 +2,8 @@ package configs
import ( import (
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const" teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"gopkg.in/yaml.v3"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"

View File

@@ -1,9 +1,9 @@
package teaconst package teaconst
const ( const (
Version = "0.4.2" Version = "0.4.7"
APINodeVersion = "0.4.2" APINodeVersion = "0.4.7"
ProductName = "Edge Admin" ProductName = "Edge Admin"
ProcessName = "edge-admin" ProcessName = "edge-admin"

View File

@@ -21,7 +21,7 @@ import (
func Generate() error { func Generate() error {
err := generateComponentsJSFile() err := generateComponentsJSFile()
if err != nil { if err != nil {
return errors.New("generate 'components.js' failed: " + err.Error()) return errors.New("generate 'components.src.js' failed: " + err.Error())
} }
return nil return nil
@@ -115,7 +115,7 @@ func generateComponentsJSFile() error {
buffer.Write([]byte{'\n', '\n'}) buffer.Write([]byte{'\n', '\n'})
} }
fp, err := os.OpenFile(filepath.Clean(Tea.PublicFile("/js/components.js")), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777) fp, err := os.OpenFile(filepath.Clean(Tea.PublicFile("/js/components.src.js")), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -13,9 +13,12 @@ import (
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/rands" "github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/sessions" "github.com/iwind/TeaGo/sessions"
"github.com/iwind/TeaGo/types"
"github.com/iwind/gosock/pkg/gosock" "github.com/iwind/gosock/pkg/gosock"
"gopkg.in/yaml.v3"
"io/ioutil" "io/ioutil"
"log" "log"
"net"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@@ -58,6 +61,9 @@ func (this *AdminNode) Run() {
return return
} }
// 添加端口到防火墙
this.addPortsToFirewall()
// 监听信号 // 监听信号
sigQueue := make(chan os.Signal) sigQueue := make(chan os.Signal)
signal.Notify(sigQueue, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT) signal.Notify(sigQueue, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT)
@@ -201,6 +207,44 @@ https:
return nil 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节点 // 启动API节点
func (this *AdminNode) startAPINode() { func (this *AdminNode) startAPINode() {
configPath := Tea.Root + "/edge-api/configs/api.yaml" configPath := Tea.Root + "/edge-api/configs/api.yaml"

View File

@@ -16,6 +16,8 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/connectivity" "google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/encoding/gzip"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"net/url" "net/url"
"sync" "sync"
@@ -482,6 +484,10 @@ func (this *RPCClient) ServerStatBoardRPC() pb.ServerStatBoardServiceClient {
return pb.NewServerStatBoardServiceClient(this.pickConn()) return pb.NewServerStatBoardServiceClient(this.pickConn())
} }
func (this *RPCClient) ServerDomainHourlyStatRPC() pb.ServerDomainHourlyStatServiceClient {
return pb.NewServerDomainHourlyStatServiceClient(this.pickConn())
}
func (this *RPCClient) ServerStatBoardChartRPC() pb.ServerStatBoardChartServiceClient { func (this *RPCClient) ServerStatBoardChartRPC() pb.ServerStatBoardChartServiceClient {
return pb.NewServerStatBoardChartServiceClient(this.pickConn()) return pb.NewServerStatBoardChartServiceClient(this.pickConn())
} }
@@ -494,6 +500,10 @@ func (this *RPCClient) UserPlanRPC() pb.UserPlanServiceClient {
return pb.NewUserPlanServiceClient(this.pickConn()) return pb.NewUserPlanServiceClient(this.pickConn())
} }
func (this *RPCClient) TrafficDailyStatRPC() pb.TrafficDailyStatServiceClient {
return pb.NewTrafficDailyStatServiceClient(this.pickConn())
}
// Context 构造Admin上下文 // Context 构造Admin上下文
func (this *RPCClient) Context(adminId int64) context.Context { func (this *RPCClient) Context(adminId int64) context.Context {
ctx := context.Background() ctx := context.Background()
@@ -560,12 +570,14 @@ func (this *RPCClient) init() error {
return errors.New("parse endpoint failed: " + err.Error()) return errors.New("parse endpoint failed: " + err.Error())
} }
var conn *grpc.ClientConn var conn *grpc.ClientConn
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
grpc.UseCompressor(gzip.Name))
if u.Scheme == "http" { 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" { } else if u.Scheme == "https" {
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
})), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024))) })), callOptions)
} else { } else {
return errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'") return errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'")
} }

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

24
internal/utils/json.go Normal file
View 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
}

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

View File

@@ -46,11 +46,31 @@ func FormatCount(count int64) string {
if count < 1000 { if count < 1000 {
return types.String(count) return types.String(count)
} }
if count < 1000 * 1000 { if count < 1000*1000 {
return fmt.Sprintf("%.1fK", float32(count)/1000) return fmt.Sprintf("%.1fK", float32(count)/1000)
} }
if count < 1000 * 1000 * 1000{ if count < 1000*1000*1000 {
return fmt.Sprintf("%.1fM", float32(count)/1000/1000) return fmt.Sprintf("%.1fM", float32(count)/1000/1000)
} }
return fmt.Sprintf("%.1fB", float32(count)/1000/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)
}

View File

@@ -1,26 +1,36 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package numberutils package numberutils_test
import "testing" import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
"testing"
)
func TestFormatBytes(t *testing.T) { func TestFormatBytes(t *testing.T) {
t.Log(FormatBytes(1)) t.Log(numberutils.FormatBytes(1))
t.Log(FormatBytes(1000)) t.Log(numberutils.FormatBytes(1000))
t.Log(FormatBytes(1_000_000)) t.Log(numberutils.FormatBytes(1_000_000))
t.Log(FormatBytes(1_000_000_000)) t.Log(numberutils.FormatBytes(1_000_000_000))
t.Log(FormatBytes(1_000_000_000_000)) t.Log(numberutils.FormatBytes(1_000_000_000_000))
t.Log(FormatBytes(1_000_000_000_000_000)) t.Log(numberutils.FormatBytes(1_000_000_000_000_000))
t.Log(FormatBytes(1_000_000_000_000_000_000)) t.Log(numberutils.FormatBytes(1_000_000_000_000_000_000))
t.Log(FormatBytes(9_000_000_000_000_000_000)) t.Log(numberutils.FormatBytes(9_000_000_000_000_000_000))
} }
func TestFormatCount(t *testing.T) { func TestFormatCount(t *testing.T) {
t.Log(FormatCount(1)) t.Log(numberutils.FormatCount(1))
t.Log(FormatCount(1000)) t.Log(numberutils.FormatCount(1000))
t.Log(FormatCount(1500)) t.Log(numberutils.FormatCount(1500))
t.Log(FormatCount(1_000_000)) t.Log(numberutils.FormatCount(1_000_000))
t.Log(FormatCount(1_500_000)) t.Log(numberutils.FormatCount(1_500_000))
t.Log(FormatCount(1_000_000_000)) t.Log(numberutils.FormatCount(1_000_000_000))
t.Log(FormatCount(1_500_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))
}

View 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
)

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

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs" "github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc" "github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/utils" "github.com/TeaOSLab/EdgeAdmin/internal/utils"
@@ -55,7 +56,14 @@ func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
if len(size) > 0 { if len(size) > 0 {
return NewActionPage(this, total, 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) { func (this *ParentAction) Nav(mainMenu string, tab string, firstMenu string) {

View File

@@ -92,6 +92,7 @@ func (this *IndexAction) RunGet(params struct{}) {
"name": node.Name, "name": node.Name,
"accessAddrs": node.AccessAddrs, "accessAddrs": node.AccessAddrs,
"restAccessAddrs": restAccessAddrs, "restAccessAddrs": restAccessAddrs,
"isPrimary": node.IsPrimary,
"status": maps.Map{ "status": maps.Map{
"isActive": status.IsActive, "isActive": status.IsActive,
"updatedAt": status.UpdatedAt, "updatedAt": status.UpdatedAt,

View File

@@ -129,6 +129,7 @@ func (this *IndexAction) RunGet(params struct {
"restAccessAddrs": restAccessAddrs, "restAccessAddrs": restAccessAddrs,
"hasHTTPS": hasHTTPS, "hasHTTPS": hasHTTPS,
"certs": certs, "certs": certs,
"isPrimary": node.IsPrimary,
} }
this.Show() this.Show()

View File

@@ -29,13 +29,13 @@ func (this *UpdateAction) RunGet(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
node := nodeResp.ApiNode var node = nodeResp.ApiNode
if node == nil { if node == nil {
this.WriteString("要操作的节点不存在") this.WriteString("要操作的节点不存在")
return return
} }
httpConfig := &serverconfigs.HTTPProtocolConfig{} var httpConfig = &serverconfigs.HTTPProtocolConfig{}
if len(node.HttpJSON) > 0 { if len(node.HttpJSON) > 0 {
err = json.Unmarshal(node.HttpJSON, httpConfig) err = json.Unmarshal(node.HttpJSON, httpConfig)
if err != nil { if err != nil {
@@ -43,7 +43,7 @@ func (this *UpdateAction) RunGet(params struct {
return return
} }
} }
httpsConfig := &serverconfigs.HTTPSProtocolConfig{} var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
if len(node.HttpsJSON) > 0 { if len(node.HttpsJSON) > 0 {
err = json.Unmarshal(node.HttpsJSON, httpsConfig) err = json.Unmarshal(node.HttpsJSON, httpsConfig)
if err != nil { 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, httpConfig.Listen...)
listens = append(listens, httpsConfig.Listen...) listens = append(listens, httpsConfig.Listen...)
restHTTPConfig := &serverconfigs.HTTPProtocolConfig{} var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
if len(node.RestHTTPJSON) > 0 { if len(node.RestHTTPJSON) > 0 {
err = json.Unmarshal(node.RestHTTPJSON, restHTTPConfig) err = json.Unmarshal(node.RestHTTPJSON, restHTTPConfig)
if err != nil { if err != nil {
@@ -65,7 +65,7 @@ func (this *UpdateAction) RunGet(params struct {
return return
} }
} }
restHTTPSConfig := &serverconfigs.HTTPSProtocolConfig{} var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
if len(node.RestHTTPSJSON) > 0 { if len(node.RestHTTPSJSON) > 0 {
err = json.Unmarshal(node.RestHTTPSJSON, restHTTPSConfig) err = json.Unmarshal(node.RestHTTPSJSON, restHTTPSConfig)
if err != nil { 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, restHTTPConfig.Listen...)
restListens = append(restListens, restHTTPSConfig.Listen...) restListens = append(restListens, restHTTPSConfig.Listen...)
// 证书信息 // 证书信息
certs := []*sslconfigs.SSLCertConfig{} var certs = []*sslconfigs.SSLCertConfig{}
sslPolicyId := int64(0) var sslPolicyId = int64(0)
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 { if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId}) sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON var sslPolicyConfigJSON = sslPolicyConfigResp.SslPolicyJSON
if len(sslPolicyConfigJSON) > 0 { if len(sslPolicyConfigJSON) > 0 {
sslPolicyId = httpsConfig.SSLPolicyRef.SSLPolicyId 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 { if len(node.AccessAddrsJSON) > 0 {
err = json.Unmarshal(node.AccessAddrsJSON, &accessAddrs) err = json.Unmarshal(node.AccessAddrsJSON, &accessAddrs)
if err != nil { if err != nil {
@@ -122,6 +122,7 @@ func (this *UpdateAction) RunGet(params struct {
"certs": certs, "certs": certs,
"sslPolicyId": sslPolicyId, "sslPolicyId": sslPolicyId,
"accessAddrs": accessAddrs, "accessAddrs": accessAddrs,
"isPrimary": node.IsPrimary,
} }
this.Show() this.Show()
@@ -139,6 +140,7 @@ func (this *UpdateAction) RunPost(params struct {
AccessAddrsJSON []byte AccessAddrsJSON []byte
Description string Description string
IsOn bool IsOn bool
IsPrimary bool
Must *actions.Must Must *actions.Must
}) { }) {
@@ -146,11 +148,11 @@ func (this *UpdateAction) RunPost(params struct {
Field("name", params.Name). Field("name", params.Name).
Require("请输入API节点名称") Require("请输入API节点名称")
httpConfig := &serverconfigs.HTTPProtocolConfig{} var httpConfig = &serverconfigs.HTTPProtocolConfig{}
httpsConfig := &serverconfigs.HTTPSProtocolConfig{} var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
// 监听地址 // 监听地址
listens := []*serverconfigs.NetworkAddressConfig{} var listens = []*serverconfigs.NetworkAddressConfig{}
err := json.Unmarshal(params.ListensJSON, &listens) err := json.Unmarshal(params.ListensJSON, &listens)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -170,8 +172,8 @@ func (this *UpdateAction) RunPost(params struct {
} }
// Rest监听地址 // Rest监听地址
restHTTPConfig := &serverconfigs.HTTPProtocolConfig{} var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
restHTTPSConfig := &serverconfigs.HTTPSProtocolConfig{} var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
if params.RestIsOn { if params.RestIsOn {
restListens := []*serverconfigs.NetworkAddressConfig{} restListens := []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(params.RestListensJSON, &restListens) 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 { if len(params.CertIdsJSON) > 0 {
err = json.Unmarshal(params.CertIdsJSON, &certIds) err = json.Unmarshal(params.CertIdsJSON, &certIds)
if err != nil { if err != nil {
@@ -203,7 +205,7 @@ func (this *UpdateAction) RunPost(params struct {
this.Fail("请添加至少一个证书") this.Fail("请添加至少一个证书")
} }
certRefs := []*sslconfigs.SSLCertRef{} var certRefs = []*sslconfigs.SSLCertRef{}
for _, certId := range certIds { for _, certId := range certIds {
certRefs = append(certRefs, &sslconfigs.SSLCertRef{ certRefs = append(certRefs, &sslconfigs.SSLCertRef{
IsOn: true, IsOn: true,
@@ -217,7 +219,7 @@ func (this *UpdateAction) RunPost(params struct {
} }
// 创建策略 // 创建策略
sslPolicyId := params.SslPolicyId var sslPolicyId = params.SslPolicyId
if sslPolicyId == 0 { if sslPolicyId == 0 {
if len(certIds) > 0 { if len(certIds) > 0 {
sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{ 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) err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -291,6 +293,7 @@ func (this *UpdateAction) RunPost(params struct {
RestHTTPSJSON: restHTTPSJSON, RestHTTPSJSON: restHTTPSJSON,
AccessAddrsJSON: params.AccessAddrsJSON, AccessAddrsJSON: params.AccessAddrsJSON,
IsOn: params.IsOn, IsOn: params.IsOn,
IsPrimary: params.IsPrimary,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -54,6 +54,7 @@ func init() {
GetPost("/settings/dns", new(dns.IndexAction)). GetPost("/settings/dns", new(dns.IndexAction)).
GetPost("/settings/system", new(system.IndexAction)). GetPost("/settings/system", new(system.IndexAction)).
GetPost("/settings/ssh", new(ssh.IndexAction)). GetPost("/settings/ssh", new(ssh.IndexAction)).
GetPost("/settings/ssh/test", new(ssh.TestAction)).
GetPost("/settings/thresholds", new(thresholds.IndexAction)). GetPost("/settings/thresholds", new(thresholds.IndexAction)).
// 分组相关 // 分组相关

View File

@@ -33,7 +33,7 @@ func (this *DetailAction) RunGet(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
node := nodeResp.Node var node = nodeResp.Node
if node == nil { if node == nil {
this.WriteString("找不到要操作的节点") this.WriteString("找不到要操作的节点")
return return
@@ -197,7 +197,7 @@ func (this *DetailAction) RunGet(params struct {
} }
// 运行状态 // 运行状态
status := &nodeconfigs.NodeStatus{} var status = &nodeconfigs.NodeStatus{}
if len(node.StatusJSON) > 0 { if len(node.StatusJSON) > 0 {
err = json.Unmarshal(node.StatusJSON, &status) err = json.Unmarshal(node.StatusJSON, &status)
if err != nil { if err != nil {
@@ -285,6 +285,8 @@ func (this *DetailAction) RunGet(params struct {
"isOn": node.IsOn, "isOn": node.IsOn,
"records": recordMaps, "records": recordMaps,
"routes": routeMaps, "routes": routeMaps,
"level": node.Level,
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
"status": maps.Map{ "status": maps.Map{
"isActive": status.IsActive, "isActive": status.IsActive,
@@ -298,9 +300,9 @@ func (this *DetailAction) RunGet(params struct {
"buildVersion": status.BuildVersion, "buildVersion": status.BuildVersion,
"cpuPhysicalCount": status.CPUPhysicalCount, "cpuPhysicalCount": status.CPUPhysicalCount,
"cpuLogicalCount": status.CPULogicalCount, "cpuLogicalCount": status.CPULogicalCount,
"load1m": fmt.Sprintf("%.2f", status.Load1m), "load1m": numberutils.FormatFloat2(status.Load1m),
"load5m": fmt.Sprintf("%.2f", status.Load5m), "load5m": numberutils.FormatFloat2(status.Load5m),
"load15m": fmt.Sprintf("%.2f", status.Load15m), "load15m": numberutils.FormatFloat2(status.Load15m),
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize), "cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize), "cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
}, },

View File

@@ -4,6 +4,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils" "github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
@@ -43,7 +44,7 @@ func (this *LogsAction) RunGet(params struct {
this.Data["tag"] = params.Tag this.Data["tag"] = params.Tag
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{ countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
Role: "node", Role: nodeconfigs.NodeRoleNode,
NodeId: params.NodeId, NodeId: params.NodeId,
DayFrom: params.DayFrom, DayFrom: params.DayFrom,
DayTo: params.DayTo, DayTo: params.DayTo,

View File

@@ -38,6 +38,7 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
"isOn": node.IsOn, "isOn": node.IsOn,
"isUp": node.IsUp, "isUp": node.IsUp,
"group": groupMap, "group": groupMap,
"level": node.Level,
} }
var clusterId int64 = 0 var clusterId int64 = 0
if node.NodeCluster != nil { if node.NodeCluster != nil {
@@ -60,11 +61,15 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
"name": "DNS设置", "name": "DNS设置",
"url": prefix + "/settings/dns?" + query, "url": prefix + "/settings/dns?" + query,
"isActive": menuItem == "dns", "isActive": menuItem == "dns",
"isOn": len(node.DnsRoutes) > 0,
}, },
{ {
"name": "缓存设置", "name": "缓存设置",
"url": prefix + "/settings/cache?" + query, "url": prefix + "/settings/cache?" + query,
"isActive": menuItem == "cache", "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 { if teaconst.IsPlus {
@@ -81,11 +86,13 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
"name": "SSH设置", "name": "SSH设置",
"url": prefix + "/settings/ssh?" + query, "url": prefix + "/settings/ssh?" + query,
"isActive": menuItem == "ssh", "isActive": menuItem == "ssh",
"isOn": node.NodeLogin != nil,
}, },
{ {
"name": "系统设置", "name": "系统设置",
"url": prefix + "/settings/system?" + query, "url": prefix + "/settings/system?" + query,
"isActive": menuItem == "system", "isActive": menuItem == "system",
"isOn": node.MaxCPU > 0,
}, },
}...) }...)
parentAction.Data["leftMenuItems"] = menuItems parentAction.Data["leftMenuItems"] = menuItems

View File

@@ -59,6 +59,7 @@ func (this *IndexAction) RunGet(params struct {
var nodeMap = this.Data["node"].(maps.Map) var nodeMap = this.Data["node"].(maps.Map)
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
nodeMap["cacheDiskDir"] = node.CacheDiskDir
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
this.Show() this.Show()
@@ -67,6 +68,7 @@ func (this *IndexAction) RunGet(params struct {
func (this *IndexAction) RunPost(params struct { func (this *IndexAction) RunPost(params struct {
NodeId int64 NodeId int64
MaxCacheDiskCapacityJSON []byte MaxCacheDiskCapacityJSON []byte
CacheDiskDir string
MaxCacheMemoryCapacityJSON []byte MaxCacheMemoryCapacityJSON []byte
Must *actions.Must Must *actions.Must
@@ -106,6 +108,7 @@ func (this *IndexAction) RunPost(params struct {
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{ _, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity, MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
CacheDiskDir: params.CacheDiskDir,
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity, MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
}) })
if err != nil { if err != nil {

View File

@@ -10,6 +10,8 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"net"
"regexp"
) )
type IndexAction struct { type IndexAction struct {
@@ -33,7 +35,7 @@ func (this *IndexAction) RunGet(params struct {
// 登录信息 // 登录信息
var loginMap maps.Map = nil var loginMap maps.Map = nil
if node.NodeLogin != nil { if node.NodeLogin != nil {
loginParams := maps.Map{} var loginParams = maps.Map{}
if len(node.NodeLogin.Params) > 0 { if len(node.NodeLogin.Params) > 0 {
err = json.Unmarshal(node.NodeLogin.Params, &loginParams) err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
if err != nil { if err != nil {
@@ -42,7 +44,7 @@ func (this *IndexAction) RunGet(params struct {
} }
} }
grantMap := maps.Map{} var grantMap = maps.Map{}
grantId := loginParams.GetInt64("grantId") grantId := loginParams.GetInt64("grantId")
if grantId > 0 { if grantId > 0 {
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId}) 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) var nodeMap = this.Data["node"].(maps.Map)
nodeMap["login"] = loginMap nodeMap["login"] = loginMap
@@ -89,8 +130,13 @@ func (this *IndexAction) RunPost(params struct {
}) { }) {
defer this.CreateLogInfo("修改节点 %d SSH登录信息", params.NodeId) 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 检查登录授权 // TODO 检查登录授权
loginInfo := &pb.NodeLogin{ var loginInfo = &pb.NodeLogin{
Id: params.LoginId, Id: params.LoginId,
Name: "SSH", Name: "SSH",
Type: "ssh", Type: "ssh",

View File

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

View File

@@ -10,6 +10,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
) )
type UpdateAction struct { type UpdateAction struct {
@@ -37,7 +38,7 @@ func (this *UpdateAction) RunGet(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
node := nodeResp.Node var node = nodeResp.Node
if node == nil { if node == nil {
this.WriteString("找不到要操作的节点") this.WriteString("找不到要操作的节点")
return return
@@ -97,7 +98,7 @@ func (this *UpdateAction) RunGet(params struct {
} }
} }
var m = maps.Map{ var nodeMap = maps.Map{
"id": node.Id, "id": node.Id,
"name": node.Name, "name": node.Name,
"ipAddresses": ipAddressMaps, "ipAddresses": ipAddressMaps,
@@ -105,15 +106,16 @@ func (this *UpdateAction) RunGet(params struct {
"isOn": node.IsOn, "isOn": node.IsOn,
"group": groupMap, "group": groupMap,
"region": regionMap, "region": regionMap,
"level": node.Level,
} }
if node.NodeCluster != nil { if node.NodeCluster != nil {
m["primaryCluster"] = maps.Map{ nodeMap["primaryCluster"] = maps.Map{
"id": node.NodeCluster.Id, "id": node.NodeCluster.Id,
"name": node.NodeCluster.Name, "name": node.NodeCluster.Name,
} }
} else { } else {
m["primaryCluster"] = nil nodeMap["primaryCluster"] = nil
} }
if len(node.SecondaryNodeClusters) > 0 { if len(node.SecondaryNodeClusters) > 0 {
@@ -124,12 +126,14 @@ func (this *UpdateAction) RunGet(params struct {
"name": cluster.Name, "name": cluster.Name,
}) })
} }
m["secondaryClusters"] = secondaryClusterMaps nodeMap["secondaryClusters"] = secondaryClusterMaps
} else { } else {
m["secondaryClusters"] = []interface{}{} nodeMap["secondaryClusters"] = []interface{}{}
} }
this.Data["node"] = m this.Data["node"] = nodeMap
this.Data["canUpdateLevel"] = this.CanUpdateLevel(2)
this.Show() this.Show()
} }
@@ -144,11 +148,12 @@ func (this *UpdateAction) RunPost(params struct {
PrimaryClusterId int64 PrimaryClusterId int64
SecondaryClusterIds []byte SecondaryClusterIds []byte
IsOn bool IsOn bool
Level int32
Must *actions.Must Must *actions.Must
}) { }) {
// 创建日志 // 创建日志
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d", params.NodeId) defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 基本信息", params.NodeId)
if params.NodeId <= 0 { if params.NodeId <= 0 {
this.Fail("要操作的节点不存在") 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{ _, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
NodeId: params.NodeId, NodeId: params.NodeId,
NodeGroupId: params.GroupId, NodeGroupId: params.GroupId,
@@ -194,6 +203,7 @@ func (this *UpdateAction) RunPost(params struct {
NodeClusterId: params.PrimaryClusterId, NodeClusterId: params.PrimaryClusterId,
SecondaryNodeClusterIds: secondaryClusterIds, SecondaryNodeClusterIds: secondaryClusterIds,
IsOn: params.IsOn, IsOn: params.IsOn,
Level: params.Level,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

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

View File

@@ -3,6 +3,8 @@ package cluster
import ( import (
"encoding/json" "encoding/json"
"fmt" "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/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -29,17 +31,21 @@ func (this *NodesAction) RunGet(params struct {
InstalledState int InstalledState int
ActiveState int ActiveState int
Keyword string Keyword string
Level int32
CpuOrder string CpuOrder string
MemoryOrder string MemoryOrder string
TrafficInOrder string TrafficInOrder string
TrafficOutOrder string TrafficOutOrder string
LoadOrder string
}) { }) {
this.Data["groupId"] = params.GroupId this.Data["groupId"] = params.GroupId
this.Data["regionId"] = params.RegionId this.Data["regionId"] = params.RegionId
this.Data["installState"] = params.InstalledState this.Data["installState"] = params.InstalledState
this.Data["activeState"] = params.ActiveState this.Data["activeState"] = params.ActiveState
this.Data["keyword"] = params.Keyword 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}) 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, NodeClusterId: params.ClusterId,
NodeGroupId: params.GroupId, NodeGroupId: params.GroupId,
NodeRegionId: params.RegionId, NodeRegionId: params.RegionId,
Level: params.Level,
InstallState: types.Int32(params.InstalledState), InstallState: types.Int32(params.InstalledState),
ActiveState: types.Int32(params.ActiveState), ActiveState: types.Int32(params.ActiveState),
Keyword: params.Keyword, Keyword: params.Keyword,
@@ -72,7 +79,7 @@ func (this *NodesAction) RunGet(params struct {
return return
} }
page := this.NewPage(countResp.Count) var page = this.NewPage(countResp.Count)
this.Data["page"] = page.AsHTML() this.Data["page"] = page.AsHTML()
var req = &pb.ListEnabledNodesMatchRequest{ var req = &pb.ListEnabledNodesMatchRequest{
@@ -81,6 +88,7 @@ func (this *NodesAction) RunGet(params struct {
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
NodeGroupId: params.GroupId, NodeGroupId: params.GroupId,
NodeRegionId: params.RegionId, NodeRegionId: params.RegionId,
Level: params.Level,
InstallState: types.Int32(params.InstalledState), InstallState: types.Int32(params.InstalledState),
ActiveState: types.Int32(params.ActiveState), ActiveState: types.Int32(params.ActiveState),
Keyword: params.Keyword, Keyword: params.Keyword,
@@ -101,13 +109,17 @@ func (this *NodesAction) RunGet(params struct {
req.TrafficOutAsc = true req.TrafficOutAsc = true
} else if params.TrafficOutOrder == "desc" { } else if params.TrafficOutOrder == "desc" {
req.TrafficOutDesc = true 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) nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), req)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
nodeMaps := []maps.Map{} var nodeMaps = []maps.Map{}
for _, node := range nodesResp.Nodes { for _, node := range nodesResp.Nodes {
// 状态 // 状态
isSynced := false isSynced := false
@@ -199,6 +211,7 @@ func (this *NodesAction) RunGet(params struct {
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100), "memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
"trafficInBytes": status.TrafficInBytes, "trafficInBytes": status.TrafficInBytes,
"trafficOutBytes": status.TrafficOutBytes, "trafficOutBytes": status.TrafficOutBytes,
"load1m": numberutils.FormatFloat2(status.Load1m),
}, },
"cluster": maps.Map{ "cluster": maps.Map{
"id": node.NodeCluster.Id, "id": node.NodeCluster.Id,
@@ -210,12 +223,13 @@ func (this *NodesAction) RunGet(params struct {
"group": groupMap, "group": groupMap,
"region": regionMap, "region": regionMap,
"dnsRouteNames": dnsRouteNames, "dnsRouteNames": dnsRouteNames,
"level": node.Level,
}) })
} }
this.Data["nodes"] = nodeMaps this.Data["nodes"] = nodeMaps
// 所有分组 // 所有分组
groupMaps := []maps.Map{} var groupMaps = []maps.Map{}
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{ groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
}) })
@@ -224,12 +238,12 @@ func (this *NodesAction) RunGet(params struct {
return return
} }
for _, group := range groupsResp.NodeGroups { 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 { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
countNodes := countResp.Count countNodes := countNodesInGroupResp.Count
groupName := group.Name groupName := group.Name
if countNodes > 0 { if countNodes > 0 {
groupName += "(" + strconv.FormatInt(countNodes, 10) + ")" groupName += "(" + strconv.FormatInt(countNodes, 10) + ")"
@@ -248,7 +262,7 @@ func (this *NodesAction) RunGet(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
regionMaps := []maps.Map{} var regionMaps = []maps.Map{}
for _, region := range regionsResp.NodeRegions { for _, region := range regionsResp.NodeRegions {
regionMaps = append(regionMaps, maps.Map{ regionMaps = append(regionMaps, maps.Map{
"id": region.Id, "id": region.Id,
@@ -257,6 +271,12 @@ func (this *NodesAction) RunGet(params struct {
} }
this.Data["regions"] = regionMaps 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{ _, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
ItemType: "cluster", ItemType: "cluster",

View File

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

View File

@@ -34,6 +34,8 @@ func (this *CreatePopupAction) RunPost(params struct {
// ipset // ipset
IpsetWhiteName string IpsetWhiteName string
IpsetBlackName string IpsetBlackName string
IpsetWhiteNameIPv6 string
IpsetBlackNameIPv6 string
IpsetAutoAddToIPTables bool IpsetAutoAddToIPTables bool
IpsetAutoAddToFirewalld bool IpsetAutoAddToFirewalld bool
@@ -49,7 +51,7 @@ func (this *CreatePopupAction) RunPost(params struct {
Must *actions.Must Must *actions.Must
CSRF *actionutils.CSRF CSRF *actionutils.CSRF
}) { }) {
defer this.CreateLogInfo("创建WAF动作") defer this.CreateLogInfo("创建集群 %d 的WAF动作", params.ClusterId)
params.Must. params.Must.
Field("name", params.Name). Field("name", params.Name).
@@ -66,11 +68,19 @@ func (this *CreatePopupAction) RunPost(params struct {
Match(`^\w+$`, "请输入正确的IPSet白名单名称"). Match(`^\w+$`, "请输入正确的IPSet白名单名称").
Field("ipsetBlackName", params.IpsetBlackName). Field("ipsetBlackName", params.IpsetBlackName).
Require("请输入IPSet黑名单名称"). 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{ actionParams = &firewallconfigs.FirewallActionIPSetConfig{
WhiteName: params.IpsetWhiteName, WhiteName: params.IpsetWhiteName,
BlackName: params.IpsetBlackName, BlackName: params.IpsetBlackName,
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
BlackNameIPv6: params.IpsetBlackNameIPv6,
AutoAddToIPTables: params.IpsetAutoAddToIPTables, AutoAddToIPTables: params.IpsetAutoAddToIPTables,
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld, AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
} }

View File

@@ -63,6 +63,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
// ipset // ipset
IpsetWhiteName string IpsetWhiteName string
IpsetBlackName string IpsetBlackName string
IpsetWhiteNameIPv6 string
IpsetBlackNameIPv6 string
IpsetAutoAddToIPTables bool IpsetAutoAddToIPTables bool
IpsetAutoAddToFirewalld bool IpsetAutoAddToFirewalld bool
@@ -95,11 +97,19 @@ func (this *UpdatePopupAction) RunPost(params struct {
Match(`^\w+$`, "请输入正确的IPSet白名单名称"). Match(`^\w+$`, "请输入正确的IPSet白名单名称").
Field("ipsetBlackName", params.IpsetBlackName). Field("ipsetBlackName", params.IpsetBlackName).
Require("请输入IPSet黑名单名称"). 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{ actionParams = &firewallconfigs.FirewallActionIPSetConfig{
WhiteName: params.IpsetWhiteName, WhiteName: params.IpsetWhiteName,
BlackName: params.IpsetBlackName, BlackName: params.IpsetBlackName,
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
BlackNameIPv6: params.IpsetBlackNameIPv6,
AutoAddToIPTables: params.IpsetAutoAddToIPTables, AutoAddToIPTables: params.IpsetAutoAddToIPTables,
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld, AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
} }

View File

@@ -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/thresholds"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa" "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/waf"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/webp"
clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils" clusters "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo" "github.com/iwind/TeaGo"
@@ -38,6 +39,7 @@ func init() {
// DNS // DNS
Prefix("/clusters/cluster/settings/dns"). Prefix("/clusters/cluster/settings/dns").
GetPost("", new(dns.IndexAction)). GetPost("", new(dns.IndexAction)).
Post("/randomName", new(dns.RandomNameAction)).
// 消息 // 消息
Prefix("/clusters/cluster/settings/message"). Prefix("/clusters/cluster/settings/message").
@@ -74,6 +76,9 @@ func init() {
GetPost("/createPopup", new(metrics.CreatePopupAction)). GetPost("/createPopup", new(metrics.CreatePopupAction)).
Post("/delete", new(metrics.DeleteAction)). Post("/delete", new(metrics.DeleteAction)).
// WebP
Prefix("/clusters/cluster/settings/webp").
GetPost("", new(webp.IndexAction)).
EndAll() EndAll()
}) })
} }

View File

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

View File

@@ -8,6 +8,8 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"net"
"regexp"
) )
type UpdateNodeSSHAction struct { type UpdateNodeSSHAction struct {
@@ -31,7 +33,7 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
return return
} }
node := nodeResp.Node var node = nodeResp.Node
this.Data["node"] = maps.Map{ this.Data["node"] = maps.Map{
"id": node.Id, "id": node.Id,
"name": node.Name, "name": node.Name,
@@ -43,7 +45,7 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
} }
// SSH // SSH
loginParams := maps.Map{ var loginParams = maps.Map{
"host": "", "host": "",
"port": "", "port": "",
"grantId": 0, "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 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}) grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -101,7 +115,12 @@ func (this *UpdateNodeSSHAction) RunPost(params struct {
this.Fail("需要选择或填写至少一个认证信息") 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, Id: params.LoginId,
Name: "SSH", Name: "SSH",
Type: "ssh", Type: "ssh",

View File

@@ -13,7 +13,7 @@ import (
"strconv" "strconv"
) )
// 单个集群的帮助 // ClusterHelper 单个集群的帮助
type ClusterHelper struct { 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/nodes?clusterId="+clusterIdString, "server", selectedTabbar == "node")
tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting") tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
tabbar.Add("删除集群", "", "/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete") 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) actionutils.SetTabbar(action, tabbar)
// 左侧菜单 // 左侧菜单
secondMenuItem := action.Data.GetString("secondMenuItem") secondMenuItem := action.Data.GetString("secondMenuItem")
switch selectedTabbar { switch selectedTabbar {
case "setting": 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": "基础设置", "name": "基础设置",
"url": "/clusters/cluster/settings?clusterId=" + clusterId, "url": "/clusters/cluster/settings?clusterId=" + clusterId,
"isActive": selectedItem == "basic", "isActive": selectedItem == "basic",
"isOn": true,
}) })
items = append(items, maps.Map{ items = append(items, maps.Map{
"name": "缓存设置", "name": "缓存设置",
@@ -124,6 +130,12 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
"isActive": selectedItem == "dns", "isActive": selectedItem == "dns",
"isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0, "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{ items = append(items, maps.Map{
"name": "统计指标", "name": "统计指标",
"url": "/clusters/cluster/settings/metrics?clusterId=" + clusterId, "url": "/clusters/cluster/settings/metrics?clusterId=" + clusterId,
@@ -157,6 +169,7 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
"name": "系统服务", "name": "系统服务",
"url": "/clusters/cluster/settings/services?clusterId=" + clusterId, "url": "/clusters/cluster/settings/services?clusterId=" + clusterId,
"isActive": selectedItem == "service", "isActive": selectedItem == "service",
"isOn": info != nil && info.HasSystemServices,
}) })
{ {
items = append(items, maps.Map{ items = append(items, maps.Map{

View File

@@ -27,6 +27,22 @@ func (this *CreateAction) RunGet(params struct{}) {
} }
this.Data["hasDomains"] = hasDomainsResp.Exist 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() this.Show()
} }

View File

@@ -1,15 +1,12 @@
package clusters package clusters
import ( import (
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"time"
) )
type IndexAction struct { type IndexAction struct {
@@ -24,11 +21,27 @@ func (this *IndexAction) RunGet(params struct {
Keyword string Keyword string
SearchType string SearchType string
}) { }) {
isSearching := len(params.Keyword) > 0 var isSearching = len(params.Keyword) > 0
this.Data["keyword"] = params.Keyword this.Data["keyword"] = params.Keyword
this.Data["searchType"] = params.SearchType this.Data["searchType"] = params.SearchType
this.Data["isSearching"] = isSearching 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{} latestClusterMaps := []maps.Map{}
if !isSearching { if !isSearching {
@@ -46,12 +59,6 @@ func (this *IndexAction) RunGet(params struct {
} }
this.Data["latestClusters"] = latestClusterMaps 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{ countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{
Keyword: params.Keyword, Keyword: params.Keyword,
@@ -137,6 +144,7 @@ func (this *IndexAction) RunGet(params struct {
"dnsDomainName": dnsDomainName, "dnsDomainName": dnsDomainName,
"countServers": countServersResp.Count, "countServers": countServersResp.Count,
"timeZone": cluster.TimeZone, "timeZone": cluster.TimeZone,
"isPinned": cluster.IsPinned,
}) })
} }
} }
@@ -157,149 +165,3 @@ func (this *IndexAction) RunGet(params struct {
this.Show() 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()
}

View File

@@ -16,6 +16,8 @@ func init() {
Prefix("/clusters"). Prefix("/clusters").
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/create", new(CreateAction)). GetPost("/create", new(CreateAction)).
Post("/pin", new(PinAction)).
Get("/nodes", new(NodesAction)).
// 只要登录即可访问的Action // 只要登录即可访问的Action
EndHelpers(). EndHelpers().

View File

@@ -1,19 +1,28 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package servers package logs
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/types"
"strings"
) )
type FixLogAction struct { type FixAction struct {
actionutils.ParentAction actionutils.ParentAction
} }
func (this *FixLogAction) RunPost(params struct { func (this *FixAction) RunPost(params struct {
LogIds []int64 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}) _, err := this.RPC().NodeLogRPC().FixNodeLogs(this.AdminContext(), &pb.FixNodeLogsRequest{NodeLogIds: params.LogIds})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -0,0 +1,25 @@
// 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"
)
type FixAllAction struct {
actionutils.ParentAction
}
func (this *FixAllAction) RunPost(params struct {
}) {
defer this.CreateLogInfo("设置所有日志为已修复")
_, err := this.RPC().NodeLogRPC().FixAllNodeLogs(this.AdminContext(), &pb.FixAllNodeLogsRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -3,8 +3,10 @@ package logs
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils" "github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "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/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
) )
@@ -14,8 +16,11 @@ type IndexAction struct {
} }
func (this *IndexAction) Init() { func (this *IndexAction) Init() {
if this.ParamString("type") == "unread" { var paramType = this.ParamString("type")
if paramType == "unread" {
this.FirstMenu("unread") this.FirstMenu("unread")
} else if paramType == "needFix" {
this.FirstMenu("needFix")
} else { } else {
this.FirstMenu("index") this.FirstMenu("index")
} }
@@ -26,7 +31,7 @@ func (this *IndexAction) RunGet(params struct {
DayTo string DayTo string
Keyword string Keyword string
Level string Level string
Type string Type string // unread, needFix
Tag string Tag string
ClusterId int64 ClusterId int64
NodeId int64 NodeId int64
@@ -40,6 +45,13 @@ func (this *IndexAction) RunGet(params struct {
this.Data["clusterId"] = params.ClusterId this.Data["clusterId"] = params.ClusterId
this.Data["nodeId"] = params.NodeId 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() this.Data["tags"] = nodelogutils.FindNodeCommonTags()
@@ -54,6 +66,18 @@ func (this *IndexAction) RunGet(params struct {
} }
this.Data["countUnreadLogs"] = countUnreadResp.Count this.Data["countUnreadLogs"] = countUnreadResp.Count
// 需要修复数量
countNeedFixResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
Role: nodeconfigs.NodeRoleNode,
AllServers: true,
FixedState: int32(configutils.BoolStateNo),
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["countNeedFixLogs"] = countNeedFixResp.Count
// 日志数量 // 日志数量
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{ countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
@@ -65,13 +89,15 @@ func (this *IndexAction) RunGet(params struct {
Level: params.Level, Level: params.Level,
IsUnread: params.Type == "unread", IsUnread: params.Type == "unread",
Tag: params.Tag, Tag: params.Tag,
FixedState: int32(fixedState),
AllServers: allServers,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
count := countResp.Count var count = countResp.Count
page := this.NewPage(count) var page = this.NewPage(count)
this.Data["page"] = page.AsHTML() this.Data["page"] = page.AsHTML()
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{ logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
@@ -84,6 +110,8 @@ func (this *IndexAction) RunGet(params struct {
Level: params.Level, Level: params.Level,
IsUnread: params.Type == "unread", IsUnread: params.Type == "unread",
Tag: params.Tag, Tag: params.Tag,
FixedState: int32(fixedState),
AllServers: allServers,
Offset: page.Offset, Offset: page.Offset,
Size: page.Size, Size: page.Size,
}) })
@@ -92,14 +120,14 @@ func (this *IndexAction) RunGet(params struct {
return return
} }
logs := []maps.Map{} var logs = []maps.Map{}
for _, log := range logsResp.NodeLogs { for _, log := range logsResp.NodeLogs {
// 节点信息 // 节点信息
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: log.NodeId}) nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: log.NodeId})
if err != nil { if err != nil {
continue continue
} }
node := nodeResp.Node var node = nodeResp.Node
if node == nil || node.NodeCluster == nil { if node == nil || node.NodeCluster == nil {
continue continue
} }
@@ -118,6 +146,11 @@ func (this *IndexAction) RunGet(params struct {
} }
} }
var isFixed = true
if !log.IsFixed && log.ServerId > 0 && lists.ContainsString([]string{"success", "warning", "error"}, log.Level) {
isFixed = false
}
logs = append(logs, maps.Map{ logs = append(logs, maps.Map{
"id": log.Id, "id": log.Id,
"tag": log.Tag, "tag": log.Tag,
@@ -127,6 +160,7 @@ func (this *IndexAction) RunGet(params struct {
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"), "isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
"count": log.Count, "count": log.Count,
"isRead": log.IsRead, "isRead": log.IsRead,
"isFixed": isFixed,
"node": maps.Map{ "node": maps.Map{
"id": node.Id, "id": node.Id,
"cluster": maps.Map{ "cluster": maps.Map{

View File

@@ -16,6 +16,8 @@ func init() {
Get("", new(IndexAction)). Get("", new(IndexAction)).
Post("/readLogs", new(ReadLogsAction)). Post("/readLogs", new(ReadLogsAction)).
Post("/readAllLogs", new(ReadAllLogsAction)). Post("/readAllLogs", new(ReadAllLogsAction)).
Post("/fix", new(FixAction)).
Post("/fixAll", new(FixAllAction)).
EndAll() EndAll()
}) })
} }

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

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

View File

@@ -35,11 +35,11 @@ func (this *SelectPopupAction) RunGet(params struct {
return return
} }
var count = countResp.Count var count = countResp.Count
var page = this.NewPage(count) var pageSize int64 = 6
page.Size = 6
if params.PageSize > 0 { if params.PageSize > 0 {
page.Size = params.PageSize pageSize = params.PageSize
} }
var page = this.NewPage(count, pageSize)
this.Data["page"] = page.AsHTML() this.Data["page"] = page.AsHTML()
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{ clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{

View File

@@ -1,3 +1,8 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build !plus
// +build !plus
package providers package providers
import ( import (
@@ -60,8 +65,9 @@ func (this *CreatePopupAction) RunPost(params struct {
Type string Type string
// DNSPod // DNSPod
ParamId string ParamId string
ParamToken string ParamToken string
ParamRegion string
// AliDNS // AliDNS
ParamAccessKeyId string ParamAccessKeyId string
@@ -76,8 +82,8 @@ func (this *CreatePopupAction) RunPost(params struct {
ParamApiSecret string ParamApiSecret string
// CloudFlare // CloudFlare
CloudFlareAPIKey string ParamCloudFlareAPIKey string
CloudFlareEmail string ParamCloudFlareEmail string
// Local EdgeDNS // Local EdgeDNS
ParamLocalEdgeDNSClusterId int64 ParamLocalEdgeDNSClusterId int64
@@ -106,6 +112,7 @@ func (this *CreatePopupAction) RunPost(params struct {
apiParams["id"] = params.ParamId apiParams["id"] = params.ParamId
apiParams["token"] = params.ParamToken apiParams["token"] = params.ParamToken
apiParams["region"] = params.ParamRegion
case "alidns": case "alidns":
params.Must. params.Must.
Field("paramAccessKeyId", params.ParamAccessKeyId). Field("paramAccessKeyId", params.ParamAccessKeyId).
@@ -135,12 +142,12 @@ func (this *CreatePopupAction) RunPost(params struct {
apiParams["apiSecret"] = params.ParamApiSecret apiParams["apiSecret"] = params.ParamApiSecret
case "cloudFlare": case "cloudFlare":
params.Must. params.Must.
Field("cloudFlareAPIKey", params.CloudFlareAPIKey). Field("paramCloudFlareAPIKey", params.ParamCloudFlareAPIKey).
Require("请输入API密钥"). Require("请输入API密钥").
Field("cloudFlareEmail", params.CloudFlareEmail). Field("paramCloudFlareEmail", params.ParamCloudFlareEmail).
Email("请输入正确格式的邮箱地址") Email("请输入正确格式的邮箱地址")
apiParams["apiKey"] = params.CloudFlareAPIKey apiParams["apiKey"] = params.ParamCloudFlareAPIKey
apiParams["email"] = params.CloudFlareEmail apiParams["email"] = params.ParamCloudFlareEmail
case "localEdgeDNS": case "localEdgeDNS":
params.Must. params.Must.
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId). Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).

View File

@@ -5,6 +5,8 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"regexp"
"strings"
) )
type IndexAction struct { type IndexAction struct {
@@ -17,12 +19,20 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct { func (this *IndexAction) RunGet(params struct {
Keyword string Keyword string
Domain string
}) { }) {
this.Data["keyword"] = params.Keyword 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{ countResp, err := this.RPC().DNSProviderRPC().CountAllEnabledDNSProviders(this.AdminContext(), &pb.CountAllEnabledDNSProvidersRequest{
AdminId: this.AdminId(), AdminId: this.AdminId(),
Keyword: params.Keyword, Keyword: params.Keyword,
Domain: domain,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -35,6 +45,7 @@ func (this *IndexAction) RunGet(params struct {
providersResp, err := this.RPC().DNSProviderRPC().ListEnabledDNSProviders(this.AdminContext(), &pb.ListEnabledDNSProvidersRequest{ providersResp, err := this.RPC().DNSProviderRPC().ListEnabledDNSProviders(this.AdminContext(), &pb.ListEnabledDNSProvidersRequest{
AdminId: this.AdminId(), AdminId: this.AdminId(),
Keyword: params.Keyword, Keyword: params.Keyword,
Domain: domain,
Offset: page.Offset, Offset: page.Offset,
Size: page.Size, Size: page.Size,
}) })

View File

@@ -1,3 +1,6 @@
//go:build !plus
// +build !plus
package providers package providers
import ( import (
@@ -89,8 +92,9 @@ func (this *UpdatePopupAction) RunPost(params struct {
Type string Type string
// DNSPod // DNSPod
ParamId string ParamId string
ParamToken string ParamToken string
ParamRegion string
// AliDNS // AliDNS
ParamAccessKeyId string ParamAccessKeyId string
@@ -105,8 +109,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
ParamApiSecret string ParamApiSecret string
// CloudFlare // CloudFlare
CloudFlareAPIKey string ParamCloudFlareAPIKey string
CloudFlareEmail string ParamCloudFlareEmail string
// Local EdgeDNS // Local EdgeDNS
ParamLocalEdgeDNSClusterId int64 ParamLocalEdgeDNSClusterId int64
@@ -137,6 +141,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
apiParams["id"] = params.ParamId apiParams["id"] = params.ParamId
apiParams["token"] = params.ParamToken apiParams["token"] = params.ParamToken
apiParams["region"] = params.ParamRegion
case "alidns": case "alidns":
params.Must. params.Must.
Field("paramAccessKeyId", params.ParamAccessKeyId). Field("paramAccessKeyId", params.ParamAccessKeyId).
@@ -166,12 +171,12 @@ func (this *UpdatePopupAction) RunPost(params struct {
apiParams["apiSecret"] = params.ParamApiSecret apiParams["apiSecret"] = params.ParamApiSecret
case "cloudFlare": case "cloudFlare":
params.Must. params.Must.
Field("cloudFlareAPIKey", params.CloudFlareAPIKey). Field("paramCloudFlareAPIKey", params.ParamCloudFlareAPIKey).
Require("请输入API密钥"). Require("请输入API密钥").
Field("cloudFlareEmail", params.CloudFlareEmail). Field("paramCloudFlareEmail", params.ParamCloudFlareEmail).
Email("请输入正确格式的邮箱地址") Email("请输入正确格式的邮箱地址")
apiParams["apiKey"] = params.CloudFlareAPIKey apiParams["apiKey"] = params.ParamCloudFlareAPIKey
apiParams["email"] = params.CloudFlareEmail apiParams["email"] = params.ParamCloudFlareEmail
case "localEdgeDNS": case "localEdgeDNS":
params.Must. params.Must.
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId). Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).

View File

@@ -27,7 +27,7 @@ func (this *ExportExcelAction) RunGet(params struct {
}) { }) {
logsResp, err := this.RPC().LogRPC().ListLogs(this.AdminContext(), &pb.ListLogsRequest{ logsResp, err := this.RPC().LogRPC().ListLogs(this.AdminContext(), &pb.ListLogsRequest{
Offset: 0, Offset: 0,
Size: 1000, // 日志最大导出1000条TODO 将来可以配置 Size: 10000, // 日志最大导出10000TODO 将来可以配置
DayFrom: params.DayFrom, DayFrom: params.DayFrom,
DayTo: params.DayTo, DayTo: params.DayTo,
Keyword: params.Keyword, Keyword: params.Keyword,
@@ -38,7 +38,7 @@ func (this *ExportExcelAction) RunGet(params struct {
return return
} }
wb := xlsx.NewFile() var wb = xlsx.NewFile()
sheet, err := wb.AddSheet("default") sheet, err := wb.AddSheet("default")
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -47,7 +47,7 @@ func (this *ExportExcelAction) RunGet(params struct {
// 头部 // 头部
{ {
row := sheet.AddRow() var row = sheet.AddRow()
row.SetHeight(25) row.SetHeight(25)
row.AddCell().SetString("ID") row.AddCell().SetString("ID")
row.AddCell().SetString("日期") row.AddCell().SetString("日期")
@@ -61,8 +61,8 @@ func (this *ExportExcelAction) RunGet(params struct {
// 数据 // 数据
for _, log := range logsResp.Logs { for _, log := range logsResp.Logs {
regionName := "" var regionName = ""
ispName := "" var ispName = ""
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: log.Ip}) regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: log.Ip})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -86,7 +86,7 @@ func (this *ExportExcelAction) RunGet(params struct {
} }
} }
row := sheet.AddRow() var row = sheet.AddRow()
row.SetHeight(25) row.SetHeight(25)
row.AddCell().SetInt64(log.Id) row.AddCell().SetInt64(log.Id)
row.AddCell().SetString(timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt)) 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("Content-Disposition", "attachment; filename=\"LOG-"+timeutil.Format("YmdHis")+".xlsx\"")
this.AddHeader("Cache-Control", "max-age=0") this.AddHeader("Cache-Control", "max-age=0")
buf := bytes.NewBuffer([]byte{}) var buf = bytes.NewBuffer([]byte{})
err = wb.Write(buf) err = wb.Write(buf)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -1,179 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ipbox
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/cmd"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreatePopupAction) RunGet(params struct{}) {
this.Data["types"] = serverconfigs.FindAllAccessLogStorageTypes()
this.Data["syslogPriorities"] = serverconfigs.AccessLogSyslogStoragePriorities
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
Name string
Type string
// file
FilePath string
FileAutoCreate bool
// es
EsEndpoint string
EsIndex string
EsMappingType string
EsUsername string
EsPassword string
// mysql
MysqlHost string
MysqlPort int
MysqlUsername string
MysqlPassword string
MysqlDatabase string
MysqlTable string
MysqlLogField string
// tcp
TcpNetwork string
TcpAddr string
// syslog
SyslogProtocol string
SyslogServerAddr string
SyslogServerPort int
SyslogSocket string
SyslogTag string
SyslogPriority int
// command
CommandCommand string
CommandArgs string
CommandDir string
IsPublic bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
var policyId int64 = 0
defer func() {
this.CreateLogInfo("创建访问日志策略 %d", policyId)
}()
params.Must.
Field("name", params.Name).
Require("请输入日志策略的名称").
Field("type", params.Type).
Require("请选择存储类型")
var options interface{} = nil
switch params.Type {
case serverconfigs.AccessLogStorageTypeFile:
params.Must.
Field("filePath", params.FilePath).
Require("请输入日志文件路径")
storage := new(serverconfigs.AccessLogFileStorageConfig)
storage.Path = params.FilePath
storage.AutoCreate = params.FileAutoCreate
options = storage
case serverconfigs.AccessLogStorageTypeES:
params.Must.
Field("esEndpoint", params.EsEndpoint).
Require("请输入Endpoint").
Field("esIndex", params.EsIndex).
Require("请输入Index名称").
Field("esMappingType", params.EsMappingType).
Require("请输入Mapping名称")
storage := new(serverconfigs.AccessLogESStorageConfig)
storage.Endpoint = params.EsEndpoint
storage.Index = params.EsIndex
storage.MappingType = params.EsMappingType
storage.Username = params.EsUsername
storage.Password = params.EsPassword
options = storage
case serverconfigs.AccessLogStorageTypeTCP:
params.Must.
Field("tcpNetwork", params.TcpNetwork).
Require("请选择网络协议").
Field("tcpAddr", params.TcpAddr).
Require("请输入网络地址")
storage := new(serverconfigs.AccessLogTCPStorageConfig)
storage.Network = params.TcpNetwork
storage.Addr = params.TcpAddr
options = storage
case serverconfigs.AccessLogStorageTypeSyslog:
switch params.SyslogProtocol {
case serverconfigs.AccessLogSyslogStorageProtocolTCP, serverconfigs.AccessLogSyslogStorageProtocolUDP:
params.Must.
Field("syslogServerAddr", params.SyslogServerAddr).
Require("请输入网络地址")
case serverconfigs.AccessLogSyslogStorageProtocolSocket:
params.Must.
Field("syslogSocket", params.SyslogSocket).
Require("请输入Socket路径")
}
storage := new(serverconfigs.AccessLogSyslogStorageConfig)
storage.Protocol = params.SyslogProtocol
storage.ServerAddr = params.SyslogServerAddr
storage.ServerPort = params.SyslogServerPort
storage.Socket = params.SyslogSocket
storage.Tag = params.SyslogTag
storage.Priority = params.SyslogPriority
options = storage
case serverconfigs.AccessLogStorageTypeCommand:
params.Must.
Field("commandCommand", params.CommandCommand).
Require("请输入可执行命令")
storage := new(serverconfigs.AccessLogCommandStorageConfig)
storage.Command = params.CommandCommand
storage.Args = cmd.ParseArgs(params.CommandArgs)
storage.Dir = params.CommandDir
options = storage
}
if options == nil {
this.Fail("找不到选择的存储类型")
}
optionsJSON, err := json.Marshal(options)
if err != nil {
this.ErrorPage(err)
return
}
createResp, err := this.RPC().HTTPAccessLogPolicyRPC().CreateHTTPAccessLogPolicy(this.AdminContext(), &pb.CreateHTTPAccessLogPolicyRequest{
Name: params.Name,
Type: params.Type,
OptionsJSON: optionsJSON,
CondsJSON: nil, // TODO
IsPublic: params.IsPublic,
})
if err != nil {
this.ErrorPage(err)
return
}
policyId = createResp.HttpAccessLogPolicyId
this.Success()
}

View File

@@ -1,26 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ipbox
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
PolicyId int64
}) {
defer this.CreateLogInfo("删除访问日志策略 %d", params.PolicyId)
_, err := this.RPC().HTTPAccessLogPolicyRPC().DeleteHTTPAccessLogPolicy(this.AdminContext(), &pb.DeleteHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: params.PolicyId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,57 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ipbox
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "index")
}
func (this *IndexAction) RunGet(params struct{}) {
countResp, err := this.RPC().HTTPAccessLogPolicyRPC().CountAllEnabledHTTPAccessLogPolicies(this.AdminContext(), &pb.CountAllEnabledHTTPAccessLogPoliciesRequest{})
if err != nil {
this.ErrorPage(err)
return
}
page := this.NewPage(countResp.Count)
this.Data["page"] = page.AsHTML()
policiesResp, err := this.RPC().HTTPAccessLogPolicyRPC().ListEnabledHTTPAccessLogPolicies(this.AdminContext(), &pb.ListEnabledHTTPAccessLogPoliciesRequest{
Offset: page.Offset,
Size: page.Size,
})
var policyMaps = []maps.Map{}
for _, policy := range policiesResp.HttpAccessLogPolicies {
var optionsMap = maps.Map{}
if len(policy.OptionsJSON) > 0 {
err = json.Unmarshal(policy.OptionsJSON, &optionsMap)
if err != nil {
this.ErrorPage(err)
return
}
}
policyMaps = append(policyMaps, maps.Map{
"id": policy.Id,
"name": policy.Name,
"type": policy.Type,
"typeName": serverconfigs.FindAccessLogStorageTypeName(policy.Type),
"isOn": policy.IsOn,
"isPublic": policy.IsPublic,
"options": optionsMap,
})
}
this.Data["policies"] = policyMaps
this.Show()
}

View File

@@ -1,36 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ipbox
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
)
type PolicyAction struct {
actionutils.ParentAction
}
func (this *PolicyAction) Init() {
this.Nav("", "", "policy")
}
func (this *PolicyAction) RunGet(params struct {
PolicyId int64
}) {
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
if err != nil {
this.ErrorPage(err)
return
}
var policyMap = this.Data.GetMap("policy")
if policyMap.GetString("type") == serverconfigs.AccessLogStorageTypeSyslog {
this.Data["syslogPriorityName"] = serverconfigs.FindAccessLogSyslogStoragePriorityName(policyMap.GetMap("options").GetInt("priority"))
} else {
this.Data["syslogPriorityName"] = ""
}
this.Show()
}

View File

@@ -1,49 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package policyutils
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
// InitPolicy 初始化访问日志策略
func InitPolicy(parent *actionutils.ParentAction, policyId int64) error {
rpcClient, err := rpc.SharedRPC()
if err != nil {
return err
}
policyResp, err := rpcClient.HTTPAccessLogPolicyRPC().FindEnabledHTTPAccessLogPolicy(parent.AdminContext(), &pb.FindEnabledHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: policyId})
if err != nil {
return err
}
var policy = policyResp.HttpAccessLogPolicy
if policy == nil {
return errors.New("can not find policy '" + types.String(policyId) + "'")
}
var options = maps.Map{}
if len(policy.OptionsJSON) > 0 {
err = json.Unmarshal(policy.OptionsJSON, &options)
if err != nil {
return err
}
}
parent.Data["policy"] = maps.Map{
"id": policy.Id,
"name": policy.Name,
"type": policy.Type,
"typeName": serverconfigs.FindAccessLogStorageTypeName(policy.Type),
"isOn": policy.IsOn,
"isPublic": policy.IsPublic,
"options": options,
}
return nil
}

View File

@@ -1,57 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ipbox
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
)
type TestAction struct {
actionutils.ParentAction
}
func (this *TestAction) Init() {
this.Nav("", "", "test")
}
func (this *TestAction) RunGet(params struct {
PolicyId int64
}) {
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
if err != nil {
this.ErrorPage(err)
return
}
this.Show()
}
func (this *TestAction) RunPost(params struct {
PolicyId int64
BodyJSON []byte
Must *actions.Must
}) {
defer this.CreateLogInfo("测试向访问日志策略 %d 写入数据", params.PolicyId)
var accessLog = &pb.HTTPAccessLog{}
err := json.Unmarshal(params.BodyJSON, accessLog)
if err != nil {
this.Fail("发送内容不是有效的JSON" + err.Error())
}
_, err = this.RPC().HTTPAccessLogPolicyRPC().WriteHTTPAccessLogPolicy(this.AdminContext(), &pb.WriteHTTPAccessLogPolicyRequest{
HttpAccessLogPolicyId: params.PolicyId,
HttpAccessLog: accessLog,
})
if err != nil {
this.Fail("发送失败:" + err.Error())
return
}
this.Success()
}

View File

@@ -1,195 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ipbox
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/accesslogs/policyutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/cmd"
)
type UpdateAction struct {
actionutils.ParentAction
}
func (this *UpdateAction) Init() {
this.Nav("", "", "update")
}
func (this *UpdateAction) RunGet(params struct {
PolicyId int64
}) {
err := policyutils.InitPolicy(this.Parent(), params.PolicyId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["types"] = serverconfigs.FindAllAccessLogStorageTypes()
this.Data["syslogPriorities"] = serverconfigs.AccessLogSyslogStoragePriorities
this.Show()
}
func (this *UpdateAction) RunPost(params struct {
PolicyId int64
Name string
// file
FilePath string
FileAutoCreate bool
// es
EsEndpoint string
EsIndex string
EsMappingType string
EsUsername string
EsPassword string
// mysql
MysqlHost string
MysqlPort int
MysqlUsername string
MysqlPassword string
MysqlDatabase string
MysqlTable string
MysqlLogField string
// tcp
TcpNetwork string
TcpAddr string
// syslog
SyslogProtocol string
SyslogServerAddr string
SyslogServerPort int
SyslogSocket string
SyslogTag string
SyslogPriority int
// command
CommandCommand string
CommandArgs string
CommandDir string
IsOn bool
IsPublic bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改访问日志策略 %d", params.PolicyId)
policyResp, err := this.RPC().HTTPAccessLogPolicyRPC().FindEnabledHTTPAccessLogPolicy(this.AdminContext(), &pb.FindEnabledHTTPAccessLogPolicyRequest{HttpAccessLogPolicyId: params.PolicyId})
if err != nil {
this.ErrorPage(err)
return
}
var policy = policyResp.HttpAccessLogPolicy
if policy == nil {
this.Fail("找不到要修改的策略")
return
}
params.Must.
Field("name", params.Name).
Require("请输入日志策略的名称")
var options interface{} = nil
switch policy.Type {
case serverconfigs.AccessLogStorageTypeFile:
params.Must.
Field("filePath", params.FilePath).
Require("请输入日志文件路径")
storage := new(serverconfigs.AccessLogFileStorageConfig)
storage.Path = params.FilePath
storage.AutoCreate = params.FileAutoCreate
options = storage
case serverconfigs.AccessLogStorageTypeES:
params.Must.
Field("esEndpoint", params.EsEndpoint).
Require("请输入Endpoint").
Field("esIndex", params.EsIndex).
Require("请输入Index名称").
Field("esMappingType", params.EsMappingType).
Require("请输入Mapping名称")
storage := new(serverconfigs.AccessLogESStorageConfig)
storage.Endpoint = params.EsEndpoint
storage.Index = params.EsIndex
storage.MappingType = params.EsMappingType
storage.Username = params.EsUsername
storage.Password = params.EsPassword
options = storage
case serverconfigs.AccessLogStorageTypeTCP:
params.Must.
Field("tcpNetwork", params.TcpNetwork).
Require("请选择网络协议").
Field("tcpAddr", params.TcpAddr).
Require("请输入网络地址")
storage := new(serverconfigs.AccessLogTCPStorageConfig)
storage.Network = params.TcpNetwork
storage.Addr = params.TcpAddr
options = storage
case serverconfigs.AccessLogStorageTypeSyslog:
switch params.SyslogProtocol {
case serverconfigs.AccessLogSyslogStorageProtocolTCP, serverconfigs.AccessLogSyslogStorageProtocolUDP:
params.Must.
Field("syslogServerAddr", params.SyslogServerAddr).
Require("请输入网络地址")
case serverconfigs.AccessLogSyslogStorageProtocolSocket:
params.Must.
Field("syslogSocket", params.SyslogSocket).
Require("请输入Socket路径")
}
storage := new(serverconfigs.AccessLogSyslogStorageConfig)
storage.Protocol = params.SyslogProtocol
storage.ServerAddr = params.SyslogServerAddr
storage.ServerPort = params.SyslogServerPort
storage.Socket = params.SyslogSocket
storage.Tag = params.SyslogTag
storage.Priority = params.SyslogPriority
options = storage
case serverconfigs.AccessLogStorageTypeCommand:
params.Must.
Field("commandCommand", params.CommandCommand).
Require("请输入可执行命令")
storage := new(serverconfigs.AccessLogCommandStorageConfig)
storage.Command = params.CommandCommand
storage.Args = cmd.ParseArgs(params.CommandArgs)
storage.Dir = params.CommandDir
options = storage
}
if options == nil {
this.Fail("找不到选择的存储类型")
}
optionsJSON, err := json.Marshal(options)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPAccessLogPolicyRPC().UpdateHTTPAccessLogPolicy(this.AdminContext(), &pb.UpdateHTTPAccessLogPolicyRequest{
HttpAccessLogPolicyId: params.PolicyId,
Name: params.Name,
OptionsJSON: optionsJSON,
CondsJSON: nil, // TODO
IsOn: params.IsOn,
IsPublic: params.IsPublic,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -26,14 +26,14 @@ func (this *CertPopupAction) RunGet(params struct {
return return
} }
certConfig := &sslconfigs.SSLCertConfig{} var certConfig = &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.SslCertJSON, certConfig) err = json.Unmarshal(certResp.SslCertJSON, certConfig)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
reverseCommonNames := []string{} var reverseCommonNames = []string{}
for i := len(certConfig.CommonNames) - 1; i >= 0; i-- { for i := len(certConfig.CommonNames) - 1; i >= 0; i-- {
reverseCommonNames = append(reverseCommonNames, certConfig.CommonNames[i]) reverseCommonNames = append(reverseCommonNames, certConfig.CommonNames[i])
} }
@@ -62,7 +62,7 @@ func (this *CertPopupAction) RunGet(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
serverMaps := []maps.Map{} var serverMaps = []maps.Map{}
for _, server := range serversResp.Servers { for _, server := range serversResp.Servers {
serverMaps = append(serverMaps, maps.Map{ serverMaps = append(serverMaps, maps.Map{
"id": server.Id, "id": server.Id,

View File

@@ -1,8 +1,11 @@
package certs package certs
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"net/http" "net/http"
) )
@@ -13,14 +16,29 @@ func NewHelper() *Helper {
return &Helper{} return &Helper{}
} }
func (this *Helper) BeforeAction(action *actions.ActionObject) { func (this *Helper) BeforeAction(actionWrapper actions.ActionWrapper) {
var action = actionWrapper.Object()
if action.Request.Method != http.MethodGet { if action.Request.Method != http.MethodGet {
return return
} }
action.Data["teaMenu"] = "servers" action.Data["teaMenu"] = "servers"
action.Data["leftMenuItems"] = []maps.Map{ var countOCSP int64 = 0
parentAction, ok := actionWrapper.(actionutils.ActionInterface)
if ok {
countOCSPResp, err := parentAction.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(parentAction.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{})
if err == nil {
countOCSP = countOCSPResp.Count
}
}
var ocspMenuName = "OCSP日志"
if countOCSP > 0 {
ocspMenuName += "(" + types.String(countOCSP) + ")"
}
var menu = []maps.Map{
{ {
"name": "证书", "name": "证书",
"url": "/servers/certs", "url": "/servers/certs",
@@ -31,5 +49,11 @@ func (this *Helper) BeforeAction(action *actions.ActionObject) {
"url": "/servers/certs/acme", "url": "/servers/certs/acme",
"isActive": action.Data.GetString("leftMenuItem") == "acme", "isActive": action.Data.GetString("leftMenuItem") == "acme",
}, },
{
"name": ocspMenuName,
"url": "/servers/certs/ocsp",
"isActive": action.Data.GetString("leftMenuItem") == "ocsp",
},
} }
action.Data["leftMenuItems"] = menu
} }

View File

@@ -25,12 +25,12 @@ func (this *IndexAction) RunGet(params struct {
this.Data["type"] = params.Type this.Data["type"] = params.Type
this.Data["keyword"] = params.Keyword this.Data["keyword"] = params.Keyword
countAll := int64(0) var countAll = int64(0)
countCA := int64(0) var countCA = int64(0)
countAvailable := int64(0) var countAvailable = int64(0)
countExpired := int64(0) var countExpired = int64(0)
count7Days := int64(0) var count7Days = int64(0)
count30Days := int64(0) var count30Days = int64(0)
// 计算数量 // 计算数量
{ {
@@ -147,7 +147,7 @@ func (this *IndexAction) RunGet(params struct {
return return
} }
certConfigs := []*sslconfigs.SSLCertConfig{} var certConfigs = []*sslconfigs.SSLCertConfig{}
err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs) err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -155,8 +155,8 @@ func (this *IndexAction) RunGet(params struct {
} }
this.Data["certs"] = certConfigs this.Data["certs"] = certConfigs
certMaps := []maps.Map{} var certMaps = []maps.Map{}
nowTime := time.Now().Unix() var nowTime = time.Now().Unix()
for _, certConfig := range certConfigs { for _, certConfig := range certConfigs {
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{SslCertId: certConfig.Id}) countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{SslCertId: certConfig.Id})
if err != nil { if err != nil {

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/accounts" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/accounts"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/users" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/users"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/ocsp"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo" "github.com/iwind/TeaGo"
) )
@@ -55,6 +56,14 @@ func init() {
GetPost("/updatePopup", new(accounts.UpdatePopupAction)). GetPost("/updatePopup", new(accounts.UpdatePopupAction)).
Post("/delete", new(accounts.DeleteAction)). Post("/delete", new(accounts.DeleteAction)).
// OCSP
Prefix("/servers/certs/ocsp").
Data("leftMenuItem", "ocsp").
Get("", new(ocsp.IndexAction)).
Post("/reset", new(ocsp.ResetAction)).
Post("/resetAll", new(ocsp.ResetAllAction)).
Post("/ignore", new(ocsp.IgnoreAction)).
// //
EndAll() EndAll()
}) })

View File

@@ -0,0 +1,26 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type IgnoreAction struct {
actionutils.ParentAction
}
func (this *IgnoreAction) RunPost(params struct {
CertIds []int64
}) {
defer this.CreateLogInfo("忽略一组证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().IgnoreSSLCertsWithOCSPError(this.AdminContext(), &pb.IgnoreSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,65 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
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"
"time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.SecondMenu("ocsp")
}
func (this *IndexAction) RunGet(params struct {
Keyword string
}) {
this.Data["keyword"] = params.Keyword
countResp, err := this.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(this.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{Keyword: params.Keyword})
if err != nil {
this.ErrorPage(err)
return
}
var count = countResp.Count
var page = this.NewPage(count)
this.Data["page"] = page.AsHTML()
certsResp, err := this.RPC().SSLCertRPC().ListSSLCertsWithOCSPError(this.AdminContext(), &pb.ListSSLCertsWithOCSPErrorRequest{
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
var certMaps = []maps.Map{}
for _, cert := range certsResp.SslCerts {
certMaps = append(certMaps, maps.Map{
"id": cert.Id,
"isOn": cert.IsOn,
"dnsNames": cert.DnsNames,
"commonNames": cert.CommonNames,
"hasOCSP": len(cert.Ocsp) > 0,
"ocspIsUpdated": cert.OcspIsUpdated,
"ocspError": cert.OcspError,
"isCA": cert.IsCA,
"isACME": cert.IsACME,
"name": cert.Name,
"isExpired": cert.TimeEndAt < time.Now().Unix(),
"beginDay": timeutil.FormatTime("Y-m-d", cert.TimeBeginAt),
"endDay": timeutil.FormatTime("Y-m-d", cert.TimeEndAt),
})
}
this.Data["certs"] = certMaps
this.Show()
}

View File

@@ -0,0 +1,26 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type ResetAction struct {
actionutils.ParentAction
}
func (this *ResetAction) RunPost(params struct {
CertIds []int64
}) {
defer this.CreateLogInfo("重置一组证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().ResetSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,24 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type ResetAllAction struct {
actionutils.ParentAction
}
func (this *ResetAllAction) RunPost(params struct{}) {
defer this.CreateLogInfo("忽略所有证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().ResetAllSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetAllSSLCertsWithOCSPErrorRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -70,13 +70,13 @@ func (this *UpdatePopupAction) RunPost(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
certConfigJSON := certConfigResp.SslCertJSON var certConfigJSON = certConfigResp.SslCertJSON
if len(certConfigJSON) == 0 { if len(certConfigJSON) == 0 {
this.NotFound("cert", params.CertId) this.NotFound("cert", params.CertId)
return return
} }
certConfig := &sslconfigs.SSLCertConfig{} var certConfig = &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certConfigJSON, certConfig) err = json.Unmarshal(certConfigJSON, certConfig)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -99,7 +99,6 @@ func (this *UpdatePopupAction) RunPost(params struct {
} }
} }
} else { } else {
if params.CertFile != nil { if params.CertFile != nil {
certConfig.CertData, err = params.CertFile.Read() certConfig.CertData, err = params.CertFile.Read()
if err != nil { if err != nil {
@@ -132,6 +131,13 @@ func (this *UpdatePopupAction) RunPost(params struct {
this.Fail("证书格式错误:无法读取到证书有效期") this.Fail("证书格式错误:无法读取到证书有效期")
} }
if certConfig.TimeBeginAt < 0 {
this.Fail("证书校验错误有效期开始时间过小不能小于1970年1月1日")
}
if certConfig.TimeEndAt < 0 {
this.Fail("证书校验错误有效期结束时间过小不能小于1970年1月1日")
}
// 保存 // 保存
_, err = this.RPC().SSLCertRPC().UpdateSSLCert(this.AdminContext(), &pb.UpdateSSLCertRequest{ _, err = this.RPC().SSLCertRPC().UpdateSSLCert(this.AdminContext(), &pb.UpdateSSLCertRequest{
SslCertId: params.CertId, SslCertId: params.CertId,

View File

@@ -41,8 +41,8 @@ func (this *UploadPopupAction) RunPost(params struct {
Field("name", params.Name). Field("name", params.Name).
Require("请输入证书说明") Require("请输入证书说明")
certData := []byte{} var certData = []byte{}
keyData := []byte{} var keyData = []byte{}
if params.TextMode { if params.TextMode {
if len(params.CertText) == 0 { if len(params.CertText) == 0 {
@@ -80,12 +80,12 @@ func (this *UploadPopupAction) RunPost(params struct {
} }
// 校验 // 校验
sslConfig := &sslconfigs.SSLCertConfig{ var certConfig = &sslconfigs.SSLCertConfig{
IsCA: params.IsCA, IsCA: params.IsCA,
CertData: certData, CertData: certData,
KeyData: keyData, KeyData: keyData,
} }
err := sslConfig.Init() err := certConfig.Init()
if err != nil { if err != nil {
if params.IsCA { if params.IsCA {
this.Fail("证书校验错误:" + err.Error()) this.Fail("证书校验错误:" + err.Error())
@@ -93,10 +93,17 @@ func (this *UploadPopupAction) RunPost(params struct {
this.Fail("证书或密钥校验错误:" + err.Error()) this.Fail("证书或密钥校验错误:" + err.Error())
} }
} }
if len(timeutil.Format("Y", sslConfig.TimeEnd())) != 4 { if len(timeutil.Format("Y", certConfig.TimeEnd())) != 4 {
this.Fail("证书格式错误:无法读取到证书有效期") this.Fail("证书格式错误:无法读取到证书有效期")
} }
if certConfig.TimeBeginAt < 0 {
this.Fail("证书校验错误有效期开始时间过小不能小于1970年1月1日")
}
if certConfig.TimeEndAt < 0 {
this.Fail("证书校验错误有效期结束时间过小不能小于1970年1月1日")
}
// 保存 // 保存
createResp, err := this.RPC().SSLCertRPC().CreateSSLCert(this.AdminContext(), &pb.CreateSSLCertRequest{ createResp, err := this.RPC().SSLCertRPC().CreateSSLCert(this.AdminContext(), &pb.CreateSSLCertRequest{
IsOn: params.IsOn, IsOn: params.IsOn,
@@ -106,10 +113,10 @@ func (this *UploadPopupAction) RunPost(params struct {
IsCA: params.IsCA, IsCA: params.IsCA,
CertData: certData, CertData: certData,
KeyData: keyData, KeyData: keyData,
TimeBeginAt: sslConfig.TimeBeginAt, TimeBeginAt: certConfig.TimeBeginAt,
TimeEndAt: sslConfig.TimeEndAt, TimeEndAt: certConfig.TimeEndAt,
DnsNames: sslConfig.DNSNames, DnsNames: certConfig.DNSNames,
CommonNames: sslConfig.CommonNames, CommonNames: certConfig.CommonNames,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -117,13 +124,13 @@ func (this *UploadPopupAction) RunPost(params struct {
} }
// 查询已创建的证书并返回,方便调用者进行后续处理 // 查询已创建的证书并返回,方便调用者进行后续处理
certId := createResp.SslCertId var certId = createResp.SslCertId
configResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: certId}) configResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{SslCertId: certId})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
certConfig := &sslconfigs.SSLCertConfig{} certConfig = &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(configResp.SslCertJSON, certConfig) err = json.Unmarshal(configResp.SslCertJSON, certConfig)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -32,10 +32,12 @@ func (this *CreatePopupAction) RunPost(params struct {
FileDir string FileDir string
FileMemoryCapacityJSON []byte FileMemoryCapacityJSON []byte
FileOpenFileCacheMax int FileOpenFileCacheMax int
FileEnableSendfile bool
CapacityJSON []byte CapacityJSON []byte
MaxSizeJSON []byte MaxSizeJSON []byte
MaxKeys int64 MaxKeys int64
SyncCompressionCache bool
Description string Description string
IsOn bool IsOn bool
@@ -76,7 +78,8 @@ func (this *CreatePopupAction) RunPost(params struct {
MemoryPolicy: &serverconfigs.HTTPCachePolicy{ MemoryPolicy: &serverconfigs.HTTPCachePolicy{
Capacity: memoryCapacity, Capacity: memoryCapacity,
}, },
OpenFileCache: openFileCacheConfig, OpenFileCache: openFileCacheConfig,
EnableSendfile: params.FileEnableSendfile,
} }
case serverconfigs.CachePolicyStorageMemory: case serverconfigs.CachePolicyStorageMemory:
options = &serverconfigs.HTTPMemoryCacheStorage{} options = &serverconfigs.HTTPMemoryCacheStorage{}
@@ -90,14 +93,15 @@ func (this *CreatePopupAction) RunPost(params struct {
return return
} }
createResp, err := this.RPC().HTTPCachePolicyRPC().CreateHTTPCachePolicy(this.AdminContext(), &pb.CreateHTTPCachePolicyRequest{ createResp, err := this.RPC().HTTPCachePolicyRPC().CreateHTTPCachePolicy(this.AdminContext(), &pb.CreateHTTPCachePolicyRequest{
IsOn: params.IsOn, IsOn: params.IsOn,
Name: params.Name, Name: params.Name,
Description: params.Description, Description: params.Description,
CapacityJSON: params.CapacityJSON, CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys, MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON, MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type, Type: params.Type,
OptionsJSON: optionsJSON, OptionsJSON: optionsJSON,
SyncCompressionCache: params.SyncCompressionCache,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -17,15 +17,18 @@ func (this *IndexAction) Init() {
} }
func (this *IndexAction) RunGet(params struct { func (this *IndexAction) RunGet(params struct {
ClusterId int64 ClusterId int64
Keyword string Keyword string
StorageType string
}) { }) {
this.Data["keyword"] = params.Keyword this.Data["keyword"] = params.Keyword
this.Data["clusterId"] = params.ClusterId this.Data["clusterId"] = params.ClusterId
this.Data["storageType"] = params.StorageType
countResp, err := this.RPC().HTTPCachePolicyRPC().CountAllEnabledHTTPCachePolicies(this.AdminContext(), &pb.CountAllEnabledHTTPCachePoliciesRequest{ countResp, err := this.RPC().HTTPCachePolicyRPC().CountAllEnabledHTTPCachePolicies(this.AdminContext(), &pb.CountAllEnabledHTTPCachePoliciesRequest{
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
Keyword: params.Keyword, Keyword: params.Keyword,
Type: params.StorageType,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -38,6 +41,7 @@ func (this *IndexAction) RunGet(params struct {
listResp, err := this.RPC().HTTPCachePolicyRPC().ListEnabledHTTPCachePolicies(this.AdminContext(), &pb.ListEnabledHTTPCachePoliciesRequest{ listResp, err := this.RPC().HTTPCachePolicyRPC().ListEnabledHTTPCachePolicies(this.AdminContext(), &pb.ListEnabledHTTPCachePoliciesRequest{
Keyword: params.Keyword, Keyword: params.Keyword,
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
Type: params.StorageType,
Offset: page.Offset, Offset: page.Offset,
Size: page.Size, Size: page.Size,
}) })
@@ -70,5 +74,8 @@ func (this *IndexAction) RunGet(params struct {
} }
this.Data["infos"] = infos this.Data["infos"] = infos
// 所有的存储类型
this.Data["storageTypes"] = serverconfigs.AllCachePolicyStorageTypes
this.Show() this.Show()
} }

View File

@@ -26,13 +26,13 @@ func (this *UpdateAction) RunGet(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
configJSON := configResp.HttpCachePolicyJSON var configJSON = configResp.HttpCachePolicyJSON
if len(configJSON) == 0 { if len(configJSON) == 0 {
this.NotFound("cachePolicy", params.CachePolicyId) this.NotFound("cachePolicy", params.CachePolicyId)
return return
} }
cachePolicy := &serverconfigs.HTTPCachePolicy{} var cachePolicy = &serverconfigs.HTTPCachePolicy{}
err = json.Unmarshal(configJSON, cachePolicy) err = json.Unmarshal(configJSON, cachePolicy)
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -56,10 +56,12 @@ func (this *UpdateAction) RunPost(params struct {
FileDir string FileDir string
FileMemoryCapacityJSON []byte FileMemoryCapacityJSON []byte
FileOpenFileCacheMax int FileOpenFileCacheMax int
FileEnableSendfile bool
CapacityJSON []byte CapacityJSON []byte
MaxSizeJSON []byte MaxSizeJSON []byte
MaxKeys int64 MaxKeys int64
SyncCompressionCache bool
Description string Description string
IsOn bool IsOn bool
@@ -105,7 +107,8 @@ func (this *UpdateAction) RunPost(params struct {
MemoryPolicy: &serverconfigs.HTTPCachePolicy{ MemoryPolicy: &serverconfigs.HTTPCachePolicy{
Capacity: memoryCapacity, Capacity: memoryCapacity,
}, },
OpenFileCache: openFileCacheConfig, OpenFileCache: openFileCacheConfig,
EnableSendfile: params.FileEnableSendfile,
} }
case serverconfigs.CachePolicyStorageMemory: case serverconfigs.CachePolicyStorageMemory:
options = &serverconfigs.HTTPMemoryCacheStorage{} options = &serverconfigs.HTTPMemoryCacheStorage{}
@@ -135,15 +138,16 @@ func (this *UpdateAction) RunPost(params struct {
} }
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{ _, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{
HttpCachePolicyId: params.CachePolicyId, HttpCachePolicyId: params.CachePolicyId,
IsOn: params.IsOn, IsOn: params.IsOn,
Name: params.Name, Name: params.Name,
Description: params.Description, Description: params.Description,
CapacityJSON: params.CapacityJSON, CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys, MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON, MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type, Type: params.Type,
OptionsJSON: optionsJSON, OptionsJSON: optionsJSON,
SyncCompressionCache: params.SyncCompressionCache,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -25,6 +25,7 @@ func (this *LogAction) RunGet(params struct {
RequestId string RequestId string
FirewallPolicyId int64 FirewallPolicyId int64
GroupId int64 GroupId int64
Partition int32 `default:"-1"`
}) { }) {
if len(params.Day) == 0 { if len(params.Day) == 0 {
params.Day = timeutil.Format("Y-m-d") params.Day = timeutil.Format("Y-m-d")
@@ -33,15 +34,18 @@ func (this *LogAction) RunGet(params struct {
this.Data["path"] = this.Request.URL.Path this.Data["path"] = this.Request.URL.Path
this.Data["day"] = params.Day this.Data["day"] = params.Day
this.Data["groupId"] = params.GroupId this.Data["groupId"] = params.GroupId
this.Data["accessLogs"] = []interface{}{} this.Data["accessLogs"] = []maps.Map{}
this.Data["partition"] = params.Partition
day := params.Day var day = params.Day
ipList := []string{} var ipList = []string{}
var wafMaps = []maps.Map{}
if len(day) > 0 && regexp.MustCompile(`\d{4}-\d{2}-\d{2}`).MatchString(day) { if len(day) > 0 && regexp.MustCompile(`\d{4}-\d{2}-\d{2}`).MatchString(day) {
day = strings.ReplaceAll(day, "-", "") day = strings.ReplaceAll(day, "-", "")
size := int64(10) var size = int64(20)
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: params.Partition,
RequestId: params.RequestId, RequestId: params.RequestId,
FirewallPolicyId: params.FirewallPolicyId, FirewallPolicyId: params.FirewallPolicyId,
FirewallRuleGroupId: params.GroupId, FirewallRuleGroupId: params.GroupId,
@@ -58,11 +62,31 @@ func (this *LogAction) RunGet(params struct {
} else { } else {
this.Data["accessLogs"] = resp.HttpAccessLogs this.Data["accessLogs"] = resp.HttpAccessLogs
for _, accessLog := range resp.HttpAccessLogs { for _, accessLog := range resp.HttpAccessLogs {
// IP
if len(accessLog.RemoteAddr) > 0 { if len(accessLog.RemoteAddr) > 0 {
if !lists.ContainsString(ipList, accessLog.RemoteAddr) { if !lists.ContainsString(ipList, accessLog.RemoteAddr) {
ipList = append(ipList, accessLog.RemoteAddr) ipList = append(ipList, accessLog.RemoteAddr)
} }
} }
// WAF信息集合
if accessLog.FirewallPolicyId > 0 && accessLog.FirewallRuleGroupId > 0 && accessLog.FirewallRuleSetId > 0 {
// 检查Set是否已经存在
var existSet = false
for _, wafMap := range wafMaps {
if wafMap.GetInt64("setId") == accessLog.FirewallRuleSetId {
existSet = true
break
}
}
if !existSet {
wafMaps = append(wafMaps, maps.Map{
"policyId": accessLog.FirewallPolicyId,
"groupId": accessLog.FirewallRuleGroupId,
"setId": accessLog.FirewallRuleSetId,
})
}
}
} }
} }
this.Data["hasMore"] = resp.HasMore this.Data["hasMore"] = resp.HasMore
@@ -74,6 +98,7 @@ func (this *LogAction) RunGet(params struct {
if len(params.RequestId) > 0 { if len(params.RequestId) > 0 {
this.Data["hasPrev"] = true this.Data["hasPrev"] = true
prevResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ prevResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: params.Partition,
RequestId: params.RequestId, RequestId: params.RequestId,
FirewallPolicyId: params.FirewallPolicyId, FirewallPolicyId: params.FirewallPolicyId,
FirewallRuleGroupId: params.GroupId, FirewallRuleGroupId: params.GroupId,
@@ -131,5 +156,79 @@ func (this *LogAction) RunGet(params struct {
} }
this.Data["regions"] = regionMap this.Data["regions"] = regionMap
// WAF相关
var wafInfos = map[int64]maps.Map{} // set id => WAF Map
var wafPolicyCacheMap = map[int64]*pb.HTTPFirewallPolicy{} // id => *pb.HTTPFirewallPolicy
var wafGroupCacheMap = map[int64]*pb.HTTPFirewallRuleGroup{} // id => *pb.HTTPFirewallRuleGroup
var wafSetCacheMap = map[int64]*pb.HTTPFirewallRuleSet{} // id => *pb.HTTPFirewallRuleSet
for _, wafMap := range wafMaps {
var policyId = wafMap.GetInt64("policyId")
var groupId = wafMap.GetInt64("groupId")
var setId = wafMap.GetInt64("setId")
if policyId > 0 {
pbPolicy, ok := wafPolicyCacheMap[policyId]
if !ok {
policyResp, err := this.RPC().HTTPFirewallPolicyRPC().FindEnabledHTTPFirewallPolicy(this.AdminContext(), &pb.FindEnabledHTTPFirewallPolicyRequest{HttpFirewallPolicyId: policyId})
if err != nil {
this.ErrorPage(err)
return
}
pbPolicy = policyResp.HttpFirewallPolicy
wafPolicyCacheMap[policyId] = pbPolicy
}
if pbPolicy != nil {
wafMap = maps.Map{
"policy": maps.Map{
"id": pbPolicy.Id,
"name": pbPolicy.Name,
"serverId": pbPolicy.ServerId,
},
}
if groupId > 0 {
pbGroup, ok := wafGroupCacheMap[groupId]
if !ok {
groupResp, err := this.RPC().HTTPFirewallRuleGroupRPC().FindEnabledHTTPFirewallRuleGroup(this.AdminContext(), &pb.FindEnabledHTTPFirewallRuleGroupRequest{FirewallRuleGroupId: groupId})
if err != nil {
this.ErrorPage(err)
return
}
pbGroup = groupResp.FirewallRuleGroup
wafGroupCacheMap[groupId] = pbGroup
}
if pbGroup != nil {
wafMap["group"] = maps.Map{
"id": pbGroup.Id,
"name": pbGroup.Name,
}
if setId > 0 {
pbSet, ok := wafSetCacheMap[setId]
if !ok {
setResp, err := this.RPC().HTTPFirewallRuleSetRPC().FindEnabledHTTPFirewallRuleSet(this.AdminContext(), &pb.FindEnabledHTTPFirewallRuleSetRequest{FirewallRuleSetId: setId})
if err != nil {
this.ErrorPage(err)
return
}
pbSet = setResp.FirewallRuleSet
wafSetCacheMap[setId] = pbSet
}
if pbSet != nil {
wafMap["set"] = maps.Map{
"id": pbSet.Id,
"name": pbSet.Name,
}
}
}
}
}
}
}
wafInfos[setId] = wafMap
}
this.Data["wafInfos"] = wafInfos
this.Show() this.Show()
} }

View File

@@ -96,6 +96,7 @@ func (this *PolicyAction) RunGet(params struct {
"blockOptions": firewallPolicy.BlockOptions, "blockOptions": firewallPolicy.BlockOptions,
"useLocalFirewall": firewallPolicy.UseLocalFirewall, "useLocalFirewall": firewallPolicy.UseLocalFirewall,
"synFlood": firewallPolicy.SYNFlood, "synFlood": firewallPolicy.SYNFlood,
"log": firewallPolicy.Log,
} }
// 正在使用此策略的集群 // 正在使用此策略的集群

View File

@@ -58,6 +58,11 @@ func (this *UpdateAction) RunGet(params struct {
} }
} }
// log
if firewallPolicy.Log == nil {
firewallPolicy.Log = firewallconfigs.DefaultHTTPFirewallPolicyLogConfig
}
this.Data["firewallPolicy"] = maps.Map{ this.Data["firewallPolicy"] = maps.Map{
"id": firewallPolicy.Id, "id": firewallPolicy.Id,
"name": firewallPolicy.Name, "name": firewallPolicy.Name,
@@ -67,10 +72,11 @@ func (this *UpdateAction) RunGet(params struct {
"blockOptions": firewallPolicy.BlockOptions, "blockOptions": firewallPolicy.BlockOptions,
"useLocalFirewall": firewallPolicy.UseLocalFirewall, "useLocalFirewall": firewallPolicy.UseLocalFirewall,
"synFloodConfig": firewallPolicy.SYNFlood, "synFloodConfig": firewallPolicy.SYNFlood,
"log": firewallPolicy.Log,
} }
// 预置分组 // 预置分组
groups := []maps.Map{} var groups = []maps.Map{}
templatePolicy := firewallconfigs.HTTPFirewallTemplate() templatePolicy := firewallconfigs.HTTPFirewallTemplate()
for _, group := range templatePolicy.AllRuleGroups() { for _, group := range templatePolicy.AllRuleGroups() {
if len(group.Code) > 0 { if len(group.Code) > 0 {
@@ -101,6 +107,7 @@ func (this *UpdateAction) RunPost(params struct {
Mode string Mode string
UseLocalFirewall bool UseLocalFirewall bool
SynFloodJSON []byte SynFloodJSON []byte
LogJSON []byte
Must *actions.Must Must *actions.Must
}) { }) {
@@ -128,6 +135,7 @@ func (this *UpdateAction) RunPost(params struct {
Mode: params.Mode, Mode: params.Mode,
UseLocalFirewall: params.UseLocalFirewall, UseLocalFirewall: params.UseLocalFirewall,
SynFloodJSON: params.SynFloodJSON, SynFloodJSON: params.SynFloodJSON,
LogJSON: params.LogJSON,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -299,16 +299,19 @@ func (this *CreateAction) RunPost(params struct {
} }
// 源站地址 // 源站地址
reverseProxyRefJSON := []byte{} var reverseProxyRefJSON = []byte{}
switch params.ServerType { switch params.ServerType {
case serverconfigs.ServerTypeHTTPProxy, serverconfigs.ServerTypeTCPProxy, serverconfigs.ServerTypeUDPProxy: case serverconfigs.ServerTypeHTTPProxy, serverconfigs.ServerTypeTCPProxy, serverconfigs.ServerTypeUDPProxy:
originConfigs := []*serverconfigs.OriginConfig{} var originConfigs = []*serverconfigs.OriginConfig{}
err := json.Unmarshal([]byte(params.Origins), &originConfigs) err := json.Unmarshal([]byte(params.Origins), &originConfigs)
if err != nil { if err != nil {
this.Fail("源站地址解析失败:" + err.Error()) this.Fail("源站地址解析失败:" + err.Error())
} }
if len(originConfigs) == 0 {
this.Fail("请添加至少一个源站地址")
}
originRefs := []*serverconfigs.OriginRef{} var originRefs = []*serverconfigs.OriginRef{}
for _, originConfig := range originConfigs { for _, originConfig := range originConfigs {
if originConfig.Id > 0 { if originConfig.Id > 0 {
originRefs = append(originRefs, &serverconfigs.OriginRef{ originRefs = append(originRefs, &serverconfigs.OriginRef{

View File

@@ -0,0 +1,19 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build !plus
// +build !plus
package servergrouputils
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
func filterMenuItems(leftMenuItems []maps.Map, groupId int64, urlPrefix string, menuItem string, configInfoResp *pb.FindEnabledServerGroupConfigInfoResponse) []maps.Map {
return leftMenuItems
}
func filterMenuItems2(leftMenuItems []maps.Map, groupId int64, urlPrefix string, menuItem string, configInfoResp *pb.FindEnabledServerGroupConfigInfoResponse) []maps.Map {
return leftMenuItems
}

View File

@@ -4,7 +4,6 @@ package servergrouputils
import ( import (
"errors" "errors"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
@@ -57,82 +56,7 @@ func InitGroup(parent *actionutils.ParentAction, groupId int64, menuItem string)
}, },
} }
if teaconst.IsPlus { leftMenuItems = filterMenuItems(leftMenuItems, groupId, urlPrefix, menuItem, configInfoResp)
leftMenuItems = append([]maps.Map{
{
"name": "Web设置",
"url": urlPrefix + "/web?groupId=" + types.String(groupId),
"isActive": menuItem == "web",
"isOn": configInfoResp.HasRootConfig,
},
}, leftMenuItems...)
leftMenuItems = append(leftMenuItems, []maps.Map{
{
"name": "-",
"url": "",
},
{
"name": "WAF",
"url": urlPrefix + "/waf?groupId=" + types.String(groupId),
"isActive": menuItem == "waf",
"isOn": configInfoResp.HasWAFConfig,
},
{
"name": "缓存",
"url": urlPrefix + "//cache?groupId=" + types.String(groupId),
"isActive": menuItem == "cache",
"isOn": configInfoResp.HasCacheConfig,
},
{
"name": "字符编码",
"url": urlPrefix + "/charset?groupId=" + types.String(groupId),
"isActive": menuItem == "charset",
"isOn": configInfoResp.HasCharsetConfig,
},
{
"name": "访问日志",
"url": urlPrefix + "/accessLog?groupId=" + types.String(groupId),
"isActive": menuItem == "accessLog",
"isOn": configInfoResp.HasAccessLogConfig,
},
{
"name": "统计",
"url": urlPrefix + "/stat?groupId=" + types.String(groupId),
"isActive": menuItem == "stat",
"isOn": configInfoResp.HasStatConfig,
},
{
"name": "内容压缩",
"url": urlPrefix + "/compression?groupId=" + types.String(groupId),
"isActive": menuItem == "compression",
"isOn": configInfoResp.HasCompressionConfig,
},
{
"name": "特殊页面",
"url": urlPrefix + "/pages?groupId=" + types.String(groupId),
"isActive": menuItem == "pages",
"isOn": configInfoResp.HasPagesConfig,
},
{
"name": "HTTP Header",
"url": urlPrefix + "/headers?groupId=" + types.String(groupId),
"isActive": menuItem == "headers",
"isOn": configInfoResp.HasRequestHeadersConfig || configInfoResp.HasResponseHeadersConfig,
},
{
"name": "Websocket",
"url": urlPrefix + "/websocket?groupId=" + types.String(groupId),
"isActive": menuItem == "websocket",
"isOn": configInfoResp.HasWebsocketConfig,
},
{
"name": "WebP",
"url": urlPrefix + "/webp?groupId=" + types.String(groupId),
"isActive": menuItem == "webp",
"isOn": configInfoResp.HasWebPConfig,
},
}...)
}
leftMenuItems = append(leftMenuItems, maps.Map{ leftMenuItems = append(leftMenuItems, maps.Map{
"name": "-", "name": "-",
@@ -145,14 +69,8 @@ func InitGroup(parent *actionutils.ParentAction, groupId int64, menuItem string)
"isOn": configInfoResp.HasRemoteAddrConfig, "isOn": configInfoResp.HasRemoteAddrConfig,
}) })
if teaconst.IsPlus { leftMenuItems = filterMenuItems2(leftMenuItems, groupId, urlPrefix, menuItem, configInfoResp)
leftMenuItems = append(leftMenuItems, maps.Map{
"name": "请求限制",
"url": urlPrefix + "/requestLimit?groupId=" + types.String(groupId),
"isActive": menuItem == "requestLimit",
"isOn": configInfoResp.HasRequestLimitConfig,
})
}
parent.Data["leftMenuItems"] = leftMenuItems parent.Data["leftMenuItems"] = leftMenuItems
} }

View File

@@ -64,6 +64,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains, "domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil, "hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
} }
primaryOriginMaps = append(primaryOriginMaps, m) primaryOriginMaps = append(primaryOriginMaps, m)
} }
@@ -79,6 +80,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains, "domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil, "hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
} }
backupOriginMaps = append(backupOriginMaps, m) backupOriginMaps = append(backupOriginMaps, m)
} }

View File

@@ -106,6 +106,7 @@ func (this *SettingAction) RunPost(params struct {
StripPrefix: reverseProxyConfig.StripPrefix, StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush, AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders, AddHeaders: reverseProxyConfig.AddHeaders,
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON, ProxyProtocolJSON: proxyProtocolJSON,
}) })

View File

@@ -64,6 +64,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains, "domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil, "hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
} }
primaryOriginMaps = append(primaryOriginMaps, m) primaryOriginMaps = append(primaryOriginMaps, m)
} }
@@ -79,6 +80,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains, "domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil, "hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
} }
backupOriginMaps = append(backupOriginMaps, m) backupOriginMaps = append(backupOriginMaps, m)
} }

View File

@@ -106,6 +106,7 @@ func (this *SettingAction) RunPost(params struct {
StripPrefix: reverseProxyConfig.StripPrefix, StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush, AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders, AddHeaders: reverseProxyConfig.AddHeaders,
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON, ProxyProtocolJSON: proxyProtocolJSON,
}) })

View File

@@ -64,6 +64,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains, "domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil, "hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
} }
primaryOriginMaps = append(primaryOriginMaps, m) primaryOriginMaps = append(primaryOriginMaps, m)
} }
@@ -79,6 +80,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn, "isOn": originConfig.IsOn,
"domains": originConfig.Domains, "domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil, "hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
} }
backupOriginMaps = append(backupOriginMaps, m) backupOriginMaps = append(backupOriginMaps, m)
} }

View File

@@ -96,6 +96,7 @@ func (this *SettingAction) RunPost(params struct {
StripPrefix: reverseProxyConfig.StripPrefix, StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush, AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders, AddHeaders: reverseProxyConfig.AddHeaders,
FollowRedirects: reverseProxyConfig.FollowRedirects,
}) })
this.Success() this.Success()

View File

@@ -3,6 +3,7 @@ package servers
import ( import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders" "github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
@@ -26,12 +27,15 @@ func (this *IndexAction) RunGet(params struct {
Keyword string Keyword string
AuditingFlag int32 AuditingFlag int32
CheckDNS bool CheckDNS bool
TrafficOutOrder string
}) { }) {
this.Data["clusterId"] = params.ClusterId this.Data["clusterId"] = params.ClusterId
this.Data["groupId"] = params.GroupId this.Data["groupId"] = params.GroupId
this.Data["keyword"] = params.Keyword this.Data["keyword"] = params.Keyword
this.Data["auditingFlag"] = params.AuditingFlag this.Data["auditingFlag"] = params.AuditingFlag
this.Data["checkDNS"] = params.CheckDNS this.Data["checkDNS"] = params.CheckDNS
this.Data["hasOrder"] = len(params.TrafficOutOrder) > 0
isSearching := params.AuditingFlag == 1 || params.ClusterId > 0 || params.GroupId > 0 || len(params.Keyword) > 0 isSearching := params.AuditingFlag == 1 || params.ClusterId > 0 || params.GroupId > 0 || len(params.Keyword) > 0
@@ -83,12 +87,14 @@ func (this *IndexAction) RunGet(params struct {
// 服务列表 // 服务列表
serversResp, err := this.RPC().ServerRPC().ListEnabledServersMatch(this.AdminContext(), &pb.ListEnabledServersMatchRequest{ serversResp, err := this.RPC().ServerRPC().ListEnabledServersMatch(this.AdminContext(), &pb.ListEnabledServersMatchRequest{
Offset: page.Offset, Offset: page.Offset,
Size: page.Size, Size: page.Size,
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
ServerGroupId: params.GroupId, ServerGroupId: params.GroupId,
Keyword: params.Keyword, Keyword: params.Keyword,
AuditingFlag: params.AuditingFlag, AuditingFlag: params.AuditingFlag,
TrafficOutDesc: params.TrafficOutOrder == "desc",
TrafficOutAsc: params.TrafficOutOrder == "asc",
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -205,6 +211,15 @@ func (this *IndexAction) RunGet(params struct {
auditingTime = timeutil.FormatTime("Y-m-d", server.AuditingAt) auditingTime = timeutil.FormatTime("Y-m-d", server.AuditingAt)
} }
// 统计数据
var bandwidth = ""
if server.LatestServerDailyStat != nil {
var bytesPerSecond = server.LatestServerDailyStat.Bytes / 300
if bytesPerSecond > 0 {
bandwidth = numberutils.FormatBytes(bytesPerSecond)
}
}
serverMaps = append(serverMaps, maps.Map{ serverMaps = append(serverMaps, maps.Map{
"id": server.Id, "id": server.Id,
"isOn": server.IsOn, "isOn": server.IsOn,
@@ -222,6 +237,7 @@ func (this *IndexAction) RunGet(params struct {
"auditingIsOk": auditingIsOk, "auditingIsOk": auditingIsOk,
"user": userMap, "user": userMap,
"auditingTime": auditingTime, "auditingTime": auditingTime,
"bandwidth": bandwidth,
}) })
} }
this.Data["servers"] = serverMaps this.Data["servers"] = serverMaps
@@ -260,72 +276,17 @@ func (this *IndexAction) RunGet(params struct {
// 是否有用户管理权限 // 是否有用户管理权限
this.Data["canVisitUser"] = configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeUser) this.Data["canVisitUser"] = configloaders.AllowModule(this.AdminId(), configloaders.AdminModuleCodeUser)
// 显示服务相关的日志 // 显示服务需要修复的日志数量
errorLogsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{ countNeedFixLogsResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
NodeId: 0,
Role: nodeconfigs.NodeRoleNode, Role: nodeconfigs.NodeRoleNode,
Offset: 0,
Size: 20,
Level: "error,success,warning",
FixedState: int32(configutils.BoolStateNo),
AllServers: true, AllServers: true,
FixedState: int32(configutils.BoolStateNo),
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
errorLogMaps := []maps.Map{} this.Data["countNeedFixLogs"] = countNeedFixLogsResp.Count
for _, errorLog := range errorLogsResp.NodeLogs {
serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: errorLog.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
// 服务
var server = serverResp.Server
if server == nil {
// 设置为已修复
_, err = this.RPC().NodeLogRPC().FixNodeLogs(this.AdminContext(), &pb.FixNodeLogsRequest{NodeLogIds: []int64{errorLog.Id}})
if err != nil {
this.ErrorPage(err)
return
}
continue
}
// 节点
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: errorLog.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
var node = nodeResp.Node
if node == nil || node.NodeCluster == nil {
// 设置为已修复
_, err = this.RPC().NodeLogRPC().FixNodeLogs(this.AdminContext(), &pb.FixNodeLogsRequest{NodeLogIds: []int64{errorLog.Id}})
if err != nil {
this.ErrorPage(err)
return
}
continue
}
errorLogMaps = append(errorLogMaps, maps.Map{
"id": errorLog.Id,
"description": errorLog.Description,
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", errorLog.CreatedAt),
"serverId": errorLog.ServerId,
"level": errorLog.Level,
"serverName": server.Name,
"nodeId": node.Id,
"nodeName": node.Name,
"clusterId": node.NodeCluster.Id,
})
}
this.Data["errorLogs"] = errorLogMaps
this.Show() this.Show()
} }

View File

@@ -17,7 +17,6 @@ func init() {
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/create", new(CreateAction)). GetPost("/create", new(CreateAction)).
GetPost("/update", new(UpdateAction)). GetPost("/update", new(UpdateAction)).
Post("/fixLog", new(FixLogAction)).
Post("/nearby", new(NearbyAction)). Post("/nearby", new(NearbyAction)).
// //

View File

@@ -102,34 +102,38 @@ func (this *IndexAction) RunGet(params struct {
this.Data["publicBlackIPLists"] = publicBlackIPListMaps this.Data["publicBlackIPLists"] = publicBlackIPListMaps
// 访问日志 // 访问日志
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ var hasAccessLogs = false
Day: timeutil.Format("Ymd"), Loop:
Ip: params.Ip, for _, day := range []string{timeutil.Format("Ymd"), timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1))} {
Size: 20, partitionsResp, err := this.RPC().HTTPAccessLogRPC().FindHTTPAccessLogPartitions(this.AdminContext(), &pb.FindHTTPAccessLogPartitionsRequest{Day: day})
})
if err != nil {
this.ErrorPage(err)
return
}
var accessLogs = accessLogsResp.HttpAccessLogs
if len(accessLogs) == 0 {
// 查询昨天
accessLogsResp, err = this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Day: timeutil.Format("Ymd", time.Now().AddDate(0, 0, -1)),
Ip: params.Ip,
Size: 20,
})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
accessLogs = accessLogsResp.HttpAccessLogs for _, partition := range partitionsResp.ReversePartitions {
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: partition,
Day: day,
Ip: params.Ip,
Size: 20,
})
if err != nil {
this.ErrorPage(err)
return
}
if len(accessLogs) == 0 { var accessLogs = accessLogsResp.HttpAccessLogs
accessLogs = []*pb.HTTPAccessLog{} if len(accessLogs) > 0 {
this.Data["accessLogs"] = accessLogs
hasAccessLogs = true
break Loop
}
} }
} }
this.Data["accessLogs"] = accessLogs
if !hasAccessLogs {
this.Data["accessLogs"] = []interface{}{}
}
this.Show() this.Show()
} }

View File

@@ -29,23 +29,42 @@ func (this *AccessLogsPopupAction) RunGet(params struct {
this.NotFound("ipItem", params.ItemId) this.NotFound("ipItem", params.ItemId)
return return
} }
this.Data["ipFrom"] = item.IpFrom this.Data["ipFrom"] = item.IpFrom
this.Data["ipTo"] = item.IpTo this.Data["ipTo"] = item.IpTo
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ // 多找几个Partition
Day: timeutil.Format("Ymd"), var day = timeutil.FormatTime("Ymd", item.CreatedAt)
Keyword: "ip:" + item.IpFrom + "," + item.IpTo, partitionsResp, err := this.RPC().HTTPAccessLogRPC().FindHTTPAccessLogPartitions(this.AdminContext(), &pb.FindHTTPAccessLogPartitionsRequest{Day: day})
Size: 10,
})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
var accessLogs = accessLogsResp.HttpAccessLogs
if len(accessLogs) == 0 { var hasAccessLogs = false
accessLogs = []*pb.HTTPAccessLog{}
for _, partition := range partitionsResp.ReversePartitions {
accessLogsResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: partition,
Day: day,
Keyword: "ip:" + item.IpFrom + "," + item.IpTo,
Size: 20,
})
if err != nil {
this.ErrorPage(err)
return
}
var accessLogs = accessLogsResp.HttpAccessLogs
if len(accessLogs) > 0 {
this.Data["accessLogs"] = accessLogs
hasAccessLogs = true
break
}
}
if !hasAccessLogs {
this.Data["accessLogs"] = []interface{}{}
} }
this.Data["accessLogs"] = accessLogs
this.Show() this.Show()
} }

View File

@@ -23,16 +23,22 @@ func (this *IndexAction) RunGet(params struct {
Ip string Ip string
GlobalOnly bool GlobalOnly bool
Unread bool Unread bool
EventLevel string
ListType string
}) { }) {
this.Data["type"] = "" this.Data["type"] = ""
this.Data["ip"] = params.Ip this.Data["ip"] = params.Ip
this.Data["globalOnly"] = params.GlobalOnly this.Data["globalOnly"] = params.GlobalOnly
this.Data["unread"] = params.Unread this.Data["unread"] = params.Unread
this.Data["eventLevel"] = params.EventLevel
this.Data["listType"] = params.ListType
countUnreadResp, err := this.RPC().IPItemRPC().CountAllEnabledIPItems(this.AdminContext(), &pb.CountAllEnabledIPItemsRequest{ countUnreadResp, err := this.RPC().IPItemRPC().CountAllEnabledIPItems(this.AdminContext(), &pb.CountAllEnabledIPItemsRequest{
Ip: params.Ip, Ip: params.Ip,
GlobalOnly: params.GlobalOnly, GlobalOnly: params.GlobalOnly,
Unread: true, Unread: true,
EventLevel: params.EventLevel,
ListType: params.ListType,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -44,6 +50,8 @@ func (this *IndexAction) RunGet(params struct {
Ip: params.Ip, Ip: params.Ip,
GlobalOnly: params.GlobalOnly, GlobalOnly: params.GlobalOnly,
Unread: params.Unread, Unread: params.Unread,
EventLevel: params.EventLevel,
ListType: params.ListType,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -57,6 +65,8 @@ func (this *IndexAction) RunGet(params struct {
Ip: params.Ip, Ip: params.Ip,
GlobalOnly: params.GlobalOnly, GlobalOnly: params.GlobalOnly,
Unread: params.Unread, Unread: params.Unread,
EventLevel: params.EventLevel,
ListType: params.ListType,
Offset: page.Offset, Offset: page.Offset,
Size: page.Size, Size: page.Size,
}) })
@@ -143,6 +153,22 @@ func (this *IndexAction) RunGet(params struct {
} }
} }
// 区域 & ISP
var region = ""
var isp = ""
if len(item.IpFrom) > 0 && len(item.IpTo) == 0 {
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: item.IpFrom})
if err != nil {
this.ErrorPage(err)
return
}
var ipRegion = regionResp.IpRegion
if ipRegion != nil {
region = ipRegion.Summary
isp = ipRegion.Isp
}
}
itemMaps = append(itemMaps, maps.Map{ itemMaps = append(itemMaps, maps.Map{
"id": item.Id, "id": item.Id,
"ipFrom": item.IpFrom, "ipFrom": item.IpFrom,
@@ -162,9 +188,14 @@ func (this *IndexAction) RunGet(params struct {
"sourceNode": sourceNodeMap, "sourceNode": sourceNodeMap,
"list": listMap, "list": listMap,
"policy": policyMap, "policy": policyMap,
"region": region,
"isp": isp,
}) })
} }
this.Data["items"] = itemMaps this.Data["items"] = itemMaps
// 所有级别
this.Data["eventLevels"] = firewallconfigs.FindAllFirewallEventLevels()
this.Show() this.Show()
} }

View File

@@ -20,10 +20,12 @@ func (this *ItemsAction) Init() {
} }
func (this *ItemsAction) RunGet(params struct { func (this *ItemsAction) RunGet(params struct {
ListId int64 ListId int64
Keyword string Keyword string
EventLevel string
}) { }) {
this.Data["keyword"] = params.Keyword this.Data["keyword"] = params.Keyword
this.Data["eventLevel"] = params.EventLevel
err := InitIPList(this.Parent(), params.ListId) err := InitIPList(this.Parent(), params.ListId)
if err != nil { if err != nil {
@@ -34,8 +36,9 @@ func (this *ItemsAction) RunGet(params struct {
// 数量 // 数量
var listId = params.ListId var listId = params.ListId
countResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{ countResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{
IpListId: listId, IpListId: listId,
Keyword: params.Keyword, Keyword: params.Keyword,
EventLevel: params.EventLevel,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -47,10 +50,11 @@ func (this *ItemsAction) RunGet(params struct {
// 列表 // 列表
itemsResp, err := this.RPC().IPItemRPC().ListIPItemsWithListId(this.AdminContext(), &pb.ListIPItemsWithListIdRequest{ itemsResp, err := this.RPC().IPItemRPC().ListIPItemsWithListId(this.AdminContext(), &pb.ListIPItemsWithListIdRequest{
IpListId: listId, IpListId: listId,
Keyword: params.Keyword, Keyword: params.Keyword,
Offset: page.Offset, EventLevel: params.EventLevel,
Size: page.Size, Offset: page.Offset,
Size: page.Size,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -100,6 +104,22 @@ func (this *ItemsAction) RunGet(params struct {
} }
} }
// 区域 & ISP
var region = ""
var isp = ""
if len(item.IpFrom) > 0 && len(item.IpTo) == 0 {
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: item.IpFrom})
if err != nil {
this.ErrorPage(err)
return
}
var ipRegion = regionResp.IpRegion
if ipRegion != nil {
region = ipRegion.Summary
isp = ipRegion.Isp
}
}
itemMaps = append(itemMaps, maps.Map{ itemMaps = append(itemMaps, maps.Map{
"id": item.Id, "id": item.Id,
"ipFrom": item.IpFrom, "ipFrom": item.IpFrom,
@@ -114,9 +134,14 @@ func (this *ItemsAction) RunGet(params struct {
"sourceSet": sourceSetMap, "sourceSet": sourceSetMap,
"sourceServer": sourceServerMap, "sourceServer": sourceServerMap,
"lifeSeconds": item.ExpiredAt - time.Now().Unix(), "lifeSeconds": item.ExpiredAt - time.Now().Unix(),
"region": region,
"isp": isp,
}) })
} }
this.Data["items"] = itemMaps this.Data["items"] = itemMaps
// 所有级别
this.Data["eventLevels"] = firewallconfigs.FindAllFirewallEventLevels()
this.Show() this.Show()
} }

View File

@@ -0,0 +1,55 @@
// Copyright 2022 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"
)
// CheckLogAction 检查是否有日志
type CheckLogAction struct {
actionutils.ParentAction
}
func (this *CheckLogAction) RunPost(params struct {
Day string
Partition int32
ServerId int64
RequestId string
ClusterId int64
NodeId int64
HasError bool
HasFirewallPolicy bool
Keyword string
Ip string
Domain string
Hour string
}) {
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: params.Partition,
RequestId: params.RequestId,
NodeClusterId: params.ClusterId,
NodeId: params.NodeId,
ServerId: params.ServerId,
HasError: params.HasError,
HasFirewallPolicy: params.HasFirewallPolicy,
Day: params.Day,
HourFrom: params.Hour,
HourTo: params.Hour,
Keyword: params.Keyword,
Ip: params.Ip,
Domain: params.Domain,
Size: 1,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["hasLogs"] = len(resp.HttpAccessLogs) > 0
this.Success()
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"regexp" "regexp"
"strings" "strings"
@@ -25,11 +26,13 @@ func (this *IndexAction) RunGet(params struct {
ClusterId int64 ClusterId int64
NodeId int64 NodeId int64
Day string Day string
Hour string
Keyword string Keyword string
Ip string Ip string
Domain string Domain string
HasError int HasError int
HasWAF int HasWAF int
Partition int32 `default:"-1"`
RequestId string RequestId string
ServerId int64 ServerId int64
@@ -45,6 +48,7 @@ func (this *IndexAction) RunGet(params struct {
this.Data["serverId"] = 0 this.Data["serverId"] = 0
this.Data["path"] = this.Request.URL.Path this.Data["path"] = this.Request.URL.Path
this.Data["day"] = params.Day this.Data["day"] = params.Day
this.Data["hour"] = params.Hour
this.Data["keyword"] = params.Keyword this.Data["keyword"] = params.Keyword
this.Data["ip"] = params.Ip this.Data["ip"] = params.Ip
this.Data["domain"] = params.Domain this.Data["domain"] = params.Domain
@@ -54,9 +58,11 @@ func (this *IndexAction) RunGet(params struct {
this.Data["pageSize"] = params.PageSize this.Data["pageSize"] = params.PageSize
this.Data["isSlowQuery"] = false this.Data["isSlowQuery"] = false
this.Data["slowQueryCost"] = "" this.Data["slowQueryCost"] = ""
this.Data["partition"] = params.Partition
day := params.Day var day = params.Day
ipList := []string{} var ipList = []string{}
var wafMaps = []maps.Map{}
if len(day) > 0 && regexp.MustCompile(`\d{4}-\d{2}-\d{2}`).MatchString(day) { if len(day) > 0 && regexp.MustCompile(`\d{4}-\d{2}-\d{2}`).MatchString(day) {
day = strings.ReplaceAll(day, "-", "") day = strings.ReplaceAll(day, "-", "")
@@ -69,6 +75,7 @@ func (this *IndexAction) RunGet(params struct {
var before = time.Now() var before = time.Now()
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: params.Partition,
RequestId: params.RequestId, RequestId: params.RequestId,
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
NodeId: params.NodeId, NodeId: params.NodeId,
@@ -76,6 +83,8 @@ func (this *IndexAction) RunGet(params struct {
HasError: params.HasError > 0, HasError: params.HasError > 0,
HasFirewallPolicy: params.HasWAF > 0, HasFirewallPolicy: params.HasWAF > 0,
Day: day, Day: day,
HourFrom: params.Hour,
HourTo: params.Hour,
Keyword: params.Keyword, Keyword: params.Keyword,
Ip: params.Ip, Ip: params.Ip,
Domain: params.Domain, Domain: params.Domain,
@@ -97,11 +106,31 @@ func (this *IndexAction) RunGet(params struct {
} else { } else {
this.Data["accessLogs"] = resp.HttpAccessLogs this.Data["accessLogs"] = resp.HttpAccessLogs
for _, accessLog := range resp.HttpAccessLogs { for _, accessLog := range resp.HttpAccessLogs {
// IP信息集合
if len(accessLog.RemoteAddr) > 0 { if len(accessLog.RemoteAddr) > 0 {
if !lists.ContainsString(ipList, accessLog.RemoteAddr) { if !lists.ContainsString(ipList, accessLog.RemoteAddr) {
ipList = append(ipList, accessLog.RemoteAddr) ipList = append(ipList, accessLog.RemoteAddr)
} }
} }
// WAF信息集合
if accessLog.FirewallPolicyId > 0 && accessLog.FirewallRuleGroupId > 0 && accessLog.FirewallRuleSetId > 0 {
// 检查Set是否已经存在
var existSet = false
for _, wafMap := range wafMaps {
if wafMap.GetInt64("setId") == accessLog.FirewallRuleSetId {
existSet = true
break
}
}
if !existSet {
wafMaps = append(wafMaps, maps.Map{
"policyId": accessLog.FirewallPolicyId,
"groupId": accessLog.FirewallRuleGroupId,
"setId": accessLog.FirewallRuleSetId,
})
}
}
} }
} }
this.Data["hasMore"] = resp.HasMore this.Data["hasMore"] = resp.HasMore
@@ -113,6 +142,7 @@ func (this *IndexAction) RunGet(params struct {
if len(params.RequestId) > 0 { if len(params.RequestId) > 0 {
this.Data["hasPrev"] = true this.Data["hasPrev"] = true
prevResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{ prevResp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: params.Partition,
RequestId: params.RequestId, RequestId: params.RequestId,
NodeClusterId: params.ClusterId, NodeClusterId: params.ClusterId,
NodeId: params.NodeId, NodeId: params.NodeId,
@@ -120,6 +150,8 @@ func (this *IndexAction) RunGet(params struct {
HasError: params.HasError > 0, HasError: params.HasError > 0,
HasFirewallPolicy: params.HasWAF > 0, HasFirewallPolicy: params.HasWAF > 0,
Day: day, Day: day,
HourFrom: params.Hour,
HourTo: params.Hour,
Keyword: params.Keyword, Keyword: params.Keyword,
Ip: params.Ip, Ip: params.Ip,
Domain: params.Domain, Domain: params.Domain,
@@ -137,7 +169,7 @@ func (this *IndexAction) RunGet(params struct {
} }
// 根据IP查询区域 // 根据IP查询区域
regionMap := map[string]string{} // ip => region var regionMap = map[string]string{} // ip => region
if len(ipList) > 0 { if len(ipList) > 0 {
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList}) resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
if err != nil { if err != nil {
@@ -152,5 +184,79 @@ func (this *IndexAction) RunGet(params struct {
} }
this.Data["regions"] = regionMap this.Data["regions"] = regionMap
// WAF相关
var wafInfos = map[int64]maps.Map{} // set id => WAF Map
var wafPolicyCacheMap = map[int64]*pb.HTTPFirewallPolicy{} // id => *pb.HTTPFirewallPolicy
var wafGroupCacheMap = map[int64]*pb.HTTPFirewallRuleGroup{} // id => *pb.HTTPFirewallRuleGroup
var wafSetCacheMap = map[int64]*pb.HTTPFirewallRuleSet{} // id => *pb.HTTPFirewallRuleSet
for _, wafMap := range wafMaps {
var policyId = wafMap.GetInt64("policyId")
var groupId = wafMap.GetInt64("groupId")
var setId = wafMap.GetInt64("setId")
if policyId > 0 {
pbPolicy, ok := wafPolicyCacheMap[policyId]
if !ok {
policyResp, err := this.RPC().HTTPFirewallPolicyRPC().FindEnabledHTTPFirewallPolicy(this.AdminContext(), &pb.FindEnabledHTTPFirewallPolicyRequest{HttpFirewallPolicyId: policyId})
if err != nil {
this.ErrorPage(err)
return
}
pbPolicy = policyResp.HttpFirewallPolicy
wafPolicyCacheMap[policyId] = pbPolicy
}
if pbPolicy != nil {
wafMap = maps.Map{
"policy": maps.Map{
"id": pbPolicy.Id,
"name": pbPolicy.Name,
"serverId": pbPolicy.ServerId,
},
}
if groupId > 0 {
pbGroup, ok := wafGroupCacheMap[groupId]
if !ok {
groupResp, err := this.RPC().HTTPFirewallRuleGroupRPC().FindEnabledHTTPFirewallRuleGroup(this.AdminContext(), &pb.FindEnabledHTTPFirewallRuleGroupRequest{FirewallRuleGroupId: groupId})
if err != nil {
this.ErrorPage(err)
return
}
pbGroup = groupResp.FirewallRuleGroup
wafGroupCacheMap[groupId] = pbGroup
}
if pbGroup != nil {
wafMap["group"] = maps.Map{
"id": pbGroup.Id,
"name": pbGroup.Name,
}
if setId > 0 {
pbSet, ok := wafSetCacheMap[setId]
if !ok {
setResp, err := this.RPC().HTTPFirewallRuleSetRPC().FindEnabledHTTPFirewallRuleSet(this.AdminContext(), &pb.FindEnabledHTTPFirewallRuleSetRequest{FirewallRuleSetId: setId})
if err != nil {
this.ErrorPage(err)
return
}
pbSet = setResp.FirewallRuleSet
wafSetCacheMap[setId] = pbSet
}
if pbSet != nil {
wafMap["set"] = maps.Map{
"id": pbSet.Id,
"name": pbSet.Name,
}
}
}
}
}
}
}
wafInfos[setId] = wafMap
}
this.Data["wafInfos"] = wafInfos
this.Show() this.Show()
} }

View File

@@ -17,6 +17,7 @@ func init() {
Prefix("/servers/logs"). Prefix("/servers/logs").
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/settings", new(SettingsAction)). GetPost("/settings", new(SettingsAction)).
Post("/partitionData", new(PartitionDataAction)).
EndAll() EndAll()
}) })
} }

View File

@@ -0,0 +1,37 @@
// Copyright 2022 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"
"strings"
)
// PartitionDataAction 读取分区表
type PartitionDataAction struct {
actionutils.ParentAction
}
func (this *PartitionDataAction) RunPost(params struct {
Day string
}) {
var day = params.Day
day = strings.ReplaceAll(day, "-", "")
resp, err := this.RPC().HTTPAccessLogRPC().FindHTTPAccessLogPartitions(this.AdminContext(), &pb.FindHTTPAccessLogPartitionsRequest{
Day: day,
})
if err != nil {
this.ErrorPage(err)
return
}
if len(resp.Partitions) > 0 {
this.Data["partitions"] = resp.Partitions
} else {
this.Data["partitions"] = []int32{}
}
this.Success()
}

View File

@@ -27,9 +27,11 @@ func (this *SettingsAction) RunGet(params struct{}) {
} }
var config = &serverconfigs.AccessLogQueueConfig{ var config = &serverconfigs.AccessLogQueueConfig{
MaxLength: 0, MaxLength: 0,
CountPerSecond: 0, CountPerSecond: 0,
Percent: 100, Percent: 100,
EnableAutoPartial: true,
RowsPerTable: 500_000,
} }
if len(settingsResp.ValueJSON) > 0 { if len(settingsResp.ValueJSON) > 0 {
err = json.Unmarshal(settingsResp.ValueJSON, config) err = json.Unmarshal(settingsResp.ValueJSON, config)
@@ -59,9 +61,11 @@ func (this *SettingsAction) RunGet(params struct{}) {
} }
func (this *SettingsAction) RunPost(params struct { func (this *SettingsAction) RunPost(params struct {
Percent int Percent int
CountPerSecond int CountPerSecond int
MaxLength int MaxLength int
EnableAutoPartial bool
RowsPerTable int64
Must *actions.Must Must *actions.Must
CSRF *actionutils.CSRF CSRF *actionutils.CSRF
@@ -72,9 +76,11 @@ func (this *SettingsAction) RunPost(params struct {
Lte(100, "请输入小于100的整数") Lte(100, "请输入小于100的整数")
var config = &serverconfigs.AccessLogQueueConfig{ var config = &serverconfigs.AccessLogQueueConfig{
MaxLength: params.MaxLength, MaxLength: params.MaxLength,
CountPerSecond: params.CountPerSecond, CountPerSecond: params.CountPerSecond,
Percent: params.Percent, Percent: params.Percent,
EnableAutoPartial: params.EnableAutoPartial,
RowsPerTable: params.RowsPerTable,
} }
configJSON, err := json.Marshal(config) configJSON, err := json.Marshal(config)
if err != nil { if err != nil {

View File

@@ -29,12 +29,13 @@ func (this *CreatePopupAction) RunGet(params struct {
} }
func (this *CreatePopupAction) RunPost(params struct { func (this *CreatePopupAction) RunPost(params struct {
Name string Name string
Category string Category string
KeysJSON []byte KeysJSON []byte
PeriodJSON []byte PeriodJSON []byte
Value string Value string
IsPublic bool IsPublic bool
ExpiresPeriod int32
Must *actions.Must Must *actions.Must
CSRF *actionutils.CSRF CSRF *actionutils.CSRF
@@ -68,15 +69,20 @@ func (this *CreatePopupAction) RunPost(params struct {
var period = periodMap.GetInt32("period") var period = periodMap.GetInt32("period")
var periodUnit = periodMap.GetString("unit") var periodUnit = periodMap.GetString("unit")
if params.ExpiresPeriod < 0 {
params.ExpiresPeriod = 0
}
createResp, err := this.RPC().MetricItemRPC().CreateMetricItem(this.AdminContext(), &pb.CreateMetricItemRequest{ createResp, err := this.RPC().MetricItemRPC().CreateMetricItem(this.AdminContext(), &pb.CreateMetricItemRequest{
Code: "", // TODO 未来实现 Code: "", // TODO 未来实现
Category: params.Category, Category: params.Category,
Name: params.Name, Name: params.Name,
Keys: keys, Keys: keys,
Period: period, Period: period,
PeriodUnit: periodUnit, PeriodUnit: periodUnit,
Value: params.Value, ExpiresPeriod: params.ExpiresPeriod,
IsPublic: params.IsPublic, Value: params.Value,
IsPublic: params.IsPublic,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -53,6 +53,7 @@ func (this *IndexAction) RunGet(params struct {
"period": item.Period, "period": item.Period,
"periodUnit": item.PeriodUnit, "periodUnit": item.PeriodUnit,
"periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit), "periodUnitName": serverconfigs.FindMetricPeriodUnitName(item.PeriodUnit),
"expiresPeriod": item.ExpiresPeriod,
"keys": item.Keys, "keys": item.Keys,
"value": item.Value, "value": item.Value,
"valueName": serverconfigs.FindMetricValueName(item.Category, item.Value), "valueName": serverconfigs.FindMetricValueName(item.Category, item.Value),

Some files were not shown because too many files have changed in this diff Show More