Compare commits

...
126 Commits
Author SHA1 Message Date
ssongliu 54b5cee466 fix: 解决页面加载先后导致的分页错误问题 (#2680)
Refs #2674
2023-10-26 15:31:49 +08:00
ssongliu 8607acbb22 fix: 优化终端界面菜单按钮样式 (#2676)
Refs #2669
2023-10-26 15:29:53 +08:00
ssongliu 13f5ac77c2 fix: 修改计划任务脚本执行状态判断 (#2675)
Refs #2652
2023-10-26 15:29:49 +08:00
zhengkunwang 354f0d0753 fix: 修改部分错误代码 (#2673) 2023-10-26 15:29:35 +08:00
48d4a47ed1 fix: 同步数据库时, 忽略recycle_bin和__recycle_bin__ (#2664)
* fix: 同步数据库时, 忽略recycle_bin改为__recycle_bin__

* fix: 同步数据库时, 忽略recycle_bin和__recycle_bin__

---------

Co-authored-by: tt <www@tt.local>
Co-authored-by: shao <shao@mac.local>
2023-10-26 15:29:24 +08:00
shaoandtt 0f3ea3f434 fix: 同步数据库时, 忽略recycle_bin改为__recycle_bin__ (#2659)
Co-authored-by: tt <www@tt.local>
2023-10-26 15:29:18 +08:00
ssongliu c90ad0f4ed fix: 解决容器创建默认 Cmd 失败的问题 (#2641) 2023-10-23 15:27:04 +08:00
ssongliu 61bbfac3cd fix: 计划任务报告样式调整 (#2640) 2023-10-23 15:27:01 +08:00
ssongliu fcca83b3e9 fix: 解决容器创建默认 Entrypoint 失败的问题 (#2638) 2023-10-23 14:33:10 +08:00
ssongliu 8244b679fe feat: 优化计划任务脚本执行输出 (#2637) 2023-10-23 14:33:07 +08:00
ssongliu 604949de18 feat: 优化计划任务脚本执行错误处理 (#2635) 2023-10-23 14:33:03 +08:00
ssongliu 7716df55f9 fix: 修改 OneDrive 授权码长度限制 (#2629)
Refs #2626
2023-10-23 14:33:00 +08:00
igophperand江杭辉 08fe607012 fix: ssh日志识别错误 (#2630)
Co-authored-by: 江杭辉 <jianghanghui@k.app>
2023-10-23 14:32:54 +08:00
igophper 4222a985f9 fix: 修复数据库修改端口错误 (#2627) 2023-10-23 14:32:50 +08:00
ssongliu 0ed5ae71c5 feat: OneDrive 授权码增加格式校验 (#2614)
Refs #2610
2023-10-22 08:43:44 +08:00
ssongliu a2bfa5acaa feat: 解决容器编辑内存限额失败的问题 (#2607)
Refs #2608
2023-10-22 08:43:27 +08:00
ssongliu 609aa04aba fix: 系统用户名、密码增加空格校验 (#2604)
Refs #2602
2023-10-22 08:43:07 +08:00
ssongliu 0b5b90d0c5 fix: 同步数据库时,忽略 recycle_bin (#2591)
Refs #2589
2023-10-22 08:42:41 +08:00
ssongliu 0449100e23 fix: 解决容器设置 host 网络失败的问题 (#2582)
Refs #2550
2023-10-22 08:42:13 +08:00
ssongliu 5f009152d3 feat: SSH 登陆日志适配 Debian12 (#2567)
Refs #2367
2023-10-22 08:41:22 +08:00
zhengkunwang 51ca89daba fix: 解决容器没有 entrypoint 无法打开编辑页面的问题 (#2554) 2023-10-14 10:55:51 -05:00
zhengkunwang 99951029c8 feat: 容器编辑提示增加判断条件 (#2553) 2023-10-14 10:53:57 -05:00
wanghe-fit2cloud 2d2869d184 chore: 更新 README 2023-10-14 09:29:38 +08:00
zhengkunwang 9d85d52005 fix: 解决证书详情页其他域名一直为空的问题 (#2542)
Refs https://github.com/1Panel-dev/1Panel/issues/2539
2023-10-13 10:14:11 +00:00
wanghe b2ce2c86fb feat: add sonar cloud scan (#2540) 2023-10-13 04:44:14 -05:00
ssongliu 1f92324a45 feat: 容器编辑增加提示信息 (#2529) 2023-10-12 13:58:32 +00:00
zhengkunwang 2031295ba4 feat: Node.js 环境增加下载统计 (#2528) 2023-10-12 10:00:38 +00:00
zhengkunwang f079050545 fix: 解决反向代理网站在 firefox 浏览器打开失败的问题 (#2525)
Refs https://github.com/1Panel-dev/1Panel/issues/1465
2023-10-12 09:58:38 +00:00
ssongliu cc6873c941 fix: 解决容器编辑失败时未更新容器 ID 的问题 (#2522) 2023-10-12 05:52:32 +00:00
ssongliu 0252a30f05 fix: 解决容器编辑存储卷失败导致容器丢失的问题 (#2521) 2023-10-12 03:50:31 +00:00
zhengkunwang 8dfb4854a8 fix: 解决日志审计-网站日志不显示的问题 (#2520) 2023-10-12 03:46:31 +00:00
zhengkunwang 5d9e5baec1 fix: 解决首页应用安装跳转错误的问题 (#2519) 2023-10-12 02:50:32 +00:00
ssongliu 16f9533372 fix: 依赖升级 (#2518) 2023-10-12 02:40:31 +00:00
zhengkunwang 9a1ced8cdd fix: 解决新增域名校验错误的问题 (#2516) 2023-10-12 02:24:30 +00:00
ssongliu 9f35e26e22 fix: 解决 SSH 日志批量操作失败的问题 (#2515) 2023-10-12 01:44:30 +00:00
maninhill 7f53c9bc57 chore: 更新 README 2023-10-11 20:23:43 +08:00
ssongliu ecffb04186 fix: 解决 SSH 日志统计信息勾选失效的问题 (#2513) 2023-10-11 10:36:31 +00:00
ssongliu 6d578e53ea fix: 修改部分校验规则 (#2512) 2023-10-11 09:58:31 +00:00
zhengkunwang cd376b2e97 fix: 解决 node.js 模块更新失败的问题 (#2510) 2023-10-11 09:50:30 +00:00
ssongliu c01b3764f8 feat: SSH 日志统计信息增加分页 (#2509) 2023-10-11 09:20:30 +00:00
ssongliu faf4174adf fix: 修改 UFW IP 规则优先级 (#2508) 2023-10-11 09:12:34 +00:00
ssongliu f9e22166c1 fix: 解决防火墙范围端口添加时备注不生效的问题 (#2507) 2023-10-11 07:26:31 +00:00
maninhill 7f12beab8f chore: 更新 README (#2506) 2023-10-11 02:25:29 -05:00
zhengkunwang 862585c2f9 fix: 解决部分应用删除失败的问题 (#2505) 2023-10-11 06:48:29 +00:00
ssongliu db613c3bf7 fix: 修改默认监控网卡 (#2504) 2023-10-11 06:32:28 +00:00
zhengkunwang 2e1e76b226 style: 修改网站运行环境下拉列表样式 (#2503) 2023-10-11 06:30:30 +00:00
zhengkunwang 23ed80298e feat: 同步所有应用增加提示信息 (#2501) 2023-10-11 06:16:29 +00:00
ssongliu 9130d5d2c8 fix: 容器升级增加忽略版本比较勾选 (#2500) 2023-10-11 06:00:30 +00:00
zhengkunwang 8f713c0eda fix: 解决 node.js 运行环境模块页面打开失败的问题 (#2498) 2023-10-11 03:22:29 +00:00
ssongliu 153fe5c1db fix: mfa 标题增加校验规则 (#2497) 2023-10-11 02:10:29 +00:00
ssongliu 1827fb3f46 fix: 修改容器名校验规则描述信息 (#2493) 2023-10-10 11:28:28 +00:00
zhengkunwang b628bce4f8 fix: 解决强制删除 Openresty 没有同步删除 PHP 应用的问题 (#2492) 2023-10-10 11:26:32 +00:00
ssongliu 09341d2254 fix: 解决 UFW 防火墙添加端口备注时不生效的问题 (#2491)
Refs #2487
2023-10-10 10:38:29 +00:00
zhengkunwang 7f75882811 feat: 后端增加统一参数校验方法 (#2490) 2023-10-10 10:36:29 +00:00
zhengkunwang cbd4dd9e9a feat: node.js 运行环境增加模块管理 (#2488) 2023-10-10 09:34:28 +00:00
ssongliu 42e0bff8f7 fix: 监控采集方式修改 (#2489) 2023-10-10 09:30:28 +00:00
ssongliu 5fd238c429 fix: 缓存清理样式调整 (#2485) 2023-10-10 07:48:28 +00:00
ssongliu 945f67677f fix: 解决授权 IP 为空时无法保存的问题 (#2484) 2023-10-09 11:40:26 +00:00
ssongliu 150b1a2590 fix: 解决 UFW 防火墙并发导致的批量操作失败的问题 (#2483) 2023-10-09 11:38:31 +00:00
zhengkunwang a4bd9362ed feat: node.js 运行环境增加模块列表 (#2482) 2023-10-09 11:36:32 +00:00
ssongliu 0496b282b1 fix: 解决远程数据库恢复失败的问题 (#2481) 2023-10-09 09:56:27 +00:00
zhengkunwang f61345c18d feat: 1Panel 重启增加同步应用商店 (#2479) 2023-10-09 07:46:27 +00:00
zhengkunwang 256be27f92 feat: 修改网站日志的关闭参数 (#2475)
Refs https://github.com/1Panel-dev/1Panel/issues/2374
2023-10-09 03:54:18 +00:00
zhengkunwang 2fdf2b9378 fix: 解决证书 HTTP 模式下保存了错误数据的问题 (#2476)
Refs https://github.com/1Panel-dev/1Panel/issues/2473
2023-10-09 03:52:18 +00:00
ssongliu b8d2d4e7af fix: MySQL 性能参数区分版本显示 (#2474) 2023-10-09 03:48:19 +00:00
zhengkunwang 7171c13e31 fix: 解决相同域名和端口可以重复添加的问题 (#2470) 2023-10-08 11:02:15 +00:00
zhengkunwang c0c65598c8 fix: 解决域名暂停或者移除后无法重新创建该域名的问题 (#2468)
Refs https://github.com/1Panel-dev/1Panel/issues/935
2023-10-08 10:10:14 +00:00
ssongliu 90ba0faa77 fix: 修改容器名称校验 (#2467)
Refs #2465
2023-10-08 10:02:15 +00:00
zhengkunwang 124d1e8884 feat: 启动中的 node.js 运行环境放开编辑、停止等操作 (#2466) 2023-10-08 09:54:15 +00:00
ssongliu fefb312f50 fix: 暗色模式下面板设置按钮样式调整 (#2464) 2023-10-08 09:50:15 +00:00
zhengkunwang 825fe792e7 fix: 解决 node.js 网站备份恢复之后运行环境一直启动中的问题 (#2462) 2023-10-08 09:32:15 +00:00
zhengkunwang 5bb77d7176 feat: 创建、更新 node.js 环境增加容器名称校验 (#2461) 2023-10-08 09:06:14 +00:00
ssongliu 517bae6910 fix: 优化容器列表端口显示 (#2460) 2023-10-08 09:04:18 +00:00
zhengkunwang 0dda4411da fix: 解决 node.js 运行环境网站第一次创建失败的问题 (#2459) 2023-10-08 09:02:23 +00:00
ssongliu 71b0deddb6 fix: 增加备份临时回滚文件清理项 (#2458) 2023-10-08 09:00:23 +00:00
zhengkunwang 5dc5b17bea feat: 应用列表顶部增加页码切换 (#2457)
Refs https://github.com/1Panel-dev/1Panel/issues/2293
2023-10-08 08:22:14 +00:00
zhengkunwang fa420b9346 feat: 反向代理配置默认增加协议转发 (#2456) 2023-10-08 07:12:15 +00:00
zhengkunwang 154ea0b4ce feat: 应用商店分类增加排序 (#2455) 2023-10-08 06:54:14 +00:00
ssongliu 9d0eca723c fix: 远程数据库增加删除提示 (#2454) 2023-10-08 06:52:14 +00:00
ssongliu 4c650af0e9 fix: 解决防火墙未显示具体应用占用情况的问题 (#2452) 2023-10-08 04:14:13 +00:00
zhengkunwang b09c423bcc feat: 解决创建网站切换类型显示错误的问题 (#2451) 2023-10-08 02:50:16 +00:00
dependabot[bot] 455e379ff4 build(deps-dev): bump postcss from 8.4.25 to 8.4.31 in /frontend (#2449)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.25 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.25...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-07 21:15:28 -05:00
zhengkunwang 221c87e71e style: 已安装应用按钮调整 (#2446) 2023-10-07 14:18:44 +00:00
zhengkunwang 4366714f0b feat: node.js 运行环境端口禁止输入小数 (#2445) 2023-10-07 14:16:47 +00:00
zhengkunwang d7bdf5813d feat: 网站增加选择 node.js 运行环境 (#2444) 2023-10-07 12:30:45 +00:00
zhengkunwang f258d4e443 style: 修改网站日志按钮样式 (#2442) 2023-10-07 09:02:44 +00:00
zhengkunwang 92c28b3ed1 feat: 运行环境支持选择镜像源 (#2441) 2023-10-07 09:00:47 +00:00
ssongliu e76d1e018e fix: 日志筛选项格式修改 (#2440) 2023-10-07 08:58:46 +00:00
zhengkunwang d685bed167 feat: 应用安装支持选择远程数据库 (#2439) 2023-10-07 08:02:44 +00:00
ssongliu f004df42af fix: 优化 compose 删除提示信息 (#2437) 2023-10-07 02:52:47 -05:00
ssongliu d8df9f755e fix: 修改拼写错误 (#2438) 2023-10-07 07:46:44 +00:00
ssongliu 6b1cc1088e fix: 解决防火墙 ip 规则批量操作失败的问题 (#2435)
Refs #2421 #2430
2023-10-07 06:32:43 +00:00
ssongliu bca9777a43 feat: 容器支持自定义控制台交互方式 (#2434) 2023-10-07 06:30:46 +00:00
ssongliu dc86cbc1ee feat: 缓存清理增加上传下载检查项 (#2415) 2023-09-28 09:16:19 +00:00
ssongliu 11c5558334 feat: Demo 环境白名单增加部分放行接口 (#2413) 2023-09-28 08:16:17 +00:00
ssongliu c6111de050 feat: 两步验证支持设置标题,区分系统 (#2411)
Refs #2404
2023-09-28 07:46:18 +00:00
ssongliu e8564f38ab feat: 增加系统临时文件清理功能 (#2402) 2023-09-28 07:40:17 +00:00
zhengkunwang 2624238354 feat: 网站主域名支持域名:端口 (#2410)
Refs https://github.com/1Panel-dev/1Panel/issues/2333
2023-09-28 07:30:17 +00:00
zhengkunwang aa588205e9 feat: Node.js 运行环境增加端口校验 (#2407) 2023-09-28 07:28:21 +00:00
zhengkunwang ce6069da37 feat: 已安装应用增加日志页面 (#2403) 2023-09-28 02:56:16 +00:00
zhengkunwang 4ca25d51d7 feat: Node.js 环境增加启动、停止、重启操作 (#2394) 2023-09-26 14:50:16 +00:00
zhengkunwang 1130a70052 feat: 运行环境增加 Node.js 管理 (#2390)
Refs https://github.com/1Panel-dev/1Panel/issues/397
2023-09-25 09:50:14 +00:00
ssongliu 38dadf6056 feat: 容器创建替换可输入选择框 (#2378) 2023-09-22 07:58:23 +00:00
wanghe 1905e55628 Delete .DS_Store (#2381) 2023-09-22 15:50:03 +08:00
wanghe 1cdba27cae Update .gitignore (#2380) 2023-09-22 15:46:37 +08:00
wanghe 4932c533ae feat: 增加中文(繁體)说明 (#2379) 2023-09-22 15:29:56 +08:00
ssongliu f4094e03b8 feat: 防火墙范围端口规则显示占用详情 (#2369)
Refs #729 

![image](https://github.com/1Panel-dev/1Panel/assets/73214554/0818e6b8-af81-4368-a7f9-5a55363b5c11)
2023-09-21 10:02:21 +00:00
ssongliu 975ff06d69 feat: 容器列表资源使用率增加详情显示 (#2371)
Refs #2223 

![image](https://github.com/1Panel-dev/1Panel/assets/73214554/e7f8bd8f-dd9a-4783-91eb-56759bad843e)
2023-09-21 09:34:22 +00:00
ssongliu 04eb8191ed feat: 容器镜像增加详情展示 (#2370) 2023-09-21 09:20:20 +00:00
ssongliu a5b3067cc7 feat: 全屏按钮样式统一调整 (#2366) 2023-09-20 14:16:20 +00:00
ssongliu 12d6c2c3df feat: 容器镜像列表增加是否使用标签 (#2364)
Refs #2300 

![image](https://github.com/1Panel-dev/1Panel/assets/73214554/a808d4f8-18fa-4010-8860-0a3788fa7eb0)
2023-09-20 14:14:25 +00:00
ssongliu 695f3278c3 feat: 面板系统日志增加日期选择,支持追踪读取 (#2361) 2023-09-20 08:24:26 +00:00
ssongliu 017eb3814b feat: ssh 登录日志增加概览显示 (#2347) 2023-09-20 06:18:20 +00:00
ssongliu a520bdbe56 feat: 系统授权 ip 支持 ip 段 (#2352) 2023-09-20 04:02:20 +00:00
wanghe bbf2c50b25 Create FUNDING.yml (#2357) 2023-09-20 11:29:11 +08:00
zhengkunwang 9c417e113a fix: 解决网站打开页面错误的问题 (#2350) 2023-09-19 09:22:17 +00:00
ssongliu 6876f28505 fix: 优化部分日志打印 (#2349) 2023-09-19 09:20:22 +00:00
ssongliu d4ab96d213 fix: 解决部分容器创建失败的问题 (#2348) 2023-09-19 09:18:27 +00:00
zhengkunwang 5425544a6b fix: 解决 Supervisor 停止之后一直同步状态的问题 (#2346) 2023-09-19 07:14:18 +00:00
zhengkunwang 06f6a45289 fix: 解决网站设置 PHP 源文之后没有立即生效的问题 (#2341) 2023-09-18 13:52:20 +00:00
ssongliu 9f0f3fa6cd fix: 面板设置增加默认监控网卡选择 (#2339)
Refs #752
2023-09-18 09:22:21 +00:00
ssongliu 88a4ea3513 feat: 缓存页面分页条数 (#2337)
Refs #2159 #1765
2023-09-18 09:20:25 +00:00
zhengkunwang 5ff7085f29 feat: PHP 运行环境增加扩展源选择 (#2340) 2023-09-18 09:18:20 +00:00
ssongliu 072b516d10 fix: MySQL 设置页样式统一 (#2335) 2023-09-18 06:08:19 +00:00
ssongliu 879d640793 fix: 修改登录接口文档 (#2334) 2023-09-18 06:06:18 +00:00
xin.yang ac98d63fcd redis 增加详细的远程连接信息,并添加复制按钮 (#2328)
* redis 增加详细的远程连接信息,并添加复制按钮

* 优化数据加载流程,避免出现 systemIP 被覆盖的问题
2023-09-18 10:16:19 +08:00
294 changed files with 10248 additions and 2949 deletions
+1
View File
@@ -0,0 +1 @@
custom: ["https://afdian.net/a/1Panel"]
+20
View File
@@ -0,0 +1,20 @@
name: Build
on:
push:
branches:
- dev
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarcloud:
name: SonarCloud
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUBTOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+24 -6
View File
@@ -4,18 +4,38 @@
*.dll
*.so
*.dylib
.idea
build/1panel
# Mac
.DS_Store
*/.DS_Store
# VS Code
.vscode
*.project
*.factorypath
# IntelliJ IDEA
.idea
*.iws
*.iml
*.ipr
# NetBeans
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Dependency directories
/pkg/
backend/__debug_bin
cmd/server/__debug_bin
@@ -31,7 +51,5 @@ dist/
1panel.service
install.sh
quick_start.sh
cmd/server/web/.DS_Store
cmd/server/.DS_Store
cmd/server/fileList.txt
.fileList.txt
+3 -2
View File
@@ -6,7 +6,7 @@
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=shield" alt="FOSSA Status"></a><br>
[<a href="README_EN.md">English</a>] | [<a href="README_JP.md">日本語</a>]
[<a href="docs/README_TW.md">中文(繁體)</a>] | [<a href="docs/README_EN.md">English</a>] | [<a href="docs/README_JP.md">日本語</a>]
</p>
------------------------------
@@ -16,7 +16,8 @@
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等一键搞定;
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理等;
- **安全可靠**:基于容器来管理和部署应用,最小漏洞暴露面,提供防火墙和日志审计等功能;
- **一键备份**:支持一键备份和恢复,备份数据到各类云端存储,永不丢失。
- **一键备份**:支持一键备份和恢复,备份数据到各类云端存储,永不丢失;
- **应用商店**:精选各类高质量开源工具和应用软件,助力您轻松安装和升级。
## UI 展示
+5 -8
View File
@@ -37,7 +37,7 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/sync [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
func (b *BaseApi) SyncApp(c *gin.Context) {
go appService.SyncAppListFromLocal()
res, err := appService.GetAppUpdate()
@@ -50,11 +50,8 @@ func (b *BaseApi) SyncApp(c *gin.Context) {
return
}
go func() {
global.LOG.Infof("sync app list start ...")
if err := appService.SyncAppListFromRemote(); err != nil {
global.LOG.Errorf("sync app list error [%s]", err.Error())
} else {
global.LOG.Infof("sync app list success!")
global.LOG.Errorf("Synchronization with the App Store failed [%s]", err.Error())
}
}()
helper.SuccessWithData(c, "")
@@ -93,14 +90,14 @@ func (b *BaseApi) GetApp(c *gin.Context) {
// @Security ApiKeyAuth
// @Router /apps/detail/:appId/:version/:type [get]
func (b *BaseApi) GetAppDetail(c *gin.Context) {
appId, err := helper.GetIntParamByKey(c, "appId")
appID, err := helper.GetIntParamByKey(c, "appId")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
return
}
version := c.Param("version")
appType := c.Param("type")
appDetailDTO, err := appService.GetAppDetail(appId, version, appType)
appDetailDTO, err := appService.GetAppDetail(appID, version, appType)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -154,7 +151,7 @@ func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
// @Success 200 {object} model.AppInstall
// @Security ApiKeyAuth
// @Router /apps/install [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[{"input_column":"name","input_value":"name","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[{"input_column":"name","input_value":"name","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"}
func (b *BaseApi) InstallApp(c *gin.Context) {
var req request.AppInstallCreate
if err := c.ShouldBindJSON(&req); err != nil {
+5 -5
View File
@@ -161,7 +161,7 @@ func (b *BaseApi) DeleteCheck(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/sync [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"同步已安装应用列表","formatEN":"Sync the list of installed apps"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"同步已安装应用列表","formatEN":"Sync the list of installed apps"}
func (b *BaseApi) SyncInstalled(c *gin.Context) {
if err := appInstallService.SyncAll(false); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -178,7 +178,7 @@ func (b *BaseApi) SyncInstalled(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/op [post]
// @x-panel-log {"bodyKeys":["installId","operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"name","output_value":"appName"},{"input_column":"id","input_value":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"[operate] 应用 [appKey][appName]","formatEN":"[operate] App [appKey][appName]"}
// @x-panel-log {"bodyKeys":["installId","operate"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"name","output_value":"appName"},{"input_column":"id","input_value":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"[operate] 应用 [appKey][appName]","formatEN":"[operate] App [appKey][appName]"}
func (b *BaseApi) OperateInstalled(c *gin.Context) {
var req request.AppInstalledOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -240,7 +240,7 @@ func (b *BaseApi) GetUpdateVersions(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/port/change [post]
// @x-panel-log {"bodyKeys":["key","name","port"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用端口修改 [key]-[name] => [port]","formatEN":"Application port update [key]-[name] => [port]"}
// @x-panel-log {"bodyKeys":["key","name","port"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"应用端口修改 [key]-[name] => [port]","formatEN":"Application port update [key]-[name] => [port]"}
func (b *BaseApi) ChangeAppPort(c *gin.Context) {
var req request.PortUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -311,7 +311,7 @@ func (b *BaseApi) GetParams(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/params/update [post]
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用参数修改 [installId]","formatEN":"Application param update [installId]"}
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"应用参数修改 [installId]","formatEN":"Application param update [installId]"}
func (b *BaseApi) UpdateInstalled(c *gin.Context) {
var req request.AppInstalledUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -333,7 +333,7 @@ func (b *BaseApi) UpdateInstalled(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/ignore [post]
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"忽略应用 [installId] 版本升级","formatEN":"Application param update [installId]"}
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"忽略应用 [installId] 版本升级","formatEN":"Application param update [installId]"}
func (b *BaseApi) IgnoreUpgrade(c *gin.Context) {
var req request.AppInstalledIgnoreUpgrade
if err := c.ShouldBindJSON(&req); err != nil {
+1 -1
View File
@@ -19,10 +19,10 @@ type BaseApi struct{}
// @Summary User login
// @Description 用户登录
// @Accept json
// @Param EntranceCode header string true "安全入口 base64 加密串"
// @Param request body dto.Login true "request"
// @Success 200 {object} dto.UserLoginInfo
// @Router /auth/login [post]
// @Header 200 {string} EntranceCode "安全入口"
func (b *BaseApi) Login(c *gin.Context) {
var req dto.Login
if err := c.ShouldBindJSON(&req); err != nil {
+8 -8
View File
@@ -20,7 +20,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup [post]
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建备份账号 [type]","formatEN":"create backup account [type]"}
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建备份账号 [type]","formatEN":"create backup account [type]"}
func (b *BaseApi) CreateBackup(c *gin.Context) {
var req dto.BackupOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -122,7 +122,7 @@ func (b *BaseApi) LoadOneDriveInfo(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":true,"db":"backup_accounts","output_column":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":true,"db":"backup_accounts","output_column":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
func (b *BaseApi) DeleteBackup(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
@@ -176,7 +176,7 @@ func (b *BaseApi) SearchBackupRecords(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/record/download [post]
// @x-panel-log {"bodyKeys":["source","fileName"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载备份记录 [source][fileName]","formatEN":"download backup records [source][fileName]"}
// @x-panel-log {"bodyKeys":["source","fileName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"下载备份记录 [source][fileName]","formatEN":"download backup records [source][fileName]"}
func (b *BaseApi) DownloadRecord(c *gin.Context) {
var req dto.DownloadRecord
if err := c.ShouldBindJSON(&req); err != nil {
@@ -204,7 +204,7 @@ func (b *BaseApi) DownloadRecord(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/record/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"backup_records","output_column":"file_name","output_value":"files"}],"formatZH":"删除备份记录 [files]","formatEN":"delete backup records [files]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"backup_records","output_column":"file_name","output_value":"files"}],"formatZH":"删除备份记录 [files]","formatEN":"delete backup records [files]"}
func (b *BaseApi) DeleteBackupRecord(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -231,7 +231,7 @@ func (b *BaseApi) DeleteBackupRecord(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/update [post]
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新备份账号 [types]","formatEN":"update backup account [types]"}
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新备份账号 [types]","formatEN":"update backup account [types]"}
func (b *BaseApi) UpdateBackup(c *gin.Context) {
var req dto.BackupOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -317,7 +317,7 @@ func (b *BaseApi) LoadFilesFromBackup(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/ [post]
// @x-panel-log {"bodyKeys":["type","name","detailName"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"备份 [type] 数据 [name][detailName]","formatEN":"backup [type] data [name][detailName]"}
// @x-panel-log {"bodyKeys":["type","name","detailName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"备份 [type] 数据 [name][detailName]","formatEN":"backup [type] data [name][detailName]"}
func (b *BaseApi) Backup(c *gin.Context) {
var req dto.CommonBackup
if err := c.ShouldBindJSON(&req); err != nil {
@@ -362,7 +362,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/recover [post]
// @x-panel-log {"bodyKeys":["type","name","detailName","file"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"从 [file] 恢复 [type] 数据 [name][detailName]","formatEN":"recover [type] data [name][detailName] from [file]"}
// @x-panel-log {"bodyKeys":["type","name","detailName","file"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"从 [file] 恢复 [type] 数据 [name][detailName]","formatEN":"recover [type] data [name][detailName] from [file]"}
func (b *BaseApi) Recover(c *gin.Context) {
var req dto.CommonRecover
if err := c.ShouldBindJSON(&req); err != nil {
@@ -415,7 +415,7 @@ func (b *BaseApi) Recover(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/recover/byupload [post]
// @x-panel-log {"bodyKeys":["type","name","detailName","file"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"从 [file] 恢复 [type] 数据 [name][detailName]","formatEN":"recover [type] data [name][detailName] from [file]"}
// @x-panel-log {"bodyKeys":["type","name","detailName","file"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"从 [file] 恢复 [type] 数据 [name][detailName]","formatEN":"recover [type] data [name][detailName] from [file]"}
func (b *BaseApi) RecoverByUpload(c *gin.Context) {
var req dto.CommonRecover
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -16,7 +16,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/command [post]
// @x-panel-log {"bodyKeys":["name","command"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建快捷命令 [name][command]","formatEN":"create quick command [name][command]"}
// @x-panel-log {"bodyKeys":["name","command"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建快捷命令 [name][command]","formatEN":"create quick command [name][command]"}
func (b *BaseApi) CreateCommand(c *gin.Context) {
var req dto.CommandOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -85,7 +85,7 @@ func (b *BaseApi) ListCommand(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/command/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"commands","output_column":"name","output_value":"names"}],"formatZH":"删除快捷命令 [names]","formatEN":"delete quick command [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"commands","output_column":"name","output_value":"names"}],"formatZH":"删除快捷命令 [names]","formatEN":"delete quick command [names]"}
func (b *BaseApi) DeleteCommand(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -112,7 +112,7 @@ func (b *BaseApi) DeleteCommand(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/command/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新快捷命令 [name]","formatEN":"update quick command [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新快捷命令 [name]","formatEN":"update quick command [name]"}
func (b *BaseApi) UpdateCommand(c *gin.Context) {
var req dto.CommandOperate
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -16,7 +16,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/template [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建 compose 模版 [name]","formatEN":"create compose template [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 compose 模版 [name]","formatEN":"create compose template [name]"}
func (b *BaseApi) CreateComposeTemplate(c *gin.Context) {
var req dto.ComposeTemplateCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -87,7 +87,7 @@ func (b *BaseApi) ListComposeTemplate(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/template/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"compose_templates","output_column":"name","output_value":"names"}],"formatZH":"删除 compose 模版 [names]","formatEN":"delete compose template [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"compose_templates","output_column":"name","output_value":"names"}],"formatZH":"删除 compose 模版 [names]","formatEN":"delete compose template [names]"}
func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -114,7 +114,7 @@ func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/template/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"compose_templates","output_column":"name","output_value":"name"}],"formatZH":"更新 compose 模版 [name]","formatEN":"update compose template information [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"compose_templates","output_column":"name","output_value":"name"}],"formatZH":"更新 compose 模版 [name]","formatEN":"update compose template information [name]"}
func (b *BaseApi) UpdateComposeTemplate(c *gin.Context) {
var req dto.ComposeTemplateUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+45 -17
View File
@@ -95,7 +95,7 @@ func (b *BaseApi) SearchCompose(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/compose/test [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测 compose [name] 格式","formatEN":"check compose [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"检测 compose [name] 格式","formatEN":"check compose [name]"}
func (b *BaseApi) TestCompose(c *gin.Context) {
var req dto.ComposeCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -123,7 +123,7 @@ func (b *BaseApi) TestCompose(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/compose [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建 compose [name]","formatEN":"create compose [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 compose [name]","formatEN":"create compose [name]"}
func (b *BaseApi) CreateCompose(c *gin.Context) {
var req dto.ComposeCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -151,7 +151,7 @@ func (b *BaseApi) CreateCompose(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/compose/operate [post]
// @x-panel-log {"bodyKeys":["name","operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"compose [operation] [name]","formatEN":"compose [operation] [name]"}
// @x-panel-log {"bodyKeys":["name","operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"compose [operation] [name]","formatEN":"compose [operation] [name]"}
func (b *BaseApi) OperatorCompose(c *gin.Context) {
var req dto.ComposeOperation
if err := c.ShouldBindJSON(&req); err != nil {
@@ -178,7 +178,7 @@ func (b *BaseApi) OperatorCompose(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/update [post]
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新容器 [name][image]","formatEN":"update container [name][image]"}
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新容器 [name][image]","formatEN":"update container [name][image]"}
func (b *BaseApi) ContainerUpdate(c *gin.Context) {
var req dto.ContainerOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -222,13 +222,13 @@ func (b *BaseApi) ContainerInfo(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Summary Load container limis
// @Summary Load container limits
// @Description 获取容器限制
// @Success 200 {object} dto.ResourceLimit
// @Security ApiKeyAuth
// @Router /containers/limit [get]
func (b *BaseApi) LoadResouceLimit(c *gin.Context) {
data, err := containerService.LoadResouceLimit()
func (b *BaseApi) LoadResourceLimit(c *gin.Context) {
data, err := containerService.LoadResourceLimit()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -258,7 +258,7 @@ func (b *BaseApi) ContainerListStats(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers [post]
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器 [name][image]","formatEN":"create container [name][image]"}
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建容器 [name][image]","formatEN":"create container [name][image]"}
func (b *BaseApi) ContainerCreate(c *gin.Context) {
var req dto.ContainerOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -284,7 +284,7 @@ func (b *BaseApi) ContainerCreate(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/upgrade [post]
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新容器镜像 [name][image]","formatEN":"upgrade container image [name][image]"}
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新容器镜像 [name][image]","formatEN":"upgrade container image [name][image]"}
func (b *BaseApi) ContainerUpgrade(c *gin.Context) {
var req dto.ContainerUpgrade
if err := c.ShouldBindJSON(&req); err != nil {
@@ -310,7 +310,7 @@ func (b *BaseApi) ContainerUpgrade(c *gin.Context) {
// @Success 200 {object} dto.ContainerPruneReport
// @Security ApiKeyAuth
// @Router /containers/prune [post]
// @x-panel-log {"bodyKeys":["pruneType"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清理容器 [pruneType]","formatEN":"clean container [pruneType]"}
// @x-panel-log {"bodyKeys":["pruneType"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清理容器 [pruneType]","formatEN":"clean container [pruneType]"}
func (b *BaseApi) ContainerPrune(c *gin.Context) {
var req dto.ContainerPrune
if err := c.ShouldBindJSON(&req); err != nil {
@@ -337,7 +337,7 @@ func (b *BaseApi) ContainerPrune(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/clean/log [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清理容器 [name] 日志","formatEN":"clean container [name] logs"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清理容器 [name] 日志","formatEN":"clean container [name] logs"}
func (b *BaseApi) CleanContainerLog(c *gin.Context) {
var req dto.OperationWithName
if err := c.ShouldBindJSON(&req); err != nil {
@@ -381,7 +381,7 @@ func (b *BaseApi) LoadContainerLog(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/operate [post]
// @x-panel-log {"bodyKeys":["name","operation","newName"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"容器 [name] 执行 [operation] [newName]","formatEN":"container [operation] [name] [newName]"}
// @x-panel-log {"bodyKeys":["name","operation","newName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"容器 [name] 执行 [operation] [newName]","formatEN":"container [operation] [name] [newName]"}
func (b *BaseApi) ContainerOperation(c *gin.Context) {
var req dto.ContainerOperation
if err := c.ShouldBindJSON(&req); err != nil {
@@ -532,7 +532,7 @@ func (b *BaseApi) ListNetwork(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/network/del [post]
// @x-panel-log {"bodyKeys":["names"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除容器网络 [names]","formatEN":"delete container network [names]"}
// @x-panel-log {"bodyKeys":["names"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除容器网络 [names]","formatEN":"delete container network [names]"}
func (b *BaseApi) DeleteNetwork(c *gin.Context) {
var req dto.BatchDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -559,7 +559,7 @@ func (b *BaseApi) DeleteNetwork(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/network [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器网络 name","formatEN":"create container network [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建容器网络 name","formatEN":"create container network [name]"}
func (b *BaseApi) CreateNetwork(c *gin.Context) {
var req dto.NetworkCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -634,7 +634,7 @@ func (b *BaseApi) ListVolume(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/volume/del [post]
// @x-panel-log {"bodyKeys":["names"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除容器存储卷 [names]","formatEN":"delete container volume [names]"}
// @x-panel-log {"bodyKeys":["names"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除容器存储卷 [names]","formatEN":"delete container volume [names]"}
func (b *BaseApi) DeleteVolume(c *gin.Context) {
var req dto.BatchDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -661,7 +661,7 @@ func (b *BaseApi) DeleteVolume(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/volume [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器存储卷 [name]","formatEN":"create container volume [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建容器存储卷 [name]","formatEN":"create container volume [name]"}
func (b *BaseApi) CreateVolume(c *gin.Context) {
var req dto.VolumeCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -688,7 +688,7 @@ func (b *BaseApi) CreateVolume(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/compose/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 compose [name]","formatEN":"update compose information [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 compose [name]","formatEN":"update compose information [name]"}
func (b *BaseApi) ComposeUpdate(c *gin.Context) {
var req dto.ComposeUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -706,3 +706,31 @@ func (b *BaseApi) ComposeUpdate(c *gin.Context) {
}
helper.SuccessWithData(c, nil)
}
// @Tags Container Compose
// @Summary Container Compose logs
// @Description docker-compose 日志
// @Param compose query string false "compose 文件地址"
// @Param since query string false "时间筛选"
// @Param follow query string false "是否追踪"
// @Param tail query string false "显示行号"
// @Security ApiKeyAuth
// @Router /containers/compose/search/log [get]
func (b *BaseApi) ComposeLogs(c *gin.Context) {
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
global.LOG.Errorf("gin context http handler failed, err: %v", err)
return
}
defer wsConn.Close()
compose := c.Query("compose")
since := c.Query("since")
follow := c.Query("follow") == "true"
tail := c.Query("tail")
if err := containerService.ComposeLogs(wsConn, compose, since, tail, follow); err != nil {
_ = wsConn.WriteMessage(1, []byte(err.Error()))
return
}
}
+7 -7
View File
@@ -19,7 +19,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs [post]
// @x-panel-log {"bodyKeys":["type","name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建计划任务 [type][name]","formatEN":"create cronjob [type][name]"}
// @x-panel-log {"bodyKeys":["type","name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建计划任务 [type][name]","formatEN":"create cronjob [type][name]"}
func (b *BaseApi) CreateCronjob(c *gin.Context) {
var req dto.CronjobCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -124,7 +124,7 @@ func (b *BaseApi) LoadRecordLog(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/records/clean [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"清空计划任务记录 [name]","formatEN":"clean cronjob [name] records"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"清空计划任务记录 [name]","formatEN":"clean cronjob [name] records"}
func (b *BaseApi) CleanRecord(c *gin.Context) {
var req dto.CronjobClean
if err := c.ShouldBindJSON(&req); err != nil {
@@ -148,7 +148,7 @@ func (b *BaseApi) CleanRecord(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"cronjobs","output_column":"name","output_value":"names"}],"formatZH":"删除计划任务 [names]","formatEN":"delete cronjob [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"cronjobs","output_column":"name","output_value":"names"}],"formatZH":"删除计划任务 [names]","formatEN":"delete cronjob [names]"}
func (b *BaseApi) DeleteCronjob(c *gin.Context) {
var req dto.CronjobBatchDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -175,7 +175,7 @@ func (b *BaseApi) DeleteCronjob(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"}
func (b *BaseApi) UpdateCronjob(c *gin.Context) {
var req dto.CronjobUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -202,7 +202,7 @@ func (b *BaseApi) UpdateCronjob(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/status [post]
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"修改计划任务 [name] 状态为 [status]","formatEN":"change the status of cronjob [name] to [status]."}
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"修改计划任务 [name] 状态为 [status]","formatEN":"change the status of cronjob [name] to [status]."}
func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) {
var req dto.CronjobUpdateStatus
if err := c.ShouldBindJSON(&req); err != nil {
@@ -229,7 +229,7 @@ func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/download [post]
// @x-panel-log {"bodyKeys":["recordID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"recordID","isList":false,"db":"job_records","output_column":"file","output_value":"file"}],"formatZH":"下载计划任务记录 [file]","formatEN":"download the cronjob record [file]"}
// @x-panel-log {"bodyKeys":["recordID"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"recordID","isList":false,"db":"job_records","output_column":"file","output_value":"file"}],"formatZH":"下载计划任务记录 [file]","formatEN":"download the cronjob record [file]"}
func (b *BaseApi) TargetDownload(c *gin.Context) {
var req dto.CronjobDownload
if err := c.ShouldBindJSON(&req); err != nil {
@@ -258,7 +258,7 @@ func (b *BaseApi) TargetDownload(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/handle [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"手动执行计划任务 [name]","formatEN":"manually execute the cronjob [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"手动执行计划任务 [name]","formatEN":"manually execute the cronjob [name]"}
func (b *BaseApi) HandleOnce(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
+37 -10
View File
@@ -16,7 +16,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建远程数据库 [name][type]","formatEN":"create database [name][type]"}
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建远程数据库 [name][type]","formatEN":"create database [name][type]"}
func (b *BaseApi) CreateDatabase(c *gin.Context) {
var req dto.DatabaseCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -42,7 +42,7 @@ func (b *BaseApi) CreateDatabase(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db/check [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测远程数据库 [name][type] 连接性","formatEN":"check if database [name][type] is connectable"}
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"检测远程数据库 [name][type] 连接性","formatEN":"check if database [name][type] is connectable"}
func (b *BaseApi) CheckDatabase(c *gin.Context) {
var req dto.DatabaseCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -126,15 +126,14 @@ func (b *BaseApi) GetDatabase(c *gin.Context) {
}
// @Tags Database
// @Summary Delete database
// @Description 删除远程数据库
// @Summary Check before delete remote database
// @Description Mysql 远程数据库删除前检查
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Success 200 {array} string
// @Security ApiKeyAuth
// @Router /databases/db/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"databases","output_column":"name","output_value":"names"}],"formatZH":"删除远程数据库 [names]","formatEN":"delete database [names]"}
func (b *BaseApi) DeleteDatabase(c *gin.Context) {
// @Router /db/remote/del/check [post]
func (b *BaseApi) DeleteCheckDatabase(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
@@ -145,7 +144,35 @@ func (b *BaseApi) DeleteDatabase(c *gin.Context) {
return
}
if err := databaseService.Delete(req.ID); err != nil {
apps, err := databaseService.DeleteCheck(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, apps)
}
// @Tags Database
// @Summary Delete database
// @Description 删除远程数据库
// @Accept json
// @Param request body dto.DatabaseDelete true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"databases","output_column":"name","output_value":"names"}],"formatZH":"删除远程数据库 [names]","formatEN":"delete database [names]"}
func (b *BaseApi) DeleteDatabase(c *gin.Context) {
var req dto.DatabaseDelete
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := databaseService.Delete(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@@ -160,7 +187,7 @@ func (b *BaseApi) DeleteDatabase(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新远程数据库 [name]","formatEN":"update database [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新远程数据库 [name]","formatEN":"update database [name]"}
func (b *BaseApi) UpdateDatabase(c *gin.Context) {
var req dto.DatabaseUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+7 -7
View File
@@ -19,7 +19,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /databases [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建 mysql 数据库 [name]","formatEN":"create mysql database [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 mysql 数据库 [name]","formatEN":"create mysql database [name]"}
func (b *BaseApi) CreateMysql(c *gin.Context) {
var req dto.MysqlDBCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -54,7 +54,7 @@ func (b *BaseApi) CreateMysql(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/description/update [post]
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"mysql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the mysql database [name] is modified => [description]"}
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"mysql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the mysql database [name] is modified => [description]"}
func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) {
var req dto.UpdateDescription
if err := c.ShouldBindJSON(&req); err != nil {
@@ -80,7 +80,7 @@ func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/change/password [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 密码","formatEN":"Update database [name] password"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 密码","formatEN":"Update database [name] password"}
func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
var req dto.ChangeDBInfo
if err := c.ShouldBindJSON(&req); err != nil {
@@ -115,7 +115,7 @@ func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/change/access [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 访问权限","formatEN":"Update database [name] access"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 访问权限","formatEN":"Update database [name] access"}
func (b *BaseApi) ChangeMysqlAccess(c *gin.Context) {
var req dto.ChangeDBInfo
if err := c.ShouldBindJSON(&req); err != nil {
@@ -141,7 +141,7 @@ func (b *BaseApi) ChangeMysqlAccess(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/variables/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"调整 mysql 数据库性能参数","formatEN":"adjust mysql database performance parameters"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"调整 mysql 数据库性能参数","formatEN":"adjust mysql database performance parameters"}
func (b *BaseApi) UpdateMysqlVariables(c *gin.Context) {
var req dto.MysqlVariablesUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -164,7 +164,7 @@ func (b *BaseApi) UpdateMysqlVariables(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 mysql 数据库配置信息","formatEN":"update the mysql database configuration information"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 mysql 数据库配置信息","formatEN":"update the mysql database configuration information"}
func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) {
var req dto.MysqlConfUpdateByFile
if err := c.ShouldBindJSON(&req); err != nil {
@@ -289,7 +289,7 @@ func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"删除 mysql 数据库 [name]","formatEN":"delete mysql database [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"删除 mysql 数据库 [name]","formatEN":"delete mysql database [name]"}
func (b *BaseApi) DeleteMysql(c *gin.Context) {
var req dto.MysqlDBDelete
if err := c.ShouldBindJSON(&req); err != nil {
+4 -4
View File
@@ -70,7 +70,7 @@ func (b *BaseApi) LoadPersistenceConf(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/redis/conf/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 redis 数据库配置信息","formatEN":"update the redis database configuration information"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 redis 数据库配置信息","formatEN":"update the redis database configuration information"}
func (b *BaseApi) UpdateRedisConf(c *gin.Context) {
var req dto.RedisConfUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -96,7 +96,7 @@ func (b *BaseApi) UpdateRedisConf(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/redis/password [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 redis 数据库密码","formatEN":"change the password of the redis database"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 redis 数据库密码","formatEN":"change the password of the redis database"}
func (b *BaseApi) ChangeRedisPassword(c *gin.Context) {
var req dto.ChangeRedisPass
if err := c.ShouldBindJSON(&req); err != nil {
@@ -131,7 +131,7 @@ func (b *BaseApi) ChangeRedisPassword(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/redis/persistence/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"redis 数据库持久化配置更新","formatEN":"redis database persistence configuration update"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"redis 数据库持久化配置更新","formatEN":"redis database persistence configuration update"}
func (b *BaseApi) UpdateRedisPersistenceConf(c *gin.Context) {
var req dto.RedisConfPersistenceUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -184,7 +184,7 @@ func (b *BaseApi) RedisBackupList(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/redis/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 redis 数据库配置信息","formatEN":"update the redis database configuration information"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 redis 数据库配置信息","formatEN":"update the redis database configuration information"}
func (b *BaseApi) UpdateRedisConfByFile(c *gin.Context) {
var req dto.RedisConfUpdateByFile
if err := c.ShouldBindJSON(&req); err != nil {
+4 -4
View File
@@ -62,7 +62,7 @@ func (b *BaseApi) LoadDaemonJson(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update [post]
// @x-panel-log {"bodyKeys":["key", "value"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 配置 [key]=>[value]","formatEN":"Updated the docker daemon.json configuration [key]=>[value]"}
// @x-panel-log {"bodyKeys":["key", "value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 配置 [key]=>[value]","formatEN":"Updated the docker daemon.json configuration [key]=>[value]"}
func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
var req dto.SettingUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -86,7 +86,7 @@ func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 日志配置","formatEN":"Updated the docker daemon.json log option"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 日志配置","formatEN":"Updated the docker daemon.json log option"}
func (b *BaseApi) UpdateLogOption(c *gin.Context) {
var req dto.LogOption
if err := c.ShouldBindJSON(&req); err != nil {
@@ -110,7 +110,7 @@ func (b *BaseApi) UpdateLogOption(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update/byfile [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 配置","formatEN":"Updated the docker daemon.json configuration"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 配置","formatEN":"Updated the docker daemon.json configuration"}
func (b *BaseApi) UpdateDaemonJsonByFile(c *gin.Context) {
var req dto.DaemonJsonUpdateByFile
if err := c.ShouldBindJSON(&req); err != nil {
@@ -138,7 +138,7 @@ func (b *BaseApi) UpdateDaemonJsonByFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/docker/operate [post]
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"docker 服务 [operation]","formatEN":"[operation] docker service"}
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"docker 服务 [operation]","formatEN":"[operation] docker service"}
func (b *BaseApi) OperateDocker(c *gin.Context) {
var req dto.DockerOperation
if err := c.ShouldBindJSON(&req); err != nil {
+17 -17
View File
@@ -106,7 +106,7 @@ func (b *BaseApi) GetFileTree(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建文件/文件夹 [path]","formatEN":"Create dir or file [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建文件/文件夹 [path]","formatEN":"Create dir or file [path]"}
func (b *BaseApi) CreateFile(c *gin.Context) {
var req request.FileCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -129,7 +129,7 @@ func (b *BaseApi) CreateFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/del [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除文件/文件夹 [path]","formatEN":"Delete dir or file [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除文件/文件夹 [path]","formatEN":"Delete dir or file [path]"}
func (b *BaseApi) DeleteFile(c *gin.Context) {
var req request.FileDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -152,7 +152,7 @@ func (b *BaseApi) DeleteFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/batch/del [post]
// @x-panel-log {"bodyKeys":["paths"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"批量删除文件/文件夹 [paths]","formatEN":"Batch delete dir or file [paths]"}
// @x-panel-log {"bodyKeys":["paths"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"批量删除文件/文件夹 [paths]","formatEN":"Batch delete dir or file [paths]"}
func (b *BaseApi) BatchDeleteFile(c *gin.Context) {
var req request.FileBatchDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -175,7 +175,7 @@ func (b *BaseApi) BatchDeleteFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/mode [post]
// @x-panel-log {"bodyKeys":["path","mode"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改权限 [paths] => [mode]","formatEN":"Change mode [paths] => [mode]"}
// @x-panel-log {"bodyKeys":["path","mode"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改权限 [paths] => [mode]","formatEN":"Change mode [paths] => [mode]"}
func (b *BaseApi) ChangeFileMode(c *gin.Context) {
var req request.FileCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -198,7 +198,7 @@ func (b *BaseApi) ChangeFileMode(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/owner [post]
// @x-panel-log {"bodyKeys":["path","user","group"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改用户/组 [paths] => [user]/[group]","formatEN":"Change owner [paths] => [user]/[group]"}
// @x-panel-log {"bodyKeys":["path","user","group"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改用户/组 [paths] => [user]/[group]","formatEN":"Change owner [paths] => [user]/[group]"}
func (b *BaseApi) ChangeFileOwner(c *gin.Context) {
var req request.FileRoleUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -220,7 +220,7 @@ func (b *BaseApi) ChangeFileOwner(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/compress [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"压缩文件 [name]","formatEN":"Compress file [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"压缩文件 [name]","formatEN":"Compress file [name]"}
func (b *BaseApi) CompressFile(c *gin.Context) {
var req request.FileCompress
if err := c.ShouldBindJSON(&req); err != nil {
@@ -243,7 +243,7 @@ func (b *BaseApi) CompressFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/decompress [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"解压 [path]","formatEN":"Decompress file [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"解压 [path]","formatEN":"Decompress file [path]"}
func (b *BaseApi) DeCompressFile(c *gin.Context) {
var req request.FileDeCompress
if err := c.ShouldBindJSON(&req); err != nil {
@@ -266,7 +266,7 @@ func (b *BaseApi) DeCompressFile(c *gin.Context) {
// @Success 200 {object} response.FileInfo
// @Security ApiKeyAuth
// @Router /files/content [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"获取文件内容 [path]","formatEN":"Load file content [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"获取文件内容 [path]","formatEN":"Load file content [path]"}
func (b *BaseApi) GetContent(c *gin.Context) {
var req request.FileOption
if err := c.ShouldBindJSON(&req); err != nil {
@@ -289,7 +289,7 @@ func (b *BaseApi) GetContent(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/save [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新文件内容 [path]","formatEN":"Update file content [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新文件内容 [path]","formatEN":"Update file content [path]"}
func (b *BaseApi) SaveContent(c *gin.Context) {
var req request.FileEdit
if err := c.ShouldBindJSON(&req); err != nil {
@@ -310,7 +310,7 @@ func (b *BaseApi) SaveContent(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/upload [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
func (b *BaseApi) UploadFiles(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
@@ -356,7 +356,7 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/check [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测文件 [path] 是否存在","formatEN":"Check whether file [path] exists"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"检测文件 [path] 是否存在","formatEN":"Check whether file [path] exists"}
func (b *BaseApi) CheckFile(c *gin.Context) {
var req request.FilePathCheck
if err := c.ShouldBindJSON(&req); err != nil {
@@ -384,7 +384,7 @@ func (b *BaseApi) CheckFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/rename [post]
// @x-panel-log {"bodyKeys":["oldName","newName"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"重命名 [oldName] => [newName]","formatEN":"Rename [oldName] => [newName]"}
// @x-panel-log {"bodyKeys":["oldName","newName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"重命名 [oldName] => [newName]","formatEN":"Rename [oldName] => [newName]"}
func (b *BaseApi) ChangeFileName(c *gin.Context) {
var req request.FileRename
if err := c.ShouldBindJSON(&req); err != nil {
@@ -406,7 +406,7 @@ func (b *BaseApi) ChangeFileName(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/wget [post]
// @x-panel-log {"bodyKeys":["url","path","name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载 url => [path]/[name]","formatEN":"Download url => [path]/[name]"}
// @x-panel-log {"bodyKeys":["url","path","name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"下载 url => [path]/[name]","formatEN":"Download url => [path]/[name]"}
func (b *BaseApi) WgetFile(c *gin.Context) {
var req request.FileWget
if err := c.ShouldBindJSON(&req); err != nil {
@@ -431,7 +431,7 @@ func (b *BaseApi) WgetFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/move [post]
// @x-panel-log {"bodyKeys":["oldPaths","newPath"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"移动文件 [oldPaths] => [newPath]","formatEN":"Move [oldPaths] => [newPath]"}
// @x-panel-log {"bodyKeys":["oldPaths","newPath"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"移动文件 [oldPaths] => [newPath]","formatEN":"Move [oldPaths] => [newPath]"}
func (b *BaseApi) MoveFile(c *gin.Context) {
var req request.FileMove
if err := c.ShouldBindJSON(&req); err != nil {
@@ -453,7 +453,7 @@ func (b *BaseApi) MoveFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/download [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
func (b *BaseApi) Download(c *gin.Context) {
filePath := c.Query("path")
file, err := os.Open(filePath)
@@ -474,7 +474,7 @@ func (b *BaseApi) Download(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/chunkdownload [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
func (b *BaseApi) DownloadChunkFiles(c *gin.Context) {
var req request.FileChunkDownload
if err := c.ShouldBindJSON(&req); err != nil {
@@ -552,7 +552,7 @@ func (b *BaseApi) DownloadChunkFiles(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /files/size [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"获取文件夹大小 [path]","formatEN":"Load file size [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"获取文件夹大小 [path]","formatEN":"Load file size [path]"}
func (b *BaseApi) Size(c *gin.Context) {
var req request.DirSizeReq
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -63,7 +63,7 @@ func (b *BaseApi) SearchFirewallRule(c *gin.Context) {
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /hosts/firewall/operate [post]
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operation] 防火墙","formatEN":"[operation] firewall"}
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] 防火墙","formatEN":"[operation] firewall"}
func (b *BaseApi) OperateFirewall(c *gin.Context) {
var req dto.FirewallOperation
if err := c.ShouldBindJSON(&req); err != nil {
@@ -91,7 +91,7 @@ func (b *BaseApi) OperateFirewall(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/firewall/port [post]
// @x-panel-log {"bodyKeys":["port","strategy"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加端口规则 [strategy] [port]","formatEN":"create port rules [strategy][port]"}
// @x-panel-log {"bodyKeys":["port","strategy"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"添加端口规则 [strategy] [port]","formatEN":"create port rules [strategy][port]"}
func (b *BaseApi) OperatePortRule(c *gin.Context) {
var req dto.PortRuleOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -117,7 +117,7 @@ func (b *BaseApi) OperatePortRule(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/firewall/ip [post]
// @x-panel-log {"bodyKeys":["strategy","address"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加 ip 规则 [strategy] [address]","formatEN":"create address rules [strategy][address]"}
// @x-panel-log {"bodyKeys":["strategy","address"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"添加 ip 规则 [strategy] [address]","formatEN":"create address rules [strategy][address]"}
func (b *BaseApi) OperateIPRule(c *gin.Context) {
var req dto.AddrRuleOperate
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -16,7 +16,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /groups [post]
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
func (b *BaseApi) CreateGroup(c *gin.Context) {
var req dto.GroupCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -42,7 +42,7 @@ func (b *BaseApi) CreateGroup(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /groups/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"name","output_value":"name"},{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"name","output_value":"name"},{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
func (b *BaseApi) DeleteGroup(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
@@ -69,7 +69,7 @@ func (b *BaseApi) DeleteGroup(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /groups/update [post]
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
func (b *BaseApi) UpdateGroup(c *gin.Context) {
var req dto.GroupUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+12 -19
View File
@@ -17,25 +17,6 @@ import (
"github.com/pkg/errors"
)
func GeneratePaginationFromReq(c *gin.Context) (*dto.PageInfo, bool) {
p, ok1 := c.GetQuery("page")
ps, ok2 := c.GetQuery("pageSize")
if !(ok1 && ok2) {
return nil, false
}
page, err := strconv.Atoi(p)
if err != nil {
return nil, false
}
pageSize, err := strconv.Atoi(ps)
if err != nil {
return nil, false
}
return &dto.PageInfo{Page: page, PageSize: pageSize}, true
}
func ErrorWithDetail(ctx *gin.Context, code int, msgKey string, err error) {
res := dto.Response{
Code: code,
@@ -132,3 +113,15 @@ func GetTxAndContext() (tx *gorm.DB, ctx context.Context) {
ctx = context.WithValue(context.Background(), constant.DB, tx)
return
}
func CheckBindAndValidate(req interface{}, c *gin.Context) error {
if err := c.ShouldBindJSON(&req); err != nil {
ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return err
}
if err := global.VALID.Struct(req); err != nil {
ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return err
}
return nil
}
+4 -4
View File
@@ -17,7 +17,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts [post]
// @x-panel-log {"bodyKeys":["name","addr"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建主机 [name][addr]","formatEN":"create host [name][addr]"}
// @x-panel-log {"bodyKeys":["name","addr"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建主机 [name][addr]","formatEN":"create host [name][addr]"}
func (b *BaseApi) CreateHost(c *gin.Context) {
var req dto.HostOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -138,7 +138,7 @@ func (b *BaseApi) SearchHost(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"hosts","output_column":"addr","output_value":"addrs"}],"formatZH":"删除主机 [addrs]","formatEN":"delete host [addrs]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"hosts","output_column":"addr","output_value":"addrs"}],"formatZH":"删除主机 [addrs]","formatEN":"delete host [addrs]"}
func (b *BaseApi) DeleteHost(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -165,7 +165,7 @@ func (b *BaseApi) DeleteHost(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/update [post]
// @x-panel-log {"bodyKeys":["name","addr"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新主机信息 [name][addr]","formatEN":"update host [name][addr]"}
// @x-panel-log {"bodyKeys":["name","addr"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新主机信息 [name][addr]","formatEN":"update host [name][addr]"}
func (b *BaseApi) UpdateHost(c *gin.Context) {
var req dto.HostOperate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -235,7 +235,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/update/group [post]
// @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"hosts","output_column":"addr","output_value":"addr"}],"formatZH":"切换主机[addr]分组 => [group]","formatEN":"change host [addr] group => [group]"}
// @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"hosts","output_column":"addr","output_value":"addr"}],"formatZH":"切换主机[addr]分组 => [group]","formatEN":"change host [addr] group => [group]"}
func (b *BaseApi) UpdateHostGroup(c *gin.Context) {
var req dto.ChangeHostGroup
if err := c.ShouldBindJSON(&req); err != nil {
+5 -5
View File
@@ -43,7 +43,7 @@ func (b *BaseApi) GetToolStatus(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/create [post]
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"}
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"}
func (b *BaseApi) InitToolConfig(c *gin.Context) {
var req request.HostToolCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -70,7 +70,7 @@ func (b *BaseApi) InitToolConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/operate [post]
// @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"}
// @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"}
func (b *BaseApi) OperateTool(c *gin.Context) {
var req request.HostToolReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -98,7 +98,7 @@ func (b *BaseApi) OperateTool(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/config [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"}
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"}
func (b *BaseApi) OperateToolConfig(c *gin.Context) {
var req request.HostToolConfig
if err := c.ShouldBindJSON(&req); err != nil {
@@ -153,7 +153,7 @@ func (b *BaseApi) GetToolLog(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/supervisor/process [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"}
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"}
func (b *BaseApi) OperateProcess(c *gin.Context) {
var req request.SupervisorProcessConfig
if err := c.ShouldBindJSON(&req); err != nil {
@@ -197,7 +197,7 @@ func (b *BaseApi) GetProcess(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/supervisor/process/file [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] Supervisor 进程文件 ","formatEN":"[operate] Supervisor Process Config file"}
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] Supervisor 进程文件 ","formatEN":"[operate] Supervisor Process Config file"}
func (b *BaseApi) GetProcessFile(c *gin.Context) {
var req request.SupervisorProcessFileReq
if err := c.ShouldBindJSON(&req); err != nil {
+7 -7
View File
@@ -64,7 +64,7 @@ func (b *BaseApi) ListImage(c *gin.Context) {
// @Success 200 {string} log
// @Security ApiKeyAuth
// @Router /containers/image/build [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"构建镜像 [name]","formatEN":"build image [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"构建镜像 [name]","formatEN":"build image [name]"}
func (b *BaseApi) ImageBuild(c *gin.Context) {
var req dto.ImageBuild
if err := c.ShouldBindJSON(&req); err != nil {
@@ -93,7 +93,7 @@ func (b *BaseApi) ImageBuild(c *gin.Context) {
// @Success 200 {string} log
// @Security ApiKeyAuth
// @Router /containers/image/pull [post]
// @x-panel-log {"bodyKeys":["repoID","imageName"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"镜像拉取 [reponame][imageName]","formatEN":"image pull [reponame][imageName]"}
// @x-panel-log {"bodyKeys":["repoID","imageName"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"镜像拉取 [reponame][imageName]","formatEN":"image pull [reponame][imageName]"}
func (b *BaseApi) ImagePull(c *gin.Context) {
var req dto.ImagePull
if err := c.ShouldBindJSON(&req); err != nil {
@@ -122,7 +122,7 @@ func (b *BaseApi) ImagePull(c *gin.Context) {
// @Success 200 {string} log
// @Security ApiKeyAuth
// @Router /containers/image/push [post]
// @x-panel-log {"bodyKeys":["repoID","tagName","name"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"[tagName] 推送到 [reponame][name]","formatEN":"push [tagName] to [reponame][name]"}
// @x-panel-log {"bodyKeys":["repoID","tagName","name"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"[tagName] 推送到 [reponame][name]","formatEN":"push [tagName] to [reponame][name]"}
func (b *BaseApi) ImagePush(c *gin.Context) {
var req dto.ImagePush
if err := c.ShouldBindJSON(&req); err != nil {
@@ -151,7 +151,7 @@ func (b *BaseApi) ImagePush(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/image/remove [post]
// @x-panel-log {"bodyKeys":["names"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"移除镜像 [names]","formatEN":"remove image [names]"}
// @x-panel-log {"bodyKeys":["names"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"移除镜像 [names]","formatEN":"remove image [names]"}
func (b *BaseApi) ImageRemove(c *gin.Context) {
var req dto.BatchDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -179,7 +179,7 @@ func (b *BaseApi) ImageRemove(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/image/save [post]
// @x-panel-log {"bodyKeys":["tagName","path","name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"保留 [tagName] 为 [path]/[name]","formatEN":"save [tagName] as [path]/[name]"}
// @x-panel-log {"bodyKeys":["tagName","path","name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"保留 [tagName] 为 [path]/[name]","formatEN":"save [tagName] as [path]/[name]"}
func (b *BaseApi) ImageSave(c *gin.Context) {
var req dto.ImageSave
if err := c.ShouldBindJSON(&req); err != nil {
@@ -207,7 +207,7 @@ func (b *BaseApi) ImageSave(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/image/tag [post]
// @x-panel-log {"bodyKeys":["repoID","targetName"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"tag 镜像 [reponame][targetName]","formatEN":"tag image [reponame][targetName]"}
// @x-panel-log {"bodyKeys":["repoID","targetName"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"tag 镜像 [reponame][targetName]","formatEN":"tag image [reponame][targetName]"}
func (b *BaseApi) ImageTag(c *gin.Context) {
var req dto.ImageTag
if err := c.ShouldBindJSON(&req); err != nil {
@@ -235,7 +235,7 @@ func (b *BaseApi) ImageTag(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/image/load [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"从 [path] 加载镜像","formatEN":"load image from [path]"}
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"从 [path] 加载镜像","formatEN":"load image from [path]"}
func (b *BaseApi) ImageLoad(c *gin.Context) {
var req dto.ImageLoad
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -92,7 +92,7 @@ func (b *BaseApi) CheckRepoStatus(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/repo [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建镜像仓库 [name]","formatEN":"create image repo [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建镜像仓库 [name]","formatEN":"create image repo [name]"}
func (b *BaseApi) CreateRepo(c *gin.Context) {
var req dto.ImageRepoCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -119,7 +119,7 @@ func (b *BaseApi) CreateRepo(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/repo/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"image_repos","output_column":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"image_repos","output_column":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
func (b *BaseApi) DeleteRepo(c *gin.Context) {
var req dto.ImageRepoDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -147,7 +147,7 @@ func (b *BaseApi) DeleteRepo(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/repo/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_column":"name","output_value":"name"}],"formatZH":"更新镜像仓库 [name]","formatEN":"update image repo information [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_column":"name","output_value":"name"}],"formatZH":"更新镜像仓库 [name]","formatEN":"update image repo information [name]"}
func (b *BaseApi) UpdateRepo(c *gin.Context) {
var req dto.ImageRepoUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+26 -5
View File
@@ -70,7 +70,7 @@ func (b *BaseApi) GetOperationLogs(c *gin.Context) {
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /logs/clean [post]
// @x-panel-log {"bodyKeys":["logType"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清空 [logType] 日志信息","formatEN":"Clean the [logType] log information"}
// @x-panel-log {"bodyKeys":["logType"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清空 [logType] 日志信息","formatEN":"Clean the [logType] log information"}
func (b *BaseApi) CleanLogs(c *gin.Context) {
var req dto.CleanLog
if err := c.ShouldBindJSON(&req); err != nil {
@@ -91,13 +91,34 @@ func (b *BaseApi) CleanLogs(c *gin.Context) {
}
// @Tags Logs
// @Summary Load system logs
// @Description 获取系统日志
// @Summary Load system log files
// @Description 获取系统日志文件列表
// @Success 200
// @Security ApiKeyAuth
// @Router /logs/system [get]
// @Router /logs/system/files [get]
func (b *BaseApi) GetSystemFiles(c *gin.Context) {
data, err := logService.ListSystemLogFile()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Logs
// @Summary Load system logs
// @Description 获取系统日志
// @Success 200
// @Security ApiKeyAuth
// @Router /logs/system [post]
func (b *BaseApi) GetSystemLogs(c *gin.Context) {
data, err := logService.LoadSystemLog()
var req dto.OperationWithName
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := logService.LoadSystemLog(req.Name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
+2 -2
View File
@@ -53,7 +53,7 @@ func (b *BaseApi) GetNginxConfigByScope(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /openResty/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新 nginx 配置 [domain]","formatEN":"Update nginx conf [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新 nginx 配置 [domain]","formatEN":"Update nginx conf [domain]"}
func (b *BaseApi) UpdateNginxConfigByScope(c *gin.Context) {
var req request.NginxConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -90,7 +90,7 @@ func (b *BaseApi) GetNginxStatus(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /openResty/file [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 nginx 配置","formatEN":"Update nginx conf"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 nginx 配置","formatEN":"Update nginx conf"}
func (b *BaseApi) UpdateNginxFile(c *gin.Context) {
var req request.NginxConfigFileUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+1 -1
View File
@@ -25,7 +25,7 @@ func (b *BaseApi) ProcessWs(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /process/stop [post]
// @x-panel-log {"bodyKeys":["PID"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"结束进程 [PID]","formatEN":"结束进程 [PID]"}
// @x-panel-log {"bodyKeys":["PID"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"结束进程 [PID]","formatEN":"结束进程 [PID]"}
func (b *BaseApi) StopProcess(c *gin.Context) {
var req request.ProcessReq
if err := c.ShouldBindJSON(&req); err != nil {
+93 -12
View File
@@ -18,8 +18,7 @@ import (
// @Router /runtimes/search [post]
func (b *BaseApi) SearchRuntimes(c *gin.Context) {
var req request.RuntimeSearch
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
total, items, err := runtimeService.Page(req)
@@ -41,11 +40,10 @@ func (b *BaseApi) SearchRuntimes(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建运行环境 [name]","formatEN":"Create runtime [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建运行环境 [name]","formatEN":"Create runtime [name]"}
func (b *BaseApi) CreateRuntime(c *gin.Context) {
var req request.RuntimeCreate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := runtimeService.Create(req); err != nil {
@@ -63,14 +61,13 @@ func (b *BaseApi) CreateRuntime(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除网站 [name]","formatEN":"Delete website [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除网站 [name]","formatEN":"Delete website [name]"}
func (b *BaseApi) DeleteRuntime(c *gin.Context) {
var req request.RuntimeDelete
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
err := runtimeService.Delete(req.ID)
err := runtimeService.Delete(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -86,11 +83,10 @@ func (b *BaseApi) DeleteRuntime(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新运行环境 [name]","formatEN":"Update runtime [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新运行环境 [name]","formatEN":"Update runtime [name]"}
func (b *BaseApi) UpdateRuntime(c *gin.Context) {
var req request.RuntimeUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := runtimeService.Update(req); err != nil {
@@ -121,3 +117,88 @@ func (b *BaseApi) GetRuntime(c *gin.Context) {
}
helper.SuccessWithData(c, res)
}
// @Tags Runtime
// @Summary Get Node package scripts
// @Description 获取 Node 项目的 scripts
// @Accept json
// @Param request body request.NodePackageReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/node/package [post]
func (b *BaseApi) GetNodePackageRunScript(c *gin.Context) {
var req request.NodePackageReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
res, err := runtimeService.GetNodePackageRunScript(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Runtime
// @Summary Operate runtime
// @Description 操作运行环境
// @Accept json
// @Param request body request.RuntimeOperate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/operate [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"操作运行环境 [name]","formatEN":"Operate runtime [name]"}
func (b *BaseApi) OperateRuntime(c *gin.Context) {
var req request.RuntimeOperate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
err := runtimeService.OperateRuntime(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Runtime
// @Summary Get Node modules
// @Description 获取 Node 项目的 modules
// @Accept json
// @Param request body request.NodeModuleReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/node/modules [post]
func (b *BaseApi) GetNodeModules(c *gin.Context) {
var req request.NodeModuleReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
res, err := runtimeService.GetNodeModules(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Runtime
// @Summary Operate Node modules
// @Description 操作 Node 项目 modules
// @Accept json
// @Param request body request.NodeModuleReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/node/modules/operate [post]
func (b *BaseApi) OperateNodeModules(c *gin.Context) {
var req request.NodeModuleOperateReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
err := runtimeService.OperateNodeModules(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
+48 -23
View File
@@ -2,10 +2,8 @@ package v1
import (
"errors"
"fmt"
"os"
"path"
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -48,7 +46,7 @@ func (b *BaseApi) GetSystemAvailable(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/update [post]
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统配置 [key] => [value]","formatEN":"update system setting [key] => [value]"}
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改系统配置 [key] => [value]","formatEN":"update system setting [key] => [value]"}
func (b *BaseApi) UpdateSetting(c *gin.Context) {
var req dto.SettingUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -75,7 +73,7 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/password/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统密码","formatEN":"update system password"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改系统密码","formatEN":"update system password"}
func (b *BaseApi) UpdatePassword(c *gin.Context) {
var req dto.PasswordUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -102,7 +100,7 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/ssl/update [post]
// @x-panel-log {"bodyKeys":["ssl"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
// @x-panel-log {"bodyKeys":["ssl"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
func (b *BaseApi) UpdateSSL(c *gin.Context) {
var req dto.SSLUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -160,7 +158,7 @@ func (b *BaseApi) DownloadSSL(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/port/update [post]
// @x-panel-log {"bodyKeys":["serverPort"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统端口 => [serverPort]","formatEN":"update system port => [serverPort]"}
// @x-panel-log {"bodyKeys":["serverPort"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改系统端口 => [serverPort]","formatEN":"update system port => [serverPort]"}
func (b *BaseApi) UpdatePort(c *gin.Context) {
var req dto.PortUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -187,7 +185,7 @@ func (b *BaseApi) UpdatePort(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/expired/handle [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"重置过期密码","formatEN":"reset an expired Password"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"重置过期密码","formatEN":"reset an expired Password"}
func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
var req dto.PasswordUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -229,7 +227,7 @@ func (b *BaseApi) LoadTimeZone(c *gin.Context) {
// @Success 200 {string} ntime
// @Security ApiKeyAuth
// @Router /settings/time/sync [post]
// @x-panel-log {"bodyKeys":["ntpSite"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步[ntpSite]","formatEN":"sync system time [ntpSite]"}
// @x-panel-log {"bodyKeys":["ntpSite"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"系统时间同步[ntpSite]","formatEN":"sync system time [ntpSite]"}
func (b *BaseApi) SyncTime(c *gin.Context) {
var req dto.SyncTime
if err := c.ShouldBindJSON(&req); err != nil {
@@ -259,7 +257,7 @@ func (b *BaseApi) LoadBaseDir(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/monitor/clean [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清空监控数据","formatEN":"clean monitor datas"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清空监控数据","formatEN":"clean monitor datas"}
func (b *BaseApi) CleanMonitor(c *gin.Context) {
if err := global.DB.Exec("DELETE FROM monitor_bases").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -278,25 +276,52 @@ func (b *BaseApi) CleanMonitor(c *gin.Context) {
}
// @Tags System Setting
// @Summary Load mfa info
// @Description 获取 mfa 信息
// @Param interval path string true "request"
// @Success 200 {object} mfa.Otp
// @Summary Scan system
// @Description 扫描系统垃圾文件
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/mfa/:interval [get]
func (b *BaseApi) GetMFA(c *gin.Context) {
intervalStr, ok := c.Params.Get("interval")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error interval in path"))
// @Router /settings/scan [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"扫描系统垃圾文件","formatEN":"scan System Junk Files"}
func (b *BaseApi) ScanSystem(c *gin.Context) {
helper.SuccessWithData(c, settingService.SystemScan())
}
// @Tags System Setting
// @Summary System clean
// @Description 清理系统垃圾文件
// @Accept json
// @Param request body []dto.Clean true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/clean [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清理系统垃圾文件","formatEN":"Clean system junk files"}
func (b *BaseApi) SystemClean(c *gin.Context) {
var req []dto.Clean
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
interval, err := strconv.Atoi(intervalStr)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("type conversion failed, err: %v", err))
settingService.SystemClean(req)
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Load mfa info
// @Description 获取 mfa 信息
// @Accept json
// @Param request body dto.MfaCredential true "request"
// @Success 200 {object} mfa.Otp
// @Security ApiKeyAuth
// @Router /settings/mfa [post]
func (b *BaseApi) LoadMFA(c *gin.Context) {
var req dto.MfaRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
otp, err := mfa.GetOtp("admin", interval)
otp, err := mfa.GetOtp("admin", req.Title, req.Interval)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -313,7 +338,7 @@ func (b *BaseApi) GetMFA(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/mfa/bind [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"mfa 绑定","formatEN":"bind mfa"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"mfa 绑定","formatEN":"bind mfa"}
func (b *BaseApi) MFABind(c *gin.Context) {
var req dto.MfaCredential
if err := c.ShouldBindJSON(&req); err != nil {
+6 -6
View File
@@ -16,7 +16,7 @@ import (
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot [post]
// @x-panel-log {"bodyKeys":["from", "description"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建系统快照 [description] 到 [from]","formatEN":"Create system backup [description] to [from]"}
// @x-panel-log {"bodyKeys":["from", "description"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建系统快照 [description] 到 [from]","formatEN":"Create system backup [description] to [from]"}
func (b *BaseApi) CreateSnapshot(c *gin.Context) {
var req dto.SnapshotCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -42,7 +42,7 @@ func (b *BaseApi) CreateSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/import [post]
// @x-panel-log {"bodyKeys":["from", "names"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"从 [from] 同步系统快照 [names]","formatEN":"Sync system snapshots [names] from [from]"}
// @x-panel-log {"bodyKeys":["from", "names"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"从 [from] 同步系统快照 [names]","formatEN":"Sync system snapshots [names] from [from]"}
func (b *BaseApi) ImportSnapshot(c *gin.Context) {
var req dto.SnapshotImport
if err := c.ShouldBindJSON(&req); err != nil {
@@ -94,7 +94,7 @@ func (b *BaseApi) LoadSnapShotStatus(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/description/update [post]
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"快照 [name] 描述信息修改 [description]","formatEN":"The description of the snapshot [name] is modified => [description]"}
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"快照 [name] 描述信息修改 [description]","formatEN":"The description of the snapshot [name] is modified => [description]"}
func (b *BaseApi) UpdateSnapDescription(c *gin.Context) {
var req dto.UpdateDescription
if err := c.ShouldBindJSON(&req); err != nil {
@@ -145,7 +145,7 @@ func (b *BaseApi) SearchSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/recover [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 恢复","formatEN":"Recover from system backup [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 恢复","formatEN":"Recover from system backup [name]"}
func (b *BaseApi) RecoverSnapshot(c *gin.Context) {
var req dto.SnapshotRecover
if err := c.ShouldBindJSON(&req); err != nil {
@@ -172,7 +172,7 @@ func (b *BaseApi) RecoverSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/rollback [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 回滚","formatEN":"Rollback from system backup [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 回滚","formatEN":"Rollback from system backup [name]"}
func (b *BaseApi) RollbackSnapshot(c *gin.Context) {
var req dto.SnapshotRecover
if err := c.ShouldBindJSON(&req); err != nil {
@@ -199,7 +199,7 @@ func (b *BaseApi) RollbackSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"删除系统快照 [name]","formatEN":"Delete system backup [name]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"删除系统快照 [name]","formatEN":"Delete system backup [name]"}
func (b *BaseApi) DeleteSnapshot(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
+44 -17
View File
@@ -9,7 +9,7 @@ import (
)
// @Tags SSH
// @Summary Load host ssh setting info
// @Summary Load host SSH setting info
// @Description 加载 SSH 配置信息
// @Success 200 {object} dto.SSHInfo
// @Security ApiKeyAuth
@@ -24,13 +24,13 @@ func (b *BaseApi) GetSSHInfo(c *gin.Context) {
}
// @Tags SSH
// @Summary Operate ssh
// @Summary Operate SSH
// @Description 修改 SSH 服务状态
// @Accept json
// @Param request body dto.Operate true "request"
// @Security ApiKeyAuth
// @Router /host/ssh/operate [post]
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"}
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"}
func (b *BaseApi) OperateSSH(c *gin.Context) {
var req dto.Operate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -50,14 +50,14 @@ func (b *BaseApi) OperateSSH(c *gin.Context) {
}
// @Tags SSH
// @Summary Update host ssh setting
// @Summary Update host SSH setting
// @Description 更新 SSH 配置
// @Accept json
// @Param request body dto.SettingUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/update [post]
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"}
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"}
func (b *BaseApi) UpdateSSH(c *gin.Context) {
var req dto.SettingUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -77,14 +77,14 @@ func (b *BaseApi) UpdateSSH(c *gin.Context) {
}
// @Tags SSH
// @Summary Update host ssh setting by file
// @Summary Update host SSH setting by file
// @Description 上传文件更新 SSH 配置
// @Accept json
// @Param request body dto.SSHConf true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
var req dto.SSHConf
if err := c.ShouldBindJSON(&req); err != nil {
@@ -104,14 +104,14 @@ func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
}
// @Tags SSH
// @Summary Generate host ssh secret
// @Description 生成 ssh 密钥
// @Summary Generate host SSH secret
// @Description 生成 SSH 密钥
// @Accept json
// @Param request body dto.GenerateSSH true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/generate [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
func (b *BaseApi) GenerateSSH(c *gin.Context) {
var req dto.GenerateSSH
if err := c.ShouldBindJSON(&req); err != nil {
@@ -131,8 +131,8 @@ func (b *BaseApi) GenerateSSH(c *gin.Context) {
}
// @Tags SSH
// @Summary Load host ssh secret
// @Description 获取 ssh 密钥
// @Summary Load host SSH secret
// @Description 获取 SSH 密钥
// @Accept json
// @Param request body dto.GenerateLoad true "request"
// @Success 200
@@ -158,13 +158,40 @@ func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
}
// @Tags SSH
// @Summary Load host ssh logs
// @Description 获取 ssh 登录日志
// @Summary Analysis host SSH logs
// @Description 分析 SSH 登录日志
// @Accept json
// @Param request body dto.SearchForAnalysis true "request"
// @Success 200 {array} dto.SSHLogAnalysis
// @Security ApiKeyAuth
// @Router /host/ssh/log/analysis [post]
func (b *BaseApi) AnalysisLog(c *gin.Context) {
var req dto.SearchForAnalysis
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := sshService.AnalysisLog(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags SSH
// @Summary Load host SSH logs
// @Description 获取 SSH 登录日志
// @Accept json
// @Param request body dto.SearchSSHLog true "request"
// @Success 200 {object} dto.SSHLog
// @Security ApiKeyAuth
// @Router /host/ssh/logs [post]
// @Router /host/ssh/log [post]
func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
var req dto.SearchSSHLog
if err := c.ShouldBindJSON(&req); err != nil {
@@ -185,8 +212,8 @@ func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
}
// @Tags SSH
// @Summary Load host ssh conf
// @Description 获取 ssh 配置文件
// @Summary Load host SSH conf
// @Description 获取 SSH 配置文件
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/conf [get]
+1 -1
View File
@@ -52,7 +52,7 @@ func (b *BaseApi) GetNotesByVersion(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/upgrade [post]
// @x-panel-log {"bodyKeys":["version"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新系统 => [version]","formatEN":"upgrade service => [version]"}
// @x-panel-log {"bodyKeys":["version"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新系统 => [version]","formatEN":"upgrade service => [version]"}
func (b *BaseApi) Upgrade(c *gin.Context) {
var req dto.Upgrade
if err := c.ShouldBindJSON(&req); err != nil {
+23 -23
View File
@@ -71,7 +71,7 @@ func (b *BaseApi) GetWebsiteOptions(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites [post]
// @x-panel-log {"bodyKeys":["primaryDomain"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建网站 [primaryDomain]","formatEN":"Create website [primaryDomain]"}
// @x-panel-log {"bodyKeys":["primaryDomain"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建网站 [primaryDomain]","formatEN":"Create website [primaryDomain]"}
func (b *BaseApi) CreateWebsite(c *gin.Context) {
var req request.WebsiteCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -95,7 +95,7 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/operate [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[operate] 网站 [domain]","formatEN":"[operate] website [domain]"}
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[operate] 网站 [domain]","formatEN":"[operate] website [domain]"}
func (b *BaseApi) OpWebsite(c *gin.Context) {
var req request.WebsiteOp
if err := c.ShouldBindJSON(&req); err != nil {
@@ -118,7 +118,7 @@ func (b *BaseApi) OpWebsite(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain]","formatEN":"Delete website [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain]","formatEN":"Delete website [domain]"}
func (b *BaseApi) DeleteWebsite(c *gin.Context) {
var req request.WebsiteDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -142,7 +142,7 @@ func (b *BaseApi) DeleteWebsite(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/update [post]
// @x-panel-log {"bodyKeys":["primaryDomain"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新网站 [primaryDomain]","formatEN":"Update website [primaryDomain]"}
// @x-panel-log {"bodyKeys":["primaryDomain"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新网站 [primaryDomain]","formatEN":"Update website [primaryDomain]"}
func (b *BaseApi) UpdateWebsite(c *gin.Context) {
var req request.WebsiteUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -232,7 +232,7 @@ func (b *BaseApi) GetWebDomains(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/domains/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_domains","output_column":"domain","output_value":"domain"}],"formatZH":"删除域名 [domain]","formatEN":"Delete domain [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_domains","output_column":"domain","output_value":"domain"}],"formatZH":"删除域名 [domain]","formatEN":"Delete domain [domain]"}
func (b *BaseApi) DeleteWebDomain(c *gin.Context) {
var req request.WebsiteDomainDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -255,7 +255,7 @@ func (b *BaseApi) DeleteWebDomain(c *gin.Context) {
// @Success 200 {object} model.WebsiteDomain
// @Security ApiKeyAuth
// @Router /websites/domains [post]
// @x-panel-log {"bodyKeys":["domain"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建域名 [domain]","formatEN":"Create domain [domain]"}
// @x-panel-log {"bodyKeys":["domain"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建域名 [domain]","formatEN":"Create domain [domain]"}
func (b *BaseApi) CreateWebDomain(c *gin.Context) {
var req request.WebsiteDomainCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -300,7 +300,7 @@ func (b *BaseApi) GetNginxConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/config/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"nginx 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"nginx 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
func (b *BaseApi) UpdateNginxConfig(c *gin.Context) {
var req request.NginxConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -344,7 +344,7 @@ func (b *BaseApi) GetHTTPSConfig(c *gin.Context) {
// @Success 200 {object} response.WebsiteHTTPS
// @Security ApiKeyAuth
// @Router /websites/:id/https [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"}
func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) {
var req request.WebsiteHTTPSOp
if err := c.ShouldBindJSON(&req); err != nil {
@@ -414,7 +414,7 @@ func (b *BaseApi) GetWebsiteWafConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"}
func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -436,7 +436,7 @@ func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/file/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置文件修改 [domain]","formatEN":"WAF conf file update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置文件修改 [domain]","formatEN":"WAF conf file update [domain]"}
func (b *BaseApi) UpdateWebsiteWafFile(c *gin.Context) {
var req request.WebsiteWafFileUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -458,7 +458,7 @@ func (b *BaseApi) UpdateWebsiteWafFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/nginx/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] Nginx 配置修改","formatEN":"[domain] Nginx conf update"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] Nginx 配置修改","formatEN":"[domain] Nginx conf update"}
func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) {
var req request.WebsiteNginxUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -480,7 +480,7 @@ func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) {
// @Success 200 {object} response.WebsiteLog
// @Security ApiKeyAuth
// @Router /websites/log [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain][operate] 日志","formatEN":"[domain][operate] logs"}
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain][operate] 日志","formatEN":"[domain][operate] logs"}
func (b *BaseApi) OpWebsiteLog(c *gin.Context) {
var req request.WebsiteLogReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -503,7 +503,7 @@ func (b *BaseApi) OpWebsiteLog(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/default/server [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改默认 server => [domain]","formatEN":"Change default server => [domain]"}
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改默认 server => [domain]","formatEN":"Change default server => [domain]"}
func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
var req request.WebsiteDefaultUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -547,7 +547,7 @@ func (b *BaseApi) GetWebsitePHPConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/php/config [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] PHP 配置修改","formatEN":"[domain] PHP conf update"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] PHP 配置修改","formatEN":"[domain] PHP conf update"}
func (b *BaseApi) UpdateWebsitePHPConfig(c *gin.Context) {
var req request.WebsitePHPConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -569,7 +569,7 @@ func (b *BaseApi) UpdateWebsitePHPConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/php/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
var req request.WebsitePHPFileUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -591,7 +591,7 @@ func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/php/version [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 版本变更 [domain]","formatEN":"php version update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 版本变更 [domain]","formatEN":"php version update [domain]"}
func (b *BaseApi) ChangePHPVersion(c *gin.Context) {
var req request.WebsitePHPVersionReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -635,7 +635,7 @@ func (b *BaseApi) GetRewriteConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/rewrite/update [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"伪静态配置修改 [domain]","formatEN":"Nginx conf rewrite update [domain]"}
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"伪静态配置修改 [domain]","formatEN":"Nginx conf rewrite update [domain]"}
func (b *BaseApi) UpdateRewriteConfig(c *gin.Context) {
var req request.NginxRewriteUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -657,7 +657,7 @@ func (b *BaseApi) UpdateRewriteConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dir/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录","formatEN":"Update domain [domain] dir"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录","formatEN":"Update domain [domain] dir"}
func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
var req request.WebsiteUpdateDir
if err := c.ShouldBindJSON(&req); err != nil {
@@ -679,7 +679,7 @@ func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dir/permission [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录权限","formatEN":"Update domain [domain] dir permission"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录权限","formatEN":"Update domain [domain] dir permission"}
func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
var req request.WebsiteUpdateDirPermission
if err := c.ShouldBindJSON(&req); err != nil {
@@ -723,7 +723,7 @@ func (b *BaseApi) GetProxyConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxies/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 反向代理配置 ","formatEN":"Update domain [domain] proxy config"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 反向代理配置 ","formatEN":"Update domain [domain] proxy config"}
func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
var req request.WebsiteProxyConfig
if err := c.ShouldBindJSON(&req); err != nil {
@@ -746,7 +746,7 @@ func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxy/file [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新反向代理文件 [domain]","formatEN":"Nginx conf proxy file update [domain]"}
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新反向代理文件 [domain]","formatEN":"Nginx conf proxy file update [domain]"}
func (b *BaseApi) UpdateProxyConfigFile(c *gin.Context) {
var req request.NginxProxyUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -854,7 +854,7 @@ func (b *BaseApi) UpdateAntiLeech(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/redirect/update [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 重定向理配置 ","formatEN":"Update domain [domain] redirect config"}
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 重定向理配置 ","formatEN":"Update domain [domain] redirect config"}
func (b *BaseApi) UpdateRedirectConfig(c *gin.Context) {
var req request.NginxRedirectReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -899,7 +899,7 @@ func (b *BaseApi) GetRedirectConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/redirect/file [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新重定向文件 [domain]","formatEN":"Nginx conf redirect file update [domain]"}
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新重定向文件 [domain]","formatEN":"Nginx conf redirect file update [domain]"}
func (b *BaseApi) UpdateRedirectConfigFile(c *gin.Context) {
var req request.NginxRedirectUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+2 -2
View File
@@ -41,7 +41,7 @@ func (b *BaseApi) PageWebsiteAcmeAccount(c *gin.Context) {
// @Success 200 {object} response.WebsiteAcmeAccountDTO
// @Security ApiKeyAuth
// @Router /websites/acme [post]
// @x-panel-log {"bodyKeys":["email"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建网站 acme [email]","formatEN":"Create website acme [email]"}
// @x-panel-log {"bodyKeys":["email"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建网站 acme [email]","formatEN":"Create website acme [email]"}
func (b *BaseApi) CreateWebsiteAcmeAccount(c *gin.Context) {
var req request.WebsiteAcmeAccountCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -64,7 +64,7 @@ func (b *BaseApi) CreateWebsiteAcmeAccount(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/acme/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_acme_accounts","output_column":"email","output_value":"email"}],"formatZH":"删除网站 acme [email]","formatEN":"Delete website acme [email]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_acme_accounts","output_column":"email","output_value":"email"}],"formatZH":"删除网站 acme [email]","formatEN":"Delete website acme [email]"}
func (b *BaseApi) DeleteWebsiteAcmeAccount(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -41,7 +41,7 @@ func (b *BaseApi) PageWebsiteDnsAccount(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dns [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建网站 dns [name]","formatEN":"Create website dns [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建网站 dns [name]","formatEN":"Create website dns [name]"}
func (b *BaseApi) CreateWebsiteDnsAccount(c *gin.Context) {
var req request.WebsiteDnsAccountCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -63,7 +63,7 @@ func (b *BaseApi) CreateWebsiteDnsAccount(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dns/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新网站 dns [name]","formatEN":"Update website dns [name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新网站 dns [name]","formatEN":"Update website dns [name]"}
func (b *BaseApi) UpdateWebsiteDnsAccount(c *gin.Context) {
var req request.WebsiteDnsAccountUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -85,7 +85,7 @@ func (b *BaseApi) UpdateWebsiteDnsAccount(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dns/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_dns_accounts","output_column":"name","output_value":"name"}],"formatZH":"删除网站 dns [name]","formatEN":"Delete website dns [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_dns_accounts","output_column":"name","output_value":"name"}],"formatZH":"删除网站 dns [name]","formatEN":"Delete website dns [name]"}
func (b *BaseApi) DeleteWebsiteDnsAccount(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {
+4 -4
View File
@@ -52,7 +52,7 @@ func (b *BaseApi) PageWebsiteSSL(c *gin.Context) {
// @Success 200 {object} request.WebsiteSSLCreate
// @Security ApiKeyAuth
// @Router /websites/ssl [post]
// @x-panel-log {"bodyKeys":["primaryDomain"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建网站 ssl [primaryDomain]","formatEN":"Create website ssl [primaryDomain]"}
// @x-panel-log {"bodyKeys":["primaryDomain"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建网站 ssl [primaryDomain]","formatEN":"Create website ssl [primaryDomain]"}
func (b *BaseApi) CreateWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLCreate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -75,7 +75,7 @@ func (b *BaseApi) CreateWebsiteSSL(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ssl/renew [post]
// @x-panel-log {"bodyKeys":["SSLId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"SSLId","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"重置 ssl [domain]","formatEN":"Renew ssl [domain]"}
// @x-panel-log {"bodyKeys":["SSLId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"SSLId","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"重置 ssl [domain]","formatEN":"Renew ssl [domain]"}
func (b *BaseApi) RenewWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLRenew
if err := c.ShouldBindJSON(&req); err != nil {
@@ -119,7 +119,7 @@ func (b *BaseApi) GetDNSResolve(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ssl/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"}
func (b *BaseApi) DeleteWebsiteSSL(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -185,7 +185,7 @@ func (b *BaseApi) GetWebsiteSSLById(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ssl/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新证书设置 [domain]","formatEN":"Update ssl config [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新证书设置 [domain]","formatEN":"Update ssl config [domain]"}
func (b *BaseApi) UpdateWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+1
View File
@@ -98,6 +98,7 @@ type AppConfigVersion struct {
type Tag struct {
Key string `json:"key"`
Name string `json:"name"`
Sort int `json:"sort"`
}
type AppForm struct {
+5
View File
@@ -11,6 +11,11 @@ type UserLoginInfo struct {
MfaStatus string `json:"mfaStatus"`
}
type MfaRequest struct {
Title string `json:"title"`
Interval int `json:"interval"`
}
type MfaCredential struct {
Secret string `json:"secret"`
Code string `json:"code"`
+11 -1
View File
@@ -44,6 +44,8 @@ type ContainerOperate struct {
Network string `json:"network"`
PublishAllPorts bool `json:"publishAllPorts"`
ExposedPorts []PortHelper `json:"exposedPorts"`
Tty bool `json:"tty"`
OpenStdin bool `json:"openStdin"`
Cmd []string `json:"cmd"`
Entrypoint []string `json:"entrypoint"`
CPUShares int64 `json:"cpuShares"`
@@ -63,8 +65,16 @@ type ContainerUpgrade struct {
}
type ContainerListStats struct {
ContainerID string `json:"containerID"`
ContainerID string `json:"containerID"`
CPUTotalUsage uint64 `json:"cpuTotalUsage"`
SystemUsage uint64 `json:"systemUsage"`
CPUPercent float64 `json:"cpuPercent"`
PercpuUsage int `json:"percpuUsage"`
MemoryCache uint64 `json:"memoryCache"`
MemoryUsage uint64 `json:"memoryUsage"`
MemoryLimit uint64 `json:"memoryLimit"`
MemoryPercent float64 `json:"memoryPercent"`
}
+4 -4
View File
@@ -3,10 +3,10 @@ package dto
import "time"
type DashboardBase struct {
WebsiteNumber int `json:"websiteNumber"`
DatabaseNumber int `json:"databaseNumber"`
CronjobNumber int `json:"cronjobNumber"`
AppInstalldNumber int `json:"appInstalldNumber"`
WebsiteNumber int `json:"websiteNumber"`
DatabaseNumber int `json:"databaseNumber"`
CronjobNumber int `json:"cronjobNumber"`
AppInstalledNumber int `json:"appInstalledNumber"`
Hostname string `json:"hostname"`
OS string `json:"os"`
+6
View File
@@ -271,3 +271,9 @@ type DatabaseUpdate struct {
Password string `json:"password" validate:"required"`
Description string `json:"description"`
}
type DatabaseDelete struct {
ID uint `json:"id" validate:"required"`
ForceDelete bool `json:"forceDelete"`
DeleteBackup bool `json:"deleteBackup"`
}
+1
View File
@@ -5,6 +5,7 @@ import "time"
type ImageInfo struct {
ID string `json:"id"`
CreatedAt time.Time `json:"createdAt"`
IsUsed bool `json:"isUsed"`
Tags []string `json:"tags"`
Size string `json:"size"`
}
+1
View File
@@ -11,6 +11,7 @@ type AppSearch struct {
Tags []string `json:"tags"`
Type string `json:"type"`
Recommend bool `json:"recommend"`
Resource string `json:"resource"`
}
type AppInstallCreate struct {
+34 -1
View File
@@ -17,10 +17,20 @@ type RuntimeCreate struct {
Image string `json:"image"`
Type string `json:"type"`
Version string `json:"version"`
Source string `json:"source"`
CodeDir string `json:"codeDir"`
NodeConfig
}
type NodeConfig struct {
Install bool `json:"install"`
Clean bool `json:"clean"`
Port int `json:"port"`
}
type RuntimeDelete struct {
ID uint `json:"id"`
ID uint `json:"id"`
ForceDelete bool `json:"forceDelete"`
}
type RuntimeUpdate struct {
@@ -30,4 +40,27 @@ type RuntimeUpdate struct {
Image string `json:"image"`
Version string `json:"version"`
Rebuild bool `json:"rebuild"`
Source string `json:"source"`
CodeDir string `json:"codeDir"`
NodeConfig
}
type NodePackageReq struct {
CodeDir string `json:"codeDir"`
}
type RuntimeOperate struct {
Operate string `json:"operate"`
ID uint `json:"ID"`
}
type NodeModuleOperateReq struct {
Operate string `json:"operate" validate:"oneof=install uninstall update"`
ID uint `json:"ID" validate:"required"`
Module string `json:"module"`
PkgManager string `json:"pkgManager" validate:"oneof=npm yarn"`
}
type NodeModuleReq struct {
ID uint `json:"ID" validate:"required"`
}
+5 -2
View File
@@ -1,6 +1,7 @@
package response
import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"time"
@@ -13,8 +14,9 @@ type AppRes struct {
}
type AppUpdateRes struct {
CanUpdate bool `json:"canUpdate"`
AppStoreLastModified int `json:"appStoreLastModified"`
CanUpdate bool `json:"canUpdate"`
AppStoreLastModified int `json:"appStoreLastModified"`
AppList *dto.AppList `json:"appList"`
}
type AppDTO struct {
@@ -77,6 +79,7 @@ type AppService struct {
Label string `json:"label"`
Value string `json:"value"`
Config interface{} `json:"config"`
From string `json:"from"`
}
type AppParam struct {
+52 -5
View File
@@ -1,9 +1,56 @@
package response
import "github.com/1Panel-dev/1Panel/backend/app/model"
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"time"
)
type RuntimeRes struct {
model.Runtime
AppParams []AppParam `json:"appParams"`
AppID uint `json:"appId"`
type RuntimeDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Resource string `json:"resource"`
AppDetailID uint `json:"appDetailID"`
AppID uint `json:"appID"`
Source string `json:"source"`
Status string `json:"status"`
Type string `json:"type"`
Image string `json:"image"`
Params map[string]interface{} `json:"params"`
Message string `json:"message"`
Version string `json:"version"`
CreatedAt time.Time `json:"createdAt"`
CodeDir string `json:"codeDir"`
AppParams []AppParam `json:"appParams"`
Port int `json:"port"`
Path string `json:"path"`
}
type PackageScripts struct {
Name string `json:"name"`
Script string `json:"script"`
}
func NewRuntimeDTO(runtime model.Runtime) RuntimeDTO {
return RuntimeDTO{
ID: runtime.ID,
Name: runtime.Name,
Resource: runtime.Resource,
AppDetailID: runtime.AppDetailID,
Status: runtime.Status,
Type: runtime.Type,
Image: runtime.Image,
Message: runtime.Message,
CreatedAt: runtime.CreatedAt,
CodeDir: runtime.CodeDir,
Version: runtime.Version,
Port: runtime.Port,
Path: runtime.GetPath(),
}
}
type NodeModule struct {
Name string `json:"name"`
Version string `json:"version"`
License string `json:"license"`
Description string `json:"description"`
}
+34 -4
View File
@@ -13,10 +13,14 @@ type SettingInfo struct {
TimeZone string `json:"timeZone"`
NtpSite string `json:"ntpSite"`
Port string `json:"port"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
Language string `json:"language"`
Port string `json:"port"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
Language string `json:"language"`
DefaultNetwork string `json:"defaultNetwork"`
LastCleanTime string `json:"lastCleanTime"`
LastCleanSize string `json:"lastCleanSize"`
LastCleanData string `json:"lastCleanData"`
ServerPort string `json:"serverPort"`
SSL string `json:"ssl"`
@@ -135,3 +139,29 @@ type SyncTime struct {
type Upgrade struct {
Version string `json:"version"`
}
type CleanData struct {
SystemClean []CleanTree `json:"systemClean"`
UploadClean []CleanTree `json:"uploadClean"`
DownloadClean []CleanTree `json:"downloadClean"`
SystemLogClean []CleanTree `json:"systemLogClean"`
}
type CleanTree struct {
ID string `json:"id"`
Label string `json:"label"`
Children []CleanTree `json:"children"`
Type string `json:"type"`
Name string `json:"name"`
Size uint64 `json:"size"`
IsCheck bool `json:"isCheck"`
IsRecommend bool `json:"isRecommend"`
}
type Clean struct {
TreeType string `json:"treeType"`
Name string `json:"name"`
Size uint64 `json:"size"`
}
+21
View File
@@ -36,6 +36,27 @@ type SSHLog struct {
SuccessfulCount int `json:"successfulCount"`
FailedCount int `json:"failedCount"`
}
type SearchForAnalysis struct {
PageInfo
OrderBy string `json:"orderBy" validate:"required,oneof=Success Failed"`
}
type AnalysisRes struct {
Total int64 `json:"total"`
Items []SSHLogAnalysis `json:"items"`
SuccessfulCount int `json:"successfulCount"`
FailedCount int `json:"failedCount"`
}
type SSHLogAnalysis struct {
Address string `json:"address"`
Area string `json:"area"`
SuccessfulCount int `json:"successfulCount"`
FailedCount int `json:"failedCount"`
Status string `json:"status"`
}
type SSHHistory struct {
Date time.Time `json:"date"`
DateStr string `json:"dateStr"`
+23
View File
@@ -1,5 +1,10 @@
package model
import (
"github.com/1Panel-dev/1Panel/backend/constant"
"path"
)
type Runtime struct {
BaseModel
Name string `gorm:"type:varchar;not null" json:"name"`
@@ -13,5 +18,23 @@ type Runtime struct {
Type string `gorm:"type:varchar;not null" json:"type"`
Status string `gorm:"type:varchar;not null" json:"status"`
Resource string `gorm:"type:varchar;not null" json:"resource"`
Port int `gorm:"type:integer;" json:"port"`
Message string `gorm:"type:longtext;" json:"message"`
CodeDir string `gorm:"type:varchar;" json:"codeDir"`
}
func (r *Runtime) GetComposePath() string {
return path.Join(r.GetPath(), "docker-compose.yml")
}
func (r *Runtime) GetEnvPath() string {
return path.Join(r.GetPath(), ".env")
}
func (r *Runtime) GetPath() string {
return path.Join(constant.RuntimeDir, r.Type, r.Name)
}
func (r *Runtime) GetLogPath() string {
return path.Join(r.GetPath(), "build.log")
}
+1
View File
@@ -4,4 +4,5 @@ type Tag struct {
BaseModel
Key string `json:"key" gorm:"type:varchar(64);not null"`
Name string `json:"name" gorm:"type:varchar(64);not null"`
Sort int `json:"sort" gorm:"type:int;not null;default:1"`
}
+7
View File
@@ -24,6 +24,7 @@ type ICommonRepo interface {
WithByDate(startTime, endTime time.Time) DBOption
WithByStartDate(startTime time.Time) DBOption
WithByStatus(status string) DBOption
WithByFrom(from string) DBOption
}
type CommonRepo struct{}
@@ -80,6 +81,12 @@ func (c *CommonRepo) WithByStatus(status string) DBOption {
}
}
func (c *CommonRepo) WithByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`from` = ?", from)
}
}
func (c *CommonRepo) WithLikeName(name string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(name) == 0 {
+7
View File
@@ -22,6 +22,7 @@ type ICronjobRepo interface {
WithByJobID(id int) DBOption
WithByBackupID(id uint) DBOption
WithByRecordDropID(id int) DBOption
WithByRecordFile(file string) DBOption
Save(id uint, cronjob model.Cronjob) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
@@ -121,6 +122,12 @@ func (c *CronjobRepo) WithByBackupID(id uint) DBOption {
}
}
func (c *CronjobRepo) WithByRecordFile(file string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("records = ?", file)
}
}
func (c *CronjobRepo) WithByRecordDropID(id int) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("id < ?", id)
+7
View File
@@ -17,6 +17,7 @@ type IRuntimeRepo interface {
WithNotId(id uint) DBOption
WithStatus(status string) DBOption
WithDetailId(id uint) DBOption
WithPort(port int) DBOption
Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error)
Create(ctx context.Context, runtime *model.Runtime) error
Save(runtime *model.Runtime) error
@@ -59,6 +60,12 @@ func (r *RuntimeRepo) WithNotId(id uint) DBOption {
}
}
func (r *RuntimeRepo) WithPort(port int) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("port = ?", port)
}
}
func (r *RuntimeRepo) Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error) {
var runtimes []model.Runtime
db := getDb(opts...).Model(&model.Runtime{})
+1 -1
View File
@@ -31,7 +31,7 @@ func (t TagRepo) DeleteAll(ctx context.Context) error {
func (t TagRepo) All() ([]model.Tag, error) {
var tags []model.Tag
if err := getDb().Where("1 = 1 ").Find(&tags).Error; err != nil {
if err := getDb().Where("1 = 1 ").Order("sort asc").Find(&tags).Error; err != nil {
return nil, err
}
return tags, nil
+80 -63
View File
@@ -61,6 +61,9 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
if req.Recommend {
opts = append(opts, appRepo.GetRecommend())
}
if req.Resource != "" {
opts = append(opts, appRepo.WithResource(req.Resource))
}
if len(req.Tags) != 0 {
tags, err := tagRepo.GetByKeys(req.Tags)
if err != nil {
@@ -151,12 +154,12 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) {
return &appDTO, nil
}
func (a AppService) GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error) {
func (a AppService) GetAppDetail(appID uint, version, appType string) (response.AppDetailDTO, error) {
var (
appDetailDTO response.AppDetailDTO
opts []repo.DBOption
)
opts = append(opts, appDetailRepo.WithAppId(appId), appDetailRepo.WithVersion(version))
opts = append(opts, appDetailRepo.WithAppId(appID), appDetailRepo.WithVersion(version))
detail, err := appDetailRepo.GetFirst(opts...)
if err != nil {
return appDetailDTO, err
@@ -165,7 +168,7 @@ func (a AppService) GetAppDetail(appId uint, version, appType string) (response.
appDetailDTO.Enable = true
if appType == "runtime" {
app, err := appRepo.GetFirst(commonRepo.WithByID(appId))
app, err := appRepo.GetFirst(commonRepo.WithByID(appID))
if err != nil {
return appDetailDTO, err
}
@@ -176,36 +179,39 @@ func (a AppService) GetAppDetail(appId uint, version, appType string) (response.
return appDetailDTO, err
}
}
buildPath := path.Join(versionPath, "build")
paramsPath := path.Join(buildPath, "config.json")
if !fileOp.Stat(paramsPath) {
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
}
param, err := fileOp.GetContent(paramsPath)
if err != nil {
return appDetailDTO, err
}
paramMap := make(map[string]interface{})
if err := json.Unmarshal(param, &paramMap); err != nil {
return appDetailDTO, err
}
appDetailDTO.Params = paramMap
composePath := path.Join(buildPath, "docker-compose.yml")
if !fileOp.Stat(composePath) {
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
}
compose, err := fileOp.GetContent(composePath)
if err != nil {
return appDetailDTO, err
}
composeMap := make(map[string]interface{})
if err := yaml.Unmarshal(compose, &composeMap); err != nil {
return appDetailDTO, err
}
if service, ok := composeMap["services"]; ok {
servicesMap := service.(map[string]interface{})
for k := range servicesMap {
appDetailDTO.Image = k
switch app.Type {
case constant.RuntimePHP:
buildPath := path.Join(versionPath, "build")
paramsPath := path.Join(buildPath, "config.json")
if !fileOp.Stat(paramsPath) {
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
}
param, err := fileOp.GetContent(paramsPath)
if err != nil {
return appDetailDTO, err
}
paramMap := make(map[string]interface{})
if err := json.Unmarshal(param, &paramMap); err != nil {
return appDetailDTO, err
}
appDetailDTO.Params = paramMap
composePath := path.Join(buildPath, "docker-compose.yml")
if !fileOp.Stat(composePath) {
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
}
compose, err := fileOp.GetContent(composePath)
if err != nil {
return appDetailDTO, err
}
composeMap := make(map[string]interface{})
if err := yaml.Unmarshal(compose, &composeMap); err != nil {
return appDetailDTO, err
}
if service, ok := composeMap["services"]; ok {
servicesMap := service.(map[string]interface{})
for k := range servicesMap {
appDetailDTO.Image = k
}
}
}
} else {
@@ -267,7 +273,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
return
}
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
err = buserr.New(constant.ErrNameIsExist)
err = buserr.New(constant.ErrAppNameExist)
return
}
var (
@@ -450,11 +456,11 @@ func (a AppService) SyncAppListFromLocal() {
defer func() {
if err != nil {
global.LOG.Errorf("sync app failed %v", err)
global.LOG.Errorf("Sync local app failed %v", err)
}
}()
global.LOG.Infof("start sync local apps...")
global.LOG.Infof("Starting local application synchronization ...")
dirEntries, err = os.ReadDir(localAppDir)
if err != nil {
return
@@ -660,17 +666,14 @@ func (a AppService) SyncAppListFromLocal() {
}
}
tx.Commit()
global.LOG.Infof("sync local apps success")
global.LOG.Infof("Synchronization of local applications completed")
}
func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
res := &response.AppUpdateRes{
CanUpdate: false,
}
setting, err := NewISettingService().GetSettingInfo()
if err != nil {
return nil, err
}
versionUrl := fmt.Sprintf("%s/%s/1panel.json.version.txt", global.CONF.System.AppRepo, global.CONF.System.Mode)
versionRes, err := http2.GetHttpRes(versionUrl)
if err != nil {
@@ -682,38 +685,35 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
return nil, err
}
lastModifiedStr := string(body)
lastModified, err := strconv.Atoi(lastModifiedStr)
if err != nil {
return nil, err
}
setting, err := NewISettingService().GetSettingInfo()
if err != nil {
return nil, err
}
appStoreLastModified, _ := strconv.Atoi(setting.AppStoreLastModified)
res.AppStoreLastModified = appStoreLastModified
if setting.AppStoreLastModified == "" || lastModified != appStoreLastModified {
res.CanUpdate = true
return res, err
}
if err = getAppFromRepo(fmt.Sprintf("%s/%s/1panel.json.zip", global.CONF.System.AppRepo, global.CONF.System.Mode)); err != nil {
return nil, err
}
listFile := path.Join(constant.ResourceDir, "1panel.json")
content, err := os.ReadFile(listFile)
list, err := getAppList()
if err != nil {
return nil, err
}
list := &dto.AppList{}
if err = json.Unmarshal(content, list); err != nil {
return nil, err
return res, err
}
if list.Extra.Version != "" && setting.SystemVersion != list.Extra.Version && !common.CompareVersion(setting.SystemVersion, list.Extra.Version) {
global.LOG.Errorf("The current version is too low to synchronize with the App Store. The minimum required version is %s", list.Extra.Version)
return nil, buserr.New("ErrVersionTooLow")
}
res.AppList = list
return res, nil
}
func getAppFromRepo(downloadPath string) error {
downloadUrl := downloadPath
global.LOG.Infof("download file from %s", downloadUrl)
global.LOG.Infof("[AppStore] download file from %s", downloadUrl)
fileOp := files.NewFileOp()
packagePath := path.Join(constant.ResourceDir, path.Base(downloadUrl))
if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
@@ -728,25 +728,40 @@ func getAppFromRepo(downloadPath string) error {
return nil
}
func getAppList() (*dto.AppList, error) {
list := &dto.AppList{}
if err := getAppFromRepo(fmt.Sprintf("%s/%s/1panel.json.zip", global.CONF.System.AppRepo, global.CONF.System.Mode)); err != nil {
return nil, err
}
listFile := path.Join(constant.ResourceDir, "1panel.json")
content, err := os.ReadFile(listFile)
if err != nil {
return nil, err
}
if err = json.Unmarshal(content, list); err != nil {
return nil, err
}
return list, nil
}
func (a AppService) SyncAppListFromRemote() (err error) {
global.LOG.Infof("Starting synchronization with App Store...")
updateRes, err := a.GetAppUpdate()
if err != nil {
return err
}
if !updateRes.CanUpdate {
global.LOG.Infof("The App Store is at the latest version")
return
}
if err = getAppFromRepo(fmt.Sprintf("%s/%s/1panel.json.zip", global.CONF.System.AppRepo, global.CONF.System.Mode)); err != nil {
return err
}
listFile := path.Join(constant.ResourceDir, "1panel.json")
content, err := os.ReadFile(listFile)
if err != nil {
return err
}
list := &dto.AppList{}
if err = json.Unmarshal(content, list); err != nil {
return
if updateRes.AppList == nil {
list, err = getAppList()
if err != nil {
return
}
} else {
list = updateRes.AppList
}
if err = NewISettingService().Update("AppStoreLastModified", strconv.Itoa(list.LastModified)); err != nil {
@@ -768,6 +783,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
tags = append(tags, &model.Tag{
Key: t.Key,
Name: t.Name,
Sort: t.Sort,
})
}
oldApps, err := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
@@ -957,5 +973,6 @@ func (a AppService) SyncAppListFromRemote() (err error) {
}
}
tx.Commit()
global.LOG.Infof("Synchronization with the App Store was successful!")
return
}
+9 -6
View File
@@ -428,7 +428,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
var res []response.AppService
if DatabaseKeys[key] > 0 {
dbs, _ := databaseRepo.GetList(databaseRepo.WithByFrom("local"), commonRepo.WithByType(key))
dbs, _ := databaseRepo.GetList(commonRepo.WithByType(key))
if len(dbs) == 0 {
return res, nil
}
@@ -447,6 +447,9 @@ func (a *AppInstallService) GetServices(key string) ([]response.AppService, erro
_ = json.Unmarshal([]byte(install.Param), &paramMap)
}
service.Config = paramMap
service.From = constant.AppResourceLocal
} else {
service.From = constant.AppResourceRemote
}
res = append(res, service)
}
@@ -515,7 +518,7 @@ func (a *AppInstallService) ChangeAppPort(req request.PortUpdate) error {
return nil
}
if err := updateInstallInfoInDB(req.Key, "", "port", true, strconv.FormatInt(req.Port, 10)); err != nil {
if err := updateInstallInfoInDB(req.Key, req.Name, "port", true, strconv.FormatInt(req.Port, 10)); err != nil {
return nil
}
@@ -533,9 +536,9 @@ func (a *AppInstallService) ChangeAppPort(req request.PortUpdate) error {
return nil
}
func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error) {
func (a *AppInstallService) DeleteCheck(installID uint) ([]dto.AppResource, error) {
var res []dto.AppResource
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installID))
if err != nil {
return nil, err
}
@@ -559,8 +562,8 @@ func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, erro
})
}
}
if app.Type == "runtime" {
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(appInstall.ID))
if app.Type == constant.Runtime {
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(appInstall.ID), commonRepo.WithByFrom(constant.AppResourceLocal))
for _, resource := range resources {
linkInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(resource.AppInstallId))
res = append(res, dto.AppResource{
+61 -7
View File
@@ -82,6 +82,33 @@ func checkPort(key string, params map[string]interface{}) (int, error) {
return 0, nil
}
func checkPortExist(port int) error {
errMap := make(map[string]interface{})
errMap["port"] = port
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithPort(port))
if appInstall.ID > 0 {
errMap["type"] = i18n.GetMsgByKey("TYPE_APP")
errMap["name"] = appInstall.Name
return buserr.WithMap("ErrPortExist", errMap, nil)
}
runtime, _ := runtimeRepo.GetFirst(runtimeRepo.WithPort(port))
if runtime != nil {
errMap["type"] = i18n.GetMsgByKey("TYPE_RUNTIME")
errMap["name"] = runtime.Name
return buserr.WithMap("ErrPortExist", errMap, nil)
}
domain, _ := websiteDomainRepo.GetFirst(websiteDomainRepo.WithPort(port))
if domain.ID > 0 {
errMap["type"] = i18n.GetMsgByKey("TYPE_DOMAIN")
errMap["name"] = domain.Domain
return buserr.WithMap("ErrPortExist", errMap, nil)
}
if common.ScanPort(port) {
return buserr.WithDetail(constant.ErrPortInUsed, port, nil)
}
return nil
}
var DatabaseKeys = map[string]uint{
"mysql": 3306,
"mariadb": 3306,
@@ -173,9 +200,13 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
}
if !reflect.DeepEqual(dbConfig, dto.AppDatabase{}) && dbConfig.ServiceName != "" {
dbInstall, err := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(dbConfig.ServiceName))
if err != nil {
return err
hostName := params["PANEL_DB_HOST_NAME"]
if hostName == nil || hostName.(string) == "" {
return nil
}
database, _ := databaseRepo.Get(commonRepo.WithByName(hostName.(string)))
if database.ID == 0 {
return nil
}
var resourceId uint
if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" {
@@ -190,11 +221,11 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
var createMysql dto.MysqlDBCreate
createMysql.Name = dbConfig.DbName
createMysql.Username = dbConfig.DbUser
createMysql.Database = dbInstall.Name
createMysql.Database = database.Name
createMysql.Format = "utf8mb4"
createMysql.Permission = "%"
createMysql.Password = dbConfig.Password
createMysql.From = "local"
createMysql.From = database.From
mysqldb, err := NewIMysqlService().Create(ctx, createMysql)
if err != nil {
return err
@@ -205,8 +236,13 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
var installResource model.AppInstallResource
installResource.ResourceId = resourceId
installResource.AppInstallId = appInstall.ID
installResource.LinkId = dbInstall.ID
installResource.Key = dbInstall.App.Key
if database.AppInstallID > 0 {
installResource.LinkId = database.AppInstallID
} else {
installResource.LinkId = database.ID
}
installResource.Key = database.Type
installResource.From = database.From
if err := appInstallResourceRepo.Create(ctx, &installResource); err != nil {
return err
}
@@ -259,6 +295,22 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
switch install.App.Key {
case constant.AppOpenresty:
websites, _ := websiteRepo.List()
for _, website := range websites {
if website.AppInstallID > 0 {
websiteAppInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if websiteAppInstall.AppId > 0 {
websiteApp, _ := appRepo.GetFirst(commonRepo.WithByID(websiteAppInstall.AppId))
if websiteApp.Type == constant.RuntimePHP {
go func() {
_, _ = compose.Down(install.GetComposePath())
_ = op.DeleteDir(install.GetPath())
}()
_ = appInstallRepo.Delete(ctx, websiteAppInstall)
}
}
}
}
_ = websiteRepo.DeleteAll(ctx)
_ = websiteDomainRepo.DeleteAll(ctx)
case constant.AppMysql, constant.AppMariaDB:
@@ -559,6 +611,8 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
envParams[k] = strconv.FormatFloat(t, 'f', -1, 32)
case uint:
envParams[k] = strconv.Itoa(int(t))
case int:
envParams[k] = strconv.Itoa(t)
default:
envParams[k] = t.(string)
}
+22 -18
View File
@@ -173,31 +173,36 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
newEnvFile := ""
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
for _, resource := range resources {
if resource.From != "local" {
continue
}
resourceApp, err := appInstallRepo.GetFirst(commonRepo.WithByID(resource.LinkId))
if err != nil {
return err
}
if resource.Key == "mysql" || resource.Key == "mariadb" {
mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, resourceApp.Name)
var database model.Database
switch resource.From {
case constant.AppResourceRemote:
database, err = databaseRepo.Get(commonRepo.WithByID(resource.LinkId))
if err != nil {
return err
}
case constant.AppResourceLocal:
resourceApp, err := appInstallRepo.GetFirst(commonRepo.WithByID(resource.LinkId))
if err != nil {
return err
}
database, err = databaseRepo.Get(databaseRepo.WithAppInstallID(resourceApp.ID), commonRepo.WithByType(resource.Key), databaseRepo.WithByFrom(constant.AppResourceLocal), commonRepo.WithByName(resourceApp.Name))
if err != nil {
return err
}
}
if database.Type == "mysql" || database.Type == "mariadb" {
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
if err != nil {
return err
}
newDB, envMap, err := reCreateDB(db.ID, resourceApp, oldInstall.Env)
newDB, envMap, err := reCreateDB(db.ID, database, oldInstall.Env)
if err != nil {
return err
}
oldHost := fmt.Sprintf("\"PANEL_DB_HOST\":\"%v\"", envMap["PANEL_DB_HOST"].(string))
newHost := fmt.Sprintf("\"PANEL_DB_HOST\":\"%v\"", mysqlInfo.ServiceName)
newHost := fmt.Sprintf("\"PANEL_DB_HOST\":\"%v\"", database.Address)
oldInstall.Env = strings.ReplaceAll(oldInstall.Env, oldHost, newHost)
envMap["PANEL_DB_HOST"] = mysqlInfo.ServiceName
envMap["PANEL_DB_HOST"] = database.Address
newEnvFile, err = coverEnvJsonToStr(oldInstall.Env)
if err != nil {
return err
@@ -252,10 +257,10 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
return nil
}
func reCreateDB(dbID uint, app model.AppInstall, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
func reCreateDB(dbID uint, database model.Database, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
mysqlService := NewIMysqlService()
ctx := context.Background()
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, Database: app.Name, Type: app.App.Key, DeleteBackup: false, ForceDelete: true})
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, Database: database.Name, Type: database.Type, DeleteBackup: false, ForceDelete: true})
envMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(oldEnv), &envMap); err != nil {
@@ -266,8 +271,8 @@ func reCreateDB(dbID uint, app model.AppInstall, oldEnv string) (*model.Database
oldPassword, _ := envMap["PANEL_DB_USER_PASSWORD"].(string)
createDB, err := mysqlService.Create(context.Background(), dto.MysqlDBCreate{
Name: oldName,
From: "local",
Database: app.Name,
From: database.From,
Database: database.Name,
Format: "utf8mb4",
Username: oldUser,
Password: oldPassword,
@@ -276,6 +281,5 @@ func reCreateDB(dbID uint, app model.AppInstall, oldEnv string) (*model.Database
if err != nil {
return nil, envMap, err
}
return createDB, envMap, nil
}
+128
View File
@@ -0,0 +1,128 @@
package service
import (
"encoding/json"
"errors"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"io/fs"
"os"
"path"
"strings"
"time"
)
func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string) error {
fileOp := files.NewFileOp()
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
if !fileOp.Stat(tmpDir) {
if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
return fmt.Errorf("mkdir %s failed, err: %v", backupDir, err)
}
}
defer func() {
_ = os.RemoveAll(tmpDir)
}()
remarkInfo, _ := json.Marshal(runtime)
remarkInfoPath := fmt.Sprintf("%s/runtime.json", tmpDir)
if err := fileOp.SaveFile(remarkInfoPath, string(remarkInfo), fs.ModePerm); err != nil {
return err
}
appPath := runtime.GetPath()
if err := handleTar(appPath, tmpDir, "runtime.tar.gz", ""); err != nil {
return err
}
if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil {
return err
}
return nil
}
func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback bool) error {
isOk := false
fileOp := files.NewFileOp()
if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil {
return err
}
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
defer func() {
go startRuntime(runtime)
_ = os.RemoveAll(strings.ReplaceAll(recoverFile, ".tar.gz", ""))
}()
if !fileOp.Stat(tmpPath+"/runtime.json") || !fileOp.Stat(tmpPath+"/runtime.tar.gz") {
return errors.New("the wrong recovery package does not have runtime.json or runtime.tar.gz files")
}
var oldRuntime model.Runtime
runtimeJson, err := os.ReadFile(tmpPath + "/runtime.json")
if err != nil {
return err
}
if err := json.Unmarshal(runtimeJson, &oldRuntime); err != nil {
return fmt.Errorf("unmarshal runtime.json failed, err: %v", err)
}
if oldRuntime.Type != runtime.Type || oldRuntime.Name != runtime.Name {
return errors.New("the current backup file does not match the application")
}
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("runtime/%s_%s.tar.gz", runtime.Name, time.Now().Format("20060102150405")))
if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
return fmt.Errorf("backup runtime %s for rollback before recover failed, err: %v", runtime.Name, err)
}
defer func() {
if !isOk {
global.LOG.Info("recover failed, start to rollback now")
if err := handleRuntimeRecover(runtime, rollbackFile, true); err != nil {
global.LOG.Errorf("rollback runtime %s from %s failed, err: %v", runtime.Name, rollbackFile, err)
return
}
global.LOG.Infof("rollback runtime %s from %s successful", runtime.Name, rollbackFile)
_ = os.RemoveAll(rollbackFile)
} else {
_ = os.RemoveAll(rollbackFile)
}
}()
}
newEnvFile, err := coverEnvJsonToStr(runtime.Env)
if err != nil {
return err
}
runtimeDir := runtime.GetPath()
backPath := fmt.Sprintf("%s_bak", runtimeDir)
_ = fileOp.Rename(runtimeDir, backPath)
_ = fileOp.CreateDir(runtimeDir, 0755)
if err := handleUnTar(tmpPath+"/runtime.tar.gz", fmt.Sprintf("%s/%s", constant.RuntimeDir, runtime.Type)); err != nil {
global.LOG.Errorf("handle recover from runtime.tar.gz failed, err: %v", err)
_ = fileOp.DeleteDir(runtimeDir)
_ = fileOp.Rename(backPath, runtimeDir)
return err
}
_ = fileOp.DeleteDir(backPath)
if len(newEnvFile) != 0 {
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.RuntimeDir, runtime.Type, runtime.Name)
file, err := os.OpenFile(envPath, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
_, _ = file.WriteString(newEnvFile)
}
oldRuntime.ID = runtime.ID
oldRuntime.Status = constant.RuntimeStarting
if err := runtimeRepo.Save(&oldRuntime); err != nil {
global.LOG.Errorf("save db app install failed, err: %v", err)
return err
}
isOk = true
return nil
}
+28 -2
View File
@@ -132,7 +132,8 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
return err
}
if website.Type == constant.Deployment {
switch website.Type {
case constant.Deployment:
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil {
return err
@@ -145,7 +146,19 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
global.LOG.Errorf("docker-compose restart failed, err: %v", err)
return err
}
case constant.Runtime:
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID))
if err != nil {
return err
}
if runtime.Type == constant.RuntimeNode {
if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true); err != nil {
return err
}
global.LOG.Info("put runtime.tar.gz into tmp dir successful")
}
}
siteDir := fmt.Sprintf("%s/openresty/%s/www/sites", constant.AppInstallDir, nginxInfo.Name)
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir); err != nil {
global.LOG.Errorf("handle recover from web.tar.gz failed, err: %v", err)
@@ -194,7 +207,8 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
}
global.LOG.Info("put openresty conf into tmp dir successful")
if website.Type == constant.Deployment {
switch website.Type {
case constant.Deployment:
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil {
return err
@@ -203,7 +217,19 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
return err
}
global.LOG.Info("put app.tar.gz into tmp dir successful")
case constant.Runtime:
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID))
if err != nil {
return err
}
if runtime.Type == constant.RuntimeNode {
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias)); err != nil {
return err
}
global.LOG.Info("put runtime.tar.gz into tmp dir successful")
}
}
websiteDir := fmt.Sprintf("%s/openresty/%s/www/sites/%s", constant.AppInstallDir, nginxInfo.Name, website.Alias)
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), ""); err != nil {
return err
+78 -40
View File
@@ -51,7 +51,7 @@ type IContainerService interface {
ContainerUpgrade(req dto.ContainerUpgrade) error
ContainerInfo(req dto.OperationWithName) (*dto.ContainerOperate, error)
ContainerListStats() ([]dto.ContainerListStats, error)
LoadResouceLimit() (*dto.ResourceLimit, error)
LoadResourceLimit() (*dto.ResourceLimit, error)
ContainerLogClean(req dto.OperationWithName) error
ContainerOperation(req dto.ContainerOperation) error
ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error
@@ -66,6 +66,7 @@ type IContainerService interface {
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
LoadContainerLogs(req dto.OperationWithNameAndType) string
ComposeLogs(wsConn *websocket.Conn, composePath, since, tail string, follow bool) error
}
func NewIContainerService() IContainerService {
@@ -208,8 +209,7 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
wg.Add(len(list))
for i := 0; i < len(list); i++ {
go func(item types.Container) {
cpu, mem := loadCpuAndMem(client, item.ID)
datas = append(datas, dto.ContainerListStats{CPUPercent: cpu, MemoryPercent: mem, ContainerID: item.ID})
datas = append(datas, loadCpuAndMem(client, item.ID))
wg.Done()
}(list[i])
}
@@ -226,6 +226,8 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
switch req.Type {
case "container":
inspectInfo, err = client.ContainerInspect(context.Background(), req.ID)
case "image":
inspectInfo, _, err = client.ImageInspectWithRaw(context.Background(), req.ID)
case "network":
inspectInfo, err = client.NetworkInspect(context.TODO(), req.ID, types.NetworkInspectOptions{})
case "volume":
@@ -286,7 +288,7 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
return report, nil
}
func (u *ContainerService) LoadResouceLimit() (*dto.ResourceLimit, error) {
func (u *ContainerService) LoadResourceLimit() (*dto.ResourceLimit, error) {
cpuCounts, err := cpu.Counts(true)
if err != nil {
return nil, fmt.Errorf("load cpu limit failed, err: %v", err)
@@ -314,15 +316,6 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
return buserr.New(constant.ErrContainerName)
}
var config container.Config
var hostConf container.HostConfig
var networkConf network.NetworkingConfig
if err := loadConfigInfo(req, &config, &hostConf, &networkConf); err != nil {
return err
}
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
if !checkImageExist(client, req.Image) || req.ForcePull {
if err := pullImages(ctx, client, req.Image); err != nil {
if !req.ForcePull {
@@ -331,7 +324,22 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err)
}
}
container, err := client.ContainerCreate(ctx, &config, &hostConf, &networkConf, &v1.Platform{}, req.Name)
imageInfo, _, err := client.ImageInspectWithRaw(ctx, req.Image)
if err != nil {
return err
}
if len(req.Entrypoint) == 0 {
req.Entrypoint = imageInfo.Config.Entrypoint
}
if len(req.Cmd) == 0 {
req.Cmd = imageInfo.Config.Cmd
}
config, hostConf, networkConf, err := loadConfigInfo(true, req, nil)
if err != nil {
return err
}
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
if err != nil {
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
return err
@@ -366,6 +374,8 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
}
}
data.Cmd = oldContainer.Config.Cmd
data.OpenStdin = oldContainer.Config.OpenStdin
data.Tty = oldContainer.Config.Tty
data.Entrypoint = oldContainer.Config.Entrypoint
data.Env = oldContainer.Config.Env
data.CPUShares = oldContainer.HostConfig.CPUShares
@@ -427,19 +437,17 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
return err
}
config := oldContainer.Config
hostConf := oldContainer.HostConfig
var networkConf network.NetworkingConfig
if err := loadConfigInfo(req, config, hostConf, &networkConf); err != nil {
config, hostConf, networkConf, err := loadConfigInfo(false, req, &oldContainer)
if err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return err
}
global.LOG.Infof("new container info %s has been update, now start to recreate", req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, &networkConf, &v1.Platform{}, req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
if err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return fmt.Errorf("update contianer failed, err: %v", err)
return fmt.Errorf("update container failed, err: %v", err)
}
global.LOG.Infof("update container %s successful! now check if the container is started.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
@@ -485,7 +493,7 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
container, err := client.ContainerCreate(ctx, config, hostConf, &networkConf, &v1.Platform{}, req.Name)
if err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return fmt.Errorf("upgrade contianer failed, err: %v", err)
return fmt.Errorf("upgrade container failed, err: %v", err)
}
global.LOG.Infof("upgrade container %s successful! now check if the container is started.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
@@ -681,14 +689,14 @@ func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) s
}
func stringsToMap(list []string) map[string]string {
var lableMap = make(map[string]string)
var labelMap = make(map[string]string)
for _, label := range list {
if strings.Contains(label, "=") {
sps := strings.SplitN(label, "=", 2)
lableMap[sps[0]] = sps[1]
labelMap[sps[0]] = sps[1]
}
}
return lableMap
return labelMap
}
func calculateCPUPercentUnix(stats *types.StatsJSON) float64 {
@@ -764,26 +772,36 @@ func pullImages(ctx context.Context, client *client.Client, image string) error
return nil
}
func loadCpuAndMem(client *client.Client, container string) (float64, float64) {
func loadCpuAndMem(client *client.Client, container string) dto.ContainerListStats {
data := dto.ContainerListStats{
ContainerID: container,
}
res, err := client.ContainerStats(context.Background(), container, false)
if err != nil {
return 0, 0
return data
}
body, err := io.ReadAll(res.Body)
if err != nil {
res.Body.Close()
return 0, 0
return data
}
res.Body.Close()
var stats *types.StatsJSON
if err := json.Unmarshal(body, &stats); err != nil {
return 0, 0
return data
}
CPUPercent := calculateCPUPercentUnix(stats)
MemPercent := calculateMemPercentUnix(stats.MemoryStats)
return CPUPercent, MemPercent
data.CPUTotalUsage = stats.CPUStats.CPUUsage.TotalUsage - stats.PreCPUStats.CPUUsage.TotalUsage
data.SystemUsage = stats.CPUStats.SystemUsage - stats.PreCPUStats.SystemUsage
data.CPUPercent = calculateCPUPercentUnix(stats)
data.PercpuUsage = len(stats.CPUStats.CPUUsage.PercpuUsage)
data.MemoryCache = stats.MemoryStats.Stats["cache"]
data.MemoryUsage = stats.MemoryStats.Usage
data.MemoryLimit = stats.MemoryStats.Limit
data.MemoryPercent = calculateMemPercentUnix(stats.MemoryStats)
return data
}
func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {
@@ -832,26 +850,40 @@ func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {
return portMap, nil
}
func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf *container.HostConfig, networkConf *network.NetworkingConfig) error {
func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types.ContainerJSON) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) {
var config container.Config
var hostConf container.HostConfig
if !isCreate {
config = *oldContainer.Config
hostConf = *oldContainer.HostConfig
}
var networkConf network.NetworkingConfig
portMap, err := checkPortStats(req.ExposedPorts)
if err != nil {
return err
return nil, nil, nil, err
}
exposeds := make(nat.PortSet)
exposed := make(nat.PortSet)
for port := range portMap {
exposeds[port] = struct{}{}
exposed[port] = struct{}{}
}
config.Image = req.Image
config.Cmd = req.Cmd
config.Entrypoint = req.Entrypoint
config.Env = req.Env
config.Labels = stringsToMap(req.Labels)
config.ExposedPorts = exposeds
config.ExposedPorts = exposed
config.OpenStdin = req.OpenStdin
config.Tty = req.Tty
if len(req.Network) != 0 {
switch req.Network {
case "host", "none", "bridge":
hostConf.NetworkMode = container.NetworkMode(req.Network)
}
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
} else {
networkConf = &network.NetworkingConfig{}
networkConf = network.NetworkingConfig{}
}
hostConf.AutoRemove = req.AutoRemove
@@ -863,6 +895,7 @@ func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf
}
hostConf.NanoCPUs = int64(req.NanoCPUs * 1000000000)
hostConf.Memory = int64(req.Memory * 1024 * 1024)
hostConf.MemorySwap = 0
hostConf.PortBindings = portMap
hostConf.Binds = []string{}
config.Volumes = make(map[string]struct{})
@@ -870,7 +903,7 @@ func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf
config.Volumes[volume.ContainerDir] = struct{}{}
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
}
return nil
return &config, &hostConf, &networkConf, nil
}
func reCreateAfterUpdate(name string, client *client.Client, config *container.Config, hostConf *container.HostConfig, networkConf *types.NetworkSettings) {
@@ -892,6 +925,7 @@ func reCreateAfterUpdate(name string, client *client.Client, config *container.C
if err := client.ContainerStart(ctx, oldContainer.ID, types.ContainerStartOptions{}); err != nil {
global.LOG.Errorf("restart after container update failed, err: %v", err)
}
global.LOG.Errorf("recreate after container update successful")
}
func loadVolumeBinds(binds []string) []dto.VolumeHelper {
@@ -939,9 +973,13 @@ func simplifyPort(ports []types.Port) []string {
return datas
}
if len(ports) == 1 {
itemPortStr := fmt.Sprintf("%s:%v/%s", ports[0].IP, ports[0].PrivatePort, ports[0].Type)
ip := ""
if len(ports[0].IP) != 0 {
ip = ports[0].IP + ":"
}
itemPortStr := fmt.Sprintf("%s%v/%s", ip, ports[0].PrivatePort, ports[0].Type)
if ports[0].PublicPort != 0 {
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", ports[0].IP, ports[0].PublicPort, ports[0].PrivatePort, ports[0].Type)
itemPortStr = fmt.Sprintf("%s%v->%v/%s", ip, ports[0].PublicPort, ports[0].PrivatePort, ports[0].Type)
}
datas = append(datas, itemPortStr)
return datas
+43
View File
@@ -4,6 +4,7 @@ import (
"bufio"
"errors"
"fmt"
"github.com/gorilla/websocket"
"io"
"os"
"os/exec"
@@ -261,3 +262,45 @@ func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
}
return nil
}
func (u *ContainerService) ComposeLogs(wsConn *websocket.Conn, composePath, since, tail string, follow bool) error {
if cmd.CheckIllegal(composePath, since, tail) {
return buserr.New(constant.ErrCmdIllegal)
}
command := fmt.Sprintf("docker-compose -f %s logs", composePath)
if tail != "0" {
command += " --tail " + tail
}
if since != "all" {
command += " --since " + since
}
if follow {
command += " -f"
}
command += " 2>&1"
cmd := exec.Command("bash", "-c", command)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
if err := cmd.Start(); err != nil {
return err
}
buffer := make([]byte, 1024)
for {
n, err := stdout.Read(buffer)
if err != nil {
if err == io.EOF {
break
}
global.LOG.Errorf("read bytes from compose log failed, err: %v", err)
continue
}
if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil {
global.LOG.Errorf("send message with compose log to ws failed, err: %v", err)
break
}
}
return nil
}
+3 -3
View File
@@ -45,7 +45,7 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
if err != nil {
return nil, err
}
baseInfo.AppInstalldNumber = len(appInstall)
baseInfo.AppInstalledNumber = len(appInstall)
dbs, err := mysqlRepo.List()
if err != nil {
return nil, err
@@ -56,11 +56,11 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
return nil, err
}
baseInfo.WebsiteNumber = len(website)
cornjobs, err := cronjobRepo.List()
cronjobs, err := cronjobRepo.List()
if err != nil {
return nil, err
}
baseInfo.CronjobNumber = len(cornjobs)
baseInfo.CronjobNumber = len(cronjobs)
cpuInfo, err := cpu.Info()
if err == nil {
+40 -5
View File
@@ -3,10 +3,13 @@ package service
import (
"context"
"fmt"
"os"
"path"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/1Panel-dev/1Panel/backend/utils/mysql"
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
@@ -22,7 +25,8 @@ type IDatabaseService interface {
CheckDatabase(req dto.DatabaseCreate) bool
Create(req dto.DatabaseCreate) error
Update(req dto.DatabaseUpdate) error
Delete(id uint) error
DeleteCheck(id uint) ([]string, error)
Delete(req dto.DatabaseDelete) error
List(dbType string) ([]dto.DatabaseOption, error)
}
@@ -114,16 +118,47 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
return nil
}
func (u *DatabaseService) Delete(id uint) error {
db, _ := databaseRepo.Get(commonRepo.WithByID(id))
func (u *DatabaseService) DeleteCheck(id uint) ([]string, error) {
var appInUsed []string
apps, _ := appInstallResourceRepo.GetBy(databaseRepo.WithByFrom("remote"), appInstallResourceRepo.WithLinkId(id))
for _, app := range apps {
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
if appInstall.ID != 0 {
appInUsed = append(appInUsed, appInstall.Name)
}
}
return appInUsed, nil
}
func (u *DatabaseService) Delete(req dto.DatabaseDelete) error {
db, _ := databaseRepo.Get(commonRepo.WithByID(req.ID))
if db.ID == 0 {
return constant.ErrRecordNotFound
}
if err := databaseRepo.Delete(context.Background(), commonRepo.WithByID(id)); err != nil {
if req.DeleteBackup {
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/%s/%s", db.Type, db.Name))
if _, err := os.Stat(uploadDir); err == nil {
_ = os.RemoveAll(uploadDir)
}
localDir, err := loadLocalDir()
if err != nil && !req.ForceDelete {
return err
}
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s", db.Type, db.Name))
if _, err := os.Stat(backupDir); err == nil {
_ = os.RemoveAll(backupDir)
}
_ = backupRepo.DeleteRecord(context.Background(), commonRepo.WithByType(db.Type), commonRepo.WithByName(db.Name))
global.LOG.Infof("delete database %s-%s backups successful", db.Type, db.Name)
}
if err := databaseRepo.Delete(context.Background(), commonRepo.WithByID(req.ID)); err != nil && !req.ForceDelete {
return err
}
if db.From != "local" {
if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByMysqlName(db.Name)); err != nil {
if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByMysqlName(db.Name)); err != nil && !req.ForceDelete {
return err
}
}
+6 -6
View File
@@ -452,7 +452,7 @@ func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool,
if err != nil {
return false, err
}
hosts, err := excuteSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
hosts, err := executeSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
if err != nil {
return false, err
}
@@ -470,7 +470,7 @@ func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.Mys
if err != nil {
return nil, err
}
variableMap, err := excuteSqlForMaps(app.ContainerName, app.Password, "show global variables;")
variableMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global variables;")
if err != nil {
return nil, err
}
@@ -489,7 +489,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
return nil, err
}
statusMap, err := excuteSqlForMaps(app.ContainerName, app.Password, "show global status;")
statusMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global status;")
if err != nil {
return nil, err
}
@@ -513,7 +513,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
info.File = "OFF"
info.Position = "OFF"
rows, err := excuteSqlForRows(app.ContainerName, app.Password, "show master status;")
rows, err := executeSqlForRows(app.ContainerName, app.Password, "show master status;")
if err != nil {
return nil, err
}
@@ -552,7 +552,7 @@ func (u *MysqlService) LoadDatabaseFile(req dto.OperationWithNameAndType) (strin
return string(content), nil
}
func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) {
func executeSqlForMaps(containerName, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput()
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
@@ -571,7 +571,7 @@ func excuteSqlForMaps(containerName, password, command string) (map[string]strin
return rowMap, nil
}
func excuteSqlForRows(containerName, password, command string) ([]string, error) {
func executeSqlForRows(containerName, password, command string) ([]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput()
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
+122 -87
View File
@@ -46,9 +46,6 @@ func (u *FirewallService) LoadBaseInfo() (dto.FirewallBaseInfo, error) {
baseInfo.Name = "-"
client, err := firewall.NewFirewallClient()
if err != nil {
if err.Error() == "no such type" {
return baseInfo, nil
}
return baseInfo, err
}
baseInfo.Name = client.Name()
@@ -111,14 +108,19 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
}
}
if req.Type == "port" {
apps := u.loadPortByApp()
for i := 0; i < len(datas); i++ {
datas[i].UsedStatus = checkPortUsed(datas[i].Port, datas[i].Protocol, apps)
}
}
var datasFilterStatus []fireClient.FireInfo
if len(req.Status) != 0 {
for _, data := range datas {
portItem, _ := strconv.Atoi(data.Port)
if req.Status == "free" && !common.ScanPortWithProto(portItem, data.Protocol) {
if req.Status == "free" && len(data.UsedStatus) == 0 {
datasFilterStatus = append(datasFilterStatus, data)
}
if req.Status == "used" && common.ScanPortWithProto(portItem, data.Protocol) {
if req.Status == "used" && len(data.UsedStatus) != 0 {
datasFilterStatus = append(datasFilterStatus, data)
}
}
@@ -167,23 +169,6 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
}
}
if req.Type == "port" {
apps := u.loadPortByApp()
for i := 0; i < len(backDatas); i++ {
port, _ := strconv.Atoi(backDatas[i].Port)
backDatas[i].IsUsed = common.ScanPort(port)
if backDatas[i].Protocol == "udp" {
backDatas[i].IsUsed = common.ScanUDPPort(port)
continue
}
for _, app := range apps {
if app.HttpPort == backDatas[i].Port || app.HttpsPort == backDatas[i].Port {
backDatas[i].APPName = app.AppName
break
}
}
}
}
go u.cleanUnUsedData(client)
return int64(total), backDatas, nil
@@ -227,7 +212,6 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
protos := strings.Split(req.Protocol, "/")
itemAddress := strings.Split(strings.TrimSuffix(req.Address, ","), ",")
var wg sync.WaitGroup
if client.Name() == "ufw" {
if strings.Contains(req.Port, ",") || strings.Contains(req.Port, "-") {
for _, proto := range protos {
@@ -238,36 +222,35 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
req.Address = addr
req.Port = strings.ReplaceAll(req.Port, "-", ":")
req.Protocol = proto
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
req.Port = strings.ReplaceAll(req.Port, ":", "-")
if err := u.addPortRecord(req); err != nil {
global.LOG.Errorf("add record %s/%s failed (strategy: %s, address: %s), err: %v", req.Port, req.Protocol, req.Strategy, req.Address, err)
}
}
}
return nil
}
if req.Protocol == "tcp/udp" {
req.Protocol = ""
}
for _, addr := range itemAddress {
if len(addr) == 0 {
addr = "Anywhere"
}
if req.Protocol == "tcp/udp" {
req.Protocol = ""
}
req.Address = addr
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
if len(req.Protocol) == 0 {
req.Protocol = "tcp/udp"
}
if err := u.addPortRecord(req); err != nil {
global.LOG.Errorf("add record %s/%s failed (strategy: %s, address: %s), err: %v", req.Port, req.Protocol, req.Strategy, req.Address, err)
}
}
wg.Wait()
return nil
}
@@ -277,14 +260,10 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
for _, addr := range itemAddress {
req.Protocol = proto
req.Address = addr
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}
} else {
ports := strings.Split(itemPorts, ",")
@@ -296,20 +275,15 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
req.Address = addr
req.Port = port
req.Protocol = proto
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}
}
}
}
wg.Wait()
if reload {
return client.Reload()
}
@@ -327,24 +301,18 @@ func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload boo
return err
}
var wg sync.WaitGroup
addressList := strings.Split(req.Address, ",")
for _, addr := range addressList {
if len(addr) == 0 {
for i := 0; i < len(addressList); i++ {
if len(addressList[i]) == 0 {
continue
}
fireInfo.Address = addr
wg.Add(1)
go func(req dto.AddrRuleOperate) {
defer wg.Done()
if err := client.RichRules(fireInfo, req.Operation); err != nil {
global.LOG.Errorf("%s address %s failed (strategy: %s), err: %v", req.Operation, req.Address, req.Strategy, err)
}
req.Address = fireInfo.Address
_ = u.addAddressRecord(req)
}(req)
fireInfo.Address = addressList[i]
if err := client.RichRules(fireInfo, req.Operation); err != nil {
global.LOG.Errorf("%s address %s failed (strategy: %s), err: %v", req.Operation, addressList[i], req.Strategy, err)
}
req.Address = addressList[i]
_ = u.addAddressRecord(req)
}
wg.Wait()
if reload {
return client.Reload()
}
@@ -392,25 +360,15 @@ func (u *FirewallService) BatchOperateRule(req dto.BatchRuleOperate) error {
if err != nil {
return err
}
var wgBatch sync.WaitGroup
if req.Type == "port" {
for _, rule := range req.Rules {
wgBatch.Add(1)
go func(item dto.PortRuleOperate) {
defer wgBatch.Done()
_ = u.OperatePortRule(item, false)
}(rule)
_ = u.OperatePortRule(rule, false)
}
wgBatch.Wait()
return client.Reload()
}
for _, rule := range req.Rules {
itemRule := dto.AddrRuleOperate{Operation: rule.Operation, Address: rule.Address, Strategy: rule.Strategy}
wgBatch.Add(1)
go func(item dto.AddrRuleOperate) {
defer wgBatch.Done()
_ = u.OperateAddressRule(item, false)
}(itemRule)
_ = u.OperateAddressRule(itemRule, false)
}
return client.Reload()
}
@@ -608,3 +566,80 @@ func (u *FirewallService) addAddressRecord(req dto.AddrRuleOperate) error {
Description: req.Description,
})
}
func listIpRules(strategy string) ([]string, error) {
client, err := firewall.NewFirewallClient()
if err != nil {
return nil, err
}
addrs, err := client.ListAddress()
if err != nil {
return nil, err
}
var rules []string
for _, addr := range addrs {
if addr.Strategy == strategy {
rules = append(rules, addr.Address)
}
}
return rules, nil
}
func checkPortUsed(ports, proto string, apps []portOfApp) string {
var portList []int
if strings.Contains(ports, "-") || strings.Contains(ports, ",") {
if strings.Contains(ports, "-") {
port1, err := strconv.Atoi(strings.Split(ports, "-")[0])
if err != nil {
global.LOG.Errorf(" convert string %s to int failed, err: %v", strings.Split(ports, "-")[0], err)
return ""
}
port2, err := strconv.Atoi(strings.Split(ports, "-")[1])
if err != nil {
global.LOG.Errorf(" convert string %s to int failed, err: %v", strings.Split(ports, "-")[1], err)
return ""
}
for i := port1; i <= port2; i++ {
portList = append(portList, i)
}
} else {
portLists := strings.Split(ports, ",")
for _, item := range portLists {
portItem, _ := strconv.Atoi(item)
portList = append(portList, portItem)
}
}
var usedPorts []string
for _, port := range portList {
portItem := fmt.Sprintf("%v", port)
isUsedByApp := false
for _, app := range apps {
if app.HttpPort == portItem || app.HttpsPort == portItem {
isUsedByApp = true
usedPorts = append(usedPorts, fmt.Sprintf("%s (%s)", portItem, app.AppName))
break
}
}
if !isUsedByApp && common.ScanPortWithProto(port, proto) {
usedPorts = append(usedPorts, fmt.Sprintf("%v", port))
}
}
return strings.Join(usedPorts, ",")
}
for _, app := range apps {
if app.HttpPort == ports || app.HttpsPort == ports {
return fmt.Sprintf("(%s)", app.AppName)
}
}
port, err := strconv.Atoi(ports)
if err != nil {
global.LOG.Errorf(" convert string %v to int failed, err: %v", port, err)
return ""
}
if common.ScanPortWithProto(port, proto) {
return "inUsed"
}
return ""
}
+11
View File
@@ -53,6 +53,7 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
if err != nil {
return 0, nil, err
}
containers, _ := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if len(req.Info) != 0 {
length, count := len(list), 0
for count < length {
@@ -77,6 +78,7 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
records = append(records, dto.ImageInfo{
ID: image.ID,
Tags: image.RepoTags,
IsUsed: checkUsed(image.ID, containers),
CreatedAt: time.Unix(image.Created, 0),
Size: size,
})
@@ -415,3 +417,12 @@ func formatFileSize(fileSize int64) (size string) {
return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024))
}
}
func checkUsed(imageID string, containers []types.Container) bool {
for _, container := range containers {
if container.ImageID == imageID {
return true
}
}
return false
}
+54 -4
View File
@@ -1,8 +1,13 @@
package service
import (
"fmt"
"os"
"path"
"path/filepath"
"sort"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
@@ -19,13 +24,14 @@ type LogService struct{}
const logs = "https://resource.fit2cloud.com/installation-log.sh"
type ILogService interface {
ListSystemLogFile() ([]string, error)
CreateLoginLog(operation model.LoginLog) error
PageLoginLog(search dto.SearchLgLogWithPage) (int64, interface{}, error)
CreateOperationLog(operation model.OperationLog) error
PageOperationLog(search dto.SearchOpLogWithPage) (int64, interface{}, error)
LoadSystemLog() (string, error)
LoadSystemLog(name string) (string, error)
CleanLogs(logtype string) error
}
@@ -38,6 +44,39 @@ func (u *LogService) CreateLoginLog(operation model.LoginLog) error {
return logRepo.CreateLoginLog(&operation)
}
func (u *LogService) ListSystemLogFile() ([]string, error) {
logDir := path.Join(global.CONF.System.BaseDir, "1panel/log")
var files []string
if err := filepath.Walk(logDir, func(pathItem string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
if info.Name() == "1Panel.log" {
files = append(files, time.Now().Format("2006-01-02"))
return nil
}
itemFileName := strings.TrimPrefix(info.Name(), "1Panel-")
itemFileName = strings.TrimSuffix(itemFileName, ".gz")
itemFileName = strings.TrimSuffix(itemFileName, ".log")
files = append(files, itemFileName)
return nil
}
return nil
}); err != nil {
return nil, err
}
if len(files) < 2 {
return files, nil
}
sort.Slice(files, func(i, j int) bool {
return files[i] > files[j]
})
return files, nil
}
func (u *LogService) PageLoginLog(req dto.SearchLgLogWithPage) (int64, interface{}, error) {
total, ops, err := logRepo.PageLoginLog(
req.Page,
@@ -81,10 +120,21 @@ func (u *LogService) PageOperationLog(req dto.SearchOpLogWithPage) (int64, inter
return total, dtoOps, err
}
func (u *LogService) LoadSystemLog() (string, error) {
filePath := path.Join(global.CONF.System.DataDir, "log/1Panel.log")
func (u *LogService) LoadSystemLog(name string) (string, error) {
if name == time.Now().Format("2006-01-02") {
name = "1Panel.log"
} else {
name = "1Panel-" + name + ".log"
}
filePath := path.Join(global.CONF.System.DataDir, "log", name)
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
fileGzPath := path.Join(global.CONF.System.DataDir, "log", name+".gz")
if _, err := os.Stat(fileGzPath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
if err := handleGunzip(fileGzPath); err != nil {
return "", fmt.Errorf("handle ungzip file %s failed, err: %v", fileGzPath, err)
}
}
content, err := os.ReadFile(filePath)
if err != nil {
+128 -90
View File
@@ -1,6 +1,7 @@
package service
import (
"context"
"fmt"
"strconv"
"time"
@@ -15,21 +16,28 @@ import (
"github.com/shirou/gopsutil/v3/net"
)
type MonitorService struct{}
type MonitorService struct {
DiskIO chan ([]disk.IOCountersStat)
NetIO chan ([]net.IOCountersStat)
}
var monitorCancel context.CancelFunc
type IMonitorService interface {
Run()
saveIODataToDB(ctx context.Context, interval float64)
saveNetDataToDB(ctx context.Context, interval float64)
}
func NewIMonitorService() IMonitorService {
return &MonitorService{}
return &MonitorService{
DiskIO: make(chan []disk.IOCountersStat, 2),
NetIO: make(chan []net.IOCountersStat, 2),
}
}
func (m *MonitorService) Run() {
monitorStatus, _ := settingRepo.Get(settingRepo.WithByKey("MonitorStatus"))
if monitorStatus.Value == "disable" {
return
}
var itemModel model.MonitorBase
totalPercent, _ := cpu.Percent(3*time.Second, false)
if len(totalPercent) == 1 {
@@ -50,8 +58,8 @@ func (m *MonitorService) Run() {
global.LOG.Errorf("Insert basic monitoring data failed, err: %v", err)
}
go loadDiskIO()
go loadNetIO()
m.loadDiskIO()
m.loadNetIO()
MonitorStoreDays, err := settingRepo.Get(settingRepo.WithByKey("MonitorStoreDays"))
if err != nil {
@@ -64,115 +72,145 @@ func (m *MonitorService) Run() {
_ = settingRepo.DelMonitorNet(timeForDelete)
}
func loadDiskIO() {
func (m *MonitorService) loadDiskIO() {
ioStat, _ := disk.IOCounters()
var diskIOList []disk.IOCountersStat
for _, io := range ioStat {
diskIOList = append(diskIOList, io)
}
m.DiskIO <- diskIOList
}
time.Sleep(60 * time.Second)
func (m *MonitorService) loadNetIO() {
netStat, _ := net.IOCounters(true)
netStatAll, _ := net.IOCounters(false)
var netList []net.IOCountersStat
netList = append(netList, netStat...)
netList = append(netList, netStatAll...)
m.NetIO <- netList
}
ioStat2, _ := disk.IOCounters()
var ioList []model.MonitorIO
for _, io2 := range ioStat2 {
for _, io1 := range ioStat {
if io2.Name == io1.Name {
var itemIO model.MonitorIO
itemIO.Name = io1.Name
if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes {
itemIO.Read = uint64(float64(io2.ReadBytes-io1.ReadBytes) / 60)
}
if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes {
itemIO.Write = uint64(float64(io2.WriteBytes-io1.WriteBytes) / 60)
}
func (m *MonitorService) saveIODataToDB(ctx context.Context, interval float64) {
defer close(m.DiskIO)
for {
select {
case <-ctx.Done():
return
case ioStat := <-m.DiskIO:
select {
case <-ctx.Done():
return
case ioStat2 := <-m.DiskIO:
var ioList []model.MonitorIO
for _, io2 := range ioStat2 {
for _, io1 := range ioStat {
if io2.Name == io1.Name {
var itemIO model.MonitorIO
itemIO.Name = io1.Name
if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes {
itemIO.Read = uint64(float64(io2.ReadBytes-io1.ReadBytes) / interval / 60)
}
if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes {
itemIO.Write = uint64(float64(io2.WriteBytes-io1.WriteBytes) / interval / 60)
}
if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount {
itemIO.Count = uint64(float64(io2.ReadCount-io1.ReadCount) / 60)
}
writeCount := uint64(0)
if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount {
writeCount = uint64(float64(io2.WriteCount-io1.WriteCount) / 60)
}
if writeCount > itemIO.Count {
itemIO.Count = writeCount
}
if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount {
itemIO.Count = uint64(float64(io2.ReadCount-io1.ReadCount) / interval / 60)
}
writeCount := uint64(0)
if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount {
writeCount = uint64(float64(io2.WriteCount-io1.WriteCount) / interval * 60)
}
if writeCount > itemIO.Count {
itemIO.Count = writeCount
}
if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime {
itemIO.Time = uint64(float64(io2.ReadTime-io1.ReadTime) / 60)
if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime {
itemIO.Time = uint64(float64(io2.ReadTime-io1.ReadTime) / interval / 60)
}
writeTime := uint64(0)
if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime {
writeTime = uint64(float64(io2.WriteTime-io1.WriteTime) / interval / 60)
}
if writeTime > itemIO.Time {
itemIO.Time = writeTime
}
ioList = append(ioList, itemIO)
break
}
}
}
writeTime := uint64(0)
if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime {
writeTime = uint64(float64(io2.WriteTime-io1.WriteTime) / 60)
if err := settingRepo.BatchCreateMonitorIO(ioList); err != nil {
global.LOG.Errorf("Insert io monitoring data failed, err: %v", err)
}
if writeTime > itemIO.Time {
itemIO.Time = writeTime
}
ioList = append(ioList, itemIO)
break
m.DiskIO <- ioStat2
}
}
}
if err := settingRepo.BatchCreateMonitorIO(ioList); err != nil {
global.LOG.Errorf("Insert io monitoring data failed, err: %v", err)
}
}
func loadNetIO() {
netStat, _ := net.IOCounters(true)
netStatAll, _ := net.IOCounters(false)
func (m *MonitorService) saveNetDataToDB(ctx context.Context, interval float64) {
defer close(m.NetIO)
for {
select {
case <-ctx.Done():
return
case netStat := <-m.NetIO:
select {
case <-ctx.Done():
return
case netStat2 := <-m.NetIO:
var netList []model.MonitorNetwork
for _, net2 := range netStat2 {
for _, net1 := range netStat {
if net2.Name == net1.Name {
var itemNet model.MonitorNetwork
itemNet.Name = net1.Name
time.Sleep(60 * time.Second)
netStat2, _ := net.IOCounters(true)
var netList []model.MonitorNetwork
for _, net2 := range netStat2 {
for _, net1 := range netStat {
if net2.Name == net1.Name {
var itemNet model.MonitorNetwork
itemNet.Name = net1.Name
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / interval / 60
}
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / interval / 60
}
netList = append(netList, itemNet)
break
}
}
}
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60
if err := settingRepo.BatchCreateMonitorNet(netList); err != nil {
global.LOG.Errorf("Insert network monitoring data failed, err: %v", err)
}
netList = append(netList, itemNet)
break
m.NetIO <- netStat2
}
}
}
netStatAll2, _ := net.IOCounters(false)
for _, net2 := range netStatAll2 {
for _, net1 := range netStatAll {
if net2.Name == net1.Name {
var itemNet model.MonitorNetwork
itemNet.Name = net1.Name
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60
}
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60
}
netList = append(netList, itemNet)
break
}
}
}
if err := settingRepo.BatchCreateMonitorNet(netList); err != nil {
global.LOG.Errorf("Insert network monitoring data failed, err: %v", err)
}
}
func StartMonitor(removeBefore bool, interval string) error {
if removeBefore {
monitorCancel()
global.Cron.Remove(cron.EntryID(global.MonitorCronID))
}
imservice := NewIMonitorService()
monitorID, err := global.Cron.AddJob(fmt.Sprintf("@every %sm", interval), imservice)
intervalItem, err := strconv.Atoi(interval)
if err != nil {
return err
}
imservice.Run()
service := NewIMonitorService()
ctx, cancel := context.WithCancel(context.Background())
monitorCancel = cancel
monitorID, err := global.Cron.AddJob(fmt.Sprintf("@every %sm", interval), service)
if err != nil {
return err
}
service.Run()
go service.saveIODataToDB(ctx, float64(intervalItem))
go service.saveNetDataToDB(ctx, float64(intervalItem))
global.MonitorCronID = int(monitorID)
return nil
}
+389 -149
View File
@@ -3,7 +3,6 @@ package service
import (
"context"
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
@@ -12,11 +11,16 @@ import (
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
cmd2 "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/env"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/pkg/errors"
"github.com/subosito/gotenv"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"
)
@@ -25,11 +29,15 @@ type RuntimeService struct {
}
type IRuntimeService interface {
Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error)
Page(req request.RuntimeSearch) (int64, []response.RuntimeDTO, error)
Create(create request.RuntimeCreate) error
Delete(id uint) error
Delete(delete request.RuntimeDelete) error
Update(req request.RuntimeUpdate) error
Get(id uint) (res *response.RuntimeRes, err error)
Get(id uint) (res *response.RuntimeDTO, err error)
GetNodePackageRunScript(req request.NodePackageReq) ([]response.PackageScripts, error)
OperateRuntime(req request.RuntimeOperate) error
GetNodeModules(req request.NodeModuleReq) ([]response.NodeModule, error)
OperateNodeModules(req request.NodeModuleOperateReq) error
}
func NewRuntimeService() IRuntimeService {
@@ -37,24 +45,52 @@ func NewRuntimeService() IRuntimeService {
}
func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithName(create.Name))
var (
opts []repo.DBOption
)
if create.Name != "" {
opts = append(opts, commonRepo.WithLikeName(create.Name))
}
if create.Type != "" {
opts = append(opts, commonRepo.WithByType(create.Type))
}
exist, _ := runtimeRepo.GetFirst(opts...)
if exist != nil {
return buserr.New(constant.ErrNameIsExist)
}
if create.Resource == constant.ResourceLocal {
runtime := &model.Runtime{
Name: create.Name,
Resource: create.Resource,
Type: create.Type,
Version: create.Version,
Status: constant.RuntimeNormal,
fileOp := files.NewFileOp()
switch create.Type {
case constant.RuntimePHP:
if create.Resource == constant.ResourceLocal {
runtime := &model.Runtime{
Name: create.Name,
Resource: create.Resource,
Type: create.Type,
Version: create.Version,
Status: constant.RuntimeNormal,
}
return runtimeRepo.Create(context.Background(), runtime)
}
exist, _ = runtimeRepo.GetFirst(runtimeRepo.WithImage(create.Image))
if exist != nil {
return buserr.New(constant.ErrImageExist)
}
case constant.RuntimeNode:
if !fileOp.Stat(create.CodeDir) {
return buserr.New(constant.ErrPathNotFound)
}
create.Install = true
if err = checkPortExist(create.Port); err != nil {
return err
}
if containerName, ok := create.Params["CONTAINER_NAME"]; ok {
if err := checkContainerName(containerName.(string)); err != nil {
return err
}
}
return runtimeRepo.Create(context.Background(), runtime)
}
exist, _ = runtimeRepo.GetFirst(runtimeRepo.WithImage(create.Image))
if exist != nil {
return buserr.New(constant.ErrImageExist)
}
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(create.AppDetailID))
if err != nil {
return err
@@ -63,64 +99,40 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
if err != nil {
return err
}
fileOp := files.NewFileOp()
appVersionDir := path.Join(constant.AppResourceDir, app.Resource, app.Key, appDetail.Version)
if !fileOp.Stat(appVersionDir) || appDetail.Update {
if err := downloadApp(app, appDetail, nil); err != nil {
return err
}
}
buildDir := path.Join(appVersionDir, "build")
if !fileOp.Stat(buildDir) {
return buserr.New(constant.ErrDirNotFound)
}
runtimeDir := path.Join(constant.RuntimeDir, create.Type)
tempDir := filepath.Join(runtimeDir, fmt.Sprintf("%d", time.Now().UnixNano()))
if err = fileOp.CopyDir(buildDir, tempDir); err != nil {
return
}
oldDir := path.Join(tempDir, "build")
newNameDir := path.Join(runtimeDir, create.Name)
defer func() {
if err != nil {
_ = fileOp.DeleteDir(newNameDir)
}
}()
if oldDir != newNameDir {
if err = fileOp.Rename(oldDir, newNameDir); err != nil {
return
}
if err = fileOp.DeleteDir(tempDir); err != nil {
return
}
}
composeContent, envContent, forms, err := handleParams(create.Image, create.Type, newNameDir, create.Params)
if err != nil {
return
}
runtime := &model.Runtime{
Name: create.Name,
DockerCompose: string(composeContent),
Env: string(envContent),
AppDetailID: create.AppDetailID,
Type: create.Type,
Image: create.Image,
Resource: create.Resource,
Status: constant.RuntimeBuildIng,
Version: create.Version,
Params: string(forms),
Name: create.Name,
AppDetailID: create.AppDetailID,
Type: create.Type,
Image: create.Image,
Resource: create.Resource,
Version: create.Version,
}
if err = runtimeRepo.Create(context.Background(), runtime); err != nil {
return
switch create.Type {
case constant.RuntimePHP:
if err = handlePHP(create, runtime, fileOp, appVersionDir); err != nil {
return
}
case constant.RuntimeNode:
runtime.Port = create.Port
if err = handleNode(create, runtime, fileOp, appVersionDir); err != nil {
return
}
}
go buildRuntime(runtime, "", false)
return
return runtimeRepo.Create(context.Background(), runtime)
}
func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) {
func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.RuntimeDTO, error) {
var (
opts []repo.DBOption
res []response.RuntimeRes
res []response.RuntimeDTO
)
if req.Name != "" {
opts = append(opts, commonRepo.WithLikeName(req.Name))
@@ -128,113 +140,161 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt
if req.Status != "" {
opts = append(opts, runtimeRepo.WithStatus(req.Status))
}
if req.Type != "" {
opts = append(opts, commonRepo.WithByType(req.Type))
}
total, runtimes, err := runtimeRepo.Page(req.Page, req.PageSize, opts...)
if err != nil {
return 0, nil, err
}
for _, runtime := range runtimes {
res = append(res, response.RuntimeRes{
Runtime: runtime,
})
runtimeDTO := response.NewRuntimeDTO(runtime)
runtimeDTO.Params = make(map[string]interface{})
envs, err := gotenv.Unmarshal(runtime.Env)
if err != nil {
return 0, nil, err
}
for k, v := range envs {
runtimeDTO.Params[k] = v
}
res = append(res, runtimeDTO)
}
return total, res, nil
}
func (r *RuntimeService) Delete(id uint) error {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(runtimeDelete.ID))
if err != nil {
return err
}
website, _ := websiteRepo.GetFirst(websiteRepo.WithRuntimeID(id))
website, _ := websiteRepo.GetFirst(websiteRepo.WithRuntimeID(runtimeDelete.ID))
if website.ID > 0 {
return buserr.New(constant.ErrDelWithWebsite)
}
if runtime.Resource == constant.ResourceAppstore {
client, err := docker.NewClient()
if err != nil {
return err
}
imageID, err := client.GetImageIDByName(runtime.Image)
if err != nil {
return err
}
if imageID != "" {
if err := client.DeleteImage(imageID); err != nil {
global.LOG.Errorf("delete image id [%s] error %v", imageID, err)
projectDir := runtime.GetPath()
switch runtime.Type {
case constant.RuntimePHP:
client, err := docker.NewClient()
if err != nil {
return err
}
imageID, err := client.GetImageIDByName(runtime.Image)
if err != nil {
return err
}
if imageID != "" {
if err := client.DeleteImage(imageID); err != nil {
global.LOG.Errorf("delete image id [%s] error %v", imageID, err)
}
}
case constant.RuntimeNode:
if out, err := compose.Down(runtime.GetComposePath()); err != nil && !runtimeDelete.ForceDelete {
if out != "" {
return errors.New(out)
}
return err
}
}
runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
if err := files.NewFileOp().DeleteDir(runtimeDir); err != nil {
if err := files.NewFileOp().DeleteDir(projectDir); err != nil && !runtimeDelete.ForceDelete {
return err
}
}
return runtimeRepo.DeleteBy(commonRepo.WithByID(id))
return runtimeRepo.DeleteBy(commonRepo.WithByID(runtimeDelete.ID))
}
func (r *RuntimeService) Get(id uint) (*response.RuntimeRes, error) {
func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return nil, err
}
res := &response.RuntimeRes{}
res.Runtime = *runtime
res := response.NewRuntimeDTO(*runtime)
if runtime.Resource == constant.ResourceLocal {
return res, nil
return &res, nil
}
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(runtime.AppDetailID))
if err != nil {
return nil, err
}
res.AppID = appDetail.AppId
var (
appForm dto.AppForm
appParams []response.AppParam
)
if err := json.Unmarshal([]byte(runtime.Params), &appForm); err != nil {
return nil, err
}
envs, err := gotenv.Unmarshal(runtime.Env)
if err != nil {
return nil, err
}
for _, form := range appForm.FormFields {
if v, ok := envs[form.EnvKey]; ok {
appParam := response.AppParam{
Edit: false,
Key: form.EnvKey,
Rule: form.Rule,
Type: form.Type,
Required: form.Required,
}
if form.Edit {
appParam.Edit = true
}
appParam.LabelZh = form.LabelZh
appParam.LabelEn = form.LabelEn
appParam.Multiple = form.Multiple
appParam.Value = v
if form.Type == "select" {
if form.Multiple {
if v == "" {
appParam.Value = []string{}
switch runtime.Type {
case constant.RuntimePHP:
var (
appForm dto.AppForm
appParams []response.AppParam
)
if err := json.Unmarshal([]byte(runtime.Params), &appForm); err != nil {
return nil, err
}
envs, err := gotenv.Unmarshal(runtime.Env)
if err != nil {
return nil, err
}
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
res.Source = v
}
for _, form := range appForm.FormFields {
if v, ok := envs[form.EnvKey]; ok {
appParam := response.AppParam{
Edit: false,
Key: form.EnvKey,
Rule: form.Rule,
Type: form.Type,
Required: form.Required,
}
if form.Edit {
appParam.Edit = true
}
appParam.LabelZh = form.LabelZh
appParam.LabelEn = form.LabelEn
appParam.Multiple = form.Multiple
appParam.Value = v
if form.Type == "select" {
if form.Multiple {
if v == "" {
appParam.Value = []string{}
} else {
appParam.Value = strings.Split(v, ",")
}
} else {
appParam.Value = strings.Split(v, ",")
}
} else {
for _, fv := range form.Values {
if fv.Value == v {
appParam.ShowValue = fv.Label
break
for _, fv := range form.Values {
if fv.Value == v {
appParam.ShowValue = fv.Label
break
}
}
}
appParam.Values = form.Values
}
appParam.Values = form.Values
appParams = append(appParams, appParam)
}
appParams = append(appParams, appParam)
}
res.AppParams = appParams
case constant.RuntimeNode:
res.Params = make(map[string]interface{})
envs, err := gotenv.Unmarshal(runtime.Env)
if err != nil {
return nil, err
}
for k, v := range envs {
switch k {
case "NODE_APP_PORT", "PANEL_APP_PORT_HTTP":
port, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
res.Params[k] = port
default:
res.Params[k] = v
}
}
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
res.Source = v
}
}
res.AppParams = appParams
return res, nil
return &res, nil
}
func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
@@ -242,36 +302,216 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
if err != nil {
return err
}
oldImage := runtime.Image
if runtime.Resource == constant.ResourceLocal {
runtime.Version = req.Version
return runtimeRepo.Save(runtime)
}
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
if exist != nil {
return buserr.New(constant.ErrImageExist)
oldImage := runtime.Image
switch runtime.Type {
case constant.RuntimePHP:
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
if exist != nil {
return buserr.New(constant.ErrImageExist)
}
case constant.RuntimeNode:
if runtime.Port != req.Port {
if err = checkPortExist(req.Port); err != nil {
return err
}
runtime.Port = req.Port
}
if containerName, ok := req.Params["CONTAINER_NAME"]; ok {
envs, err := gotenv.Unmarshal(runtime.Env)
if err != nil {
return err
}
oldContainerName := envs["CONTAINER_NAME"]
if containerName != oldContainerName {
if err := checkContainerName(containerName.(string)); err != nil {
return err
}
}
}
}
runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
composeContent, envContent, _, err := handleParams(req.Image, runtime.Type, runtimeDir, req.Params)
projectDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
create := request.RuntimeCreate{
Image: req.Image,
Type: runtime.Type,
Source: req.Source,
Params: req.Params,
CodeDir: req.CodeDir,
Version: req.Version,
NodeConfig: request.NodeConfig{
Port: req.Port,
Install: true,
},
}
composeContent, envContent, _, err := handleParams(create, projectDir)
if err != nil {
return err
}
if err != nil {
return err
}
runtime.Image = req.Image
runtime.Env = string(envContent)
runtime.DockerCompose = string(composeContent)
runtime.Status = constant.RuntimeBuildIng
_ = runtimeRepo.Save(runtime)
client, err := docker.NewClient()
if err != nil {
return err
switch runtime.Type {
case constant.RuntimePHP:
runtime.Image = req.Image
runtime.Status = constant.RuntimeBuildIng
_ = runtimeRepo.Save(runtime)
client, err := docker.NewClient()
if err != nil {
return err
}
imageID, err := client.GetImageIDByName(oldImage)
if err != nil {
return err
}
go buildRuntime(runtime, imageID, req.Rebuild)
case constant.RuntimeNode:
runtime.Version = req.Version
runtime.CodeDir = req.CodeDir
runtime.Port = req.Port
runtime.Status = constant.RuntimeReCreating
_ = runtimeRepo.Save(runtime)
go reCreateRuntime(runtime)
}
imageID, err := client.GetImageIDByName(oldImage)
if err != nil {
return err
}
go buildRuntime(runtime, imageID, req.Rebuild)
return nil
}
func (r *RuntimeService) GetNodePackageRunScript(req request.NodePackageReq) ([]response.PackageScripts, error) {
fileOp := files.NewFileOp()
if !fileOp.Stat(req.CodeDir) {
return nil, buserr.New(constant.ErrPathNotFound)
}
if !fileOp.Stat(path.Join(req.CodeDir, "package.json")) {
return nil, buserr.New(constant.ErrPackageJsonNotFound)
}
content, err := fileOp.GetContent(path.Join(req.CodeDir, "package.json"))
if err != nil {
return nil, err
}
var packageMap map[string]interface{}
err = json.Unmarshal(content, &packageMap)
if err != nil {
return nil, err
}
scripts, ok := packageMap["scripts"]
if !ok {
return nil, buserr.New(constant.ErrScriptsNotFound)
}
var packageScripts []response.PackageScripts
for k, v := range scripts.(map[string]interface{}) {
packageScripts = append(packageScripts, response.PackageScripts{
Name: k,
Script: v.(string),
})
}
return packageScripts, nil
}
func (r *RuntimeService) OperateRuntime(req request.RuntimeOperate) error {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return err
}
defer func() {
if err != nil {
runtime.Status = constant.RuntimeError
runtime.Message = err.Error()
_ = runtimeRepo.Save(runtime)
}
}()
switch req.Operate {
case constant.RuntimeUp:
if err = runComposeCmdWithLog(req.Operate, runtime.GetComposePath(), runtime.GetLogPath()); err != nil {
return err
}
if err = SyncRuntimeContainerStatus(runtime); err != nil {
return err
}
case constant.RuntimeDown:
if err = runComposeCmdWithLog(req.Operate, runtime.GetComposePath(), runtime.GetLogPath()); err != nil {
return err
}
runtime.Status = constant.RuntimeStopped
case constant.RuntimeRestart:
if err = runComposeCmdWithLog(constant.RuntimeDown, runtime.GetComposePath(), runtime.GetLogPath()); err != nil {
return err
}
if err = runComposeCmdWithLog(constant.RuntimeUp, runtime.GetComposePath(), runtime.GetLogPath()); err != nil {
return err
}
if err = SyncRuntimeContainerStatus(runtime); err != nil {
return err
}
}
return runtimeRepo.Save(runtime)
}
func (r *RuntimeService) GetNodeModules(req request.NodeModuleReq) ([]response.NodeModule, error) {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return nil, err
}
var res []response.NodeModule
nodeModulesPath := path.Join(runtime.CodeDir, "node_modules")
fileOp := files.NewFileOp()
if !fileOp.Stat(nodeModulesPath) {
return nil, buserr.New("ErrNodeModulesNotFound")
}
moduleDirs, err := os.ReadDir(nodeModulesPath)
if err != nil {
return nil, err
}
for _, moduleDir := range moduleDirs {
packagePath := path.Join(nodeModulesPath, moduleDir.Name(), "package.json")
if !fileOp.Stat(packagePath) {
continue
}
content, err := fileOp.GetContent(packagePath)
if err != nil {
continue
}
module := response.NodeModule{}
if err := json.Unmarshal(content, &module); err != nil {
continue
}
res = append(res, module)
}
return res, nil
}
func (r *RuntimeService) OperateNodeModules(req request.NodeModuleOperateReq) error {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return err
}
containerName, err := env.GetEnvValueByKey(runtime.GetEnvPath(), "CONTAINER_NAME")
if err != nil {
return err
}
cmd := req.PkgManager
switch req.Operate {
case constant.RuntimeInstall:
if req.PkgManager == constant.RuntimeNpm {
cmd += " install"
} else {
cmd += " add"
}
case constant.RuntimeUninstall:
if req.PkgManager == constant.RuntimeNpm {
cmd += " uninstall"
} else {
cmd += " remove"
}
case constant.RuntimeUpdate:
if req.PkgManager == constant.RuntimeNpm {
cmd += " update"
} else {
cmd += " upgrade"
}
}
cmd += " " + req.Module
return cmd2.ExecContainerScript(containerName, cmd, 5*time.Minute)
}
+239 -16
View File
@@ -10,22 +10,213 @@ import (
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/pkg/errors"
"github.com/subosito/gotenv"
"io"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
)
func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
runtimeDir := path.Join(constant.RuntimeDir, create.Type)
if err = fileOp.CopyDir(appVersionDir, runtimeDir); err != nil {
return
}
versionDir := path.Join(runtimeDir, filepath.Base(appVersionDir))
projectDir := path.Join(runtimeDir, create.Name)
defer func() {
if err != nil {
_ = fileOp.DeleteDir(projectDir)
}
}()
if err = fileOp.Rename(versionDir, projectDir); err != nil {
return
}
composeContent, envContent, _, err := handleParams(create, projectDir)
if err != nil {
return
}
runtime.DockerCompose = string(composeContent)
runtime.Env = string(envContent)
runtime.Status = constant.RuntimeCreating
runtime.CodeDir = create.CodeDir
nodeDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(runtime.AppDetailID))
if err != nil {
return err
}
go func() {
_, _ = http.Get(nodeDetail.DownloadCallBackUrl)
}()
go startRuntime(runtime)
return
}
func handlePHP(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
buildDir := path.Join(appVersionDir, "build")
if !fileOp.Stat(buildDir) {
return buserr.New(constant.ErrDirNotFound)
}
runtimeDir := path.Join(constant.RuntimeDir, create.Type)
tempDir := filepath.Join(runtimeDir, fmt.Sprintf("%d", time.Now().UnixNano()))
if err = fileOp.CopyDir(buildDir, tempDir); err != nil {
return
}
oldDir := path.Join(tempDir, "build")
projectDir := path.Join(runtimeDir, create.Name)
defer func() {
if err != nil {
_ = fileOp.DeleteDir(projectDir)
}
}()
if oldDir != projectDir {
if err = fileOp.Rename(oldDir, projectDir); err != nil {
return
}
if err = fileOp.DeleteDir(tempDir); err != nil {
return
}
}
composeContent, envContent, forms, err := handleParams(create, projectDir)
if err != nil {
return
}
runtime.DockerCompose = string(composeContent)
runtime.Env = string(envContent)
runtime.Params = string(forms)
runtime.Status = constant.RuntimeBuildIng
go buildRuntime(runtime, "", false)
return
}
func startRuntime(runtime *model.Runtime) {
if err := runComposeCmdWithLog("up", runtime.GetComposePath(), runtime.GetLogPath()); err != nil {
runtime.Status = constant.RuntimeError
runtime.Message = err.Error()
_ = runtimeRepo.Save(runtime)
return
}
if err := SyncRuntimeContainerStatus(runtime); err != nil {
runtime.Status = constant.RuntimeError
runtime.Message = err.Error()
_ = runtimeRepo.Save(runtime)
return
}
}
func reCreateRuntime(runtime *model.Runtime) {
var err error
defer func() {
if err != nil {
runtime.Status = constant.RuntimeError
runtime.Message = err.Error()
_ = runtimeRepo.Save(runtime)
}
}()
if err = runComposeCmdWithLog("down", runtime.GetComposePath(), runtime.GetLogPath()); err != nil {
return
}
if err = runComposeCmdWithLog("up", runtime.GetComposePath(), runtime.GetLogPath()); err != nil {
return
}
if err := SyncRuntimeContainerStatus(runtime); err != nil {
return
}
}
func runComposeCmdWithLog(operate string, composePath string, logPath string) error {
cmd := exec.Command("docker-compose", "-f", composePath, operate)
if operate == "up" {
cmd = exec.Command("docker-compose", "-f", composePath, operate, "-d")
}
logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
global.LOG.Errorf("Failed to open log file: %v", err)
return err
}
multiWriterStdout := io.MultiWriter(os.Stdout, logFile)
cmd.Stdout = multiWriterStdout
var stderrBuf bytes.Buffer
multiWriterStderr := io.MultiWriter(&stderrBuf, logFile, os.Stderr)
cmd.Stderr = multiWriterStderr
err = cmd.Run()
if err != nil {
return errors.New(buserr.New(constant.ErrRuntimeStart).Error() + ":" + stderrBuf.String())
}
return nil
}
func SyncRuntimeContainerStatus(runtime *model.Runtime) error {
env, err := gotenv.Unmarshal(runtime.Env)
if err != nil {
return err
}
var containerNames []string
if containerName, ok := env["CONTAINER_NAME"]; !ok {
return buserr.New("ErrContainerNameNotFound")
} else {
containerNames = append(containerNames, containerName)
}
cli, err := docker.NewClient()
if err != nil {
return err
}
containers, err := cli.ListContainersByName(containerNames)
if err != nil {
return err
}
if len(containers) == 0 {
return buserr.WithNameAndErr("ErrContainerNotFound", containerNames[0], nil)
}
container := containers[0]
interval := 10 * time.Second
retries := 60
for i := 0; i < retries; i++ {
resp, err := cli.InspectContainer(container.ID)
if err != nil {
time.Sleep(interval)
continue
}
if resp.State.Health != nil {
status := strings.ToLower(resp.State.Health.Status)
switch status {
case "starting":
runtime.Status = constant.RuntimeStarting
_ = runtimeRepo.Save(runtime)
case "healthy":
runtime.Status = constant.RuntimeRunning
_ = runtimeRepo.Save(runtime)
return nil
case "unhealthy":
runtime.Status = constant.RuntimeUnhealthy
_ = runtimeRepo.Save(runtime)
return nil
}
}
time.Sleep(interval)
}
return nil
}
func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
runtimePath := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
composePath := path.Join(runtimePath, "docker-compose.yml")
runtimePath := runtime.GetPath()
composePath := runtime.GetComposePath()
logPath := path.Join(runtimePath, "build.log")
logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
fmt.Println("Failed to open log file:", err)
global.LOG.Errorf("failed to open log file: %v", err)
return
}
defer func() {
@@ -89,34 +280,51 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
_ = runtimeRepo.Save(runtime)
}
func handleParams(image, runtimeType, runtimeDir string, params map[string]interface{}) (composeContent []byte, envContent []byte, forms []byte, err error) {
func handleParams(create request.RuntimeCreate, projectDir string) (composeContent []byte, envContent []byte, forms []byte, err error) {
fileOp := files.NewFileOp()
composeContent, err = fileOp.GetContent(path.Join(runtimeDir, "docker-compose.yml"))
composeContent, err = fileOp.GetContent(path.Join(projectDir, "docker-compose.yml"))
if err != nil {
return
}
env, err := gotenv.Read(path.Join(runtimeDir, ".env"))
envPath := path.Join(projectDir, ".env")
if !fileOp.Stat(envPath) {
_ = fileOp.CreateFile(envPath)
}
env, err := gotenv.Read(envPath)
if err != nil {
return
}
forms, err = fileOp.GetContent(path.Join(runtimeDir, "config.json"))
if err != nil {
return
}
params["IMAGE_NAME"] = image
if runtimeType == constant.RuntimePHP {
if extends, ok := params["PHP_EXTENSIONS"]; ok {
switch create.Type {
case constant.RuntimePHP:
create.Params["IMAGE_NAME"] = create.Image
forms, err = fileOp.GetContent(path.Join(projectDir, "config.json"))
if err != nil {
return
}
if extends, ok := create.Params["PHP_EXTENSIONS"]; ok {
if extendsArray, ok := extends.([]interface{}); ok {
strArray := make([]string, len(extendsArray))
for i, v := range extendsArray {
strArray[i] = strings.ToLower(fmt.Sprintf("%v", v))
}
params["PHP_EXTENSIONS"] = strings.Join(strArray, ",")
create.Params["PHP_EXTENSIONS"] = strings.Join(strArray, ",")
}
}
create.Params["CONTAINER_PACKAGE_URL"] = create.Source
case constant.RuntimeNode:
create.Params["CODE_DIR"] = create.CodeDir
create.Params["NODE_VERSION"] = create.Version
create.Params["PANEL_APP_PORT_HTTP"] = create.Port
if create.NodeConfig.Install {
create.Params["RUN_INSTALL"] = "1"
} else {
create.Params["RUN_INSTALL"] = "0"
}
create.Params["CONTAINER_PACKAGE_URL"] = create.Source
}
newMap := make(map[string]string)
handleMap(params, newMap)
handleMap(create.Params, newMap)
for k, v := range newMap {
env[k] = v
}
@@ -124,9 +332,24 @@ func handleParams(image, runtimeType, runtimeDir string, params map[string]inter
if err != nil {
return
}
if err = gotenv.Write(env, path.Join(runtimeDir, ".env")); err != nil {
if err = gotenv.Write(env, envPath); err != nil {
return
}
envContent = []byte(envStr)
return
}
func checkContainerName(name string) error {
dockerCli, err := docker.NewClient()
if err != nil {
return err
}
names, err := dockerCli.ListContainersByName([]string{name})
if err != nil {
return err
}
if len(names) > 0 {
return buserr.New(constant.ErrContainerName)
}
return nil
}
+4
View File
@@ -38,6 +38,9 @@ type ISettingService interface {
LoadFromCert() (*dto.SSLInfo, error)
HandlePasswordExpired(c *gin.Context, old, new string) error
SyncTime(req dto.SyncTime) error
SystemScan() dto.CleanData
SystemClean(req []dto.Clean)
}
func NewISettingService() ISettingService {
@@ -86,6 +89,7 @@ func (u *SettingService) Update(key, value string) error {
}
}
if value == "disable" && global.MonitorCronID != 0 {
monitorCancel()
global.Cron.Remove(cron.EntryID(global.MonitorCronID))
global.MonitorCronID = 0
}
+508
View File
@@ -0,0 +1,508 @@
package service
import (
"fmt"
"os"
"path"
"sort"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/google/uuid"
)
func (u *SettingService) SystemScan() dto.CleanData {
var (
SystemClean dto.CleanData
treeData []dto.CleanTree
)
fileOp := fileUtils.NewFileOp()
originalPath := path.Join(global.CONF.System.BaseDir, "1panel_original")
originalSize, _ := fileOp.GetDirSize(originalPath)
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "1panel_original",
Size: uint64(originalSize),
IsCheck: true,
IsRecommend: true,
Type: "1panel_original",
Children: loadTreeWithDir(true, "1panel_original", originalPath, fileOp),
})
upgradePath := path.Join(global.CONF.System.BaseDir, "1panel/tmp/upgrade")
upgradeSize, _ := fileOp.GetDirSize(upgradePath)
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "upgrade",
Size: uint64(upgradeSize),
IsCheck: false,
IsRecommend: true,
Type: "upgrade",
Children: loadTreeWithDir(true, "upgrade", upgradePath, fileOp),
})
snapTree := loadSnapshotTree(fileOp)
snapSize := uint64(0)
for _, snap := range snapTree {
snapSize += uint64(snap.Size)
}
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "snapshot",
Size: snapSize,
IsCheck: true,
IsRecommend: true,
Type: "snapshot",
Children: snapTree,
})
rollBackTree := loadRollBackTree(fileOp)
rollbackSize := uint64(0)
for _, rollback := range rollBackTree {
rollbackSize += uint64(rollback.Size)
}
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "rollback",
Size: rollbackSize,
IsCheck: true,
IsRecommend: true,
Type: "rollback",
Children: rollBackTree,
})
cachePath := path.Join(global.CONF.System.BaseDir, "1panel/cache")
cacheSize, _ := fileOp.GetDirSize(cachePath)
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "cache",
Size: uint64(cacheSize),
IsCheck: false,
IsRecommend: false,
Type: "cache",
})
unusedTree := loadUnusedFile(fileOp)
unusedSize := uint64(0)
for _, unused := range unusedTree {
unusedSize += uint64(unused.Size)
}
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "unused",
Size: unusedSize,
IsCheck: true,
IsRecommend: true,
Type: "unused",
Children: unusedTree,
})
SystemClean.SystemClean = treeData
uploadTreeData := loadUploadTree(fileOp)
SystemClean.UploadClean = append(SystemClean.UploadClean, uploadTreeData...)
downloadTreeData := loadDownloadTree(fileOp)
SystemClean.DownloadClean = append(SystemClean.DownloadClean, downloadTreeData...)
logTree := loadLogTree(fileOp)
SystemClean.SystemLogClean = append(SystemClean.SystemLogClean, logTree...)
return SystemClean
}
func (u *SettingService) SystemClean(req []dto.Clean) {
size := uint64(0)
restart := false
for _, item := range req {
size += item.Size
switch item.TreeType {
case "1panel_original":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel_original", item.Name))
case "upgrade":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/upgrade", item.Name))
case "snapshot":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/system", item.Name))
dropFileOrDir(path.Join(global.CONF.System.Backup, "system", item.Name))
case "snapshot_tmp":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/system", item.Name))
case "snapshot_local":
dropFileOrDir(path.Join(global.CONF.System.Backup, "system", item.Name))
case "rollback":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/app"))
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/database"))
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/website"))
case "rollback_app":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/app", item.Name))
case "rollback_database":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/database", item.Name))
case "rollback_website":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/website", item.Name))
case "cache":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/cache", item.Name))
restart = true
case "unused":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "original"))
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/resource/apps_bak"))
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/download"))
files, _ := os.ReadDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp"))
if len(files) == 0 {
continue
}
for _, file := range files {
if strings.HasPrefix(file.Name(), "upgrade_") {
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp", file.Name()))
}
}
case "old_original":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "original", item.Name))
case "old_apps_bak":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/resource/apps_bak", item.Name))
case "old_download":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/download", item.Name))
case "old_upgrade":
if len(item.Name) == 0 {
files, _ := os.ReadDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp"))
if len(files) == 0 {
continue
}
for _, file := range files {
if strings.HasPrefix(file.Name(), "upgrade_") {
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp", file.Name()))
}
}
} else {
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp", item.Name))
}
case "upload":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/uploads", item.Name))
if len(item.Name) == 0 {
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/upload"))
}
case "upload_tmp":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/upload", item.Name))
case "upload_app":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/uploads/app", item.Name))
case "upload_database":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/uploads/database", item.Name))
case "upload_website":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/uploads/website", item.Name))
case "upload_directory":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/uploads/directory", item.Name))
case "download":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/download", item.Name))
case "download_app":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/download/app", item.Name))
case "download_database":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/download/database", item.Name))
case "download_website":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/download/website", item.Name))
case "download_directory":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/download/directory", item.Name))
case "system_log":
if len(item.Name) == 0 {
files, _ := os.ReadDir(path.Join(global.CONF.System.BaseDir, "1panel/log"))
if len(files) == 0 {
continue
}
for _, file := range files {
if file.Name() == "1Panel.log" {
continue
}
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/log", file.Name()))
}
} else {
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/log", item.Name))
}
case "docker_log":
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/tmp/docker_logs", item.Name))
case "task_log":
pathItem := path.Join(global.CONF.System.BaseDir, "1panel/task", item.Name)
dropFileOrDir(path.Join(global.CONF.System.BaseDir, "1panel/task", item.Name))
if len(item.Name) == 0 {
files, _ := os.ReadDir(pathItem)
if len(files) == 0 {
continue
}
for _, file := range files {
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByRecordFile(path.Join(pathItem, file.Name())))
}
} else {
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByRecordFile(pathItem))
}
}
}
_ = settingRepo.Update("LastCleanTime", time.Now().Format("2006-01-02 15:04:05"))
_ = settingRepo.Update("LastCleanSize", fmt.Sprintf("%v", size))
_ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", len(req)))
if restart {
go func() {
_, err := cmd.Exec("systemctl restart 1panel.service")
if err != nil {
global.LOG.Errorf("restart system port failed, err: %v", err)
}
}()
}
}
func loadSnapshotTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
path1 := path.Join(global.CONF.System.BaseDir, "1panel/tmp/system")
list1 := loadTreeWithAllFile(true, path1, "snapshot_tmp", path1, fileOp)
if len(list1) != 0 {
size, _ := fileOp.GetDirSize(path1)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "snapshot_tmp", Size: uint64(size), Children: list1, Type: "snapshot_tmp", IsRecommend: true})
}
path2 := path.Join(global.CONF.System.Backup, "system")
list2 := loadTreeWithAllFile(true, path2, "snapshot_local", path2, fileOp)
if len(list2) != 0 {
size, _ := fileOp.GetDirSize(path2)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "snapshot_local", Size: uint64(size), Children: list2, Type: "snapshot_local", IsRecommend: true})
}
return treeData
}
func loadRollBackTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
path1 := path.Join(global.CONF.System.BaseDir, "1panel/tmp/app")
list1 := loadTreeWithAllFile(true, path1, "rollback_app", path1, fileOp)
size1, _ := fileOp.GetDirSize(path1)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "rollback_app", Size: uint64(size1), Children: list1, Type: "rollback_app", IsRecommend: true})
path2 := path.Join(global.CONF.System.BaseDir, "1panel/tmp/website")
list2 := loadTreeWithAllFile(true, path2, "rollback_website", path2, fileOp)
size2, _ := fileOp.GetDirSize(path2)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "rollback_website", Size: uint64(size2), Children: list2, Type: "rollback_website", IsRecommend: true})
path3 := path.Join(global.CONF.System.BaseDir, "1panel/tmp/database")
list3 := loadTreeWithAllFile(true, path3, "rollback_database", path3, fileOp)
size3, _ := fileOp.GetDirSize(path3)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "rollback_database", Size: uint64(size3), Children: list3, Type: "rollback_database", IsRecommend: true})
return treeData
}
func loadUnusedFile(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
path1 := path.Join(global.CONF.System.BaseDir, "original")
list1 := loadTreeWithAllFile(true, path1, "old_original", path1, fileOp)
if len(list1) != 0 {
size, _ := fileOp.GetDirSize(path1)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "old_original", Size: uint64(size), Children: list1, Type: "old_original"})
}
path2 := path.Join(global.CONF.System.BaseDir, "1panel/resource/apps_bak")
list2 := loadTreeWithAllFile(true, path2, "old_apps_bak", path2, fileOp)
if len(list2) != 0 {
size, _ := fileOp.GetDirSize(path2)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "old_apps_bak", Size: uint64(size), Children: list2, Type: "old_apps_bak"})
}
path3 := path.Join(global.CONF.System.BaseDir, "1panel/tmp/download")
list3 := loadTreeWithAllFile(true, path3, "old_download", path3, fileOp)
if len(list3) != 0 {
size, _ := fileOp.GetDirSize(path3)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "old_download", Size: uint64(size), Children: list3, Type: "old_download"})
}
path4 := path.Join(global.CONF.System.BaseDir, "1panel/tmp")
list4 := loadTreeWithDir(true, "old_upgrade", path4, fileOp)
itemSize := uint64(0)
for _, item := range list4 {
itemSize += item.Size
}
if len(list4) != 0 {
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "old_upgrade", Size: itemSize, Children: list4, Type: "old_upgrade"})
}
return treeData
}
func loadUploadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
path0 := path.Join(global.CONF.System.BaseDir, "1panel/tmp/upload")
list0 := loadTreeWithAllFile(true, path0, "upload_tmp", path0, fileOp)
size0, _ := fileOp.GetDirSize(path0)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "upload_tmp", Size: uint64(size0), Children: list0, Type: "upload_tmp", IsRecommend: true})
path1 := path.Join(global.CONF.System.BaseDir, "1panel/uploads/app")
list1 := loadTreeWithAllFile(true, path1, "upload_app", path1, fileOp)
size1, _ := fileOp.GetDirSize(path1)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "upload_app", Size: uint64(size1), Children: list1, Type: "upload_app", IsRecommend: true})
path2 := path.Join(global.CONF.System.BaseDir, "1panel/uploads/website")
list2 := loadTreeWithAllFile(true, path2, "upload_website", path2, fileOp)
size2, _ := fileOp.GetDirSize(path2)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "upload_website", Size: uint64(size2), Children: list2, Type: "upload_website", IsRecommend: true})
path3 := path.Join(global.CONF.System.BaseDir, "1panel/uploads/database")
list3 := loadTreeWithAllFile(true, path3, "upload_database", path3, fileOp)
size3, _ := fileOp.GetDirSize(path3)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "upload_database", Size: uint64(size3), Children: list3, Type: "upload_database", IsRecommend: true})
path4 := path.Join(global.CONF.System.BaseDir, "1panel/uploads/directory")
list4 := loadTreeWithAllFile(true, path4, "upload_directory", path4, fileOp)
size4, _ := fileOp.GetDirSize(path4)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "upload_directory", Size: uint64(size4), Children: list4, Type: "upload_directory", IsRecommend: true})
path5 := path.Join(global.CONF.System.BaseDir, "1panel/uploads")
uploadTreeData := loadTreeWithAllFile(true, path5, "upload", path5, fileOp)
treeData = append(treeData, uploadTreeData...)
return treeData
}
func loadDownloadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
path1 := path.Join(global.CONF.System.BaseDir, "1panel/download/app")
list1 := loadTreeWithAllFile(true, path1, "download_app", path1, fileOp)
size1, _ := fileOp.GetDirSize(path1)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "download_app", Size: uint64(size1), Children: list1, Type: "download_app", IsRecommend: true})
path2 := path.Join(global.CONF.System.BaseDir, "1panel/download/website")
list2 := loadTreeWithAllFile(true, path2, "download_website", path2, fileOp)
size2, _ := fileOp.GetDirSize(path2)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "download_website", Size: uint64(size2), Children: list2, Type: "download_website", IsRecommend: true})
path3 := path.Join(global.CONF.System.BaseDir, "1panel/download/database")
list3 := loadTreeWithAllFile(true, path3, "download_database", path3, fileOp)
size3, _ := fileOp.GetDirSize(path3)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "download_database", Size: uint64(size3), Children: list3, Type: "download_database", IsRecommend: true})
path4 := path.Join(global.CONF.System.BaseDir, "1panel/download/directory")
list4 := loadTreeWithAllFile(true, path4, "download_directory", path4, fileOp)
size4, _ := fileOp.GetDirSize(path4)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "download_directory", Size: uint64(size4), Children: list4, Type: "download_directory", IsRecommend: true})
path5 := path.Join(global.CONF.System.BaseDir, "1panel/download")
uploadTreeData := loadTreeWithAllFile(true, path5, "download", path5, fileOp)
treeData = append(treeData, uploadTreeData...)
return treeData
}
func loadLogTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
path1 := path.Join(global.CONF.System.BaseDir, "1panel/log")
list1 := loadTreeWithAllFile(true, path1, "system_log", path1, fileOp)
size := uint64(0)
for _, file := range list1 {
size += file.Size
}
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "system_log", Size: uint64(size), Children: list1, Type: "system_log", IsRecommend: true})
path2 := path.Join(global.CONF.System.BaseDir, "1panel/tmp/docker_logs")
list2 := loadTreeWithAllFile(true, path2, "docker_log", path2, fileOp)
size2, _ := fileOp.GetDirSize(path2)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "docker_log", Size: uint64(size2), Children: list2, Type: "docker_log", IsRecommend: true})
path3 := path.Join(global.CONF.System.BaseDir, "1panel/task")
list3 := loadTreeWithAllFile(false, path3, "task_log", path3, fileOp)
size3, _ := fileOp.GetDirSize(path3)
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "task_log", Size: uint64(size3), Children: list3, Type: "task_log"})
return treeData
}
func loadTreeWithDir(isCheck bool, treeType, pathItem string, fileOp fileUtils.FileOp) []dto.CleanTree {
var lists []dto.CleanTree
files, err := os.ReadDir(pathItem)
if err != nil {
return lists
}
sort.Slice(files, func(i, j int) bool {
return files[i].Name() > files[j].Name()
})
for _, file := range files {
if (treeType == "old_upgrade" || treeType == "upgrade") && !strings.HasPrefix(file.Name(), "upgrade_2023") {
continue
}
if file.IsDir() {
size, err := fileOp.GetDirSize(path.Join(pathItem, file.Name()))
if err != nil {
continue
}
item := dto.CleanTree{
ID: uuid.NewString(),
Label: file.Name(),
Type: treeType,
Size: uint64(size),
Name: strings.TrimPrefix(file.Name(), "/"),
IsCheck: isCheck,
IsRecommend: isCheck,
}
if treeType == "upgrade" && len(lists) == 0 {
item.IsCheck = false
item.IsRecommend = false
}
lists = append(lists, item)
}
}
return lists
}
func loadTreeWithAllFile(isCheck bool, originalPath, treeType, pathItem string, fileOp fileUtils.FileOp) []dto.CleanTree {
var lists []dto.CleanTree
files, err := os.ReadDir(pathItem)
if err != nil {
return lists
}
for _, file := range files {
if treeType == "system_log" && file.Name() == "1Panel.log" {
continue
}
if (treeType == "upload" || treeType == "download") && file.IsDir() && (file.Name() == "app" || file.Name() == "database" || file.Name() == "website" || file.Name() == "directory") {
continue
}
size := uint64(0)
name := strings.TrimPrefix(path.Join(pathItem, file.Name()), originalPath+"/")
if file.IsDir() {
sizeItem, err := fileOp.GetDirSize(path.Join(pathItem, file.Name()))
if err != nil {
continue
}
size = uint64(sizeItem)
} else {
fileInfo, err := file.Info()
if err != nil {
continue
}
size = uint64(fileInfo.Size())
}
item := dto.CleanTree{
ID: uuid.NewString(),
Label: file.Name(),
Type: treeType,
Size: uint64(size),
Name: name,
IsCheck: isCheck,
IsRecommend: isCheck,
}
if file.IsDir() {
item.Children = loadTreeWithAllFile(isCheck, originalPath, treeType, path.Join(pathItem, file.Name()), fileOp)
}
lists = append(lists, item)
}
return lists
}
func dropFileOrDir(itemPath string) {
global.LOG.Debugf("drop file %s", itemPath)
if err := os.RemoveAll(itemPath); err != nil {
global.LOG.Errorf("drop file %s failed, err %v", itemPath, err)
}
}
+4 -3
View File
@@ -139,7 +139,7 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
}
func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
global.LOG.Info("start to recvover panel by snapshot now")
global.LOG.Info("start to recover panel by snapshot now")
snap, err := snapshotRepo.Get(commonRepo.WithByID(req.ID))
if err != nil {
return err
@@ -884,9 +884,10 @@ func updateRollbackStatus(id uint, status string, message string) {
}
func cpBinary(src []string, dst string) error {
stderr, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
global.LOG.Debugf(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
stdout, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
if err != nil {
return errors.New(stderr)
return fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
}
return nil
}
+219 -38
View File
@@ -32,6 +32,7 @@ type ISSHService interface {
UpdateByFile(value string) error
Update(key, value string) error
GenerateSSH(req dto.GenerateSSH) error
AnalysisLog(req dto.SearchForAnalysis) (*dto.AnalysisRes, error)
LoadSSHSecret(mode string) (string, error)
LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error)
@@ -239,7 +240,7 @@ func (u *SSHService) LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error) {
if err != nil {
return err
}
if !info.IsDir() && strings.HasPrefix(info.Name(), "secure") || strings.HasPrefix(info.Name(), "auth") {
if !info.IsDir() && (strings.HasPrefix(info.Name(), "secure") || strings.HasPrefix(info.Name(), "auth")) {
if !strings.HasSuffix(info.Name(), ".gz") {
fileList = append(fileList, sshFileItem{Name: pathItem, Year: info.ModTime().Year()})
return nil
@@ -286,9 +287,9 @@ func (u *SSHService) LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error) {
case constant.StatusSuccess:
commandItem = fmt.Sprintf("cat %s | grep -a Accepted %s", file.Name, command)
case constant.StatusFailed:
commandItem = fmt.Sprintf("cat %s | grep -a 'Connection closed by authenticating user' | grep -a 'preauth' %s", file.Name, command)
commandItem = fmt.Sprintf("cat %s | grep -aE 'Failed password for|Connection closed by authenticating user' | grep -a 'preauth' %s", file.Name, command)
default:
commandItem = fmt.Sprintf("cat %s | grep -aE \"(Connection closed by authenticating user|Accepted)\" | grep -v 'invalid' %s", file.Name, command)
commandItem = fmt.Sprintf("cat %s | grep -aE \"(Failed password for|Connection closed by authenticating user|Accepted)\" | grep -v 'invalid' %s", file.Name, command)
}
}
dataItem, successCount, failedCount := loadSSHData(commandItem, showCountFrom, showCountTo, file.Year, qqWry, nyc)
@@ -303,6 +304,89 @@ func (u *SSHService) LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error) {
return &data, nil
}
func (u *SSHService) AnalysisLog(req dto.SearchForAnalysis) (*dto.AnalysisRes, error) {
var fileList []string
baseDir := "/var/log"
if err := filepath.Walk(baseDir, func(pathItem string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && (strings.HasPrefix(info.Name(), "secure") || strings.HasPrefix(info.Name(), "auth")) {
if !strings.HasSuffix(info.Name(), ".gz") {
fileList = append(fileList, pathItem)
return nil
}
itemFileName := strings.TrimSuffix(pathItem, ".gz")
if _, err := os.Stat(itemFileName); err != nil && os.IsNotExist(err) {
if err := handleGunzip(pathItem); err == nil {
fileList = append(fileList, itemFileName)
}
}
}
return nil
}); err != nil {
return nil, err
}
command := ""
sortMap := make(map[string]dto.SSHLogAnalysis)
for _, file := range fileList {
commandItem := ""
if strings.HasPrefix(path.Base(file), "secure") {
commandItem = fmt.Sprintf("cat %s | grep -aE '(Failed password for|Accepted)' | grep -v 'invalid' %s", file, command)
}
if strings.HasPrefix(path.Base(file), "auth.log") {
commandItem = fmt.Sprintf("cat %s | grep -aE \"(Connection closed by authenticating user|Accepted)\" | grep -v 'invalid' %s", file, command)
}
loadSSHDataForAnalysis(sortMap, commandItem)
}
var sortSlice []dto.SSHLogAnalysis
for key, value := range sortMap {
sortSlice = append(sortSlice, dto.SSHLogAnalysis{Address: key, SuccessfulCount: value.SuccessfulCount, FailedCount: value.FailedCount, Status: "accept"})
}
if req.OrderBy == constant.StatusSuccess {
sort.Slice(sortSlice, func(i, j int) bool {
return sortSlice[i].SuccessfulCount > sortSlice[j].SuccessfulCount
})
} else {
sort.Slice(sortSlice, func(i, j int) bool {
return sortSlice[i].FailedCount > sortSlice[j].FailedCount
})
}
qqWry, _ := qqwry.NewQQwry()
rules, _ := listIpRules("drop")
for i := 0; i < len(sortSlice); i++ {
sortSlice[i].Area = qqWry.Find(sortSlice[i].Address).Area
for _, rule := range rules {
if sortSlice[i].Address == rule {
sortSlice[i].Status = "drop"
break
}
}
}
var backData dto.AnalysisRes
for _, item := range sortSlice {
backData.FailedCount += item.FailedCount
backData.SuccessfulCount += item.SuccessfulCount
}
var data []dto.SSHLogAnalysis
total, start, end := len(sortSlice), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total {
data = make([]dto.SSHLogAnalysis, 0)
} else {
if end >= total {
end = total
}
data = sortSlice[start:end]
}
backData.Items = data
backData.Total = int64(total)
return &backData, nil
}
func (u *SSHService) LoadSSHConf() (string, error) {
if _, err := os.Stat("/etc/ssh/sshd_config"); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
@@ -324,7 +408,7 @@ func sortFileList(fileNames []sshFileItem) []sshFileItem {
return fileNames[i].Name > fileNames[j].Name
})
itemFile = append(itemFile, fileNames[len(fileNames)-1])
itemFile = append(itemFile, fileNames[:len(fileNames)-2]...)
itemFile = append(itemFile, fileNames[:len(fileNames)-1]...)
return itemFile
}
sort.Slice(fileNames, func(i, j int) bool {
@@ -382,7 +466,7 @@ func loadSSHData(command string, showCountFrom, showCountTo, currentYear int, qq
if len(itemData.Address) != 0 {
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
itemData.Area = qqWry.Find(itemData.Address).Area
itemData.Date, _ = time.ParseInLocation("2006 Jan 2 15:04:05", fmt.Sprintf("%d %s", currentYear, itemData.DateStr), nyc)
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
datas = append(datas, itemData)
}
failedCount++
@@ -392,7 +476,7 @@ func loadSSHData(command string, showCountFrom, showCountTo, currentYear int, qq
if len(itemData.Address) != 0 {
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
itemData.Area = qqWry.Find(itemData.Address).Area
itemData.Date, _ = time.ParseInLocation("2006 Jan 2 15:04:05", fmt.Sprintf("%d %s", currentYear, itemData.DateStr), nyc)
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
datas = append(datas, itemData)
}
failedCount++
@@ -402,7 +486,7 @@ func loadSSHData(command string, showCountFrom, showCountTo, currentYear int, qq
if len(itemData.Address) != 0 {
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
itemData.Area = qqWry.Find(itemData.Address).Area
itemData.Date, _ = time.ParseInLocation("2006 Jan 2 15:04:05", fmt.Sprintf("%d %s", currentYear, itemData.DateStr), nyc)
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
datas = append(datas, itemData)
}
successCount++
@@ -412,19 +496,75 @@ func loadSSHData(command string, showCountFrom, showCountTo, currentYear int, qq
return datas, successCount, failedCount
}
func loadSSHDataForAnalysis(analysisMap map[string]dto.SSHLogAnalysis, commandItem string) {
stdout, err := cmd.Exec(commandItem)
if err != nil {
return
}
lines := strings.Split(string(stdout), "\n")
for i := len(lines) - 1; i >= 0; i-- {
var itemData dto.SSHHistory
switch {
case strings.Contains(lines[i], "Failed password for"):
itemData = loadFailedSecureDatas(lines[i])
case strings.Contains(lines[i], "Connection closed by authenticating user"):
itemData = loadFailedAuthDatas(lines[i])
case strings.Contains(lines[i], "Accepted "):
itemData = loadSuccessDatas(lines[i])
}
if len(itemData.Address) != 0 {
if val, ok := analysisMap[itemData.Address]; ok {
if itemData.Status == constant.StatusSuccess {
val.SuccessfulCount++
} else {
val.FailedCount++
}
analysisMap[itemData.Address] = val
} else {
item := dto.SSHLogAnalysis{
Address: itemData.Address,
SuccessfulCount: 0,
FailedCount: 0,
}
if itemData.Status == constant.StatusSuccess {
item.SuccessfulCount = 1
} else {
item.FailedCount = 1
}
analysisMap[itemData.Address] = item
}
}
}
}
func loadSuccessDatas(line string) dto.SSHHistory {
var data dto.SSHHistory
parts := strings.Fields(line)
if len(parts) < 14 {
return data
}
data = dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[6],
User: parts[8],
Address: parts[10],
Port: parts[12],
Status: constant.StatusSuccess,
t, err := time.Parse("2006-01-02T15:04:05.999999-07:00", parts[0])
if err != nil {
if len(parts) < 14 {
return data
}
data = dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[6],
User: parts[8],
Address: parts[10],
Port: parts[12],
Status: constant.StatusSuccess,
}
} else {
if len(parts) < 12 {
return data
}
data = dto.SSHHistory{
DateStr: t.Format("2006 Jan 2 15:04:05"),
AuthMode: parts[4],
User: parts[6],
Address: parts[8],
Port: parts[10],
Status: constant.StatusSuccess,
}
}
return data
}
@@ -432,16 +572,31 @@ func loadSuccessDatas(line string) dto.SSHHistory {
func loadFailedAuthDatas(line string) dto.SSHHistory {
var data dto.SSHHistory
parts := strings.Fields(line)
if len(parts) < 14 {
return data
}
data = dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[8],
User: parts[10],
Address: parts[11],
Port: parts[13],
Status: constant.StatusFailed,
t, err := time.Parse("2006-01-02T15:04:05.999999-07:00", parts[0])
if err != nil {
if len(parts) < 14 {
return data
}
data = dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[8],
User: parts[10],
Address: parts[11],
Port: parts[13],
Status: constant.StatusFailed,
}
} else {
if len(parts) < 12 {
return data
}
data = dto.SSHHistory{
DateStr: t.Format("2006 Jan 2 15:04:05"),
AuthMode: parts[6],
User: parts[7],
Address: parts[9],
Port: parts[11],
Status: constant.StatusFailed,
}
}
if strings.Contains(line, ": ") {
data.Message = strings.Split(line, ": ")[1]
@@ -452,21 +607,39 @@ func loadFailedAuthDatas(line string) dto.SSHHistory {
func loadFailedSecureDatas(line string) dto.SSHHistory {
var data dto.SSHHistory
parts := strings.Fields(line)
if len(parts) < 14 {
return data
}
data = dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[6],
User: parts[8],
Address: parts[10],
Port: parts[12],
Status: constant.StatusFailed,
t, err := time.Parse("2006-01-02T15:04:05.999999-07:00", parts[0])
if err != nil {
if len(parts) < 14 {
return data
}
data = dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[6],
User: parts[8],
Address: parts[10],
Port: parts[12],
Status: constant.StatusFailed,
}
} else {
if len(parts) < 12 {
return data
}
index := 0
if strings.Contains(line, " invalid user") {
index = 2
}
data = dto.SSHHistory{
DateStr: t.Format("2006 Jan 2 15:04:05"),
AuthMode: parts[4],
User: parts[index+6],
Address: parts[index+8],
Port: parts[index+10],
Status: constant.StatusFailed,
}
}
if strings.Contains(line, ": ") {
data.Message = strings.Split(line, ": ")[1]
}
return data
}
@@ -485,3 +658,11 @@ func loadServiceName() (string, error) {
}
return "", errors.New("The ssh or sshd service is unavailable")
}
func loadDate(currentYear int, DateStr string, nyc *time.Location) time.Time {
itemDate, err := time.ParseInLocation("2006 Jan 2 15:04:05", fmt.Sprintf("%d %s", currentYear, DateStr), nyc)
if err != nil {
itemDate, _ = time.ParseInLocation("2006 Jan 2 15:04:05", DateStr, nyc)
}
return itemDate
}
+4 -4
View File
@@ -132,25 +132,25 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
global.LOG.Info("backup original data successful, now start to upgrade!")
if err := cpBinary([]string{tmpDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
u.handleRollback(fileOp, originalDir, 1)
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
u.handleRollback(fileOp, originalDir, 1)
return
}
if err := cpBinary([]string{tmpDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
u.handleRollback(fileOp, originalDir, 2)
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
u.handleRollback(fileOp, originalDir, 2)
return
}
if _, err := cmd.Execf("sed -i -e 's#BASE_DIR=.*#BASE_DIR=%s#g' /usr/local/bin/1pctl", global.CONF.System.BaseDir); err != nil {
u.handleRollback(fileOp, originalDir, 2)
global.LOG.Errorf("upgrade basedir in 1pctl failed, err: %v", err)
u.handleRollback(fileOp, originalDir, 2)
return
}
if err := cpBinary([]string{tmpDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
u.handleRollback(fileOp, originalDir, 3)
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
u.handleRollback(fileOp, originalDir, 3)
return
}
+107 -61
View File
@@ -185,10 +185,57 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
return err
}
defaultHttpPort := nginxInstall.HttpPort
primaryDomainArray := strings.Split(create.PrimaryDomain, ":")
primaryDomain := primaryDomainArray[0]
var (
domains []model.WebsiteDomain
ports = make(map[int]struct{})
)
domainArray := strings.Split(create.OtherDomains, "\n")
domainArray = append(domainArray, create.PrimaryDomain)
for _, domain := range domainArray {
if domain == "" {
continue
}
domainModel, err := getDomain(domain, defaultHttpPort)
if err != nil {
return err
}
if reflect.DeepEqual(domainModel, model.WebsiteDomain{}) {
continue
}
domains = append(domains, domainModel)
if domainModel.Port != defaultHttpPort {
ports[domainModel.Port] = struct{}{}
}
}
for port := range ports {
if existPorts, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithPort(port)); len(existPorts) == 0 {
errMap := make(map[string]interface{})
errMap["port"] = port
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithPort(port))
if appInstall.ID > 0 {
errMap["type"] = i18n.GetMsgByKey("TYPE_APP")
errMap["name"] = appInstall.Name
return buserr.WithMap("ErrPortExist", errMap, nil)
}
runtime, _ := runtimeRepo.GetFirst(runtimeRepo.WithPort(port))
if runtime != nil {
errMap["type"] = i18n.GetMsgByKey("TYPE_RUNTIME")
errMap["name"] = runtime.Name
return buserr.WithMap("ErrPortExist", errMap, nil)
}
if common.ScanPort(create.Port) {
return buserr.WithDetail(constant.ErrPortInUsed, create.Port, nil)
}
}
}
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
website := &model.Website{
PrimaryDomain: create.PrimaryDomain,
PrimaryDomain: primaryDomain,
Type: create.Type,
Alias: create.Alias,
Remark: create.Remark,
@@ -261,61 +308,46 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
return err
}
website.RuntimeID = runtime.ID
if runtime.Resource == constant.ResourceAppstore {
var (
req request.AppInstallCreate
nginxInstall model.AppInstall
install *model.AppInstall
)
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
req.Name = reg.ReplaceAllString(strings.ToLower(create.PrimaryDomain), "")
req.AppDetailId = create.AppInstall.AppDetailId
req.Params = create.AppInstall.Params
req.Params["IMAGE_NAME"] = runtime.Image
req.AppContainerConfig = create.AppInstall.AppContainerConfig
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
switch runtime.Type {
case constant.RuntimePHP:
if runtime.Resource == constant.ResourceAppstore {
var (
req request.AppInstallCreate
install *model.AppInstall
)
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
req.Name = reg.ReplaceAllString(strings.ToLower(create.PrimaryDomain), "")
req.AppDetailId = create.AppInstall.AppDetailId
req.Params = create.AppInstall.Params
req.Params["IMAGE_NAME"] = runtime.Image
req.AppContainerConfig = create.AppInstall.AppContainerConfig
req.Params["PANEL_WEBSITE_DIR"] = path.Join(nginxInstall.GetPath(), "/www")
tx, installCtx := getTxAndContext()
install, err = NewIAppService().Install(installCtx, req)
if err != nil {
tx.Rollback()
return err
}
tx.Commit()
website.AppInstallID = install.ID
appInstall = install
website.Proxy = fmt.Sprintf("127.0.0.1:%d", appInstall.HttpPort)
} else {
website.ProxyType = create.ProxyType
if website.ProxyType == constant.RuntimeProxyUnix {
proxy = fmt.Sprintf("unix:%s", path.Join("/www/sites", website.Alias, "php-pool", "php-fpm.sock"))
}
if website.ProxyType == constant.RuntimeProxyTcp {
proxy = fmt.Sprintf("127.0.0.1:%d", create.Port)
}
website.Proxy = proxy
}
req.Params["PANEL_WEBSITE_DIR"] = path.Join(nginxInstall.GetPath(), "/www")
tx, installCtx := getTxAndContext()
install, err = NewIAppService().Install(installCtx, req)
if err != nil {
tx.Rollback()
return err
}
tx.Commit()
website.AppInstallID = install.ID
appInstall = install
website.Proxy = fmt.Sprintf("127.0.0.1:%d", appInstall.HttpPort)
} else {
website.ProxyType = create.ProxyType
if website.ProxyType == constant.RuntimeProxyUnix {
proxy = fmt.Sprintf("unix:%s", path.Join("/www/sites", website.Alias, "php-pool", "php-fpm.sock"))
}
if website.ProxyType == constant.RuntimeProxyTcp {
proxy = fmt.Sprintf("127.0.0.1:%d", create.Port)
}
website.Proxy = proxy
case constant.RuntimeNode:
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
}
}
var domains []model.WebsiteDomain
domains = append(domains, model.WebsiteDomain{Domain: website.PrimaryDomain, Port: defaultHttpPort})
otherDomainArray := strings.Split(create.OtherDomains, "\n")
for _, domain := range otherDomainArray {
if domain == "" {
continue
}
domainModel, err := getDomain(domain, defaultHttpPort)
if err != nil {
return err
}
if reflect.DeepEqual(domainModel, model.WebsiteDomain{}) {
continue
}
domains = append(domains, domainModel)
}
if err = configDefaultNginx(website, domains, appInstall, runtime); err != nil {
return err
}
@@ -460,15 +492,21 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
return domainModel, err
}
if existDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithPort(create.Port)); len(existDomains) == 0 {
if existAppInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithPort(create.Port)); !reflect.DeepEqual(existAppInstall, model.AppInstall{}) {
return domainModel, buserr.WithMap(constant.ErrPortInOtherApp, map[string]interface{}{"port": create.Port, "apps": existAppInstall.App.Name}, nil)
}
if common.ScanPort(create.Port) {
return domainModel, buserr.WithDetail(constant.ErrPortInUsed, create.Port, nil)
if create.Port != httpPort {
if existPorts, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithPort(create.Port)); len(existPorts) == 0 {
if existAppInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithPort(create.Port)); existAppInstall.ID > 0 {
return domainModel, buserr.WithMap(constant.ErrPortInOtherApp, map[string]interface{}{"port": create.Port, "apps": existAppInstall.App.Name}, nil)
}
if common.ScanPort(create.Port) {
return domainModel, buserr.WithDetail(constant.ErrPortInUsed, create.Port, nil)
}
}
}
if existDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithDomain(create.Domain), websiteDomainRepo.WithPort(create.Port)); len(existDomains) > 0 {
return domainModel, buserr.WithDetail(constant.ErrDomainIsExist, create.Domain, nil)
}
website, err := websiteRepo.GetFirst(commonRepo.WithByID(create.WebsiteID))
if err != nil {
return domainModel, err
@@ -476,7 +514,11 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
if oldDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(create.WebsiteID), websiteDomainRepo.WithPort(create.Port)); len(oldDomains) == 0 {
ports = append(ports, create.Port)
}
domains = append(domains, create.Domain)
if oldDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(create.WebsiteID), websiteDomainRepo.WithDomain(create.Domain)); len(oldDomains) == 0 {
domains = append(domains, create.Domain)
}
if err := addListenAndServerName(website, ports, domains); err != nil {
return domainModel, err
}
@@ -955,10 +997,11 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
}
var nginxParams []dto.NginxParam
nginxParams = append(nginxParams, dto.NginxParam{
Name: key,
Name: key,
Params: []string{"off"},
})
if err := deleteNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
if err := updateNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
return nil, err
}
if err := websiteRepo.Save(context.Background(), &website); err != nil {
@@ -1211,6 +1254,9 @@ func (w WebsiteService) UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) er
if err := files.NewFileOp().WriteFile(configPath, strings.NewReader(req.Content), 0755); err != nil {
return err
}
if _, err := compose.Restart(runtimeInstall.GetComposePath()); err != nil {
return err
}
return nil
}
+3 -1
View File
@@ -135,7 +135,9 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
return res, err
}
websiteSSL.DnsAccountID = create.DnsAccountID
if create.Provider == constant.DNSAccount {
websiteSSL.DnsAccountID = create.DnsAccountID
}
websiteSSL.AcmeAccountID = acmeAccount.ID
websiteSSL.Provider = create.Provider
websiteSSL.Domains = strings.Join(otherDomainArray, ",")
+14 -12
View File
@@ -154,7 +154,7 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website,
}
}
}
if website.Type == constant.Static || website.Type == constant.Runtime {
if website.Type == constant.Static || (website.Type == constant.Runtime && runtime.Type == constant.RuntimePHP) {
if err := createIndexFile(website, runtime); err != nil {
return err
}
@@ -216,20 +216,22 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
server.UpdateDirective("include", []string{nginxInclude})
case constant.Runtime:
if runtime.Resource == constant.ResourceLocal {
switch runtime.Type {
case constant.RuntimePHP:
server.UpdateRoot(rootIndex)
localPath := path.Join(nginxInstall.GetPath(), rootIndex, "index.php")
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
}
}
if runtime.Resource == constant.ResourceAppstore {
switch runtime.Type {
case constant.RuntimePHP:
switch runtime.Type {
case constant.RuntimePHP:
if runtime.Resource == constant.ResourceLocal {
switch runtime.Type {
case constant.RuntimePHP:
server.UpdateRoot(rootIndex)
localPath := path.Join(nginxInstall.GetPath(), rootIndex, "index.php")
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
}
} else {
server.UpdateRoot(rootIndex)
server.UpdatePHPProxy([]string{website.Proxy}, "")
}
case constant.RuntimeNode:
proxy := fmt.Sprintf("http://127.0.0.1:%d", runtime.Port)
server.UpdateRootProxy([]string{proxy})
}
}
+18 -6
View File
@@ -49,7 +49,6 @@ var (
var (
ErrPortInUsed = "ErrPortInUsed"
ErrAppLimit = "ErrAppLimit"
ErrFileToLarge = "ErrFileToLarge"
ErrFileCanNotRead = "ErrFileCanNotRead"
ErrNotInstall = "ErrNotInstall"
ErrPortInOtherApp = "ErrPortInOtherApp"
@@ -60,6 +59,7 @@ var (
ErrFileParse = "ErrFileParse"
ErrInstallDirNotFound = "ErrInstallDirNotFound"
ErrContainerName = "ErrContainerName"
ErrAppNameExist = "ErrAppNameExist"
)
// website
@@ -114,11 +114,14 @@ var (
// runtime
var (
ErrDirNotFound = "ErrDirNotFound"
ErrFileNotExist = "ErrFileNotExist"
ErrImageBuildErr = "ErrImageBuildErr"
ErrImageExist = "ErrImageExist"
ErrDelWithWebsite = "ErrDelWithWebsite"
ErrDirNotFound = "ErrDirNotFound"
ErrFileNotExist = "ErrFileNotExist"
ErrImageBuildErr = "ErrImageBuildErr"
ErrImageExist = "ErrImageExist"
ErrDelWithWebsite = "ErrDelWithWebsite"
ErrRuntimeStart = "ErrRuntimeStart"
ErrPackageJsonNotFound = "ErrPackageJsonNotFound"
ErrScriptsNotFound = "ErrScriptsNotFound"
)
var (
@@ -126,3 +129,12 @@ var (
ErrOSSConn = "ErrOSSConn"
ErrEntrance = "ErrEntrance"
)
var (
ErrFirewall = "ErrFirewall"
)
// cronjob
var (
ErrBashExecute = "ErrBashExecute"
)
+22 -4
View File
@@ -4,12 +4,30 @@ const (
ResourceLocal = "local"
ResourceAppstore = "appstore"
RuntimeNormal = "normal"
RuntimeError = "error"
RuntimeBuildIng = "building"
RuntimeNormal = "normal"
RuntimeError = "error"
RuntimeBuildIng = "building"
RuntimeStarting = "starting"
RuntimeRunning = "running"
RuntimeReCreating = "recreating"
RuntimeStopped = "stopped"
RuntimeUnhealthy = "unhealthy"
RuntimeCreating = "creating"
RuntimePHP = "php"
RuntimePHP = "php"
RuntimeNode = "node"
RuntimeProxyUnix = "unix"
RuntimeProxyTcp = "tcp"
RuntimeUp = "up"
RuntimeDown = "down"
RuntimeRestart = "restart"
RuntimeInstall = "install"
RuntimeUninstall = "uninstall"
RuntimeUpdate = "update"
RuntimeNpm = "npm"
RuntimeYarn = "yarn"
)
+17 -1
View File
@@ -14,6 +14,10 @@ ErrNameIsExist: "Name is already exist"
ErrDemoEnvironment: "Demo server, prohibit this operation!"
ErrCmdTimeout: "Command execution timed out!"
ErrCmdIllegal: "The command contains illegal characters. Please modify and try again!"
ErrPortExist: '{{ .port }} port is already occupied by {{ .type }} [{{ .name }}]'
TYPE_APP: "Application"
TYPE_RUNTIME: "Runtime environment"
TYPE_DOMAIN: "Domain name"
#app
ErrPortInUsed: "{{ .detail }} port already in use"
@@ -47,6 +51,7 @@ ErrContainerMsg: '{{ .name }} container is abnormal, please check the log on the
ErrAppBackup: '{{ .name }} application backup failed err {{.err}}'
ErrImagePull: '{{ .name }} image pull failed err {{.err}}'
ErrVersionTooLow: 'The current 1Panel version is too low to update the app store, please upgrade the version'
ErrAppNameExist: 'App name is already exist'
#file
ErrFileCanNotRead: "File can not read"
@@ -99,6 +104,11 @@ ErrFileNotExist: "{{ .detail }} file does not exist! Please check source file in
ErrImageBuildErr: "Image build failed"
ErrImageExist: "Image is already exist!"
ErrDelWithWebsite: "The operating environment has been associated with a website and cannot be deleted"
ErrRuntimeStart: "Failed to start"
ErrPackageJsonNotFound: "package.json file does not exist"
ErrScriptsNotFound: "No scripts configuration item was found in package.json"
ErrContainerNameNotFound: "Unable to get container name, please check .env file"
ErrNodeModulesNotFound: "The node_modules folder does not exist! Please edit the running environment or wait for the running environment to start successfully"
#setting
ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted."
@@ -111,4 +121,10 @@ ErrConfigParse: "Configuration file format error"
ErrConfigIsNull: "The configuration file is not allowed to be empty"
ErrConfigDirNotFound: "The running directory does not exist"
ErrConfigAlreadyExist: "A configuration file with the same name already exists"
ErrUserFindErr: "Failed to find user {{ .name }} {{ .err }}"
ErrUserFindErr: "Failed to find user {{ .name }} {{ .err }}"
#ssh
ErrFirewall: "No firewalld or ufw service is detected. Please check and try again!"
#cronjob
ErrBashExecute: "Script execution error, please check the specific information in the task output text area."
+16
View File
@@ -14,6 +14,10 @@ ErrNameIsExist: "名稱已存在"
ErrDemoEnvironment: "演示伺服器,禁止此操作!"
ErrCmdTimeout: "指令執行超時!"
ErrCmdIllegal: "執行命令中存在不合法字符,請修改後重試!"
ErrPortExist: '{{ .port }} 埠已被 {{ .type }} [{{ .name }}] 佔用'
TYPE_APP: "應用"
TYPE_RUNTIME: "運作環境"
TYPE_DOMAIN: "網域名稱"
#app
ErrPortInUsed: "{{ .detail }} 端口已被佔用!"
@@ -47,6 +51,7 @@ ErrContainerMsg: '{{ .name }} 容器異常,具體請在容器頁面查看日
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{.err}}'
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{.err}}'
ErrVersionTooLow: '當前 1Panel 版本過低,無法更新應用商店,請升級版本之後操作'
ErrAppNameExist: '應用名稱已存在'
#file
ErrFileCanNotRead: "此文件不支持預覽"
@@ -99,6 +104,11 @@ ErrFileNotExist: "{{ .detail }} 文件不存在!請檢查源文件完整性!
ErrImageBuildErr: "鏡像 build 失敗"
ErrImageExist: "鏡像已存在!"
ErrDelWithWebsite: "運行環境已經關聯網站,無法刪除"
ErrRuntimeStart: "啟動失敗"
ErrPackageJsonNotFound: "package.json 文件不存在"
ErrScriptsNotFound: "沒有在 package.json 中找到 scripts 配置項"
ErrContainerNameNotFound: "無法取得容器名稱,請檢查 .env 文件"
ErrNodeModulesNotFound: "node_modules 文件夾不存在!請編輯運行環境或者等待運行環境啟動成功"
#setting
ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除"
@@ -112,3 +122,9 @@ ErrConfigIsNull: "配置文件不允許為空"
ErrConfigDirNotFound: "運行目錄不存在"
ErrConfigAlreadyExist: "已存在同名配置文件"
ErrUserFindErr: "用戶 {{ .name }} 查找失敗 {{ .err }}"
#ssh
ErrFirewall: "當前未檢測到系統 firewalld 或 ufw 服務,請檢查後重試!"
#cronjob
ErrBashExecute: "腳本執行錯誤,請在任務輸出文本域中查看具體信息。"
+16
View File
@@ -14,6 +14,10 @@ ErrNameIsExist: "名称已存在"
ErrDemoEnvironment: "演示服务器,禁止此操作!"
ErrCmdTimeout: "命令执行超时!"
ErrCmdIllegal: "执行命令中存在不合法字符,请修改后重试!"
ErrPortExist: '{{ .port }} 端口已被 {{ .type }} [{{ .name }}] 占用'
TYPE_APP: "应用"
TYPE_RUNTIME: "运行环境"
TYPE_DOMAIN: "域名"
#app
ErrPortInUsed: "{{ .detail }} 端口已被占用!"
@@ -47,6 +51,7 @@ ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日
ErrAppBackup: '{{ .name }} 应用备份失败 err {{.err}}'
ErrImagePull: '镜像拉取失败 {{.err}}'
ErrVersionTooLow: '当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作'
ErrAppNameExist: '应用名称已存在'
#file
ErrFileCanNotRead: "此文件不支持预览"
@@ -99,6 +104,11 @@ ErrFileNotExist: "{{ .detail }} 文件不存在!请检查源文件完整性!
ErrImageBuildErr: "镜像 build 失败"
ErrImageExist: "镜像已存在!"
ErrDelWithWebsite: "运行环境已经关联网站,无法删除"
ErrRuntimeStart: "启动失败"
ErrPackageJsonNotFound: "package.json 文件不存在"
ErrScriptsNotFound: "没有在 package.json 中找到 scripts 配置项"
ErrContainerNameNotFound: "无法获取容器名称,请检查 .env 文件"
ErrNodeModulesNotFound: "node_modules 文件夹不存在!请编辑运行环境或者等待运行环境启动成功"
#setting
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
@@ -112,3 +122,9 @@ ErrConfigIsNull: "配置文件不允许为空"
ErrConfigDirNotFound: "运行目录不存在"
ErrConfigAlreadyExist: "已存在同名配置文件"
ErrUserFindErr: "用户 {{ .name }} 查找失败 {{ .err }}"
#ssh
ErrFirewall: "当前未检测到系统 firewalld 或 ufw 服务,请检查后重试!"
#cronjob
ErrBashExecute: "脚本执行错误,请在任务输出文本域中查看具体信息。"
+3 -14
View File
@@ -6,26 +6,15 @@ import (
)
func Init() {
syncApp()
syncInstalledApp()
go syncApp()
go syncInstalledApp()
}
func syncApp() {
setting, err := service.NewISettingService().GetSettingInfo()
if err != nil {
global.LOG.Errorf("sync app error: %s", err.Error())
return
}
if setting.AppStoreLastModified != "0" {
global.LOG.Info("no need to sync")
return
}
global.LOG.Info("sync app start...")
if err := service.NewIAppService().SyncAppListFromRemote(); err != nil {
global.LOG.Errorf("sync app error")
global.LOG.Errorf("App Store synchronization failed")
return
}
global.LOG.Info("sync app successful")
}
func syncInstalledApp() {
+4
View File
@@ -43,6 +43,10 @@ func Init() {
migrations.UpdateDatabase,
migrations.UpdateAppInstallResource,
migrations.DropDatabaseLocal,
migrations.AddDefaultNetwork,
migrations.UpdateRuntime,
migrations.UpdateTag,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
@@ -0,0 +1,46 @@
package migrations
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
)
var AddDefaultNetwork = &gormigrate.Migration{
ID: "20230928-add-default-network",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "DefaultNetwork", Value: "all"}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "LastCleanTime", Value: ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "LastCleanSize", Value: ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "LastCleanData", Value: ""}).Error; err != nil {
return err
}
return nil
},
}
var UpdateRuntime = &gormigrate.Migration{
ID: "20230927-update-runtime",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Runtime{}); err != nil {
return err
}
return nil
},
}
var UpdateTag = &gormigrate.Migration{
ID: "20231008-update-tag",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Tag{}); err != nil {
return err
}
return nil
},
}
+11 -2
View File
@@ -1,12 +1,13 @@
package middleware
import (
"net/http"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
var whiteUrlList = map[string]struct{}{
@@ -18,6 +19,14 @@ var whiteUrlList = map[string]struct{}{
"/api/v1/logs/operation": {},
"/api/v1/logs/login": {},
"/api/v1/auth/logout": {},
"/api/v1/apps/installed/loadport": {},
"/api/v1/apps/installed/check": {},
"/api/v1/apps/installed/conninfo": {},
"/api/v1/databases/load/file": {},
"/api/v1/databases/variables": {},
"/api/v1/databases/status": {},
"/api/v1/databases/baseinfo": {},
}
func DemoHandle() gin.HandlerFunc {
+29 -1
View File
@@ -2,11 +2,13 @@ package middleware
import (
"errors"
"net"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
)
@@ -25,7 +27,10 @@ func WhiteAllow() gin.HandlerFunc {
}
clientIP := c.ClientIP()
for _, ip := range strings.Split(status.Value, ",") {
if len(ip) != 0 && ip == clientIP {
if len(ip) == 0 {
continue
}
if ip == clientIP || (strings.Contains(ip, "/") && checkIpInCidr(ip, clientIP)) {
c.Next()
return
}
@@ -33,3 +38,26 @@ func WhiteAllow() gin.HandlerFunc {
helper.ErrorWithDetail(c, constant.CodeErrIP, constant.ErrTypeInternalServer, errors.New("IP address not allowed"))
}
}
func checkIpInCidr(cidr, checkIP string) bool {
ip, ipNet, err := net.ParseCIDR(cidr)
if err != nil {
global.LOG.Errorf("parse CIDR %s failed, err: %v", cidr, err)
return false
}
for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); incIP(ip) {
if ip.String() == checkIP {
return true
}
}
return false
}
func incIP(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
+15 -15
View File
@@ -90,8 +90,8 @@ func OperationLog() gin.HandlerFunc {
}
}
}
if len(operationDic.BeforeFuntions) != 0 {
for _, funcs := range operationDic.BeforeFuntions {
if len(operationDic.BeforeFunctions) != 0 {
for _, funcs := range operationDic.BeforeFunctions {
for key, value := range formatMap {
if funcs.InputValue == key {
var names []string
@@ -109,9 +109,9 @@ func OperationLog() gin.HandlerFunc {
}
for key, value := range formatMap {
if strings.Contains(operationDic.FormatEN, "["+key+"]") {
if arrys, ok := value.([]string); ok {
operationDic.FormatZH = strings.ReplaceAll(operationDic.FormatZH, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(arrys, ",")))
operationDic.FormatEN = strings.ReplaceAll(operationDic.FormatEN, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(arrys, ",")))
if arrays, ok := value.([]string); ok {
operationDic.FormatZH = strings.ReplaceAll(operationDic.FormatZH, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(arrays, ",")))
operationDic.FormatEN = strings.ReplaceAll(operationDic.FormatEN, "["+key+"]", fmt.Sprintf("[%v]", strings.Join(arrays, ",")))
} else {
operationDic.FormatZH = strings.ReplaceAll(operationDic.FormatZH, "["+key+"]", fmt.Sprintf("[%v]", value))
operationDic.FormatEN = strings.ReplaceAll(operationDic.FormatEN, "["+key+"]", fmt.Sprintf("[%v]", value))
@@ -171,13 +171,13 @@ type swaggerJson struct {
}
type operationJson struct {
API string `json:"api"`
Method string `json:"method"`
BodyKeys []string `json:"bodyKeys"`
ParamKeys []string `json:"paramKeys"`
BeforeFuntions []functionInfo `json:"beforeFuntions"`
FormatZH string `json:"formatZH"`
FormatEN string `json:"formatEN"`
API string `json:"api"`
Method string `json:"method"`
BodyKeys []string `json:"bodyKeys"`
ParamKeys []string `json:"paramKeys"`
BeforeFunctions []functionInfo `json:"beforeFunctions"`
FormatZH string `json:"formatZH"`
FormatEN string `json:"formatEN"`
}
type functionInfo struct {
InputColumn string `json:"input_column"`
@@ -208,9 +208,9 @@ func loadLogInfo(path string) string {
if !strings.Contains(path, "/") {
return ""
}
pathArrys := strings.Split(path, "/")
if len(pathArrys) < 2 {
pathArrays := strings.Split(path, "/")
if len(pathArrays) < 2 {
return ""
}
return pathArrys[1]
return pathArrays[1]
}
+2 -1
View File
@@ -26,7 +26,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
baRouter.POST("/list", baseApi.ListContainer)
baRouter.GET("/list/stats", baseApi.ContainerListStats)
baRouter.GET("/search/log", baseApi.ContainerLogs)
baRouter.GET("/limit", baseApi.LoadResouceLimit)
baRouter.GET("/limit", baseApi.LoadResourceLimit)
baRouter.POST("/clean/log", baseApi.CleanContainerLog)
baRouter.POST("/load/log", baseApi.LoadContainerLog)
baRouter.POST("/inspect", baseApi.Inspect)
@@ -45,6 +45,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
baRouter.POST("/compose/test", baseApi.TestCompose)
baRouter.POST("/compose/operate", baseApi.OperatorCompose)
baRouter.POST("/compose/update", baseApi.ComposeUpdate)
baRouter.GET("/compose/search/log", baseApi.ComposeLogs)
baRouter.GET("/template", baseApi.ListComposeTemplate)
baRouter.POST("/template/search", baseApi.SearchComposeTemplate)
+1
View File
@@ -49,6 +49,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.GET("/db/list/:type", baseApi.ListDatabase)
cmdRouter.POST("/db/update", baseApi.UpdateDatabase)
cmdRouter.POST("/db/search", baseApi.SearchDatabase)
cmdRouter.POST("/db/del/check", baseApi.DeleteCheckDatabase)
cmdRouter.POST("/db/del", baseApi.DeleteDatabase)
}
}
+1
View File
@@ -41,6 +41,7 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
hostRouter.POST("/ssh/generate", baseApi.GenerateSSH)
hostRouter.POST("/ssh/secret", baseApi.LoadSSHSecret)
hostRouter.POST("/ssh/log", baseApi.LoadSSHLogs)
hostRouter.POST("/ssh/log/analysis", baseApi.AnalysisLog)
hostRouter.POST("/ssh/conffile/update", baseApi.UpdateSSHByfile)
hostRouter.POST("/ssh/operate", baseApi.OperateSSH)
+2 -2
View File
@@ -17,7 +17,7 @@ func (s *LogRouter) InitLogRouter(Router *gin.RouterGroup) {
operationRouter.POST("/login", baseApi.GetLoginLogs)
operationRouter.POST("/operation", baseApi.GetOperationLogs)
operationRouter.POST("/clean", baseApi.CleanLogs)
operationRouter.GET("/system", baseApi.GetSystemLogs)
operationRouter.GET("/system/files", baseApi.GetSystemFiles)
operationRouter.POST("/system", baseApi.GetSystemLogs)
}
}
+5
View File
@@ -20,5 +20,10 @@ func (r *RuntimeRouter) InitRuntimeRouter(Router *gin.RouterGroup) {
groupRouter.POST("/del", baseApi.DeleteRuntime)
groupRouter.POST("/update", baseApi.UpdateRuntime)
groupRouter.GET("/:id", baseApi.GetRuntime)
groupRouter.POST("/node/package", baseApi.GetNodePackageRunScript)
groupRouter.POST("/operate", baseApi.OperateRuntime)
groupRouter.POST("/node/modules", baseApi.GetNodeModules)
groupRouter.POST("/node/modules/operate", baseApi.OperateNodeModules)
}
}
+3 -1
View File
@@ -30,8 +30,10 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
settingRouter.GET("/time/option", baseApi.LoadTimeZone)
settingRouter.POST("/time/sync", baseApi.SyncTime)
settingRouter.POST("/monitor/clean", baseApi.CleanMonitor)
settingRouter.GET("/mfa/:interval", baseApi.GetMFA)
settingRouter.POST("/mfa", baseApi.LoadMFA)
settingRouter.POST("/mfa/bind", baseApi.MFABind)
settingRouter.POST("/scan", baseApi.ScanSystem)
settingRouter.POST("/clean", baseApi.SystemClean)
settingRouter.POST("/snapshot", baseApi.CreateSnapshot)
settingRouter.POST("/snapshot/status", baseApi.LoadSnapShotStatus)
+18 -12
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"io"
"os/exec"
"strings"
"time"
@@ -68,6 +69,18 @@ func ExecWithTimeOut(cmdStr string, timeout time.Duration) (string, error) {
return stdout.String(), nil
}
func ExecContainerScript(containerName, cmdStr string, timeout time.Duration) error {
cmdStr = fmt.Sprintf("docker exec -i %s bash -c '%s'", containerName, cmdStr)
out, err := ExecWithTimeOut(cmdStr, timeout)
if err != nil {
if out != "" {
return fmt.Errorf("%s; err: %v", out, err)
}
return err
}
return nil
}
func ExecCronjobWithTimeOut(cmdStr string, workdir string, timeout time.Duration) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
@@ -76,23 +89,16 @@ func ExecCronjobWithTimeOut(cmdStr string, workdir string, timeout time.Duration
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
output := new(bytes.Buffer)
cmd.Stdout = io.MultiWriter(output, cmd.Stdout)
cmd.Stderr = io.MultiWriter(output, cmd.Stderr)
err := cmd.Run()
if ctx.Err() == context.DeadlineExceeded {
return "", buserr.New(constant.ErrCmdTimeout)
}
errMsg := ""
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr:\n %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s \n\n; stdout:\n %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout:\n %s", stdout.String())
}
}
return errMsg, err
return output.String(), err
}
func Execf(cmdStr string, a ...interface{}) (string, error) {
+4
View File
@@ -80,6 +80,10 @@ func (c Client) DeleteImage(imageID string) error {
return nil
}
func (c Client) InspectContainer(containerID string) (types.ContainerJSON, error) {
return c.cli.ContainerInspect(context.Background(), containerID)
}
func (c Client) PullImage(imageName string, force bool) error {
if !force {
exist, err := c.CheckImageExist(imageName)
-26
View File
@@ -1,26 +0,0 @@
package encrypt
import (
"fmt"
"testing"
"github.com/1Panel-dev/1Panel/backend/init/viper"
)
func TestStringEncrypt(t *testing.T) {
viper.Init()
p, err := StringEncrypt("1Panel@2022")
if err != nil {
t.Fatal(err)
}
fmt.Println(p)
}
func TestStringDecrypt(t *testing.T) {
viper.Init()
p, err := StringDecrypt("dXn5bVtea+KVLDrLJlpnPIJNfW8TAMmqX1QNMdSGp88=")
if err != nil {
t.Fatal(err)
}
fmt.Println(p)
}
+13
View File
@@ -2,6 +2,7 @@ package env
import (
"fmt"
"github.com/joho/godotenv"
"os"
"sort"
"strconv"
@@ -37,3 +38,15 @@ func Marshal(envMap map[string]string) (string, error) {
sort.Strings(lines)
return strings.Join(lines, "\n"), nil
}
func GetEnvValueByKey(envPath, key string) (string, error) {
envMap, err := godotenv.Read(envPath)
if err != nil {
return "", err
}
value, ok := envMap[key]
if !ok {
return "", fmt.Errorf("key %s not found in %s", key, envPath)
}
return value, nil
}

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