Compare commits

...
179 Commits
Author SHA1 Message Date
ssongliu df53193f3f fix: 解决安装包下载路径错误的问题 (#4954) 2024-05-10 06:56:24 +00:00
ssongliu d5c75f4eee fix: 解决容器镜像推送失败的问题 (#4944) 2024-05-09 14:00:24 +00:00
zhengkunwang 76356eaf5b feat: WAF 增加 cdn 配置文件 (#4942) 2024-05-09 13:52:24 +00:00
ssongliu 5d9c09f69e fix: 解决数据库备份错误的问题 (#4941) 2024-05-09 13:50:24 +00:00
ssongliu e799d1cc49 fix: 解决关闭菜单选项时刷新跳转到概览页的问题 (#4939) 2024-05-09 07:44:23 +00:00
ssongliu 1090df3703 fix: 修改版本升级显示信息 (#4938) 2024-05-09 07:28:23 +00:00
zhengkunwang f3267bf137 style: 去掉多余的字符 (#4936) 2024-05-09 03:32:23 +00:00
zhengkunwang 0a426f3cd8 style: 调整证书编辑页面样式 (#4934) 2024-05-09 03:04:23 +00:00
zhengkunwang c6e1bb5245 fix: 解决自签证书火狐浏览器报错的问题 (#4926)
Refs https://github.com/1Panel-dev/1Panel/issues/4927
2024-05-08 10:48:23 +00:00
ssongliu 0fa027d01d fix: 解决升级信息获取失败的问题 (#4925) 2024-05-08 10:46:23 +00:00
zhengkunwang 395bc63946 fix: 解决网站备份恢复导致网站列表丢失的问题 (#4924) 2024-05-08 10:44:24 +00:00
John Bro 7a6d0c5380 fix: 文件列表后退、前进按钮,在根目录时无法点击问题修复 (#4923)
Refs #4723
2024-05-08 10:42:22 +00:00
ssongliu 1e192c18e7 fix: 解决容器执行 exit 退出后服务 panic 的问题 (#4922) 2024-05-08 09:38:24 +00:00
ssongliu d7df881da9 fix: 解决编排目录跳转失败的问题 (#4921)
Refs #4895
2024-05-08 09:36:23 +00:00
zhengkunwang a6f354fed9 style: 调整反向代理的源文页面大小 (#4917)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2024-05-08 06:38:23 +00:00
ssongliu be12c2397d feat: 切割网站日志计划任务增加默认周期 (#4916) 2024-05-08 06:36:23 +00:00
zhengkunwang bddb488baf fix: 解决中文域名创建 PHP 类型网站失败的问题 (#4915) 2024-05-08 06:34:23 +00:00
ssongliu 75c23271df fix: 解决获取版本升级信息失败的问题 (#4914) 2024-05-08 06:32:23 +00:00
zhengkunwang 34eb20a679 style: 解决英文状态下删除文件提示字符超出的问题 (#4913) 2024-05-08 06:30:24 +00:00
zhengkunwang b01d8949cb feat: 修改 supervisor 名称校验规则 (#4910) 2024-05-08 06:28:23 +00:00
zhengkunwang b489f5cf2f feat: 证书申请增加配置,提高申请成功率 (#4903) 2024-05-07 18:26:34 +08:00
zhengkunwang 43ebf6eef9 feat: 证书增加编辑功能 (#4901) 2024-05-07 18:01:00 +08:00
zhengkunwang 736914f443 fix: 解决进程守护启动命令带空格导致报错的问题 (#4894) 2024-05-07 18:00:48 +08:00
ssongliu 4243ccb5c2 feat: 增加许可证错误信息显示 (#4877) 2024-05-06 06:25:55 +00:00
zhengkunwang 539b600d6c feat: 网站默认配置增加支持 CDN 真实 IP (#4874) 2024-05-06 05:57:56 +00:00
John Bro e676a632b9 fix: 运行时运行目录选择器支持手动输入 (#4870)
Refs #2909
2024-05-06 05:55:56 +00:00
zhengkunwang 4f6a443b13 feat: 限制创建网站使用 default 代号 (#4869)
Refs https://github.com/1Panel-dev/1Panel/issues/4868
2024-05-06 05:53:56 +00:00
zhengkunwang 7684066689 fix: 解决计算文件夹大小线程没有回收的问题 (#4866)
Refs https://github.com/1Panel-dev/1Panel/issues/4867
2024-05-06 05:51:55 +00:00
maninhill 9719ef2edc chore: Update README.md 2024-05-03 12:23:50 +08:00
wanghe-fit2cloud a5b6121411 docs: Update README.md 2024-04-30 18:51:04 +08:00
ssongliu e8fb727676 feat: 计划任务应用、网站备份增加排除规则 (#4810) 2024-04-30 18:23:36 +08:00
ssongliu 164a48c99f pref: 优化计划任务错误显示 (#4803) 2024-04-30 17:33:15 +08:00
John Broandzhoujunhong e47d449b1b fix: 删除 PHP 和 Node.js 运行环境的提示信息优化 (#4790)
* fix: 删除 PHP 和 Node.js 运行环境的提示信息优化

* fix: 代码优化

* fix: 代码优化

---------

Co-authored-by: zhoujunhong <1298308460@qq.com>
2024-04-30 11:58:49 +08:00
zhengkunwang 5c46c26dd5 fix: 解决反向代理匹配规则为空之后无法删除的问题 (#4777)
Refs https://github.com/1Panel-dev/1Panel/issues/4771
2024-04-28 14:12:44 +00:00
zhengkunwang a40116d991 fix: 解决应用商店同步图标丢失的问题 (#4776) 2024-04-28 14:10:44 +00:00
zhengkunwang b0a3ecd3d2 fix: 解决第二次上传同名文件不显示的问题 (#4737) 2024-04-26 18:20:31 +08:00
ssongliu 29fd941d55 feat: 失败状态应用允许恢复 (#4732) 2024-04-26 18:20:19 +08:00
zhengkunwang 9851b31013 feat: 增加一些提示信息 (#4730) 2024-04-26 18:20:09 +08:00
ssongliu 6e635c691d style: 优化网站列表描述信息显示 (#4726) 2024-04-26 16:13:53 +08:00
ssongliu 5532636e02 style: 修改面板设置描述信息 (#4725) 2024-04-26 16:13:44 +08:00
John Broandzhoujunhong e47e2d63d1 feat: 文件管理页面增加回退功能 (#4723)
Co-authored-by: zhoujunhong <1298308460@qq.com>
2024-04-26 16:13:34 +08:00
ssongliu b9dde4ebf0 style: 优化概览页 CPU 显示 (#4721) 2024-04-26 16:13:12 +08:00
zhengkunwang 6a30ccd5dc perf: 优化错误日志超长下的显示 (#4711) 2024-04-25 11:09:13 +00:00
ssongliu ad6a1ac465 fix: Docker 配置自动过滤空行 (#4707)
Refs #4701
2024-04-25 11:07:12 +00:00
zhengkunwang 35f311c452 fix: 修复 WAF 地图英文模式下的显示错误 (#4704) 2024-04-25 17:48:54 +08:00
ssongliu c3dd6f2e0a pref: 释放容器 client 连接 (#4700) 2024-04-25 08:45:12 +00:00
ssongliu 94405d877f fix: 解决计划任务本地保存份数错误的问题 (#4692)
Refs #4671
2024-04-25 02:31:10 +00:00
ssongliu 9cd37e8ec5 feat: 增加内测模式 (#4685) 2024-04-24 15:12:12 +00:00
zhengkunwang 1381ef9e8e style: 优化中国地图显示 (#4681) 2024-04-24 15:10:14 +00:00
John Bro 42dffe8078 fix: 快速命令管理页面中增加关键词筛选 (#4679)
Refs #3525
2024-04-24 15:08:11 +00:00
zhengkunwang 92f019cf7c feat: 伪静态增加提示 (#4678) 2024-04-24 09:36:11 +00:00
zhengkunwang c23dfc374f fix: 解决应用升级失败没有回滚的问题 (#4677) 2024-04-24 09:34:10 +00:00
wanghe-fit2cloud 61f7374d71 docs: update CONTRIBUTING.md 2024-04-23 22:52:33 +08:00
John Bro 3fcb20d24c fix: 创建网站可以使用相同域名问题修复 (#4669)
Refs #4624
2024-04-23 14:10:09 +00:00
ssongliu d4b561e42d feat: 升级 golang.org/x/net 依赖 (#4662) 2024-04-23 10:06:09 +00:00
zhengkunwang b6b4bfe195 fix: 解决低版本 OpenResty 创建网站报错的问题 (#4661) 2024-04-23 10:04:09 +00:00
ssongliu dcc0264b67 fix: 解决容器内进程异常结束的问题 (#4660)
Refs #4653
2024-04-23 10:02:10 +00:00
ssongliu 15b1f28fb9 fix: 解决概览页折线图选择失败的问题 (#4656)
Refs #4647
2024-04-23 10:00:10 +00:00
ssongliuandssonglius11 4596f9c2c2 feat: 数据库支持 Mariadb 11.x (#4665)
Co-authored-by: ssonglius11 <ssonglius11@163.com>
2024-04-23 17:59:00 +08:00
ssongliu 3156c84b19 feat: 增加应用备份跳转目录 (#4648) 2024-04-23 03:20:08 +00:00
John Bro ac400c7188 fix: SSH 连接列表显示优化 (#4650)
Refs #4546
2024-04-23 03:18:06 +00:00
ssongliu 7fd672c1c9 feat: 升级回滚增加相关数据库文件 (#4638) 2024-04-22 14:22:27 +00:00
ssongliu 884a169a6f fix: 增加特殊字符命令过滤 (#4599) 2024-04-19 08:58:08 +00:00
ssongliu e79a5f9ae2 fix: 修改安全入口长度校验 (#4594) 2024-04-19 07:24:08 +00:00
ssongliu 25608e7378 fix: 修改许可证状态获取接口 (#4593)
Refs #4589
2024-04-19 07:22:08 +00:00
zhengkunwang dad8bac715 fix: 解决伪静态开启报错的问题 (#4591) 2024-04-19 07:20:08 +00:00
ssongliu a4ee16cf1f fix: 解决容器日志文件被删除但是进程未结束的问题 (#4588)
Refs #4582
2024-04-19 07:18:10 +00:00
dependabot[bot] 7f7465b383 chore(deps): bump github.com/docker/docker (#4586)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.0.0+incompatible to 26.0.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.0.0...v26.0.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 15:17:29 +08:00
zhengkunwang b7c3dc0d2a fix: 解决创建 PHP 网站首页无法访问的 BUG (#4577) 2024-04-18 14:40:07 +00:00
ssongliu bb02991b05 fix: 解决监控数据迁移失败的问题 (#4569)
Refs #4568
2024-04-18 14:38:06 +00:00
writegr a5fdff61ff chore: fix some typos (#4564)
Signed-off-by: writegr <wellweek@outlook.com>
2024-04-18 12:24:40 +08:00
zhengkunwang 4832081b82 fix: 解决文件上传权限错误的问题 (#4563) 2024-04-18 03:18:07 +00:00
ssongliu ef5a13f87f fix: 解决本地备份账号路径获取错误的问题 (#4560) 2024-04-18 02:36:06 +00:00
老广 e2bc8e800a docs: add projects to other readme (#4561) 2024-04-18 10:26:00 +08:00
老广 85a397949e Update README.md
Add our other projects
2024-04-17 17:08:35 +08:00
ssongliu 5cfdcedf9a fix: 解决容器日志缺失的问题 (#4549) 2024-04-17 08:52:07 +00:00
ssongliu c5bb8dab8c fix: 解决复制导致的快照失败问题 (#4547) 2024-04-17 07:28:07 +00:00
zhengkunwang f1421ba7f9 style: 修改文件编辑器配置样式 (#4535) 2024-04-16 18:59:30 +08:00
ssongliu 9e44db53a7 pref: 调整部分界面的高度问题 (#4534) 2024-04-16 18:59:14 +08:00
zhengkunwang 4814a76c47 style: 修改 openresty 的端口提示 (#4532) 2024-04-16 15:58:51 +08:00
ssongliu 2ec4b2561c feat: 修改服务初始化操作逻辑 (#4530) 2024-04-16 14:44:07 +08:00
wanghe 4efe7240ad Update tyops-check.yml 2024-04-16 13:57:03 +08:00
ssongliu ed13136221 feat: 增加许可证解绑功能 (#4522) 2024-04-15 18:37:05 +08:00
ssongliu 735fc75e35 feat: 登陆时加载许可证状态 (#4520) 2024-04-15 18:06:38 +08:00
xuwei-fit2cloud b8a52ae707 chore: 添加拼写检查Action 2024-04-15 17:58:36 +08:00
John Bro 2501a9f78a fix: 修复容器未指定 IP 编辑显示报错问题 (#4519) 2024-04-15 07:12:10 +00:00
Langel 5a8d6db43e feat: 增加菜单标签页功能 (#3267) (#4510) 2024-04-15 15:10:24 +08:00
ssongliu a3312331d2 feat: 解决登录页授权 IP 跳转失败的问题 (#4517) 2024-04-15 07:10:10 +00:00
zhengkunwang fbd0e836d7 fix:解决新建文件夹部分权限无法创建的问题 (#4515) 2024-04-15 07:08:10 +00:00
Craftsman 4935d88301 typos: Modify wrong words (#4518) 2024-04-15 15:05:00 +08:00
zhengkunwang 8625979cc3 feat: 修改 supervisor 名称限制 (#4513) 2024-04-15 03:56:10 +00:00
zhengkunwang c77742e72e fix: 解决安装应用时候,原始 docker-compose.yml 的 deploy 字段下内容会被自动覆写的问题 (#4512)
Refs https://github.com/1Panel-dev/1Panel/issues/4340
2024-04-15 03:54:09 +00:00
John Bro 43a6b4b735 feat: 容器创建支持指定 IP 地址 (#4489)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2024-04-13 11:56:07 +00:00
mobeicanyue f4ee534101 fix typos (#4503) 2024-04-13 19:49:17 +08:00
ssongliu c055a07e57 fix: 解决概览页 CPU 核心过多导致的显示问题 (#4490)
Refs #3966
2024-04-13 11:44:07 +00:00
ssongliu 62bead5c50 fix: 修改登录页跳转问题 (#4487) 2024-04-12 08:20:07 +00:00
zhengkunwang 9edafc13a3 feat: 修改中国地区名称 (#4485) 2024-04-12 04:30:07 +00:00
zhengkunwang e6ccf8be1f fix: 解决文件搜索目录包含回收站目录能进入的问题 (#4484) 2024-04-12 04:08:06 +00:00
ssongliu 222089d56a fix: 修改系统版本比较方法 (#4483) 2024-04-12 03:04:06 +00:00
zhengkunwang 96e48847d0 fix: 解决特殊字符下文件放入回收站失败的问题 (#4480) 2024-04-11 11:08:11 +00:00
zhengkunwang 38b0c42555 feat: 增加回收站文件夹限制 (#4479) 2024-04-11 11:06:10 +00:00
zhengkunwang 2eae8274f6 fix: 创建文件增加非法字符校验 (#4478) 2024-04-11 10:32:11 +00:00
ssongliu 0de79e537e fix: 修改高级功能菜单 LOGO (#4477) 2024-04-11 10:30:11 +00:00
zhengkunwang e37b87d63e fix: 解决安装应用时 deploy 字段被覆盖的问题 (#4476) 2024-04-11 10:28:11 +00:00
ssongliu 37a0329d4a fix: 解决登录页跳转错误的问题 (#4474) 2024-04-11 09:16:10 +00:00
ssongliu e037b69f52 fix: 解决登录页跳转错误的问题 (#4470) 2024-04-11 15:53:22 +08:00
zhengkunwang 34498392dc style(waf): 修改网站图标位置 (#4469) 2024-04-11 07:00:13 +00:00
ssongliu 1687b99526 feat: 增加 GPU 监控 (#4468) 2024-04-11 06:16:10 +00:00
ssongliu 0bf6db1cf8 fix: 解决僵尸进程的问题 (#4464) 2024-04-10 14:18:08 +00:00
ssongliu 0cd06803e2 fix: 监控数据迁移增加数据长度判断 (#4454) 2024-04-10 06:06:08 +00:00
guangwu 45f6a415de fix: close resource (#4456) 2024-04-10 14:05:07 +08:00
John Bro 3e3f0d9452 feat: 未认证设置状态下系统跳转页面功能实现 (#4444)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2024-04-09 14:46:09 +00:00
zhengkunwang 35785f1e40 feat: 增加文件修改权限的超时时间 (#4448)
Refs https://github.com/1Panel-dev/1Panel/issues/4291
2024-04-09 09:34:09 +00:00
zhengkunwang 437d6eb0fd feat: 网站名称支持带端口 (#4446)
Refs https://github.com/1Panel-dev/1Panel/issues/3726
2024-04-09 09:32:10 +00:00
zhengkunwang 1e2c85e771 feat: 文本编辑器记住上次设置 (#4445)
Refs https://github.com/1Panel-dev/1Panel/issues/4397
Refs https://github.com/1Panel-dev/1Panel/issues/4266
2024-04-09 09:30:09 +00:00
zhengkunwang ef075df3fe feat: 进程守护名称支持-_等字符 (#4442)
Refs https://github.com/1Panel-dev/1Panel/issues/4303
2024-04-09 08:38:09 +00:00
zhengkunwang 1e22769c8b feat: 文件上传权限优化 (#4441)
Refs https://github.com/1Panel-dev/1Panel/issues/4362
2024-04-09 08:36:09 +00:00
zhengkunwang 0751326b46 feat: 优化文件创建 (#4440) 2024-04-09 07:34:08 +00:00
zhengkunwang db4973cfde fix: 解决读取 block 文件报错的问题 (#4439) 2024-04-09 06:28:09 +00:00
zhengkunwang 0b47d692b8 fix: 解决 upstream 配置报错的问题 (#4438)
Refs https://github.com/1Panel-dev/1Panel/issues/4258
2024-04-09 06:16:09 +00:00
zhengkunwang 672ef66be8 fix: 解决 docker-compose 文件错误导致的异常 (#4431) 2024-04-08 09:54:07 +00:00
ssongliu 7ab005540b fix: 切换菜单设置接口 (#4429) 2024-04-08 09:48:08 +00:00
clonefetch 7c928735cd chore: remove repetitive word (#4430)
Signed-off-by: clonefetch <c0217@outlook.com>
2024-04-08 17:47:17 +08:00
zhengkunwang 9ec1610f34 feat: 增加一些翻译 (#4428) 2024-04-08 09:06:08 +00:00
ssongliu 4f2a340212 fix: 修改监控相关接口 (#4427) 2024-04-08 08:52:07 +00:00
ssongliu e69fd3b388 pref: 优化 OSS 连接检测错误信息 (#4426) 2024-04-08 06:44:07 +00:00
ssongliu 6991c773da feat: 监控数据使用独立数据库 (#4424) 2024-04-08 05:48:07 +00:00
ssongliu 9b88979b69 fix: 解决替换根目录失败的问题 (#4420) 2024-04-07 23:21:15 +08:00
ssongliu 7c9608727d fix: 解决升级失败的问题 (#4419) 2024-04-07 14:09:46 +00:00
ssongliu 62828c464e fix: 解决文件保存失败一直处于加载中的问题 (#4418) 2024-04-07 21:38:59 +08:00
ssongliu f1ed051135 feat: 增加概览页跳转方式 (#4417) 2024-04-07 09:29:46 +00:00
zhengkunwang 33a0c2ba30 feat: 删除网站适配防篡改 (#4415) 2024-04-07 09:25:46 +00:00
ssongliu 494da3c209 fix: 修改 xpack 依赖 (#4414) 2024-04-07 08:29:46 +00:00
wanghe 646fc4e678 Update .gitattributes 2024-04-07 11:59:42 +08:00
ssongliu cdbe24a523 fix: 修改升级等过程中复制方式 (#4402) 2024-04-06 14:32:10 +00:00
maninhill 10012c6148 chore:更新 README 2024-04-04 08:28:43 +08:00
zhengkunwang bb4fd69f3a fix: 解决没有 xpack 打包报错的问题 (#4400) 2024-04-03 09:40:07 +00:00
John Broandzhoujunhong 6ff0f14841 fix: 专业版菜单选择显示前端优化 (#4399)
Co-authored-by: zhoujunhong <1298308460@qq.com>
2024-04-03 17:27:55 +08:00
ssongliu 1088034a5c feat: 计划任务容器中执行增加 Command 选项 (#4398)
Refs #4363
2024-04-03 08:50:07 +00:00
zhengkunwang 8a011b1cf9 feat: 优化文件上传体验 (#4396) 2024-04-03 08:40:07 +00:00
Node e3eebc938a 提升文件上传体验 (#4393)
* 上传文件支持覆盖被占用的文件且上传失败时不影响原文件,增加强制覆盖选项

* 原文件存在时,保持同样的文件权限

* 制表符更新
2024-04-03 14:37:22 +08:00
John Bro 08da7802c6 feat: 专业版菜单隐藏控制功能实现 (#4392) 2024-04-03 14:11:12 +08:00
ssongliu 79ca1b4d6b pref: 专业版界面增加图标显示 (#4391) 2024-04-02 09:16:46 +00:00
ssongliu 47119e508b fix: 解决容器挂载卷回显失败的问题 (#4389)
Refs #4387
2024-04-02 09:14:45 +00:00
ssongliu 13bb5e0d30 pref: 优化界面设置提示信息 (#4382) 2024-04-01 10:52:06 +00:00
zhengkunwang 218c165c26 feat: 删除部分 .gitignore (#4380) 2024-04-01 09:52:07 +00:00
zhengkunwang d6006d34c0 feat: 修改 WAF 专业版提示 (#4377) 2024-04-01 08:38:08 +00:00
ssongliu 810ea03ac1 pref: 优化 Xpack 错误信息 (#4376) 2024-04-01 08:28:07 +00:00
ssongliu e046315616 pref: 修改描述信息 (#4375) 2024-04-01 08:00:08 +00:00
zhengkunwang 0a7f1eb286 fix: 处理时序攻击漏洞 (#4373) 2024-04-01 07:52:07 +00:00
wanghe-fit2cloud b0411b2df6 feat: 增加构建标签 2024-04-01 15:22:51 +08:00
ssongliu 471b7d9657 style: 调整 Logo 样式 (#4357) 2024-03-29 09:24:07 +00:00
ssongliu 1527c63d37 feat: 同步数据库中界面设置数据 (#4355) 2024-03-29 07:50:06 +00:00
zhengkunwang 0ebeeaebd6 fix: 解决 WAF 首次安装创建网站没有生效的问题 (#4354) 2024-03-29 07:04:06 +00:00
zhengkunwang 1ae5bef40d feat: 调整 waf 配置文件生成顺序 (#4339) 2024-03-28 08:10:07 +00:00
zhengkunwang 9b9fe5444d feat: 创建网站增加 waf 关联 (#4333) 2024-03-27 10:36:08 +00:00
ssongliu a5d853c61a fix: 解决界面设置无法上传大图片的问题 (#4332) 2024-03-27 10:34:07 +00:00
zhengkunwang 6610a3debe fix: 解决前端打包报错问题 (#4331) 2024-03-27 10:26:07 +00:00
zhengkunwang 6b244b2b03 feat: 删除旧版本 WAF 配置 (#4327) 2024-03-27 07:42:07 +00:00
刘瑞斌 0b26d70927 chore: 增加 JetBrains Toolbox 图标 (#4325) 2024-03-27 13:47:05 +08:00
ssongliu 18faed79f3 style: 调整 Xpack 界面样式与菜单位置 (#4323) 2024-03-27 03:32:07 +00:00
zhengkunwang b0cc1248f0 feat: 删除 xpack 的翻译 (#4322) 2024-03-27 03:24:06 +00:00
ssongliu 8013c7fd96 fix: 修改 Xpack 路由路径 (#4317) 2024-03-26 09:40:07 +00:00
ssongliu 306082d625 feat: 完善界面设置功能 (#4316) 2024-03-26 08:44:07 +00:00
刘瑞斌 821b8dfe63 chore: 去掉某些字体 (#4315) 2024-03-26 16:15:58 +08:00
ssongliu 8d88ed812c fix: 修改 License 状态判断 (#4309) 2024-03-26 06:08:07 +00:00
zhengkunwang aa93a6d373 feat: 删除 plugins 目录 (#4311) 2024-03-26 06:00:07 +00:00
ssongliu b4e8c8503c feat: 调整 License 导入样式 (#4305) 2024-03-25 22:49:39 +08:00
zhengkunwang 4de733e084 feat: 优化网站目录显示 (#4301)
Refs https://github.com/1Panel-dev/1Panel/issues/4280
2024-03-25 09:58:07 +00:00
ssongliu 6c67dc6ed4 feat: 完善 License 导入错误显示 (#4297) 2024-03-25 07:12:07 +00:00
ssongliu ba6991bfb6 feat: 增加 License 导入界面 (#4295) 2024-03-25 04:20:07 +00:00
zhengkunwang 33309d2d93 feat(waf): 优化配置文件读取方式 (#4288) 2024-03-23 14:04:06 +00:00
zhengkunwang 1b2208a4d0 feat(waf): 增加 IP 组功能 (#4277) 2024-03-22 10:58:08 +00:00
刘瑞斌 e3fb97fc8c ci: 替换过时的组件 (#4273) 2024-03-22 14:33:48 +08:00
an4er 1ff5bf85e9 fix: 解决命令注入waf被绕过的问题 (#4268) 2024-03-22 14:18:47 +08:00
wanghe-fit2cloud 062b2f2ae6 chore: 修改同步仓库地址 2024-03-22 14:17:40 +08:00
wanghe-fit2cloud 44445aca93 chore: 修改使用手册显示信息 2024-03-21 22:36:32 +08:00
dependabot[bot] 94de830637 chore(deps): bump github.com/docker/docker (#4256)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 25.0.3+incompatible to 25.0.5+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v25.0.3...v25.0.5)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-21 18:54:22 +08:00
Shang Yuanchun 9160726127 解决部分操作系统上 platformVersion 为空导致的显示问题 (#4259)
* fix: 解决部分操作系统上 platformVersion 为空导致的显示问题

例如archlinux,显示的是:arch-

* fix: 修改表达式 (#4259)
2024-03-21 18:54:13 +08:00
317 changed files with 6171 additions and 10662 deletions
+5 -1
View File
@@ -1 +1,5 @@
*.ts linguist-language=Go
*.ts linguist-language=Go
*.js linguist-language=Go
*.css linguist-language=Go
*.scss linguist-language=Go
*.html linguist-language=Go
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
name: 为 PR 添加标签
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUBTOKEN }}
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
uses: Yikun/hub-mirror-action@master
with:
src: 'github/1Panel-dev'
dst: 'gitee/fit2cloud-xlab'
dst: 'gitee/fit2cloud-feizhiyun'
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
dst_token: ${{ secrets.GITEE_TOKEN }}
static_list: "1Panel"
+13
View File
@@ -0,0 +1,13 @@
name: Typos Check
on: pull_request
jobs:
run:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v2
- name: Check spelling
uses: crate-ci/typos@master
+4 -6
View File
@@ -16,7 +16,8 @@ build/1panel
*.factorypath
# IntelliJ IDEA
.idea
.idea/*
!.idea/icon.png
*.iws
*.iml
*.ipr
@@ -41,11 +42,7 @@ frontend/src/xpack
backend/xpack
backend/router/entry_xpack.go
backend/server/init_xpack.go
plugins/openresty/waf/db
plugins/openresty/waf/data
plugins/openresty/waf/sites
plugins/openresty/waf/conf/websites.json
backend/utils/xpack/xpack_xpack.go
.history/
dist/
@@ -55,3 +52,4 @@ install.sh
quick_start.sh
cmd/server/fileList.txt
.fileList.txt
1Panel.code-workspace
+1
View File
@@ -13,6 +13,7 @@ builds:
- main: ./cmd/server/main.go
binary: 1panel
flags:
- -tags=xpack
- -trimpath
ldflags:
- -w -s
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

+2 -2
View File
@@ -3,9 +3,9 @@
## Create pull request
PR are always welcome, even if they only contain small fixes like typos or a few lines of code. If there will be a significant effort, please document it as an issue and get a discussion going before starting to work on it.
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot of features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
This [development guideline](https://1panel.cn/docs/dev_manual/dev_manual/) contains information about repository structure, how to setup development environment, how to run it, and more.
This [development guideline](https://1panel.cn/docs/dev_manual/dev_manual/) contains information about repository structure, how to set up development environment, how to run it, and more.
Note: If you split your pull request to small changes, please make sure any of the changes goes to master will not break anything. Otherwise, it can not be merged until this feature complete.
+9 -16
View File
@@ -19,18 +19,10 @@
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供防火墙和日志审计等功能;
- **一键备份**:支持一键备份和恢复,用户可以将数据备份到各类云端存储介质,永不丢失。
## UI 展示
![UI展示](https://resource.fit2cloud.com/1panel/img/overview.png)
1Panel 三分钟速览:https://www.bilibili.com/video/BV1Mt421n7LZ/
## 快速开始
**在线体验**
- 环境地址:<https://demo.1panel.cn/>
- 用户名:demo
- 密码:1panel
**一键安装**
执行如下命令一键安装 1Panel:
@@ -42,23 +34,24 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
**学习资料**
- [在线文档](https://1panel.cn/docs/)
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
- [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)
## 安全说明
## UI 展示
如果您在使用过程中发现任何安全问题,请通过以下方式直接联系我们:
- 邮箱:wanghe@fit2cloud.com
![UI展示](https://resource.fit2cloud.com/1panel/img/overview.png)
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## FOSSA Status
## 我们的其他明星项目
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_large)
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
- [DataEase](https://github.com/dataease/dataease/) - 人人可用的开源数据可视化分析工具
- [MeterSphere](https://github.com/metersphere/metersphere/) - 开源自动化测试平台
## License
-6
View File
@@ -3,9 +3,6 @@
如果您发现安全问题,请直接联系我们:
- wanghe@fit2cloud.com
- zhengkun@fit2cloud.com
- support@fit2cloud.com
- 400-052-0755
感谢您的支持!
@@ -14,8 +11,5 @@
All security bugs should be reported to the contact as below:
- wanghe@fit2cloud.com
- zhengkun@fit2cloud.com
- support@fit2cloud.com
- +86 400-052-0755
Thanks for your support!
+1 -1
View File
@@ -137,7 +137,7 @@ func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
// @Accept json
// @Success 200 {object} response.IgnoredApp
// @Security ApiKeyAuth
// @Router /apps/ingored [get]
// @Router /apps/ignored [get]
func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
res, err := appService.GetIgnoredApp()
if err != nil {
+9
View File
@@ -121,6 +121,15 @@ func (b *BaseApi) CheckIsSafety(c *gin.Context) {
helper.SuccessWithData(c, status)
}
func (b *BaseApi) GetResponsePage(c *gin.Context) {
pageCode, err := authService.GetResponsePage()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, pageCode)
}
// @Tags Auth
// @Summary Check System isDemo
// @Description 判断是否为demo环境
+1 -1
View File
@@ -323,7 +323,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
switch req.Type {
case "app":
if err := backupService.AppBackup(req); err != nil {
if _, err := backupService.AppBackup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
+4 -4
View File
@@ -61,7 +61,7 @@ func (b *BaseApi) LoadDaemonJson(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update [post]
// @x-panel-log {"bodyKeys":["key", "value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 配置 [key]=>[value]","formatEN":"Updated the docker daemon.json configuration [key]=>[value]"}
// @x-panel-log {"bodyKeys":["key", "value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新配置 [key]","formatEN":"Updated configuration [key]"}
func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
var req dto.SettingUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -84,7 +84,7 @@ func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/logoption/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 日志配置","formatEN":"Updated the docker daemon.json log option"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新日志配置","formatEN":"Updated the log option"}
func (b *BaseApi) UpdateLogOption(c *gin.Context) {
var req dto.LogOption
if err := helper.CheckBind(&req, c); err != nil {
@@ -107,7 +107,7 @@ func (b *BaseApi) UpdateLogOption(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/ipv6option/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json ipv6 配置","formatEN":"Updated the docker daemon.json ipv6 option"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 ipv6 配置","formatEN":"Updated the ipv6 option"}
func (b *BaseApi) UpdateIpv6Option(c *gin.Context) {
var req dto.Ipv6Option
if err := helper.CheckBind(&req, c); err != nil {
@@ -130,7 +130,7 @@ func (b *BaseApi) UpdateIpv6Option(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update/byfile [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 配置","formatEN":"Updated the docker daemon.json configuration"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新配置文件","formatEN":"Updated configuration file"}
func (b *BaseApi) UpdateDaemonJsonByFile(c *gin.Context) {
var req dto.DaemonJsonUpdateByFile
if err := helper.CheckBindAndValidate(&req, c); err != nil {
+69 -8
View File
@@ -301,28 +301,83 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
files := form.File["file"]
uploadFiles := form.File["file"]
paths := form.Value["path"]
overwrite := true
if ow, ok := form.Value["overwrite"]; ok {
if len(ow) != 0 {
parseBool, _ := strconv.ParseBool(ow[0])
overwrite = parseBool
}
}
if len(paths) == 0 || !strings.Contains(paths[0], "/") {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error paths in request"))
return
}
dir := path.Dir(paths[0])
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
_, err = os.Stat(dir)
if err != nil && os.IsNotExist(err) {
mode, err := files.GetParentMode(dir)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err = os.MkdirAll(dir, mode); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("mkdir %s failed, err: %v", dir, err))
return
}
}
info, err := os.Stat(dir)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
mode := info.Mode()
fileOp := files.NewFileOp()
success := 0
failures := make(buserr.MultiErr)
for _, file := range files {
if err := c.SaveUploadedFile(file, path.Join(paths[0], file.Filename)); err != nil {
for _, file := range uploadFiles {
dstFilename := path.Join(paths[0], file.Filename)
dstDir := path.Dir(dstFilename)
if !fileOp.Stat(dstDir) {
if err = fileOp.CreateDir(dstDir, mode); err != nil {
e := fmt.Errorf("create dir [%s] failed, err: %v", path.Dir(dstFilename), err)
failures[file.Filename] = e
global.LOG.Error(e)
continue
}
}
tmpFilename := dstFilename + ".tmp"
if err := c.SaveUploadedFile(file, tmpFilename); err != nil {
_ = os.Remove(tmpFilename)
e := fmt.Errorf("upload [%s] file failed, err: %v", file.Filename, err)
failures[file.Filename] = e
global.LOG.Error(e)
continue
}
dstInfo, statErr := os.Stat(dstFilename)
if overwrite {
_ = os.Remove(dstFilename)
}
err = os.Rename(tmpFilename, dstFilename)
if err != nil {
_ = os.Remove(tmpFilename)
e := fmt.Errorf("upload [%s] file failed, err: %v", file.Filename, err)
failures[file.Filename] = e
global.LOG.Error(e)
continue
}
if statErr == nil {
_ = os.Chmod(dstFilename, dstInfo.Mode())
} else {
_ = os.Chmod(dstFilename, mode)
}
success++
}
if success == 0 {
@@ -431,6 +486,7 @@ func (b *BaseApi) Download(c *gin.Context) {
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
}
defer file.Close()
info, _ := file.Stat()
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
@@ -539,16 +595,20 @@ func (b *BaseApi) Size(c *gin.Context) {
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
op := files.NewFileOp()
dstDir = strings.TrimSpace(dstDir)
mode, _ := files.GetParentMode(dstDir)
if mode == 0 {
mode = 0755
}
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
if err = op.CreateDir(dstDir, os.ModePerm); err != nil {
if err = op.CreateDir(dstDir, mode); err != nil {
return err
}
}
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
targetFile, err := os.OpenFile(filepath.Join(dstDir, fileName), os.O_RDWR|os.O_CREATE, mode)
if err != nil {
return err
}
defer targetFile.Close()
for i := 0; i < chunkCount; i++ {
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
@@ -584,6 +644,7 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
defer uploadFile.Close()
chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex"))
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
+34 -3
View File
@@ -15,6 +15,13 @@ import (
"github.com/shirou/gopsutil/v3/net"
)
// @Tags Monitor
// @Summary Load monitor datas
// @Description 获取监控数据
// @Param request body dto.MonitorSearch true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/monitor/search [post]
func (b *BaseApi) LoadMonitor(c *gin.Context) {
var req dto.MonitorSearch
if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -28,7 +35,7 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
var backdatas []dto.MonitorData
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {
var bases []model.MonitorBase
if err := global.DB.
if err := global.MonitorDB.
Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -45,7 +52,7 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
}
if req.Param == "all" || req.Param == "io" {
var bases []model.MonitorIO
if err := global.DB.
if err := global.MonitorDB.
Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -62,7 +69,7 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
}
if req.Param == "all" || req.Param == "network" {
var bases []model.MonitorNetwork
if err := global.DB.
if err := global.MonitorDB.
Where("name = ? AND created_at > ? AND created_at < ?", req.Info, req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -80,6 +87,30 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
helper.SuccessWithData(c, backdatas)
}
// @Tags Monitor
// @Summary Clean monitor datas
// @Description 清空监控数据
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/monitor/clean [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清空监控数据","formatEN":"clean monitor datas"}
func (b *BaseApi) CleanMonitor(c *gin.Context) {
if err := global.MonitorDB.Exec("DELETE FROM monitor_bases").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := global.MonitorDB.Exec("DELETE FROM monitor_ios").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := global.MonitorDB.Exec("DELETE FROM monitor_networks").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) GetNetworkOptions(c *gin.Context) {
netStat, _ := net.IOCounters(true)
var options []string
+14
View File
@@ -76,6 +76,20 @@ func (b *BaseApi) DeleteRuntime(c *gin.Context) {
helper.SuccessWithOutData(c)
}
func (b *BaseApi) DeleteRuntimeCheck(c *gin.Context) {
runTimeId, err := helper.GetIntParamByKey(c, "runTimeId")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
return
}
checkData, err := runtimeService.DeleteCheck(runTimeId)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, checkData)
}
// @Tags Runtime
// @Summary Update runtime
// @Description 更新运行环境
+22 -24
View File
@@ -60,6 +60,28 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Update system setting
// @Description 隐藏高级功能菜单
// @Accept json
// @Param request body dto.SettingUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/menu/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"隐藏高级功能菜单","formatEN":"Hide advanced feature menu."}
func (b *BaseApi) UpdateMenu(c *gin.Context) {
var req dto.SettingUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := settingService.Update(req.Key, req.Value); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Update system password
// @Description 更新系统登录密码
@@ -227,30 +249,6 @@ func (b *BaseApi) LoadBaseDir(c *gin.Context) {
helper.SuccessWithData(c, global.CONF.System.DataDir)
}
// @Tags System Setting
// @Summary Clean monitor datas
// @Description 清空监控数据
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/monitor/clean [post]
// @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)
return
}
if err := global.DB.Exec("DELETE FROM monitor_ios").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := global.DB.Exec("DELETE FROM monitor_networks").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Load mfa info
// @Description 获取 mfa 信息
+9 -9
View File
@@ -3,7 +3,6 @@ package v1
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
@@ -93,16 +92,17 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
}
defer wsConn.Close()
commands := "redis-cli"
commands := []string{"redis-cli"}
if len(redisConf.Requirepass) != 0 {
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass)
commands = []string{"redis-cli", "-a", redisConf.Requirepass, "--no-auth-warning"}
}
pidMap := loadMapFromDockerTop(redisConf.ContainerName)
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
itemCmds := append([]string{"exec", "-it", redisConf.ContainerName}, commands...)
slave, err := terminal.NewCommand(itemCmds)
if wshandleError(wsConn, err) {
return
}
defer killBash(redisConf.ContainerName, commands, pidMap)
defer killBash(redisConf.ContainerName, strings.Join(commands, " "), pidMap)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
@@ -161,9 +161,9 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
return
}
commands := fmt.Sprintf("docker exec -it %s %s", containerID, command)
commands := []string{"exec", "-it", containerID, command}
if len(user) != 0 {
commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command)
commands = []string{"exec", "-it", "-u", user, containerID, command}
}
pidMap := loadMapFromDockerTop(containerID)
slave, err := terminal.NewCommand(commands)
@@ -221,10 +221,10 @@ func loadMapFromDockerTop(containerID string) map[string]string {
lines := strings.Split(stdout, "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) != 2 {
if len(parts) < 2 {
continue
}
pidMap[parts[0]] = parts[1]
pidMap[parts[0]] = strings.Join(parts[1:], " ")
}
return pidMap
}
+1 -64
View File
@@ -305,69 +305,6 @@ func (b *BaseApi) CreateWebsiteCheck(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Tags Website WAF
// @Summary Load websit waf conf
// @Description 获取网站 waf 配置
// @Accept json
// @Param request body request.WebsiteWafReq true "request"
// @Success 200 {object} response.WebsiteWafConfig
// @Security ApiKeyAuth
// @Router /websites/waf/config [post]
func (b *BaseApi) GetWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := websiteService.GetWafConfig(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Website WAF
// @Summary Update website waf conf
// @Description 更新 网站 waf 配置
// @Accept json
// @Param request body request.WebsiteWafUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/update [post]
// @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 := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateWafConfig(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website WAF
// @Summary Update website waf file
// @Description 更新 网站 waf 配置文件
// @Accept json
// @Param request body request.WebsiteWafUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/file/update [post]
// @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 := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateWafFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website Nginx
// @Summary Update website nginx conf
// @Description 更新 网站 nginx 配置
@@ -433,7 +370,7 @@ func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
}
// @Tags Website
// @Summary Load websit php conf
// @Summary Load website php conf
// @Description 获取网站 php 配置
// @Accept json
// @Param id path integer true "request"
+1
View File
@@ -6,6 +6,7 @@ type SearchCommandWithPage struct {
Order string `json:"order"`
GroupID uint `json:"groupID"`
Info string `json:"info"`
Name string `json:"name"`
}
type CommandOperate struct {
+3
View File
@@ -48,6 +48,8 @@ type ContainerOperate struct {
Name string `json:"name" validate:"required"`
Image string `json:"image" validate:"required"`
Network string `json:"network"`
Ipv4 string `json:"ipv4"`
Ipv6 string `json:"ipv6"`
PublishAllPorts bool `json:"publishAllPorts"`
ExposedPorts []PortHelper `json:"exposedPorts"`
Tty bool `json:"tty"`
@@ -98,6 +100,7 @@ type ContainerStats struct {
}
type VolumeHelper struct {
Type string `json:"type"`
SourceDir string `json:"sourceDir"`
ContainerDir string `json:"containerDir"`
Mode string `json:"mode"`
+3
View File
@@ -8,6 +8,7 @@ type CronjobCreate struct {
Spec string `json:"spec" validate:"required"`
Script string `json:"script"`
Command string `json:"command"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
@@ -28,6 +29,7 @@ type CronjobUpdate struct {
Spec string `json:"spec" validate:"required"`
Script string `json:"script"`
Command string `json:"command"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
@@ -70,6 +72,7 @@ type CronjobInfo struct {
Spec string `json:"spec"`
Script string `json:"script"`
Command string `json:"command"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
+17
View File
@@ -69,6 +69,8 @@ type DashboardCurrent struct {
NetBytesSent uint64 `json:"netBytesSent"`
NetBytesRecv uint64 `json:"netBytesRecv"`
GPUData []GPUInfo `json:"gpuData"`
ShotTime time.Time `json:"shotTime"`
}
@@ -86,3 +88,18 @@ type DiskInfo struct {
InodesFree uint64 `json:"inodesFree"`
InodesUsedPercent float64 `json:"inodesUsedPercent"`
}
type GPUInfo struct {
Index uint `json:"index"`
ProductName string `json:"productName"`
GPUUtil string `json:"gpuUtil"`
Temperature string `json:"temperature"`
PerformanceState string `json:"performanceState"`
PowerUsage string `json:"powerUsage"`
PowerDraw string `json:"powerDraw"`
MaxPowerLimit string `json:"maxPowerLimit"`
MemoryUsage string `json:"memoryUsage"`
MemUsed string `json:"memUsed"`
MemTotal string `json:"memTotal"`
FanSpeed string `json:"fanSpeed"`
}
+1 -1
View File
@@ -131,7 +131,7 @@ type MysqlStatus struct {
}
type MysqlVariables struct {
BinlogCachSize string `json:"binlog_cache_size"`
BinlogCacheSize string `json:"binlog_cache_size"`
InnodbBufferPoolSize string `json:"innodb_buffer_pool_size"`
InnodbLogBufferSize string `json:"innodb_log_buffer_size"`
JoinBufferSize string `json:"join_buffer_size"`
+1 -1
View File
@@ -22,7 +22,7 @@ type FileCreate struct {
Path string `json:"path" validate:"required"`
Content string `json:"content"`
IsDir bool `json:"isDir"`
Mode int64 `json:"mode" validate:"required"`
Mode int64 `json:"mode"`
IsLink bool `json:"isLink"`
IsSymlink bool `json:"isSymlink"`
LinkPath string `json:"linkPath"`
+7 -19
View File
@@ -69,24 +69,12 @@ type WebsiteOp struct {
Operate string `json:"operate"`
}
type WebsiteWafReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Rule string `json:"rule" validate:"required"`
}
type WebsiteRedirectUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Enable bool `json:"enable"`
}
type WebsiteWafUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Enable bool `json:"enable"`
}
type WebsiteRecover struct {
WebsiteName string `json:"websiteName" validate:"required"`
Type string `json:"type" validate:"required"`
@@ -190,7 +178,7 @@ type WebsiteProxyConfig struct {
CacheTime int `json:"cacheTime" `
CacheUnit string `json:"cacheUnit"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier" validate:"required"`
Modifier string `json:"modifier"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
@@ -207,12 +195,12 @@ type WebsiteRedirectReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
}
type WebsiteWafFileUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Content string `json:"content" validate:"required"`
Type string `json:"type" validate:"required,oneof=cc ip_white ip_block url_white url_block cookie_block args_check post_check ua_check file_ext_block user_agent"`
}
type WebsiteCommonReq struct {
ID uint `json:"id" validate:"required"`
}
type WafWebsite struct {
Key string `json:"key"`
Domains []string `json:"domains"`
Host []string `json:"host"`
}
+23 -5
View File
@@ -20,6 +20,10 @@ type WebsiteSSLCreate struct {
Dir string `json:"dir"`
ID uint `json:"id"`
Description string `json:"description"`
DisableCNAME bool `json:"disableCNAME"`
SkipDNS bool `json:"skipDNS"`
Nameserver1 string `json:"nameserver1"`
Nameserver2 string `json:"nameserver2"`
}
type WebsiteDNSReq struct {
@@ -32,8 +36,9 @@ type WebsiteSSLRenew struct {
}
type WebsiteSSLApply struct {
ID uint `json:"ID" validate:"required"`
SkipDNSCheck bool `json:"SkipDNSCheck"`
ID uint `json:"ID" validate:"required"`
SkipDNSCheck bool `json:"skipDNSCheck"`
Nameservers []string `json:"nameservers"`
}
type WebsiteAcmeAccountCreate struct {
@@ -66,9 +71,22 @@ type WebsiteBatchDelReq struct {
}
type WebsiteSSLUpdate struct {
ID uint `json:"id" validate:"required"`
AutoRenew bool `json:"autoRenew"`
Description string `json:"description"`
ID uint `json:"id" validate:"required"`
AutoRenew bool `json:"autoRenew"`
Description string `json:"description"`
PrimaryDomain string `json:"primaryDomain" validate:"required"`
OtherDomains string `json:"otherDomains"`
Provider string `json:"provider" validate:"required"`
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
DnsAccountID uint `json:"dnsAccountId"`
KeyType string `json:"keyType"`
Apply bool `json:"apply"`
PushDir bool `json:"pushDir"`
Dir string `json:"dir"`
DisableCNAME bool `json:"disableCNAME"`
SkipDNS bool `json:"skipDNS"`
Nameserver1 string `json:"nameserver1"`
Nameserver2 string `json:"nameserver2"`
}
type WebsiteSSLUpload struct {
-5
View File
@@ -31,11 +31,6 @@ type WebsiteNginxConfig struct {
Params []NginxParam `json:"params"`
}
type WebsiteWafConfig struct {
Enable bool `json:"enable"`
Content string `json:"content"`
}
type WebsiteHTTPS struct {
Enable bool `json:"enable"`
HttpConfig string `json:"httpConfig"`
+5
View File
@@ -8,6 +8,7 @@ type SettingInfo struct {
SystemIP string `json:"systemIP"`
SystemVersion string `json:"systemVersion"`
DockerSockPath string `json:"dockerSockPath"`
DeveloperMode string `json:"developerMode"`
SessionTimeout string `json:"sessionTimeout"`
LocalTime string `json:"localTime"`
@@ -19,6 +20,7 @@ type SettingInfo struct {
BindAddress string `json:"bindAddress"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
MenuTabs string `json:"menuTabs"`
Language string `json:"language"`
DefaultNetwork string `json:"defaultNetwork"`
LastCleanTime string `json:"lastCleanTime"`
@@ -54,6 +56,8 @@ type SettingInfo struct {
FileRecycleBin string `json:"fileRecycleBin"`
SnapshotIgnore string `json:"snapshotIgnore"`
XpackHideMenu string `json:"xpackHideMenu"`
NoAuthSetting string `json:"noAuthSetting"`
}
type SettingUpdate struct {
@@ -137,6 +141,7 @@ type SnapshotInfo struct {
}
type UpgradeInfo struct {
TestVersion string `json:"testVersion"`
NewVersion string `json:"newVersion"`
LatestVersion string `json:"latestVersion"`
ReleaseNote string `json:"releaseNote"`
+1
View File
@@ -9,6 +9,7 @@ type Cronjob struct {
Type string `gorm:"type:varchar(64);not null" json:"type"`
Spec string `gorm:"type:varchar(64);not null" json:"spec"`
Command string `gorm:"type:varchar(64)" json:"command"`
ContainerName string `gorm:"type:varchar(64)" json:"containerName"`
Script string `gorm:"longtext" json:"script"`
Website string `gorm:"type:varchar(64)" json:"website"`
+19 -15
View File
@@ -9,26 +9,30 @@ import (
type WebsiteSSL struct {
BaseModel
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
Pem string `gorm:"type:longtext;not null" json:"pem"`
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
Type string `gorm:"type:varchar(64);not null" json:"type"`
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
CaID uint `gorm:"type:integer;not null;default:0" json:"caId"`
AutoRenew bool `gorm:"type:varchar(64);not null" json:"autoRenew"`
PrimaryDomain string `json:"primaryDomain"`
PrivateKey string `json:"privateKey"`
Pem string `json:"pem"`
Domains string `json:"domains"`
CertURL string `json:"certURL"`
Type string `json:"type"`
Provider string `json:"provider"`
Organization string `json:"organization"`
DnsAccountID uint `json:"dnsAccountId"`
AcmeAccountID uint `gorm:"column:acme_account_id" json:"acmeAccountId" `
CaID uint `json:"caId"`
AutoRenew bool `json:"autoRenew"`
ExpireDate time.Time `json:"expireDate"`
StartDate time.Time `json:"startDate"`
Status string `gorm:"not null;default:ready" json:"status"`
Status string `json:"status"`
Message string `json:"message"`
KeyType string `gorm:"not null;default:2048" json:"keyType"`
PushDir bool `gorm:"not null;default:0" json:"pushDir"`
KeyType string `json:"keyType"`
PushDir bool `json:"pushDir"`
Dir string `json:"dir"`
Description string `json:"description"`
SkipDNS bool `json:"skipDNS"`
Nameserver1 string `json:"nameserver1"`
Nameserver2 string `json:"nameserver2"`
DisableCNAME bool `json:"disableCNAME"`
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
+10
View File
@@ -16,6 +16,7 @@ type ICommandRepo interface {
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
Get(opts ...DBOption) (model.Command, error)
WithLikeName(name string) DBOption
}
func NewICommandRepo() ICommandRepo {
@@ -79,3 +80,12 @@ func (u *CommandRepo) Delete(opts ...DBOption) error {
}
return db.Delete(&model.Command{}).Error
}
func (a CommandRepo) WithLikeName(name string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(name) == 0 {
return g
}
return g.Where("name like ? or command like ?", "%"+name+"%", "%"+name+"%")
}
}
+6 -6
View File
@@ -68,20 +68,20 @@ func (u *SettingRepo) Update(key, value string) error {
}
func (u *SettingRepo) CreateMonitorBase(model model.MonitorBase) error {
return global.DB.Create(&model).Error
return global.MonitorDB.Create(&model).Error
}
func (u *SettingRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) BatchCreateMonitorNet(ioList []model.MonitorNetwork) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) DelMonitorBase(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
}
func (u *SettingRepo) DelMonitorIO(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
}
func (u *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}
+10 -1
View File
@@ -21,6 +21,7 @@ type ISSLRepo interface {
Create(ctx context.Context, ssl *model.WebsiteSSL) error
Save(ssl *model.WebsiteSSL) error
DeleteBy(opts ...DBOption) error
SaveByMap(ssl *model.WebsiteSSL, params map[string]interface{}) error
}
type WebsiteSSLRepo struct {
@@ -82,7 +83,15 @@ func (w WebsiteSSLRepo) Create(ctx context.Context, ssl *model.WebsiteSSL) error
}
func (w WebsiteSSLRepo) Save(ssl *model.WebsiteSSL) error {
return getDb().Save(&ssl).Error
return getDb().Model(&model.WebsiteSSL{BaseModel: model.BaseModel{
ID: ssl.ID,
}}).Save(&ssl).Error
}
func (w WebsiteSSLRepo) SaveByMap(ssl *model.WebsiteSSL, params map[string]interface{}) error {
return getDb().Model(&model.WebsiteSSL{BaseModel: model.BaseModel{
ID: ssl.ID,
}}).Updates(params).Error
}
func (w WebsiteSSLRepo) DeleteBy(opts ...DBOption) error {
+16 -1
View File
@@ -230,6 +230,7 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
if err != nil {
return appDetailDTO, buserr.WithDetail("ErrGetCompose", err.Error(), err)
}
defer composeRes.Body.Close()
bodyContent, err := io.ReadAll(composeRes.Body)
if err != nil {
return appDetailDTO, buserr.WithDetail("ErrGetCompose", err.Error(), err)
@@ -727,6 +728,14 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
res.CanUpdate = true
return res, err
}
apps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
for _, app := range apps {
if app.Icon == "" {
res.CanUpdate = true
return res, err
}
}
list, err := getAppList()
if err != nil {
return res, err
@@ -839,7 +848,12 @@ func (a AppService) SyncAppListFromRemote() (err error) {
if err != nil {
return err
}
iconStr := base64.StdEncoding.EncodeToString(body)
iconStr := ""
if !strings.Contains(string(body), "xml") {
iconStr = base64.StdEncoding.EncodeToString(body)
}
_ = iconRes.Body.Close()
app.Icon = iconStr
app.TagsKey = l.AppProperty.Tags
if l.AppProperty.Recommend > 0 {
@@ -862,6 +876,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
if err != nil {
return err
}
defer composeRes.Body.Close()
bodyContent, err := io.ReadAll(composeRes.Body)
if err != nil {
return err
+1
View File
@@ -712,6 +712,7 @@ func syncAppInstallStatus(appInstall *model.AppInstall) error {
if err != nil {
return err
}
defer cli.Close()
containers, err := cli.ListContainersByName(containerNames)
if err != nil {
return err
+74 -39
View File
@@ -15,6 +15,9 @@ import (
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"github.com/docker/docker/api/types/container"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
@@ -37,7 +40,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/compose"
composeV2 "github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
dockerTypes "github.com/docker/docker/api/types"
"github.com/pkg/errors"
)
@@ -364,6 +366,7 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
}
_ = websiteRepo.DeleteAll(ctx)
_ = websiteDomainRepo.DeleteAll(ctx)
xpack.RemoveTamper("")
case constant.AppMysql, constant.AppMariaDB:
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
case constant.AppPostgresql:
@@ -448,23 +451,40 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
install.Status = constant.Upgrading
go func() {
var (
upErr error
backupFile string
)
global.LOG.Infof(i18n.GetMsgByKey("UpgradeAppStart"))
if backup {
if err = NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
global.LOG.Errorf(i18n.GetMsgWithMap("ErrAppBackup", map[string]interface{}{"name": install.Name, "err": err.Error()}))
backupRecord, err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name})
if err == nil {
localDir, err := loadLocalDir()
if err == nil {
backupFile = path.Join(localDir, backupRecord.FileDir, backupRecord.FileName)
} else {
global.LOG.Errorf(i18n.GetMsgWithName("ErrAppBackup", install.Name, err))
}
} else {
global.LOG.Errorf(i18n.GetMsgWithName("ErrAppBackup", install.Name, err))
}
}
var upErr error
defer func() {
if upErr != nil {
global.LOG.Infof(i18n.GetMsgWithName("ErrAppUpgrade", install.Name, upErr))
if backup {
if err := NewIBackupService().AppRecover(dto.CommonRecover{Name: install.App.Key, DetailName: install.Name, Type: "app", Source: constant.ResourceLocal}); err != nil {
global.LOG.Infof(i18n.GetMsgWithName("AppRecover", install.Name, nil))
if err := NewIBackupService().AppRecover(dto.CommonRecover{Name: install.App.Key, DetailName: install.Name, Type: "app", Source: constant.ResourceLocal, File: backupFile}); err != nil {
global.LOG.Errorf("recover app [%s] [%s] failed %v", install.App.Key, install.Name, err)
}
}
install.Status = constant.UpgradeErr
install.Message = upErr.Error()
_ = appInstallRepo.Save(context.Background(), &install)
existInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(installID))
if existInstall.ID > 0 {
existInstall.Status = constant.UpgradeErr
existInstall.Message = upErr.Error()
_ = appInstallRepo.Save(context.Background(), &existInstall)
}
}
}()
@@ -544,13 +564,15 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
if upErr = addDockerComposeCommonParam(composeMap, install.ServiceName, config, envs); upErr != nil {
return
}
paramByte, upErr := json.Marshal(envs)
if upErr != nil {
paramByte, err := json.Marshal(envs)
if err != nil {
upErr = err
return
}
install.Env = string(paramByte)
composeByte, upErr := yaml.Marshal(composeMap)
if upErr != nil {
composeByte, err := yaml.Marshal(composeMap)
if err != nil {
upErr = err
return
}
@@ -558,23 +580,6 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
install.Version = detail.Version
install.AppDetailId = detailID
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
return
}
envParams := make(map[string]string, len(envs))
handleMap(envs, envParams)
if err = env.Write(envParams, install.GetEnvPath()); err != nil {
return
}
if err = runScript(&install, "upgrade"); err != nil {
return
}
content, err := fileOp.GetContent(install.GetEnvPath())
if err != nil {
upErr = err
@@ -592,14 +597,36 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
upErr = err
return
}
defer dockerCli.Close()
for _, image := range images {
global.LOG.Infof(i18n.GetMsgWithName("PullImageStart", image, nil))
if err = dockerCli.PullImage(image, true); err != nil {
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
return
} else {
global.LOG.Infof(i18n.GetMsgByKey("PullImageSuccess"))
}
}
}
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
upErr = err
return
}
envParams := make(map[string]string, len(envs))
handleMap(envs, envParams)
if upErr = env.Write(envParams, install.GetEnvPath()); upErr != nil {
return
}
if upErr = runScript(&install, "upgrade"); upErr != nil {
return
}
if upErr = fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); upErr != nil {
return
}
@@ -613,6 +640,7 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
}
install.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &install)
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppSuccess", install.Name, nil))
}()
return appInstallRepo.Save(context.Background(), &install)
@@ -693,8 +721,8 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
strArray[i] = strings.ToLower(fmt.Sprintf("%v", t[i]))
}
envParams[k] = strings.Join(strArray, ",")
default:
envParams[k] = t.(string)
case map[string]interface{}:
handleMap(t, envParams)
}
}
}
@@ -827,7 +855,8 @@ func checkContainerNameIsExist(containerName, appDir string) (bool, error) {
if err != nil {
return false, err
}
var options dockerTypes.ContainerListOptions
defer client.Close()
var options container.ListOptions
list, err := client.ContainerList(context.Background(), options)
if err != nil {
return false, err
@@ -1225,14 +1254,20 @@ func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName
return buserr.New(constant.ErrFileParse)
}
serviceValue := service.(map[string]interface{})
deploy := map[string]interface{}{
"resources": map[string]interface{}{
"limits": map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
},
},
deploy := map[string]interface{}{}
if de, ok := serviceValue["deploy"]; ok {
deploy = de.(map[string]interface{})
}
resource := map[string]interface{}{}
if res, ok := deploy["resources"]; ok {
resource = res.(map[string]interface{})
}
resource["limits"] = map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
}
deploy["resources"] = resource
serviceValue["deploy"] = deploy
ports, ok := serviceValue["ports"].([]interface{})
+13 -3
View File
@@ -1,6 +1,7 @@
package service
import (
"crypto/hmac"
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -19,6 +20,7 @@ type AuthService struct{}
type IAuthService interface {
CheckIsSafety(code string) (string, error)
GetResponsePage() (string, error)
VerifyCode(code string) (bool, error)
Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error)
LogOut(c *gin.Context) error
@@ -42,7 +44,7 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
if err != nil {
return nil, constant.ErrAuth
}
if info.Password != pass || nameSetting.Value != info.Name {
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
@@ -78,7 +80,7 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
if err != nil {
return nil, err
}
if info.Password != pass || nameSetting.Value != info.Name {
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
@@ -168,7 +170,7 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
if err != nil {
return false, err
}
return setting.Value == code, nil
return hmac.Equal([]byte(setting.Value), []byte(code)), nil
}
func (u *AuthService) CheckIsSafety(code string) (string, error) {
@@ -184,3 +186,11 @@ func (u *AuthService) CheckIsSafety(code string) (string, error) {
}
return "unpass", nil
}
func (u *AuthService) GetResponsePage() (string, error) {
pageCode, err := settingRepo.Get(settingRepo.WithByKey("NoAuthSetting"))
if err != nil {
return "", err
}
return pageCode.Value, nil
}
+1 -1
View File
@@ -55,7 +55,7 @@ type IBackupService interface {
WebsiteBackup(db dto.CommonBackup) error
WebsiteRecover(req dto.CommonRecover) error
AppBackup(db dto.CommonBackup) error
AppBackup(db dto.CommonBackup) (*model.BackupRecord, error)
AppRecover(req dto.CommonRecover) error
Run()
+11 -11
View File
@@ -22,26 +22,26 @@ import (
"github.com/pkg/errors"
)
func (u *BackupService) AppBackup(req dto.CommonBackup) error {
func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, error) {
localDir, err := loadLocalDir()
if err != nil {
return err
return nil, err
}
app, err := appRepo.GetFirst(appRepo.WithKey(req.Name))
if err != nil {
return err
return nil, err
}
install, err := appInstallRepo.GetFirst(commonRepo.WithByName(req.DetailName), appInstallRepo.WithAppId(app.ID))
if err != nil {
return err
return nil, err
}
timeNow := time.Now().Format("20060102150405")
itemDir := fmt.Sprintf("app/%s/%s", req.Name, req.DetailName)
backupDir := path.Join(localDir, itemDir)
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
if err := handleAppBackup(&install, backupDir, fileName); err != nil {
return err
if err := handleAppBackup(&install, backupDir, fileName, ""); err != nil {
return nil, err
}
record := &model.BackupRecord{
@@ -56,9 +56,9 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) error {
if err := backupRepo.CreateRecord(record); err != nil {
global.LOG.Errorf("save backup record failed, err: %v", err)
return err
return nil, err
}
return nil
return record, nil
}
func (u *BackupService) AppRecover(req dto.CommonRecover) error {
@@ -84,7 +84,7 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error {
return nil
}
func handleAppBackup(install *model.AppInstall, backupDir, fileName string) error {
func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excludes string) error {
fileOp := files.NewFileOp()
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
if !fileOp.Stat(tmpDir) {
@@ -103,7 +103,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
}
appPath := install.GetPath()
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
if err := handleTar(appPath, tmpDir, "app.tar.gz", excludes); err != nil {
return err
}
@@ -164,7 +164,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format("20060102150405")))
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil {
return fmt.Errorf("backup app %s for rollback before recover failed, err: %v", install.Name, err)
}
defer func() {
+8 -7
View File
@@ -4,18 +4,19 @@ 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"
"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"
)
func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string) error {
func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, excludes string) error {
fileOp := files.NewFileOp()
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
if !fileOp.Stat(tmpDir) {
@@ -34,7 +35,7 @@ func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string) err
}
appPath := runtime.GetPath()
if err := handleTar(appPath, tmpDir, "runtime.tar.gz", ""); err != nil {
if err := handleTar(appPath, tmpDir, "runtime.tar.gz", excludes); err != nil {
return err
}
if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil {
@@ -72,7 +73,7 @@ func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback
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 {
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() {
+9 -9
View File
@@ -35,7 +35,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
itemDir := fmt.Sprintf("website/%s", req.Name)
backupDir := path.Join(localDir, itemDir)
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow+common.RandStrAndNum(5))
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil {
if err := handleWebsiteBackup(&website, backupDir, fileName, ""); err != nil {
return err
}
@@ -107,7 +107,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
isOk := false
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil {
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
}
defer func() {
@@ -182,7 +182,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
return nil
}
func handleWebsiteBackup(website *model.Website, backupDir, fileName string) error {
func handleWebsiteBackup(website *model.Website, backupDir, fileName string, excludes string) error {
fileOp := files.NewFileOp()
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
if !fileOp.Stat(tmpDir) {
@@ -216,7 +216,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
if err != nil {
return err
}
if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias)); err != nil {
if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes); err != nil {
return err
}
global.LOG.Info("put app.tar.gz into tmp dir successful")
@@ -226,7 +226,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
return err
}
if runtime.Type == constant.RuntimeNode {
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias)); err != nil {
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes); err != nil {
return err
}
global.LOG.Info("put runtime.tar.gz into tmp dir successful")
@@ -234,7 +234,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
}
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 {
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), excludes); err != nil {
return err
}
global.LOG.Info("put web.tar.gz into tmp dir successful, now start to tar tmp dir")
@@ -250,18 +250,18 @@ func checkValidOfWebsite(oldWebsite, website *model.Website) error {
return buserr.WithDetail(constant.ErrBackupMatch, fmt.Sprintf("oldName: %s, oldType: %v", oldWebsite.Alias, oldWebsite.Type), nil)
}
if oldWebsite.AppInstallID != 0 {
_, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
_, err := appInstallRepo.GetFirst(commonRepo.WithByID(oldWebsite.AppInstallID))
if err != nil {
return buserr.WithDetail(constant.ErrBackupMatch, "app", nil)
}
}
if oldWebsite.RuntimeID != 0 {
if _, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID)); err != nil {
if _, err := runtimeRepo.GetFirst(commonRepo.WithByID(oldWebsite.RuntimeID)); err != nil {
return buserr.WithDetail(constant.ErrBackupMatch, "runtime", nil)
}
}
if oldWebsite.WebsiteSSLID != 0 {
if _, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID)); err != nil {
if _, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(oldWebsite.WebsiteSSLID)); err != nil {
return buserr.WithDetail(constant.ErrBackupMatch, "ssl", nil)
}
}
+1 -1
View File
@@ -65,7 +65,7 @@ func (u *CommandService) SearchForTree() ([]dto.CommandTree, error) {
}
func (u *CommandService) SearchWithPage(search dto.SearchCommandWithPage) (int64, interface{}, error) {
total, commands, err := commandRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithByGroupID(search.GroupID), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
total, commands, err := commandRepo.Page(search.Page, search.PageSize, commandRepo.WithLikeName(search.Name), commonRepo.WithLikeName(search.Info), commonRepo.WithByGroupID(search.GroupID), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
if err != nil {
return 0, nil, err
}
+133 -95
View File
@@ -29,6 +29,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
@@ -87,7 +88,10 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
if err != nil {
return 0, nil, err
}
options := types.ContainerListOptions{All: true}
defer client.Close()
options := container.ListOptions{
All: true,
}
if len(req.Filters) != 0 {
options.Filters = filters.NewArgs()
options.Filters.Add("label", req.Filters)
@@ -216,7 +220,8 @@ func (u *ContainerService) List() ([]string, error) {
if err != nil {
return nil, err
}
containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
defer client.Close()
containers, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
return nil, err
}
@@ -237,7 +242,8 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
if err != nil {
return nil, err
}
list, err := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
defer client.Close()
list, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
return nil, err
}
@@ -259,6 +265,7 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
if err != nil {
return "", err
}
defer client.Close()
var inspectInfo interface{}
switch req.Type {
case "container":
@@ -286,6 +293,7 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
if err != nil {
return report, err
}
defer client.Close()
pruneFilters := filters.NewArgs()
if req.WithTagAll {
pruneFilters.Add("dangling", "false")
@@ -347,6 +355,7 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
if err != nil {
return err
}
defer client.Close()
ctx := context.Background()
newContainer, _ := client.ContainerInspect(ctx, req.Name)
if newContainer.ContainerJSONBase != nil {
@@ -376,14 +385,14 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
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)
con, 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})
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
return err
}
global.LOG.Infof("create container %s successful! now check if the container is started and delete the container information if it is not.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
if err := client.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
return fmt.Errorf("create successful but start failed, err: %v", err)
}
return nil
@@ -394,6 +403,7 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
if err != nil {
return nil, err
}
defer client.Close()
ctx := context.Background()
oldContainer, err := client.ContainerInspect(ctx, req.Name)
if err != nil {
@@ -410,6 +420,18 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
break
}
}
networkSettings := oldContainer.NetworkSettings
bridgeNetworkSettings := networkSettings.Networks[data.Network]
if bridgeNetworkSettings.IPAMConfig != nil {
ipv4Address := bridgeNetworkSettings.IPAMConfig.IPv4Address
data.Ipv4 = ipv4Address
ipv6Address := bridgeNetworkSettings.IPAMConfig.IPv6Address
data.Ipv6 = ipv6Address
} else {
data.Ipv4 = bridgeNetworkSettings.IPAddress
}
data.Cmd = oldContainer.Config.Cmd
data.OpenStdin = oldContainer.Config.OpenStdin
data.Tty = oldContainer.Config.Tty
@@ -442,7 +464,7 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
if oldContainer.HostConfig.Memory != 0 {
data.Memory = float64(oldContainer.HostConfig.Memory) / 1024 / 1024
}
data.Volumes = loadVolumeBinds(oldContainer.HostConfig.Binds)
data.Volumes = loadVolumeBinds(oldContainer.Mounts)
return &data, nil
}
@@ -452,6 +474,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
if err != nil {
return err
}
defer client.Close()
ctx := context.Background()
newContainer, _ := client.ContainerInspect(ctx, req.Name)
if newContainer.ContainerJSONBase != nil && newContainer.ID != req.ContainerID {
@@ -471,7 +494,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
}
}
if err := client.ContainerRemove(ctx, req.ContainerID, types.ContainerRemoveOptions{Force: true}); err != nil {
if err := client.ContainerRemove(ctx, req.ContainerID, container.RemoveOptions{Force: true}); err != nil {
return err
}
@@ -482,13 +505,13 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
}
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)
con, 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 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 {
if err := client.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
return fmt.Errorf("update successful but start failed, err: %v", err)
}
@@ -500,6 +523,7 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
if err != nil {
return err
}
defer client.Close()
ctx := context.Background()
oldContainer, err := client.ContainerInspect(ctx, req.Name)
if err != nil {
@@ -523,18 +547,18 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
break
}
}
if err := client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{Force: true}); err != nil {
if err := client.ContainerRemove(ctx, req.Name, container.RemoveOptions{Force: true}); err != nil {
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)
con, 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 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 {
if err := client.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
return fmt.Errorf("upgrade successful but start failed, err: %v", err)
}
@@ -547,6 +571,7 @@ func (u *ContainerService) ContainerRename(req dto.ContainerRename) error {
if err != nil {
return err
}
defer client.Close()
newContainer, _ := client.ContainerInspect(ctx, req.NewName)
if newContainer.ContainerJSONBase != nil {
@@ -562,11 +587,12 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
if err != nil {
return err
}
defer client.Close()
for _, item := range req.Names {
global.LOG.Infof("start container %s operation %s", item, req.Operation)
switch req.Operation {
case constant.ContainerOpStart:
err = client.ContainerStart(ctx, item, types.ContainerStartOptions{})
err = client.ContainerStart(ctx, item, container.StartOptions{})
case constant.ContainerOpStop:
err = client.ContainerStop(ctx, item, container.StopOptions{})
case constant.ContainerOpRestart:
@@ -578,7 +604,7 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
case constant.ContainerOpUnpause:
err = client.ContainerUnpause(ctx, item)
case constant.ContainerOpRemove:
err = client.ContainerRemove(ctx, item, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
err = client.ContainerRemove(ctx, item, container.RemoveOptions{RemoveVolumes: true, Force: true})
}
}
return err
@@ -589,6 +615,7 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
if err != nil {
return err
}
defer client.Close()
ctx := context.Background()
containerItem, err := client.ContainerInspect(ctx, req.Name)
if err != nil {
@@ -612,7 +639,7 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
_ = os.Remove(file)
}
if err := client.ContainerStart(ctx, containerItem.ID, types.ContainerStartOptions{}); err != nil {
if err := client.ContainerStart(ctx, containerItem.ID, container.StartOptions{}); err != nil {
return err
}
return nil
@@ -623,22 +650,26 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
if cmd.CheckIllegal(container, since, tail) {
return buserr.New(constant.ErrCmdIllegal)
}
command := fmt.Sprintf("docker logs %s", container)
commandName := "docker"
commandArg := []string{"logs", container}
if containerType == "compose" {
command = fmt.Sprintf("docker-compose -f %s logs", container)
commandName = "docker-compose"
commandArg = []string{"-f", container, "logs"}
}
if tail != "0" {
command += " --tail " + tail
commandArg = append(commandArg, "--tail")
commandArg = append(commandArg, tail)
}
if since != "all" {
command += " --since " + since
commandArg = append(commandArg, "--since")
commandArg = append(commandArg, since)
}
if follow {
command += " -f"
commandArg = append(commandArg, "-f")
}
command += " 2>&1"
cmd := exec.Command("bash", "-c", command)
if !follow {
cmd := exec.Command(commandName, commandArg...)
cmd.Stderr = cmd.Stdout
stdout, _ := cmd.CombinedOutput()
if !utf8.Valid(stdout) {
return errors.New("invalid utf8")
@@ -649,50 +680,53 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
return nil
}
cmd := exec.Command(commandName, commandArg...)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
if err := cmd.Start(); err != nil {
return err
}
defer func() {
_ = cmd.Process.Signal(syscall.SIGTERM)
_ = cmd.Wait()
}()
var exitCh chan struct{}
if follow {
go func() {
_, wsData, _ := wsConn.ReadMessage()
if string(wsData) == "close conn" {
exitCh <- struct{}{}
}
}()
return err
}
cmd.Stderr = cmd.Stdout
if err := cmd.Start(); err != nil {
_ = cmd.Process.Signal(syscall.SIGTERM)
return err
}
exitCh := make(chan struct{})
go func() {
_, wsData, _ := wsConn.ReadMessage()
if string(wsData) == "close conn" {
_ = cmd.Process.Signal(syscall.SIGTERM)
exitCh <- struct{}{}
}
}()
buffer := make([]byte, 1024)
for {
select {
case <-exitCh:
return nil
default:
n, err := stdout.Read(buffer)
if err != nil {
if err == io.EOF {
return err
go func() {
buffer := make([]byte, 1024)
for {
select {
case <-exitCh:
return
default:
n, err := stdout.Read(buffer)
if err != nil {
if err == io.EOF {
return
}
global.LOG.Errorf("read bytes from log failed, err: %v", err)
return
}
if !utf8.Valid(buffer[:n]) {
continue
}
if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil {
global.LOG.Errorf("send message with log to ws failed, err: %v", err)
return
}
global.LOG.Errorf("read bytes from log failed, err: %v", err)
continue
}
if !utf8.Valid(buffer[:n]) {
continue
}
if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil {
global.LOG.Errorf("send message with log to ws failed, err: %v", err)
return err
}
}
}
}()
_ = cmd.Wait()
return nil
}
func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error) {
@@ -700,6 +734,7 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
if err != nil {
return nil, err
}
defer client.Close()
res, err := client.ContainerStats(context.TODO(), id, false)
if err != nil {
return nil, err
@@ -735,7 +770,8 @@ func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) s
if err != nil {
return ""
}
options := types.ContainerListOptions{All: true}
defer cli.Close()
options := container.ListOptions{All: true}
options.Filters = filters.NewArgs()
options.Filters.Add("label", fmt.Sprintf("%s=%s", composeProjectLabel, req.Name))
containers, err := cli.ContainerList(context.Background(), options)
@@ -875,12 +911,11 @@ func loadCpuAndMem(client *client.Client, container string) dto.ContainerListSta
return data
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
res.Body.Close()
return data
}
res.Body.Close()
var stats *types.StatsJSON
if err := json.Unmarshal(body, &stats); err != nil {
return data
@@ -976,8 +1011,21 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
case "host", "none", "bridge":
hostConf.NetworkMode = container.NetworkMode(req.Network)
}
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
if req.Ipv4 != "" || req.Ipv6 != "" {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{
req.Network: {
IPAMConfig: &network.EndpointIPAMConfig{
IPv4Address: req.Ipv4,
IPv6Address: req.Ipv6,
},
}}
} else {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
}
} else {
if req.Ipv4 != "" || req.Ipv6 != "" {
return nil, nil, nil, fmt.Errorf("Please set up the network")
}
networkConf = network.NetworkingConfig{}
}
@@ -994,10 +1042,19 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
hostConf.MemorySwap = 0
hostConf.PortBindings = portMap
hostConf.Binds = []string{}
hostConf.Mounts = []mount.Mount{}
config.Volumes = make(map[string]struct{})
for _, volume := range req.Volumes {
config.Volumes[volume.ContainerDir] = struct{}{}
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
if volume.Type == "volume" {
hostConf.Mounts = append(hostConf.Mounts, mount.Mount{
Type: mount.Type(volume.Type),
Source: volume.SourceDir,
Target: volume.ContainerDir,
})
config.Volumes[volume.ContainerDir] = struct{}{}
} else {
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
}
}
return &config, &hostConf, &networkConf, nil
}
@@ -1018,46 +1075,27 @@ func reCreateAfterUpdate(name string, client *client.Client, config *container.C
global.LOG.Errorf("recreate after container update failed, err: %v", err)
return
}
if err := client.ContainerStart(ctx, oldContainer.ID, types.ContainerStartOptions{}); err != nil {
if err := client.ContainerStart(ctx, oldContainer.ID, container.StartOptions{}); 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 {
func loadVolumeBinds(binds []types.MountPoint) []dto.VolumeHelper {
var datas []dto.VolumeHelper
for _, bind := range binds {
parts := strings.Split(bind, ":")
var volumeItem dto.VolumeHelper
if len(parts) > 3 {
continue
volumeItem.Type = string(bind.Type)
if bind.Type == "volume" {
volumeItem.SourceDir = bind.Name
} else {
volumeItem.SourceDir = bind.Source
}
volumeItem.SourceDir = parts[0]
if len(parts) == 1 {
volumeItem.ContainerDir = parts[0]
volumeItem.ContainerDir = bind.Destination
volumeItem.Mode = "ro"
if bind.RW {
volumeItem.Mode = "rw"
}
if len(parts) == 2 {
switch parts[1] {
case "r", "ro":
volumeItem.ContainerDir = parts[0]
volumeItem.Mode = "ro"
case "rw":
volumeItem.ContainerDir = parts[0]
volumeItem.Mode = "rw"
default:
volumeItem.ContainerDir = parts[1]
volumeItem.Mode = "rw"
}
}
if len(parts) == 3 {
volumeItem.ContainerDir = parts[1]
if parts[2] == "r" {
volumeItem.Mode = "ro"
} else {
volumeItem.Mode = parts[2]
}
}
datas = append(datas, volumeItem)
}
return datas
+4 -2
View File
@@ -12,6 +12,8 @@ import (
"strings"
"time"
"github.com/docker/docker/api/types/container"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
@@ -20,7 +22,6 @@ import (
"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/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"golang.org/x/net/context"
)
@@ -39,8 +40,9 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
if err != nil {
return 0, nil, err
}
defer client.Close()
options := types.ContainerListOptions{All: true}
options := container.ListOptions{All: true}
options.Filters = filters.NewArgs()
options.Filters.Add("label", composeProjectLabel)
+4
View File
@@ -19,6 +19,7 @@ func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface
if err != nil {
return 0, nil, err
}
defer client.Close()
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
if err != nil {
return 0, nil, err
@@ -81,6 +82,7 @@ func (u *ContainerService) ListNetwork() ([]dto.Options, error) {
if err != nil {
return nil, err
}
defer client.Close()
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
if err != nil {
return nil, err
@@ -100,6 +102,7 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
if err != nil {
return err
}
defer client.Close()
for _, id := range req.Names {
if err := client.NetworkRemove(context.TODO(), id); err != nil {
if strings.Contains(err.Error(), "has active endpoints") {
@@ -115,6 +118,7 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
if err != nil {
return err
}
defer client.Close()
var (
ipams []network.IPAMConfig
enableV6 bool
+3
View File
@@ -82,6 +82,7 @@ func (u *ContainerService) ListVolume() ([]dto.Options, error) {
if err != nil {
return nil, err
}
defer client.Close()
list, err := client.VolumeList(context.TODO(), volume.ListOptions{})
if err != nil {
return nil, err
@@ -102,6 +103,7 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
if err != nil {
return err
}
defer client.Close()
for _, id := range req.Names {
if err := client.VolumeRemove(context.TODO(), id, true); err != nil {
if strings.Contains(err.Error(), "volume is in use") {
@@ -117,6 +119,7 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreate) error {
if err != nil {
return err
}
defer client.Close()
arg := filters.NewArgs()
arg.Add("name", req.Name)
vos, _ := client.VolumeList(context.TODO(), volume.ListOptions{Filters: arg})
+1
View File
@@ -265,6 +265,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
upMap["name"] = req.Name
upMap["spec"] = spec
upMap["script"] = req.Script
upMap["command"] = req.Command
upMap["container_name"] = req.ContainerName
upMap["app_id"] = req.AppID
upMap["website"] = req.Website
+6 -6
View File
@@ -41,7 +41,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
if err := handleAppBackup(&app, backupDir, record.FileName); err != nil {
if err := handleAppBackup(&app, backupDir, record.FileName, cronjob.ExclusionRules); err != nil {
return err
}
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
@@ -74,7 +74,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain))
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405")+common.RandStrAndNum(5))
if err := handleWebsiteBackup(&web, backupDir, record.FileName); err != nil {
if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules); err != nil {
return err
}
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
@@ -326,7 +326,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(logFiles) != 0 {
for i := 0; i < len(logFiles); i++ {
if !logFiles[i].IsDir() {
_ = cpBinary([]string{path.Join(itemDir, logFiles[i].Name())}, dirItem)
_ = common.CopyFile(path.Join(itemDir, logFiles[i].Name()), dirItem)
}
}
}
@@ -335,7 +335,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(logFiles2) != 0 {
for i := 0; i < len(logFiles2); i++ {
if !logFiles2[i].IsDir() {
_ = cpBinary([]string{path.Join(itemDir2, logFiles2[i].Name())}, dirItem)
_ = common.CopyFile(path.Join(itemDir2, logFiles2[i].Name()), dirItem)
}
}
}
@@ -354,7 +354,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(systemLogFiles) != 0 {
for i := 0; i < len(systemLogFiles); i++ {
if !systemLogFiles[i].IsDir() {
_ = cpBinary([]string{path.Join(systemLogDir, systemLogFiles[i].Name())}, systemDir)
_ = common.CopyFile(path.Join(systemLogDir, systemLogFiles[i].Name()), systemDir)
}
}
}
@@ -370,7 +370,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(loginLogFiles) != 0 {
for i := 0; i < len(loginLogFiles); i++ {
if !loginLogFiles[i].IsDir() && (strings.HasPrefix(loginLogFiles[i].Name(), "secure") || strings.HasPrefix(loginLogFiles[i].Name(), "auth.log")) {
_ = cpBinary([]string{path.Join("/var/log", loginLogFiles[i].Name())}, loginDir)
_ = common.CopyFile(path.Join("/var/log", loginLogFiles[i].Name()), loginDir)
}
}
}
+5 -1
View File
@@ -38,7 +38,11 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
script := cronjob.Script
if len(cronjob.ContainerName) != 0 {
script = fmt.Sprintf("docker exec %s %s", cronjob.ContainerName, cronjob.Script)
command := "sh"
if len(cronjob.Command) != 0 {
command = cronjob.Command
}
script = fmt.Sprintf("docker exec %s %s -c \"%s\"", cronjob.ContainerName, command, strings.ReplaceAll(cronjob.Script, "\"", "\\\""))
}
err = u.handleShell(cronjob.Type, cronjob.Name, script, record.Records)
u.removeExpiredLog(*cronjob)
+21
View File
@@ -11,6 +11,8 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/copier"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/host"
@@ -154,6 +156,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
currentInfo.SwapMemoryUsedPercent = swapInfo.UsedPercent
currentInfo.DiskData = loadDiskInfo()
currentInfo.GPUData = loadGPUInfo()
if ioOption == "all" {
diskInfo, _ := disk.IOCounters()
@@ -289,3 +292,21 @@ func loadDiskInfo() []dto.DiskInfo {
})
return datas
}
func loadGPUInfo() []dto.GPUInfo {
list := xpack.LoadGpuInfo()
if len(list) == 0 {
return nil
}
var data []dto.GPUInfo
for _, gpu := range list {
var dataItem dto.GPUInfo
if err := copier.Copy(&dataItem, &gpu); err != nil {
continue
}
dataItem.PowerUsage = dataItem.PowerDraw + " / " + dataItem.MaxPowerLimit
dataItem.MemoryUsage = dataItem.MemUsed + " / " + dataItem.MemTotal
data = append(data, dataItem)
}
return data
}
+9 -8
View File
@@ -456,7 +456,7 @@ func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool,
if err != nil {
return false, err
}
hosts, err := executeSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
hosts, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "select host from mysql.user where user='root';")
if err != nil {
return false, err
}
@@ -474,7 +474,7 @@ func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.Mys
if err != nil {
return nil, err
}
variableMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global variables;")
variableMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global variables;")
if err != nil {
return nil, err
}
@@ -493,7 +493,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
return nil, err
}
statusMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global status;")
statusMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global status;")
if err != nil {
return nil, err
}
@@ -517,7 +517,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
info.File = "OFF"
info.Position = "OFF"
rows, err := executeSqlForRows(app.ContainerName, app.Password, "show master status;")
rows, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "show master status;")
if err != nil {
return nil, err
}
@@ -532,8 +532,8 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
return &info, nil
}
func executeSqlForMaps(containerName, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
func executeSqlForMaps(containerName, dbType, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, dbType, "-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", "")
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
@@ -551,8 +551,8 @@ func executeSqlForMaps(containerName, password, command string) (map[string]stri
return rowMap, nil
}
func executeSqlForRows(containerName, password, command string) ([]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
func executeSqlForRows(containerName, dbType, password, command string) ([]string, error) {
cmd := exec.Command("docker", "exec", containerName, dbType, "-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", "")
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
@@ -614,6 +614,7 @@ func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
if err != nil {
return nil, "", err
}
dbInfo.Type = databaseItem.Type
dbInfo.From = databaseItem.From
dbInfo.Database = database
if dbInfo.From != "local" {
+2
View File
@@ -55,6 +55,7 @@ func (u *DockerService) LoadDockerStatus() string {
if err != nil {
return constant.Stopped
}
defer client.Close()
if _, err := client.Ping(context.Background()); err != nil {
return constant.Stopped
}
@@ -72,6 +73,7 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
if err != nil {
data.Status = constant.Stopped
} else {
defer client.Close()
if _, err := client.Ping(ctx); err != nil {
data.Status = constant.Stopped
}
+45 -11
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"io/fs"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
@@ -116,22 +117,32 @@ func (f *FileService) GetFileTree(op request.FileOption) ([]response.FileTree, e
}
func (f *FileService) Create(op request.FileCreate) error {
if files.IsInvalidChar(op.Path) {
return buserr.New("ErrInvalidChar")
}
fo := files.NewFileOp()
if fo.Stat(op.Path) {
return buserr.New(constant.ErrFileIsExit)
}
if op.IsDir {
return fo.CreateDir(op.Path, fs.FileMode(op.Mode))
} else {
if op.IsLink {
if !fo.Stat(op.LinkPath) {
return buserr.New(constant.ErrLinkPathNotFound)
}
return fo.LinkFile(op.LinkPath, op.Path, op.IsSymlink)
mode := op.Mode
if mode == 0 {
fileInfo, err := os.Stat(filepath.Dir(op.Path))
if err == nil {
mode = int64(fileInfo.Mode().Perm())
} else {
return fo.CreateFile(op.Path)
mode = 0755
}
}
if op.IsDir {
return fo.CreateDirWithMode(op.Path, fs.FileMode(mode))
}
if op.IsLink {
if !fo.Stat(op.LinkPath) {
return buserr.New(constant.ErrLinkPathNotFound)
}
return fo.LinkFile(op.LinkPath, op.Path, op.IsSymlink)
}
return fo.CreateFileWithMode(op.Path, fs.FileMode(mode))
}
func (f *FileService) Delete(op request.FileDelete) error {
@@ -236,6 +247,9 @@ func (f *FileService) SaveContent(edit request.FileEdit) error {
}
func (f *FileService) ChangeName(req request.FileRename) error {
if files.IsInvalidChar(req.NewName) {
return buserr.New("ErrInvalidChar")
}
fo := files.NewFileOp()
return fo.Rename(req.OldName, req.NewName)
}
@@ -299,12 +313,32 @@ func (f *FileService) FileDownload(d request.FileDownload) (string, error) {
}
func (f *FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) {
var (
res response.DirSizeRes
)
if req.Path == "/proc" {
return res, nil
}
cmd := exec.Command("du", "-s", req.Path)
output, err := cmd.Output()
if err == nil {
fields := strings.Fields(string(output))
if len(fields) == 2 {
var cmdSize int64
_, err = fmt.Sscanf(fields[0], "%d", &cmdSize)
if err == nil {
res.Size = float64(cmdSize * 1024)
return res, nil
}
}
}
fo := files.NewFileOp()
size, err := fo.GetDirSize(req.Path)
if err != nil {
return response.DirSizeRes{}, err
return res, err
}
return response.DirSizeRes{Size: size}, nil
res.Size = size
return res, nil
}
func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) {
+32 -20
View File
@@ -13,6 +13,9 @@ import (
"strings"
"time"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
@@ -43,7 +46,7 @@ func NewIImageService() IImageService {
}
func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error) {
var (
list []types.ImageSummary
list []image.Summary
records []dto.ImageInfo
backDatas []dto.ImageInfo
)
@@ -51,11 +54,12 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
if err != nil {
return 0, nil, err
}
list, err = client.ImageList(context.Background(), types.ImageListOptions{})
defer client.Close()
list, err = client.ImageList(context.Background(), image.ListOptions{})
if err != nil {
return 0, nil, err
}
containers, _ := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
containers, _ := client.ContainerList(context.Background(), container.ListOptions{All: true})
if len(req.Info) != 0 {
length, count := len(list), 0
for count < length {
@@ -104,11 +108,12 @@ func (u *ImageService) ListAll() ([]dto.ImageInfo, error) {
if err != nil {
return nil, err
}
list, err := client.ImageList(context.Background(), types.ImageListOptions{})
defer client.Close()
list, err := client.ImageList(context.Background(), image.ListOptions{})
if err != nil {
return nil, err
}
containers, _ := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
containers, _ := client.ContainerList(context.Background(), container.ListOptions{All: true})
for _, image := range list {
size := formatFileSize(image.Size)
records = append(records, dto.ImageInfo{
@@ -124,14 +129,15 @@ func (u *ImageService) ListAll() ([]dto.ImageInfo, error) {
func (u *ImageService) List() ([]dto.Options, error) {
var (
list []types.ImageSummary
list []image.Summary
backDatas []dto.Options
)
client, err := docker.NewDockerClient()
if err != nil {
return nil, err
}
list, err = client.ImageList(context.Background(), types.ImageListOptions{})
defer client.Close()
list, err = client.ImageList(context.Background(), image.ListOptions{})
if err != nil {
return nil, err
}
@@ -150,6 +156,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
if err != nil {
return "", err
}
defer client.Close()
fileName := "Dockerfile"
if req.From == "edit" {
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
@@ -233,6 +240,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
if err != nil {
return "", err
}
defer client.Close()
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
if _, err := os.Stat(dockerLogDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dockerLogDir, os.ModePerm); err != nil {
@@ -263,7 +271,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
if err != nil {
return "", err
}
options := types.ImagePullOptions{}
options := image.PullOptions{}
if repo.Auth {
authConfig := registry.AuthConfig{
Username: repo.Username,
@@ -303,10 +311,12 @@ func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
if err != nil {
return err
}
defer client.Close()
res, err := client.ImageLoad(context.TODO(), file, true)
if err != nil {
return err
}
defer res.Body.Close()
content, err := io.ReadAll(res.Body)
if err != nil {
return err
@@ -322,6 +332,7 @@ func (u *ImageService) ImageSave(req dto.ImageSave) error {
if err != nil {
return err
}
defer client.Close()
out, err := client.ImageSave(context.TODO(), []string{req.TagName})
if err != nil {
@@ -344,6 +355,7 @@ func (u *ImageService) ImageTag(req dto.ImageTag) error {
if err != nil {
return err
}
defer client.Close()
if err := client.ImageTag(context.TODO(), req.SourceID, req.TargetName); err != nil {
return err
@@ -356,23 +368,22 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
if err != nil {
return "", err
}
defer client.Close()
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
if err != nil {
return "", err
}
options := types.ImagePushOptions{}
if repo.Auth {
authConfig := registry.AuthConfig{
Username: repo.Username,
Password: repo.Password,
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
return "", err
}
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
options.RegistryAuth = authStr
options := image.PushOptions{All: true}
authConfig := registry.AuthConfig{
Username: repo.Username,
Password: repo.Password,
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
return "", err
}
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
options.RegistryAuth = authStr
newName := fmt.Sprintf("%s/%s", repo.DownloadUrl, req.Name)
if newName != req.TagName {
if err := client.ImageTag(context.TODO(), req.TagName, newName); err != nil {
@@ -414,6 +425,7 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
if err != nil {
return err
}
defer client.Close()
for _, id := range req.Names {
if _, err := client.ImageRemove(context.TODO(), id, types.ImageRemoveOptions{Force: req.Force, PruneChildren: true}); err != nil {
if strings.Contains(err.Error(), "image is being used") || strings.Contains(err.Error(), "is using") {
+3 -1
View File
@@ -2,7 +2,6 @@ package service
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"io"
"net/http"
"os"
@@ -10,6 +9,8 @@ import (
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
@@ -76,6 +77,7 @@ func (n NginxService) GetStatus() (response.NginxStatus, error) {
if err != nil {
return response.NginxStatus{}, err
}
defer res.Body.Close()
content, err := io.ReadAll(res.Body)
if err != nil {
return response.NginxStatus{}, err
+23 -7
View File
@@ -4,6 +4,14 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"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"
@@ -19,13 +27,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/pkg/errors"
"github.com/subosito/gotenv"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
)
type RuntimeService struct {
@@ -43,6 +44,7 @@ type IRuntimeService interface {
OperateNodeModules(req request.NodeModuleOperateReq) error
SyncForRestart() error
SyncRuntimeStatus() error
DeleteCheck(installID uint) ([]dto.AppResource, error)
}
func NewRuntimeService() IRuntimeService {
@@ -176,6 +178,18 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt
return total, res, nil
}
func (r *RuntimeService) DeleteCheck(runTimeId uint) ([]dto.AppResource, error) {
var res []dto.AppResource
websites, _ := websiteRepo.GetBy(websiteRepo.WithRuntimeID(runTimeId))
for _, website := range websites {
res = append(res, dto.AppResource{
Type: "website",
Name: website.PrimaryDomain,
})
}
return res, nil
}
func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(runtimeDelete.ID))
if err != nil {
@@ -193,6 +207,7 @@ func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
if err != nil {
return err
}
defer client.Close()
imageID, err := client.GetImageIDByName(runtime.Image)
if err != nil {
return err
@@ -420,6 +435,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
if err != nil {
return err
}
defer client.Close()
imageID, err := client.GetImageIDByName(oldImage)
if err != nil {
return err
+18 -9
View File
@@ -3,6 +3,15 @@ package service
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
@@ -13,14 +22,6 @@ import (
"github.com/pkg/errors"
"github.com/subosito/gotenv"
"gopkg.in/yaml.v3"
"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) {
@@ -53,7 +54,12 @@ func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp fil
}
go func() {
_, _ = http.Get(nodeDetail.DownloadCallBackUrl)
res, err := http.Get(nodeDetail.DownloadCallBackUrl)
if err != nil {
global.LOG.Errorf("http request failed(handleNode), err: %v", err)
return
}
res.Body.Close()
}()
go startRuntime(runtime)
@@ -172,6 +178,7 @@ func SyncRuntimeContainerStatus(runtime *model.Runtime) error {
if err != nil {
return err
}
defer cli.Close()
containers, err := cli.ListContainersByName(containerNames)
if err != nil {
return err
@@ -228,6 +235,7 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
if oldImageID != "" {
client, err := docker.NewClient()
if err == nil {
defer client.Close()
newImageID, err := client.GetImageIDByName(runtime.Image)
if err == nil && newImageID != oldImageID {
global.LOG.Infof("delete imageID [%s] ", oldImageID)
@@ -390,6 +398,7 @@ func checkContainerName(name string) error {
if err != nil {
return err
}
defer dockerCli.Close()
names, err := dockerCli.ListContainersByName([]string{name})
if err != nil {
return err
-9
View File
@@ -385,15 +385,6 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
}
}
func cpBinary(src []string, dst string) error {
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 fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
}
return nil
}
func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
+10 -2
View File
@@ -43,7 +43,15 @@ func snapPanel(snap snapHelper, targetDir string) {
defer snap.Wg.Done()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel": constant.Running})
status := constant.StatusDone
if err := cpBinary([]string{"/usr/local/bin/1panel", "/usr/local/bin/1pctl", "/etc/systemd/system/1panel.service"}, targetDir); err != nil {
if err := common.CopyFile("/usr/local/bin/1panel", path.Join(targetDir, "1panel")); err != nil {
status = err.Error()
}
if err := common.CopyFile("/usr/local/bin/1pctl", targetDir); err != nil {
status = err.Error()
}
if err := common.CopyFile("/etc/systemd/system/1panel.service", targetDir); err != nil {
status = err.Error()
}
snap.Status.Panel = status
@@ -59,7 +67,7 @@ func snapDaemonJson(snap snapHelper, targetDir string) {
return
}
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": constant.Running})
if err := cpBinary([]string{"/etc/docker/daemon.json"}, path.Join(targetDir, "daemon.json")); err != nil {
if err := common.CopyFile("/etc/docker/daemon.json", targetDir); err != nil {
status = err.Error()
}
snap.Status.DaemonJson = status
+6 -7
View File
@@ -13,6 +13,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/pkg/errors"
)
@@ -88,7 +89,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
}
if req.IsNew || snap.InterruptStep == "1PanelBinary" {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel"), "/usr/local/bin/1panel"); err != nil {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel"), "/usr/local/bin"); err != nil {
updateRecoverStatus(snap.ID, isRecover, "1PanelBinary", constant.StatusFailed, err.Error())
return
}
@@ -96,7 +97,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
req.IsNew = true
}
if req.IsNew || snap.InterruptStep == "1PctlBinary" {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1pctl"), "/usr/local/bin/1pctl"); err != nil {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1pctl"), "/usr/local/bin"); err != nil {
updateRecoverStatus(snap.ID, isRecover, "1PctlBinary", constant.StatusFailed, err.Error())
return
}
@@ -104,7 +105,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
req.IsNew = true
}
if req.IsNew || snap.InterruptStep == "1PanelService" {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel.service"), "/etc/systemd/system/1panel.service"); err != nil {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel.service"), "/etc/systemd/system"); err != nil {
updateRecoverStatus(snap.ID, isRecover, "1PanelService", constant.StatusFailed, err.Error())
return
}
@@ -235,10 +236,8 @@ func recoverPanel(src string, dst string) error {
if _, err := os.Stat(src); err != nil {
return fmt.Errorf("file is not found in %s, err: %v", src, err)
}
global.LOG.Debugf(fmt.Sprintf("\\cp -f %s %s", src, dst))
stdout, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", src, dst))
if err != nil {
return fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
if err := common.CopyFile(src, dst); err != nil {
return fmt.Errorf("cp file failed, err: %v", err)
}
return nil
}
+139 -54
View File
@@ -7,12 +7,11 @@ import (
"net/http"
"os"
"path"
"strconv"
"strings"
"time"
"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/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
@@ -37,45 +36,43 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
if err != nil {
return nil, err
}
latestVersion, err := u.loadVersion(true, currentVersion.Value)
DeveloperMode, err := settingRepo.Get(settingRepo.WithByKey("DeveloperMode"))
if err != nil {
global.LOG.Infof("load latest version failed, err: %v", err)
return nil, err
}
if !common.CompareVersion(string(latestVersion), currentVersion.Value) {
return nil, err
upgrade.TestVersion, upgrade.NewVersion, upgrade.LatestVersion = u.loadVersionByMode(DeveloperMode.Value, currentVersion.Value)
var itemVersion string
if len(upgrade.LatestVersion) != 0 {
itemVersion = upgrade.LatestVersion
}
upgrade.LatestVersion = latestVersion
if latestVersion[0:4] == currentVersion.Value[0:4] {
upgrade.NewVersion = ""
} else {
newerVersion, err := u.loadVersion(false, currentVersion.Value)
if err != nil {
global.LOG.Infof("load newer version failed, err: %v", err)
return nil, err
}
if newerVersion == currentVersion.Value {
upgrade.NewVersion = ""
} else {
upgrade.NewVersion = newerVersion
}
}
itemVersion := upgrade.LatestVersion
if upgrade.NewVersion != "" {
if len(upgrade.NewVersion) != 0 {
itemVersion = upgrade.NewVersion
}
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, itemVersion, itemVersion))
if (global.CONF.System.Mode == "dev" || DeveloperMode.Value == "enable") && len(upgrade.TestVersion) != 0 {
itemVersion = upgrade.TestVersion
}
if len(itemVersion) == 0 {
return &upgrade, nil
}
mode := global.CONF.System.Mode
if strings.Contains(itemVersion, "beta") {
mode = "beta"
}
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, mode, itemVersion, itemVersion))
if err != nil {
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", latestVersion, err)
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", itemVersion, err)
}
upgrade.ReleaseNote = notes
return &upgrade, nil
}
func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version, req.Version))
mode := global.CONF.System.Mode
if strings.Contains(req.Version, "beta") {
mode = "beta"
}
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, mode, req.Version, req.Version))
if err != nil {
return "", fmt.Errorf("load releases-notes of version %s failed, err: %v", req.Version, err)
}
@@ -99,7 +96,11 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
return err
}
downloadPath := fmt.Sprintf("%s/%s/%s/release", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version)
mode := global.CONF.System.Mode
if strings.Contains(req.Version, "beta") {
mode = "beta"
}
downloadPath := fmt.Sprintf("%s/%s/%s/release", global.CONF.System.RepoUrl, mode, req.Version)
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", itemArch)
_ = settingRepo.Update("SystemStatus", "Upgrading")
go func() {
@@ -130,13 +131,13 @@ 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 {
if err := common.CopyFile(path.Join(tmpDir, "1panel"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
u.handleRollback(originalDir, 1)
return
}
if err := cpBinary([]string{tmpDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
if err := common.CopyFile(path.Join(tmpDir, "1pctl"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
u.handleRollback(originalDir, 2)
return
@@ -147,7 +148,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
return
}
if err := cpBinary([]string{tmpDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
if err := common.CopyFile(path.Join(tmpDir, "1panel.service"), "/etc/systemd/system"); err != nil {
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
u.handleRollback(originalDir, 3)
return
@@ -173,66 +174,150 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
if err := fileOp.Copy("/etc/systemd/system/1panel.service", originalDir); err != nil {
return err
}
dbPath := global.CONF.System.DbPath + "/" + global.CONF.System.DbFile
if err := fileOp.Copy(dbPath, originalDir); err != nil {
checkPointOfWal()
if err := handleTar(path.Join(global.CONF.System.BaseDir, "1panel/db"), originalDir, "db.tar.gz", "./1Panel.db-*"); err != nil {
return err
}
return nil
}
func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
dbPath := global.CONF.System.DbPath + "/1Panel.db"
_ = settingRepo.Update("SystemStatus", "Free")
if err := cpBinary([]string{originalDir + "/1Panel.db"}, dbPath); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
checkPointOfWal()
if _, err := os.Stat(path.Join(originalDir, "1Panel.db")); err == nil {
if err := common.CopyFile(path.Join(originalDir, "1Panel.db"), global.CONF.System.DbPath); err != nil {
global.LOG.Errorf("rollback 1panel db failed, err: %v", err)
}
}
if err := cpBinary([]string{originalDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
if _, err := os.Stat(path.Join(originalDir, "db.tar.gz")); err == nil {
if err := handleUnTar(path.Join(originalDir, "db.tar.gz"), global.CONF.System.DbPath); err != nil {
global.LOG.Errorf("rollback 1panel db failed, err: %v", err)
}
}
if err := common.CopyFile(path.Join(originalDir, "1panel"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
}
if errStep == 1 {
return
}
if err := cpBinary([]string{originalDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
if err := common.CopyFile(path.Join(originalDir, "1pctl"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
if errStep == 2 {
return
}
if err := cpBinary([]string{originalDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
if err := common.CopyFile(path.Join(originalDir, "1panel.service"), "/etc/systemd/system"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
}
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (string, error) {
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode)
func (u *UpgradeService) loadVersionByMode(developer, currentVersion string) (string, string, string) {
var current, latest string
if global.CONF.System.Mode == "dev" {
betaVersionLatest := u.loadVersion(true, currentVersion, "beta")
devVersionLatest := u.loadVersion(true, currentVersion, "dev")
if common.ComparePanelVersion(betaVersionLatest, devVersionLatest) {
return betaVersionLatest, "", ""
}
return devVersionLatest, "", ""
}
betaVersionLatest := ""
latest = u.loadVersion(true, currentVersion, "stable")
current = u.loadVersion(false, currentVersion, "stable")
if developer == "enable" {
betaVersionLatest = u.loadVersion(true, currentVersion, "beta")
}
if current != latest {
return betaVersionLatest, current, latest
}
versionPart := strings.Split(current, ".")
if len(versionPart) < 3 {
return betaVersionLatest, current, latest
}
num, _ := strconv.Atoi(versionPart[1])
if num == 0 {
return betaVersionLatest, current, latest
}
if num >= 10 {
if current[:6] == currentVersion[:6] {
return betaVersionLatest, current, ""
}
return betaVersionLatest, "", latest
}
if current[:5] == currentVersion[:5] {
return betaVersionLatest, current, ""
}
return betaVersionLatest, "", latest
}
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion, mode string) string {
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, mode)
if !isLatest {
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, global.CONF.System.Mode)
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, mode)
}
latestVersionRes, err := http.Get(path)
if err != nil {
return "", buserr.New(constant.ErrOSSConn)
global.LOG.Errorf("load latest version from oss failed, err: %v", err)
return ""
}
defer latestVersionRes.Body.Close()
version, err := io.ReadAll(latestVersionRes.Body)
if err != nil {
return "", buserr.New(constant.ErrOSSConn)
versionByte, err := io.ReadAll(latestVersionRes.Body)
version := string(versionByte)
if err != nil || strings.Contains(version, "<") {
global.LOG.Errorf("load latest version from oss failed, err: %v", version)
return ""
}
if isLatest {
return string(version), nil
return u.checkVersion(version, currentVersion)
}
versionMap := make(map[string]string)
if err := json.Unmarshal(version, &versionMap); err != nil {
return "", buserr.New(constant.ErrOSSConn)
if err := json.Unmarshal(versionByte, &versionMap); err != nil {
global.LOG.Errorf("load latest version from oss failed (error unmarshal), err: %v", err)
return ""
}
if len(currentVersion) < 4 {
return "", fmt.Errorf("current version is error format: %s", currentVersion)
versionPart := strings.Split(currentVersion, ".")
if len(versionPart) < 3 {
global.LOG.Errorf("current version is error format: %s", currentVersion)
return ""
}
num, _ := strconv.Atoi(versionPart[1])
if num == 0 {
global.LOG.Errorf("current version is error format: %s", currentVersion)
return ""
}
if num >= 10 {
if version, ok := versionMap[currentVersion[0:5]]; ok {
return u.checkVersion(version, currentVersion)
}
return ""
}
if version, ok := versionMap[currentVersion[0:4]]; ok {
return version, nil
return u.checkVersion(version, currentVersion)
}
return "", buserr.New(constant.ErrOSSConn)
return ""
}
func (u *UpgradeService) checkVersion(v2, v1 string) string {
addSuffix := false
if !strings.Contains(v1, "-") {
v1 = v1 + "-lts"
}
if !strings.Contains(v2, "-") {
addSuffix = true
v2 = v2 + "-lts"
}
if common.ComparePanelVersion(v2, v1) {
if addSuffix {
return strings.TrimSuffix(v2, "-lts")
}
return v2
}
return ""
}
func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
+124 -83
View File
@@ -61,6 +61,7 @@ type IWebsiteService interface {
UpdateWebsite(req request.WebsiteUpdate) error
DeleteWebsite(req request.WebsiteDelete) error
GetWebsite(id uint) (response.WebsiteDTO, error)
CreateWebsiteDomain(create request.WebsiteDomainCreate) ([]model.WebsiteDomain, error)
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
DeleteWebsiteDomain(domainId uint) error
@@ -75,10 +76,6 @@ type IWebsiteService interface {
ChangeDefaultServer(id uint) error
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
UpdateWafConfig(req request.WebsiteWafUpdate) error
UpdateWafFile(req request.WebsiteWafFileUpdate) (err error)
GetPHPConfig(id uint) (*response.PHPConfig, error)
UpdatePHPConfig(req request.WebsitePHPConfigUpdate) error
UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) error
@@ -182,9 +179,10 @@ func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
}
func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error) {
primaryDomainArray := strings.Split(create.PrimaryDomain, ":")
primaryDomain := primaryDomainArray[0]
alias := create.Alias
if alias == "default" {
return buserr.New("ErrDefaultAlias")
}
if common.ContainsChinese(alias) {
alias, err = common.PunycodeEncode(alias)
if err != nil {
@@ -217,7 +215,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
website := &model.Website{
PrimaryDomain: primaryDomain,
PrimaryDomain: create.PrimaryDomain,
Type: create.Type,
Alias: alias,
Remark: create.Remark,
@@ -298,7 +296,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
install *model.AppInstall
)
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
req.Name = reg.ReplaceAllString(strings.ToLower(create.PrimaryDomain), "")
req.Name = reg.ReplaceAllString(strings.ToLower(alias), "")
req.AppDetailId = create.AppInstall.AppDetailId
req.Params = create.AppInstall.Params
req.Params["IMAGE_NAME"] = runtime.Image
@@ -327,12 +325,16 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
case constant.RuntimeNode:
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
}
}
if err = configDefaultNginx(website, domains, appInstall, runtime); err != nil {
return err
}
if err = createWafConfig(website, domains); err != nil {
return err
}
tx, ctx := helper.GetTxAndContext()
defer tx.Rollback()
if err = websiteRepo.Create(ctx, website); err != nil {
@@ -425,17 +427,18 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
if err != nil {
return err
}
if err := delNginxConfig(website, req.ForceDelete); err != nil {
if err = delNginxConfig(website, req.ForceDelete); err != nil {
return err
}
if err = delWafConfig(website, req.ForceDelete); err != nil {
return err
}
if checkIsLinkApp(website) && req.DeleteApp {
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
if !reflect.DeepEqual(model.AppInstall{}, appInstall) {
if err := deleteAppInstall(appInstall, true, req.ForceDelete, true); err != nil && !req.ForceDelete {
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if appInstall.ID > 0 {
if err = deleteAppInstall(appInstall, true, req.ForceDelete, true); err != nil && !req.ForceDelete {
return err
}
}
@@ -494,6 +497,53 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
return nil, err
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return nil, err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if fileOp.Stat(wafDataPath) {
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return nil, err
}
var websitesArray []request.WafWebsite
if content != nil {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return nil, err
}
}
for index, wafWebsite := range websitesArray {
if wafWebsite.Key == website.Alias {
wafSite := request.WafWebsite{
Key: website.Alias,
Domains: wafWebsite.Domains,
Host: wafWebsite.Host,
}
for _, domain := range domainModels {
wafSite.Domains = append(wafSite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 {
wafSite.Host = append(wafSite.Host, domain.Domain+":"+string(rune(domain.Port)))
}
}
if len(wafSite.Host) == 0 {
wafSite.Host = []string{}
}
websitesArray[index] = wafSite
break
}
}
websitesContent, err := json.Marshal(websitesArray)
if err != nil {
return nil, err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return nil, err
}
}
return domainModels, websiteDomainRepo.BatchCreate(context.TODO(), domainModels)
}
@@ -523,6 +573,7 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
if oldDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(webSiteDomain.WebsiteID), websiteDomainRepo.WithDomain(webSiteDomain.Domain)); len(oldDomains) == 1 {
domains = append(domains, webSiteDomain.Domain)
}
if len(ports) > 0 || len(domains) > 0 {
stringBinds := make([]string, len(ports))
for i := 0; i < len(ports); i++ {
@@ -533,6 +584,63 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
}
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if fileOp.Stat(wafDataPath) {
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
var newWebsitesArray []request.WafWebsite
if content != nil {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
for _, wafWebsite := range websitesArray {
if wafWebsite.Key == website.Alias {
wafSite := wafWebsite
oldDomains := wafSite.Domains
var newDomains []string
for _, domain := range oldDomains {
if domain == webSiteDomain.Domain {
continue
}
newDomains = append(newDomains, domain)
}
wafSite.Domains = newDomains
oldHostArray := wafSite.Host
var newHostArray []string
for _, host := range oldHostArray {
if host == webSiteDomain.Domain+":"+string(rune(webSiteDomain.Port)) {
continue
}
newHostArray = append(newHostArray, host)
}
wafSite.Host = newHostArray
if len(wafSite.Host) == 0 {
wafSite.Host = []string{}
}
newWebsitesArray = append(newWebsitesArray, wafSite)
} else {
newWebsitesArray = append(newWebsitesArray, wafWebsite)
}
}
websitesContent, err := json.Marshal(newWebsitesArray)
if err != nil {
return err
}
if err = fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
}
return websiteDomainRepo.DeleteBy(context.TODO(), commonRepo.WithByID(domainId))
}
@@ -852,56 +960,6 @@ func (w WebsiteService) PreInstallCheck(req request.WebsiteInstallCheckReq) ([]r
return nil, nil
}
func (w WebsiteService) GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error) {
var res response.WebsiteWafConfig
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return res, nil
}
res.Enable = true
if req.Key != "" {
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"set"}, &website)
if err != nil {
return res, nil
}
for _, param := range params {
if param.Params[0] == req.Key {
res.Enable = len(param.Params) > 1 && param.Params[1] == "on"
break
}
}
}
nginxFull, err := getNginxFull(&website)
if err != nil {
return res, nil
}
filePath := path.Join(nginxFull.SiteDir, "sites", website.Alias, "waf", "rules", req.Rule+".json")
content, err := os.ReadFile(filePath)
if err != nil {
return res, nil
}
res.Content = string(content)
return res, nil
}
func (w WebsiteService) UpdateWafConfig(req request.WebsiteWafUpdate) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return err
}
updateValue := "on"
if !req.Enable {
updateValue = "off"
}
return updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{
{Name: "set", Params: []string{req.Key, updateValue}},
}, &website)
}
func (w WebsiteService) UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
@@ -2339,23 +2397,6 @@ func (w WebsiteService) UpdateRedirectFile(req request.NginxRedirectUpdate) (err
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
}
func (w WebsiteService) UpdateWafFile(req request.WebsiteWafFileUpdate) (err error) {
var (
website model.Website
nginxInstall model.AppInstall
)
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return err
}
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return
}
rulePath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "waf", "rules", fmt.Sprintf("%s.json", req.Type))
return files.NewFileOp().WriteFile(rulePath, strings.NewReader(req.Content), 0755)
}
func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error) {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
+4 -3
View File
@@ -82,7 +82,7 @@ func (w WebsiteCAService) Create(create request.WebsiteCACreate) (*request.Websi
}
rootCA := &x509.Certificate{
SerialNumber: big.NewInt(time.Now().Unix()),
SerialNumber: big.NewInt(time.Now().Unix() + 1),
Subject: pkixName,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
@@ -279,7 +279,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
notAfter = notAfter.AddDate(0, 0, req.Time)
}
interCsr := &x509.Certificate{
SerialNumber: big.NewInt(time.Now().Unix()),
SerialNumber: big.NewInt(time.Now().Unix() + 2),
Subject: rootCsr.Subject,
NotBefore: time.Now(),
NotAfter: notAfter,
@@ -315,7 +315,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
subject := rootCsr.Subject
subject.CommonName = commonName
csr := &x509.Certificate{
SerialNumber: big.NewInt(time.Now().Unix()),
SerialNumber: big.NewInt(time.Now().Unix() + 3),
Subject: subject,
NotBefore: time.Now(),
NotAfter: notAfter,
@@ -346,6 +346,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
websiteSSL.StartDate = cert.NotBefore
websiteSSL.Type = cert.Issuer.CommonName
websiteSSL.Organization = rootCsr.Subject.Organization[0]
websiteSSL.Status = constant.SSLReady
if req.Renew {
if err := websiteSSLRepo.Save(websiteSSL); err != nil {
+58 -4
View File
@@ -102,6 +102,12 @@ func (w WebsiteSSLService) Search(search request.WebsiteSSLSearch) ([]response.W
}
func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error) {
if create.Nameserver1 != "" && !common.IsValidIP(create.Nameserver1) {
return create, buserr.New("ErrParseIP")
}
if create.Nameserver2 != "" && !common.IsValidIP(create.Nameserver2) {
return create, buserr.New("ErrParseIP")
}
var res request.WebsiteSSLCreate
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(create.AcmeAccountID))
if err != nil {
@@ -116,6 +122,10 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
KeyType: create.KeyType,
PushDir: create.PushDir,
Description: create.Description,
Nameserver1: create.Nameserver1,
Nameserver2: create.Nameserver2,
SkipDNS: create.SkipDNS,
DisableCNAME: create.DisableCNAME,
}
if create.PushDir {
if !files.NewFileOp().Stat(create.Dir) {
@@ -191,7 +201,7 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
if err != nil {
return err
}
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, apply.SkipDNSCheck); err != nil {
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, *websiteSSL); err != nil {
return err
}
case constant.Http:
@@ -368,9 +378,53 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
if err != nil {
return err
}
websiteSSL.AutoRenew = update.AutoRenew
websiteSSL.Description = update.Description
return websiteSSLRepo.Save(websiteSSL)
updateParams := make(map[string]interface{})
updateParams["primary_domain"] = update.PrimaryDomain
updateParams["description"] = update.Description
updateParams["provider"] = update.Provider
updateParams["key_type"] = update.KeyType
updateParams["push_dir"] = update.PushDir
updateParams["disable_cname"] = update.DisableCNAME
updateParams["skip_dns"] = update.SkipDNS
updateParams["nameserver1"] = update.Nameserver1
updateParams["nameserver2"] = update.Nameserver2
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(update.AcmeAccountID))
if err != nil {
return err
}
updateParams["acme_account_id"] = acmeAccount.ID
if update.PushDir {
if !files.NewFileOp().Stat(update.Dir) {
return buserr.New(constant.ErrLinkPathNotFound)
}
updateParams["dir"] = update.Dir
}
var domains []string
if update.OtherDomains != "" {
otherDomainArray := strings.Split(update.OtherDomains, "\n")
for _, domain := range otherDomainArray {
if !common.IsValidDomain(domain) {
return buserr.WithName("ErrDomainFormat", domain)
}
domains = append(domains, domain)
}
}
updateParams["domains"] = strings.Join(domains, ",")
if update.Provider == constant.DNSAccount || update.Provider == constant.Http {
updateParams["auto_renew"] = update.AutoRenew
} else {
updateParams["auto_renew"] = false
}
if update.Provider == constant.DNSAccount {
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(update.DnsAccountID))
if err != nil {
return err
}
updateParams["dns_account_id"] = dnsAccount.ID
}
return websiteSSLRepo.SaveByMap(websiteSSL, updateParams)
}
func (w WebsiteSSLService) Upload(req request.WebsiteSSLUpload) error {
+150 -5
View File
@@ -1,7 +1,9 @@
package service
import (
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"log"
"os"
"path"
@@ -197,7 +199,7 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website,
}
}
}
return fileOp.CopyDir(path.Join(nginxFolder, "www", "common", "waf", "rules"), path.Join(siteFolder, "waf"))
return nil
}
func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, appInstall *model.AppInstall, runtime *model.Runtime) error {
@@ -233,12 +235,8 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
server.UpdateServerName(serverNames)
siteFolder := path.Join("/www", "sites", website.Alias)
commonFolder := path.Join("/www", "common")
server.UpdateDirective("access_log", []string{path.Join(siteFolder, "log", "access.log")})
server.UpdateDirective("error_log", []string{path.Join(siteFolder, "log", "error.log")})
server.UpdateDirective("access_by_lua_file", []string{path.Join(commonFolder, "waf", "access.lua")})
server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")})
server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")})
rootIndex := path.Join("/www/sites", website.Alias, "index")
switch website.Type {
@@ -285,6 +283,103 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
return nil
}
func createWafConfig(website *model.Website, domains []model.WebsiteDomain) error {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
if !common.CompareVersion(nginxInstall.Version, "1.21.4.3-2-0") {
return nil
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if !fileOp.Stat(wafDataPath) {
return nil
}
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
if len(content) != 0 {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
wafWebsite := request.WafWebsite{
Key: website.Alias,
Domains: make([]string, 0),
Host: make([]string, 0),
}
for _, domain := range domains {
wafWebsite.Domains = append(wafWebsite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 {
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+string(rune(domain.Port)))
}
}
websitesArray = append(websitesArray, wafWebsite)
websitesContent, err := json.Marshal(websitesArray)
if err != nil {
return err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
var (
sitesDir = path.Join(wafDataPath, "sites")
defaultConfigPath = path.Join(wafDataPath, "conf", "siteConfig.json")
defaultRuleDir = path.Join(wafDataPath, "rules")
websiteDir = path.Join(sitesDir, website.Alias)
)
defaultConfigContent, err := fileOp.GetContent(defaultConfigPath)
if err != nil {
return err
}
if !fileOp.Stat(websiteDir) {
if err = fileOp.CreateDir(websiteDir, 0755); err != nil {
return err
}
}
defer func() {
if err != nil {
_ = fileOp.DeleteDir(websiteDir)
}
}()
if err = fileOp.SaveFileWithByte(path.Join(websiteDir, "config.json"), defaultConfigContent, 0644); err != nil {
return err
}
websiteRuleDir := path.Join(websiteDir, "rules")
if !fileOp.Stat(websiteRuleDir) {
if err := fileOp.CreateDir(websiteRuleDir, 0755); err != nil {
return err
}
}
defaultRulesName := []string{"acl", "args", "cookie", "defaultUaBlack", "defaultUrlBlack", "fileExt", "header", "methodWhite", "cdn"}
for _, ruleName := range defaultRulesName {
srcPath := path.Join(defaultRuleDir, ruleName+".json")
if fileOp.Stat(srcPath) {
_ = fileOp.Copy(srcPath, websiteRuleDir)
}
}
if err = opNginx(nginxInstall.ContainerName, constant.NginxCheck); err != nil {
return err
}
if err = opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
return err
}
return nil
}
func delNginxConfig(website model.Website, force bool) error {
nginxApp, err := appRepo.GetFirst(appRepo.WithKey(constant.AppOpenresty))
if err != nil {
@@ -310,6 +405,7 @@ func delNginxConfig(website model.Website, force bool) error {
}
sitePath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias)
if fileOp.Stat(sitePath) {
xpack.RemoveTamper(website.Alias)
_ = fileOp.DeleteDir(sitePath)
}
@@ -322,6 +418,55 @@ func delNginxConfig(website model.Website, force bool) error {
return nil
}
func delWafConfig(website model.Website, force bool) error {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
if !common.CompareVersion(nginxInstall.Version, "1.21.4.3-2-0") {
return nil
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if !fileOp.Stat(wafDataPath) {
return nil
}
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
var newWebsiteArray []request.WafWebsite
if len(content) > 0 {
if err = json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
for _, wafWebsite := range websitesArray {
if wafWebsite.Key != website.Alias {
newWebsiteArray = append(newWebsiteArray, wafWebsite)
}
}
websitesContent, err := json.Marshal(newWebsiteArray)
if err != nil {
return err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
_ = fileOp.DeleteDir(path.Join(wafDataPath, "sites", website.Alias))
if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
if force {
return nil
}
return err
}
return nil
}
func addListenAndServerName(website model.Website, ports []int, domains []string) error {
nginxFull, err := getNginxFull(&website)
if err != nil {
+7 -3
View File
@@ -47,10 +47,14 @@ func WithDetail(Key string, detail interface{}, err error) BusinessError {
}
func WithErr(Key string, err error) BusinessError {
paramMap := map[string]interface{}{}
if err != nil {
paramMap["err"] = err
}
return BusinessError{
Msg: Key,
Detail: "",
Err: err,
Msg: Key,
Map: paramMap,
Err: err,
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ type System struct {
Entrance string `mapstructure:"entrance"`
IsDemo bool `mapstructure:"is_demo"`
AppRepo string `mapstructure:"app_repo"`
ChangeUserInfo bool `mapstructure:"change_user_info"`
ChangeUserInfo string `mapstructure:"change_user_info"`
OneDriveID string `mapstructure:"one_drive_id"`
OneDriveSc string `mapstructure:"one_drive_sc"`
}
+13
View File
@@ -18,6 +18,8 @@ const (
CodeErrDomain = 409
CodeErrInternalServer = 500
CodeErrHeader = 406
CodeErrXpack = 410
)
// internal
@@ -43,6 +45,9 @@ var (
ErrNameIsExist = "ErrNameIsExist"
ErrDemoEnvironment = "ErrDemoEnvironment"
ErrCmdIllegal = "ErrCmdIllegal"
ErrXpackNotFound = "ErrXpackNotFound"
ErrXpackNotActive = "ErrXpackNotActive"
ErrXpackOutOfDate = "ErrXpackOutOfDate"
)
// app
@@ -150,3 +155,11 @@ var (
var (
ErrNotExistUser = "ErrNotExistUser"
)
// license
var (
ErrLicense = "ErrLicense"
ErrLicenseCheck = "ErrLicenseCheck"
ErrLicenseSave = "ErrLicenseSave"
ErrLicenseSync = "ErrLicenseSync"
)
+3 -1
View File
@@ -1,6 +1,8 @@
package cron
import (
"fmt"
mathRand "math/rand"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
@@ -41,7 +43,7 @@ func Run() {
if _, err := global.Cron.AddJob("@daily", job.NewSSLJob()); err != nil {
global.LOG.Errorf("can not add ssl corn job: %s", err.Error())
}
if _, err := global.Cron.AddJob("@daily", job.NewAppStoreJob()); err != nil {
if _, err := global.Cron.AddJob(fmt.Sprintf("%v %v * * *", mathRand.Intn(60), mathRand.Intn(3)), job.NewAppStoreJob()); err != nil {
global.LOG.Errorf("can not add appstore corn job: %s", err.Error())
}
+8 -7
View File
@@ -13,13 +13,14 @@ import (
)
var (
DB *gorm.DB
LOG *logrus.Logger
CONF configs.ServerConfig
VALID *validator.Validate
SESSION *psession.PSession
CACHE *badger_db.Cache
Viper *viper.Viper
DB *gorm.DB
MonitorDB *gorm.DB
LOG *logrus.Logger
CONF configs.ServerConfig
VALID *validator.Validate
SESSION *psession.PSession
CACHE *badger_db.Cache
Viper *viper.Viper
Cron *cron.Cron
MonitorCronID cron.EntryID
+21
View File
@@ -31,6 +31,27 @@ func GetMsgWithMap(key string, maps map[string]interface{}) string {
}
}
func GetMsgWithName(key string, name string, err error) string {
var (
content string
dataMap = make(map[string]interface{})
)
dataMap["name"] = name
if err != nil {
dataMap["err"] = err.Error()
}
content, _ = global.I18n.Localize(&i18n.LocalizeConfig{
MessageID: key,
TemplateData: dataMap,
})
content = strings.ReplaceAll(content, "<no value>", "")
if content == "" {
return key
} else {
return content
}
}
func GetErrMsg(key string, maps map[string]interface{}) string {
var content string
if maps == nil {
+28 -5
View File
@@ -61,6 +61,12 @@ AppStoreIsSyncing: 'The App Store is syncing, please try again later'
ErrGetCompose: "Failed to obtain docker-compose.yml file! {{ .detail }}"
ErrAppWarn: "Abnormal status, please check the log"
ErrAppParamKey: "Parameter {{ .name }} field exception"
ErrAppUpgrade: "Failed to upgrade application {{ .name }} {{ .err }}"
AppRecover: "App {{ .name }} rolled back "
PullImageStart: "Start pulling image {{ .name }}"
PullImageSuccess: "Image pulled successfully"
UpgradeAppStart: "Start upgrading application {{ .name }}"
UpgradeAppSuccess: "App {{ .name }} upgraded successfully"
#file
ErrFileCanNotRead: "File can not read"
@@ -74,18 +80,20 @@ ErrFileDownloadDir: "Download folder not supported"
ErrCmdNotFound: "{{ .name}} command does not exist, please install this command on the host first"
ErrSourcePathNotFound: "Source directory does not exist"
ErrFavoriteExist: "This path has been collected"
ErrInvalidChar: "Illegal characters are prohibited"
#website
ErrDomainIsExist: "Domain is already exist"
ErrAliasIsExist: "Alias is already exist"
ErrAppDelete: 'Other Website use this App'
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}"'
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}"'
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}'
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}'
ErrPHPResource: 'The local runtime does not support switching!'
ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the index directory, which may cause Access denied errors when accessing the website.'
ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the index directory, which may cause an Access denied error when accessing the website. Please click the save button above'
ErrDomainIsUsed: "Domain is already used by website {{ .name }}"
ErrDomainFormat: "{{ .name }} domain format error"
ErrDefaultAlias: "default is a reserved code name, please use another code name"
#ssl
ErrSSLCannotDelete: "The certificate {{ .name }} is being used by the website and cannot be removed"
@@ -144,7 +152,7 @@ ErrNodeModulesNotFound: "The node_modules folder does not exist! Please edit the
#setting
ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted."
ErrBackupCheck: "Backup account test connection failed {{ .err}}"
ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment."
ErrOSSConn: "Unable to retrieve the latest version, please check if the server can connect to the external network."
ErrEntrance: "Security entrance information error. Please check and try again!"
#tool
@@ -171,4 +179,19 @@ ErrBanAction: "Setting failed, the current {{ .name }} service is unavailable, p
ErrScope: "Modification of this configuration is not supported"
ErrStateChange: "State modification failed"
ErrRuleExist: "Rule is Exist"
ErrRuleNotExist: "Rule is not Exist"
ErrRuleNotExist: "Rule is not Exist"
ErrParseIP: "IP format error"
ErrDefaultIP: "default is a reserved name, please change it to another name"
ErrGroupInUse: "The IP group is used by the black/white list and cannot be deleted"
ErrGroupExist: "IP group name already exists"
ErrIPRange: "Wrong IP range"
ErrIPExist: "IP is exit"
#license
ErrLicense: "License format error, please check and try again!"
ErrLicenseCheck: "License verification failed, please check and try again!"
ErrLicenseSave: "Failed to save license information, error {{ .err }}, please try again!"
ErrLicenseSync: "Failed to sync license information, no license information detected in the database!"
ErrXpackNotFound: "This section is a professional edition feature, please import the license first in Panel Settings-License interface"
ErrXpackNotActive: "This section is a professional edition feature, please synchronize the license status first in Panel Settings-License interface"
ErrXpackOutOfDate: "The current license has expired, please re-import the license in Panel Settings-License interface"
+29 -5
View File
@@ -23,6 +23,7 @@ ErrTypePortRange: '連接埠範圍需要在 1-65535 之間'
Success: "成功"
Failed: "失敗"
SystemRestart: "系統重啟導致任務中斷"
ErrInvalidChar: "禁止使用非法字元"
#app
ErrPortInUsed: "{{ .detail }} 端口已被佔用!"
@@ -61,6 +62,12 @@ AppStoreIsSyncing: '應用程式商店正在同步中,請稍後再試'
ErrGetCompose: "docker-compose.yml 檔案取得失敗!{{ .detail }}"
ErrAppWarn: "狀態異常,請查看日誌"
ErrAppParamKey: "參數 {{ .name }} 欄位異常"
ErrAppUpgrade: "應用程式 {{ .name }} 升級失敗 {{ .err }}"
AppRecover: "應用程式 {{ .name }} 回滾 "
PullImageStart: "開始拉取鏡像 {{ .name }}"
PullImageSuccess: "鏡像拉取成功"
UpgradeAppStart: "開始升級應用程式 {{ .name }}"
UpgradeAppSuccess: "應用程式 {{ .name }} 升級成功"
#file
ErrFileCanNotRead: "此文件不支持預覽"
@@ -80,12 +87,13 @@ ErrDomainIsExist: "域名已存在"
ErrAliasIsExist: "代號已存在"
ErrAppDelete: '其他網站使用此應用,無法刪除'
ErrGroupIsUsed: '分組正在使用中,無法刪除'
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}"'
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}"'
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}'
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}'
ErrPHPResource: '本地運行環境不支持切換!'
ErrPathPermission: 'index 目錄下檢測到非 1000:1000 權限文件夾,可能導致網站訪問 Access denied 錯誤'
ErrPathPermission: 'index 目錄下偵測到非 1000:1000 權限資料夾,可能導致網站存取 Access denied 錯誤,請點擊上方儲存按鈕'
ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
ErrDomainFormat: "{{ .name }} 域名格式不正確"
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
#ssl
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
@@ -145,7 +153,7 @@ ErrNodeModulesNotFound: "node_modules 文件夾不存在!請編輯運行環境
#setting
ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除"
ErrBackupCheck: "備份帳號測試連接失敗 {{ .err}}"
ErrOSSConn: "無法成功請求最新版本,請檢查伺服器是否能夠連接到外部網絡環境。"
ErrOSSConn: "無法獲取最新版本,請確認伺服器是否能夠連接外部網路。"
ErrEntrance: "安全入口信息錯誤,請檢查後重試!"
#tool
@@ -171,5 +179,21 @@ ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後
#waf
ErrScope: "不支援修改此配置"
ErrStateChange: "狀態修改失敗"
ErrRuleExist: "規則名稱已存在"
ErrRuleExist: "規則已存在"
ErrRuleNotExist: "規則不存在"
ErrParseIP: "IP 格式錯誤"
ErrDefaultIP: "default 為保留名稱,請更換其他名稱"
ErrGroupInUse: "IP 群組被黑/白名單使用,無法刪除"
ErrGroupExist: "IP 群組名稱已存在"
ErrIPRange: "IP 範圍錯誤"
ErrIPExist: "IP 已存在"
#license
ErrLicense: "許可證格式錯誤,請檢查後重試!"
ErrLicenseCheck: "許可證校驗失敗,請檢查後重試!"
ErrLicenseSave: "許可證信息保存失敗,錯誤 {{ .err }}, 請重試!"
ErrLicenseSync: "許可證信息同步失敗,資料庫中未檢測到許可證信息!"
ErrXpackNotFound: "該部分為專業版功能,請先在 面板設置-許可證 界面導入許可證"
ErrXpackNotActive: "該部分為專業版功能,請先在 面板設置-許可證 界面同步許可證狀態"
ErrXpackOutOfDate: "當前許可證已過期,請重新在 面板設置-許可證 界面導入許可證"
+30 -6
View File
@@ -61,6 +61,12 @@ AppStoreIsSyncing: '应用商店正在同步中,请稍后再试'
ErrGetCompose: "docker-compose.yml 文件获取失败!{{ .detail }}"
ErrAppWarn: "状态异常,请查看日志"
ErrAppParamKey: "参数 {{ .name }} 字段异常"
ErrAppUpgrade: "应用 {{ .name }} 升级失败 {{ .err }}"
AppRecover: "应用 {{ .name }} 回滚 "
PullImageStart: "开始拉取镜像 {{ .name }}"
PullImageSuccess: "镜像拉取成功"
UpgradeAppStart: "开始升级应用 {{ .name }}"
UpgradeAppSuccess: "应用 {{ .name }} 升级成功"
#file
ErrFileCanNotRead: "此文件不支持预览"
@@ -74,18 +80,20 @@ ErrFileDownloadDir: "不支持下载文件夹"
ErrCmdNotFound: "{{ .name}} 命令不存在,请先在宿主机安装此命令"
ErrSourcePathNotFound: "源目录不存在"
ErrFavoriteExist: "已收藏此路径"
ErrInvalidChar: "禁止使用非法字符"
#website
ErrDomainIsExist: "域名已存在"
ErrAliasIsExist: "代号已存在"
ErrAppDelete: '其他网站使用此应用,无法删除'
ErrGroupIsUsed: '分组正在使用中,无法删除'
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}"'
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}"'
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}'
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}'
ErrPHPResource: '本地运行环境不支持切换!'
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误'
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误,请点击上方保存按钮'
ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
ErrDomainFormat: "{{ .name }} 域名格式不正确"
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
#ssl
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
@@ -144,7 +152,7 @@ ErrNodeModulesNotFound: "node_modules 文件夹不存在!请编辑运行环境
#setting
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
ErrBackupCheck: "备份账号测试连接失败 {{ .err}}"
ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。"
ErrOSSConn: "无法获取最新版本,请确认服务器是否能够连接外部网络。"
ErrEntrance: "安全入口信息错误,请检查后重试!"
#tool
@@ -170,5 +178,21 @@ ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后
#waf
ErrScope: "不支持修改此配置"
ErrStateChange: "状态修改失败"
ErrRuleExist: "规则名称已存在"
ErrRuleNotExist: "规则不存在"
ErrRuleExist: "规则已存在"
ErrRuleNotExist: "规则不存在"
ErrParseIP: "IP 格式错误"
ErrDefaultIP: "default 为保留名称,请更换其他名称"
ErrGroupInUse: "IP 组被黑/白名单使用,无法删除"
ErrGroupExist: "IP 组名称已存在"
ErrIPRange: "IP 范围错误"
ErrIPExist: "IP 已存在"
#license
ErrLicense: "许可证格式错误,请检查后重试!"
ErrLicenseCheck: "许可证校验失败,请检查后重试!"
ErrLicenseSave: "许可证信息保存失败,错误 {{ .err }},请重试!"
ErrLicenseSync: "许可证信息同步失败,数据库中未检测到许可证信息!"
ErrXpackNotFound: "该部分为专业版功能,请先在 面板设置-许可证 界面导入许可证"
ErrXpackNotActive: "该部分为专业版功能,请先在 面板设置-许可证 界面同步许可证状态"
ErrXpackOutOfDate: "当前许可证已过期,请重新在 面板设置-许可证 界面导入许可证"
+35 -1
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"log"
"os"
"path"
"time"
"github.com/1Panel-dev/1Panel/backend/global"
@@ -34,6 +35,7 @@ func Init() {
Colorful: false,
},
)
initMonitorDB(newLogger)
db, err := gorm.Open(sqlite.Open(fullPath), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
@@ -45,7 +47,7 @@ func Init() {
_ = db.Exec("PRAGMA journal_mode = WAL;")
sqlDB, dbError := db.DB()
if dbError != nil {
panic(err)
panic(dbError)
}
sqlDB.SetConnMaxIdleTime(10)
sqlDB.SetMaxOpenConns(100)
@@ -54,3 +56,35 @@ func Init() {
global.DB = db
global.LOG.Info("init db successfully")
}
func initMonitorDB(newLogger logger.Interface) {
if _, err := os.Stat(global.CONF.System.DbPath); err != nil {
if err := os.MkdirAll(global.CONF.System.DbPath, os.ModePerm); err != nil {
panic(fmt.Errorf("init db dir failed, err: %v", err))
}
}
fullPath := path.Join(global.CONF.System.DbPath, "monitor.db")
if _, err := os.Stat(fullPath); err != nil {
if _, err := os.Create(fullPath); err != nil {
panic(fmt.Errorf("init db file failed, err: %v", err))
}
}
db, err := gorm.Open(sqlite.Open(fullPath), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
Logger: newLogger,
})
if err != nil {
panic(err)
}
sqlDB, dbError := db.DB()
if dbError != nil {
panic(dbError)
}
sqlDB.SetConnMaxIdleTime(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
global.MonitorDB = db
global.LOG.Info("init monitor db successfully")
}
+52 -15
View File
@@ -4,6 +4,8 @@ import (
"encoding/base64"
"encoding/json"
"os"
"path"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
@@ -57,25 +59,12 @@ func Init() {
global.LOG.Fatalf("init service before start failed, err: %v", err)
}
if global.CONF.System.ChangeUserInfo {
if err := settingRepo.Update("UserName", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init username before start failed, err: %v", err)
}
pass, _ := encrypt.StringEncrypt(common.RandStrAndNum(10))
if err := settingRepo.Update("Password", pass); err != nil {
global.LOG.Fatalf("init password before start failed, err: %v", err)
}
if err := settingRepo.Update("SecurityEntrance", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl", sudo)
}
handleUserInfo(global.CONF.System.ChangeUserInfo, settingRepo)
handleCronjobStatus()
handleSnapStatus()
loadLocalDir()
initDir()
}
func handleSnapStatus() {
@@ -173,3 +162,51 @@ func loadLocalDir() {
}
global.LOG.Errorf("error type dir: %T", varMap["dir"])
}
func handleUserInfo(tags string, settingRepo repo.ISettingRepo) {
if len(tags) == 0 {
return
}
if tags == "all" {
if err := settingRepo.Update("UserName", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init username before start failed, err: %v", err)
}
pass, _ := encrypt.StringEncrypt(common.RandStrAndNum(10))
if err := settingRepo.Update("Password", pass); err != nil {
global.LOG.Fatalf("init password before start failed, err: %v", err)
}
if err := settingRepo.Update("SecurityEntrance", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
return
}
if strings.Contains(global.CONF.System.ChangeUserInfo, "username") {
if err := settingRepo.Update("UserName", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init username before start failed, err: %v", err)
}
}
if strings.Contains(global.CONF.System.ChangeUserInfo, "password") {
pass, _ := encrypt.StringEncrypt(common.RandStrAndNum(10))
if err := settingRepo.Update("Password", pass); err != nil {
global.LOG.Fatalf("init password before start failed, err: %v", err)
}
}
if strings.Contains(global.CONF.System.ChangeUserInfo, "entrance") {
if err := settingRepo.Update("SecurityEntrance", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
}
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=%v/d' /usr/local/bin/1pctl", sudo, global.CONF.System.ChangeUserInfo)
}
func initDir() {
composePath := path.Join(global.CONF.System.BaseDir, "1panel/docker/compose/")
if _, err := os.Stat(composePath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(composePath, os.ModePerm); err != nil {
global.LOG.Errorf("mkdir %s failed, err: %v", composePath, err)
return
}
}
}
+9
View File
@@ -75,6 +75,15 @@ func Init() {
migrations.AddSnapshotIgnore,
migrations.AddDatabaseIsDelete,
migrations.AddXpackHideMenu,
migrations.AddCronjobCommand,
migrations.NewMonitorDB,
migrations.AddNoAuthSetting,
migrations.UpdateXpackHideMenu,
migrations.AddMenuTabsSetting,
migrations.AddDeveloperSetting,
migrations.AddWebsiteSSLColumn,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
+139
View File
@@ -2,6 +2,7 @@ package migrations
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
)
@@ -25,3 +26,141 @@ var AddDatabaseIsDelete = &gormigrate.Migration{
return nil
},
}
var AddXpackHideMenu = &gormigrate.Migration{
ID: "20240328-add-xpack-hide-menu",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "XpackHideMenu", Value: "{\"id\":\"1\",\"label\":\"/xpack\",\"isCheck\":true,\"title\":\"xpack.menu\",\"children\":[{\"id\":\"2\",\"title\":\"xpack.waf.name\",\"path\":\"/xpack/waf/dashboard\",\"label\":\"Dashboard\",\"isCheck\":true},{\"id\":\"3\",\"title\":\"xpack.tamper.tamper\",\"path\":\"/xpack/tamper\",\"label\":\"Tamper\",\"isCheck\":true},{\"id\":\"4\",\"title\":\"xpack.setting.setting\",\"path\":\"/xpack/setting\",\"label\":\"XSetting\",\"isCheck\":true}]}"}).Error; err != nil {
return err
}
return nil
},
}
var AddCronjobCommand = &gormigrate.Migration{
ID: "20240403-add-cronjob-command",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Cronjob{}); err != nil {
return err
}
return nil
},
}
var NewMonitorDB = &gormigrate.Migration{
ID: "20240408-new-monitor-db",
Migrate: func(tx *gorm.DB) error {
var (
bases []model.MonitorBase
ios []model.MonitorIO
networks []model.MonitorNetwork
)
_ = tx.Find(&bases).Error
_ = tx.Find(&ios).Error
_ = tx.Find(&networks).Error
if err := global.MonitorDB.AutoMigrate(&model.MonitorBase{}, &model.MonitorIO{}, &model.MonitorNetwork{}); err != nil {
return err
}
_ = global.MonitorDB.Exec("DELETE FROM monitor_bases").Error
_ = global.MonitorDB.Exec("DELETE FROM monitor_ios").Error
_ = global.MonitorDB.Exec("DELETE FROM monitor_networks").Error
if len(bases) != 0 {
for i := 0; i <= len(bases)/200; i++ {
var itemData []model.MonitorBase
if 200*(i+1) <= len(bases) {
itemData = bases[200*i : 200*(i+1)]
} else {
itemData = bases[200*i:]
}
if len(itemData) != 0 {
if err := global.MonitorDB.Create(&itemData).Error; err != nil {
return err
}
}
}
}
if len(ios) != 0 {
for i := 0; i <= len(ios)/200; i++ {
var itemData []model.MonitorIO
if 200*(i+1) <= len(ios) {
itemData = ios[200*i : 200*(i+1)]
} else {
itemData = ios[200*i:]
}
if len(itemData) != 0 {
if err := global.MonitorDB.Create(&itemData).Error; err != nil {
return err
}
}
}
}
if len(networks) != 0 {
for i := 0; i <= len(networks)/200; i++ {
var itemData []model.MonitorNetwork
if 200*(i+1) <= len(networks) {
itemData = networks[200*i : 200*(i+1)]
} else {
itemData = networks[200*i:]
}
if len(itemData) != 0 {
if err := global.MonitorDB.Create(&itemData).Error; err != nil {
return err
}
}
}
}
return nil
},
}
var AddNoAuthSetting = &gormigrate.Migration{
ID: "20240328-add-no-auth-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "NoAuthSetting", Value: "200"}).Error; err != nil {
return err
}
return nil
},
}
var UpdateXpackHideMenu = &gormigrate.Migration{
ID: "20240411-update-xpack-hide-menu",
Migrate: func(tx *gorm.DB) error {
if err := tx.Model(&model.Setting{}).Where("key", "XpackHideMenu").Updates(map[string]interface{}{"value": "{\"id\":\"1\",\"label\":\"/xpack\",\"isCheck\":true,\"title\":\"xpack.menu\",\"children\":[{\"id\":\"2\",\"title\":\"xpack.waf.name\",\"path\":\"/xpack/waf/dashboard\",\"label\":\"Dashboard\",\"isCheck\":true},{\"id\":\"3\",\"title\":\"xpack.tamper.tamper\",\"path\":\"/xpack/tamper\",\"label\":\"Tamper\",\"isCheck\":true},{\"id\":\"4\",\"title\":\"xpack.gpu.gpu\",\"path\":\"/xpack/gpu\",\"label\":\"GPU\",\"isCheck\":true},{\"id\":\"5\",\"title\":\"xpack.setting.setting\",\"path\":\"/xpack/setting\",\"label\":\"XSetting\",\"isCheck\":true}]}"}).Error; err != nil {
return err
}
return nil
},
}
var AddMenuTabsSetting = &gormigrate.Migration{
ID: "20240415-add-menu-tabs-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "MenuTabs", Value: "disable"}).Error; err != nil {
return err
}
return nil
},
}
var AddDeveloperSetting = &gormigrate.Migration{
ID: "20240423-add-developer-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "DeveloperMode", Value: "disable"}).Error; err != nil {
return err
}
return nil
},
}
var AddWebsiteSSLColumn = &gormigrate.Migration{
ID: "20240508-update-website-ssl",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil {
return err
}
return nil
},
}
+6 -1
View File
@@ -2,6 +2,9 @@ package router
import (
"fmt"
"net/http"
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/middleware"
@@ -12,7 +15,6 @@ import (
"github.com/gin-gonic/gin"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"net/http"
)
var (
@@ -21,6 +23,7 @@ var (
func setWebStatic(rootRouter *gin.RouterGroup) {
rootRouter.StaticFS("/public", http.FS(web.Favicon))
rootRouter.Static("/api/v1/images", "./uploads")
rootRouter.Use(func(c *gin.Context) {
c.Next()
})
@@ -61,6 +64,8 @@ func Routers() *gin.Engine {
PublicGroup.GET("/health", func(c *gin.Context) {
c.JSON(200, "ok")
})
baseApi := v1.ApiGroupApp.BaseApi
PublicGroup.GET("/api/v1/respagecode", baseApi.GetResponsePage)
PublicGroup.Use(gzip.Gzip(gzip.DefaultCompression))
setWebStatic(PublicGroup)
}
+4 -4
View File
@@ -96,7 +96,7 @@ func Init() {
global.CONF.System.Username = username
global.CONF.System.Password = password
global.CONF.System.Entrance = entrance
global.CONF.System.ChangeUserInfo = loadChange()
global.CONF.System.ChangeUserInfo = loadChangeInfo()
global.Viper = v
}
@@ -112,10 +112,10 @@ func loadParams(param string) string {
return info
}
func loadChange() bool {
func loadChangeInfo() string {
stdout, err := cmd.Exec("grep '^CHANGE_USER_INFO=' /usr/bin/1pctl | cut -d'=' -f2")
if err != nil {
return false
return ""
}
return stdout == "true\n"
return strings.ReplaceAll(stdout, "\n", "")
}
+3
View File
@@ -27,6 +27,9 @@ var whiteUrlList = map[string]struct{}{
"/api/v1/databases/variables": {},
"/api/v1/databases/status": {},
"/api/v1/databases/baseinfo": {},
"/api/v1/waf/attack/stat": {},
"/api/v1/waf/config/website": {},
}
func DemoHandle() gin.HandlerFunc {
-1
View File
@@ -6,7 +6,6 @@ func commonGroups() []CommonRouter {
&DashboardRouter{},
&HostRouter{},
&ContainerRouter{},
&MonitorRouter{},
&LogRouter{},
&FileRouter{},
&ToolboxRouter{},
+5
View File
@@ -35,6 +35,11 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) {
hostRouter.POST("/firewall/update/addr", baseApi.UpdateAddrRule)
hostRouter.POST("/firewall/update/description", baseApi.UpdateFirewallDescription)
hostRouter.POST("/monitor/search", baseApi.LoadMonitor)
hostRouter.POST("/monitor/clean", baseApi.CleanMonitor)
hostRouter.GET("/monitor/netoptions", baseApi.GetNetworkOptions)
hostRouter.GET("/monitor/iooptions", baseApi.GetIOOptions)
hostRouter.GET("/ssh/conf", baseApi.LoadSSHConf)
hostRouter.POST("/ssh/search", baseApi.GetSSHInfo)
hostRouter.POST("/ssh/update", baseApi.UpdateSSH)
-23
View File
@@ -1,23 +0,0 @@
package router
import (
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
"github.com/1Panel-dev/1Panel/backend/middleware"
"github.com/gin-gonic/gin"
)
type MonitorRouter struct{}
func (s *MonitorRouter) InitRouter(Router *gin.RouterGroup) {
monitorRouter := Router.Group("monitors").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v1.ApiGroupApp.BaseApi
{
monitorRouter.POST("/search", baseApi.LoadMonitor)
monitorRouter.GET("/netoptions", baseApi.GetNetworkOptions)
monitorRouter.GET("/iooptions", baseApi.GetIOOptions)
}
}
+1
View File
@@ -15,6 +15,7 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
baseApi := v1.ApiGroupApp.BaseApi
{
groupRouter.GET("/installed/delete/check/:runTimeId", baseApi.DeleteRuntimeCheck)
groupRouter.POST("/search", baseApi.SearchRuntimes)
groupRouter.POST("", baseApi.CreateRuntime)
groupRouter.POST("/del", baseApi.DeleteRuntime)
+1 -1
View File
@@ -23,13 +23,13 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
settingRouter.POST("/update", baseApi.UpdateSetting)
settingRouter.GET("/interface", baseApi.LoadInterfaceAddr)
settingRouter.POST("/menu/update", baseApi.UpdateMenu)
settingRouter.POST("/bind/update", baseApi.UpdateBindInfo)
settingRouter.POST("/port/update", baseApi.UpdatePort)
settingRouter.POST("/ssl/update", baseApi.UpdateSSL)
settingRouter.GET("/ssl/info", baseApi.LoadFromCert)
settingRouter.POST("/ssl/download", baseApi.DownloadSSL)
settingRouter.POST("/password/update", baseApi.UpdatePassword)
settingRouter.POST("/monitor/clean", baseApi.CleanMonitor)
settingRouter.POST("/mfa", baseApi.LoadMFA)
settingRouter.POST("/mfa/bind", baseApi.MFABind)
-4
View File
@@ -39,10 +39,6 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.GET("/:id/https", baseApi.GetHTTPSConfig)
groupRouter.POST("/:id/https", baseApi.UpdateHTTPSConfig)
groupRouter.POST("/waf/config", baseApi.GetWebsiteWafConfig)
groupRouter.POST("/waf/update", baseApi.UpdateWebsiteWafConfig)
groupRouter.POST("/waf/file/update", baseApi.UpdateWebsiteWafFile)
groupRouter.GET("/php/config/:id", baseApi.GetWebsitePHPConfig)
groupRouter.POST("/php/config", baseApi.UpdateWebsitePHPConfig)
groupRouter.POST("/php/update", baseApi.UpdatePHPFile)
+5 -7
View File
@@ -6,7 +6,7 @@ import (
"path"
"path/filepath"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
)
type localClient struct {
@@ -54,9 +54,8 @@ func (c localClient) Upload(src, target string) (bool, error) {
}
}
stdout, err := cmd.Execf("\\cp -f %s %s", src, path.Join(c.dir, target))
if err != nil {
return false, fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
if err := common.CopyFile(src, targetFilePath); err != nil {
return false, fmt.Errorf("cp file failed, err: %v", err)
}
return true, nil
}
@@ -73,9 +72,8 @@ func (c localClient) Download(src, target string) (bool, error) {
}
}
stdout, err := cmd.Execf("\\cp -f %s %s", localPath, target)
if err != nil {
return false, fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
if err := common.CopyFile(localPath, target); err != nil {
return false, fmt.Errorf("cp file failed, err: %v", err)
}
return true, nil
}
@@ -120,10 +120,12 @@ func (m minIoClient) Download(src, target string) (bool, error) {
if err != nil {
return false, err
}
defer object.Close()
localFile, err := os.Create(target)
if err != nil {
return false, err
}
defer localFile.Close()
if _, err = io.Copy(localFile, object); err != nil {
return false, err
}
@@ -223,11 +223,11 @@ func RefreshToken(grantType string, varMap map[string]interface{}) (string, stri
if err != nil {
return "", "", fmt.Errorf("request for access token failed, err: %v", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", "", fmt.Errorf("read data from response body failed, err: %v", err)
}
defer resp.Body.Close()
tokenMap := map[string]interface{}{}
if err := json.Unmarshal(respBody, &tokenMap); err != nil {
@@ -387,9 +387,9 @@ func (o *oneDriveClient) upBig(ctx context.Context, srcPath, folderID string, fi
if err != nil {
return false, err
}
res.Body.Close()
if res.StatusCode != 201 && res.StatusCode != 202 && res.StatusCode != 200 {
data, _ := io.ReadAll(res.Body)
res.Body.Close()
return false, errors.New(string(data))
}
}
+1 -1
View File
@@ -50,12 +50,12 @@ func (s sftpClient) Upload(src, target string) (bool, error) {
if err != nil {
return false, err
}
defer sshClient.Close()
client, err := sftp.NewClient(sshClient)
if err != nil {
return false, err
}
defer client.Close()
defer sshClient.Close()
srcFile, err := os.Open(src)
if err != nil {
+1 -1
View File
@@ -178,7 +178,7 @@ func CheckIllegal(args ...string) bool {
if strings.Contains(arg, "&") || strings.Contains(arg, "|") || strings.Contains(arg, ";") ||
strings.Contains(arg, "$") || strings.Contains(arg, "'") || strings.Contains(arg, "`") ||
strings.Contains(arg, "(") || strings.Contains(arg, ")") || strings.Contains(arg, "\"") ||
strings.Contains(arg, "\n") || strings.Contains(arg, "\r") {
strings.Contains(arg, "\n") || strings.Contains(arg, "\r") || strings.Contains(arg, ">") || strings.Contains(arg, "<") {
return true
}
}
+86
View File
@@ -6,6 +6,8 @@ import (
"io"
mathRand "math/rand"
"net"
"os"
"path"
"reflect"
"regexp"
"sort"
@@ -43,6 +45,43 @@ func CompareVersion(version1, version2 string) bool {
return false
}
func ComparePanelVersion(version1, version2 string) bool {
if version1 == version2 {
return false
}
version1s := SplitStr(version1, ".", "-")
version2s := SplitStr(version2, ".", "-")
if len(version2s) > len(version1s) {
for i := 0; i < len(version2s)-len(version1s); i++ {
version1s = append(version1s, "0")
}
}
if len(version1s) > len(version2s) {
for i := 0; i < len(version1s)-len(version2s); i++ {
version2s = append(version2s, "0")
}
}
n := min(len(version1s), len(version2s))
for i := 0; i < n; i++ {
if version1s[i] == version2s[i] {
continue
} else {
v1, err1 := strconv.Atoi(version1s[i])
if err1 != nil {
return version1s[i] > version2s[i]
}
v2, err2 := strconv.Atoi(version2s[i])
if err2 != nil {
return version1s[i] > version2s[i]
}
return v1 > v2
}
}
return true
}
func extractNumbers(version string) []string {
var numbers []string
start := -1
@@ -82,6 +121,36 @@ func GetSortedVersions(versions []string) []string {
return versions
}
func CopyFile(src, dst string) error {
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()
if path.Base(src) != path.Base(dst) {
dst = path.Join(dst, path.Base(src))
}
if _, err := os.Stat(path.Dir(dst)); err != nil {
if os.IsNotExist(err) {
_ = os.MkdirAll(path.Dir(dst), os.ModePerm)
}
}
target, err := os.OpenFile(dst+"_temp", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return err
}
defer target.Close()
if _, err = io.Copy(target, source); err != nil {
return err
}
if err = os.Rename(dst+"_temp", dst); err != nil {
return err
}
return nil
}
func IsCrossVersion(version1, version2 string) bool {
version1s := strings.Split(version1, ".")
version2s := strings.Split(version2, ".")
@@ -235,3 +304,20 @@ func PunycodeEncode(text string) (string, error) {
}
return ascii, nil
}
func SplitStr(str string, spi ...string) []string {
lists := []string{str}
var results []string
for _, s := range spi {
results = []string{}
for _, list := range lists {
results = append(results, strings.Split(list, s)...)
}
lists = results
}
return results
}
func IsValidIP(ip string) bool {
return net.ParseIP(ip) != nil
}
+5
View File
@@ -33,6 +33,10 @@ func NewClient() (Client, error) {
}, nil
}
func (c Client) Close() {
_ = c.cli.Close()
}
func NewDockerClient() (*client.Client, error) {
var settingItem model.Setting
_ = global.DB.Where("key = ?", "DockerSockPath").First(&settingItem).Error
@@ -150,6 +154,7 @@ func CreateDefaultDockerNetwork() error {
global.LOG.Errorf("init docker client error %s", err.Error())
return err
}
defer cli.Close()
if !cli.NetworkExist("1panel-network") {
if err := cli.CreateNetwork("1panel-network"); err != nil {
global.LOG.Errorf("create default docker network error %s", err.Error())
+54 -24
View File
@@ -15,7 +15,6 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
@@ -57,6 +56,13 @@ func (f FileOp) CreateDir(dst string, mode fs.FileMode) error {
return f.Fs.MkdirAll(dst, mode)
}
func (f FileOp) CreateDirWithMode(dst string, mode fs.FileMode) error {
if err := f.Fs.MkdirAll(dst, mode); err != nil {
return err
}
return f.ChmodRWithMode(dst, mode, true)
}
func (f FileOp) CreateFile(dst string) error {
if _, err := f.Fs.Create(dst); err != nil {
return err
@@ -64,6 +70,14 @@ func (f FileOp) CreateFile(dst string) error {
return nil
}
func (f FileOp) CreateFileWithMode(dst string, mode fs.FileMode) error {
file, err := f.Fs.OpenFile(dst, os.O_CREATE, mode)
if err != nil {
return err
}
return file.Close()
}
func (f FileOp) LinkFile(source string, dst string, isSymlink bool) error {
if isSymlink {
osFs := afero.OsFs{}
@@ -149,7 +163,7 @@ func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error {
if cmd.HasNoPasswordSudo() {
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
}
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
if msg, err := cmd.ExecWithTimeOut(cmdStr, 10*time.Second); err != nil {
if msg != "" {
return errors.New(msg)
}
@@ -166,7 +180,24 @@ func (f FileOp) ChmodR(dst string, mode int64, sub bool) error {
if cmd.HasNoPasswordSudo() {
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
}
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
if msg, err := cmd.ExecWithTimeOut(cmdStr, 10*time.Second); err != nil {
if msg != "" {
return errors.New(msg)
}
return err
}
return nil
}
func (f FileOp) ChmodRWithMode(dst string, mode fs.FileMode, sub bool) error {
cmdStr := fmt.Sprintf(`chmod %v "%s"`, fmt.Sprintf("%o", mode.Perm()), dst)
if sub {
cmdStr = fmt.Sprintf(`chmod -R %v "%s"`, fmt.Sprintf("%o", mode.Perm()), dst)
}
if cmd.HasNoPasswordSudo() {
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
}
if msg, err := cmd.ExecWithTimeOut(cmdStr, 10*time.Second); err != nil {
if msg != "" {
return errors.New(msg)
}
@@ -282,6 +313,7 @@ func (f FileOp) DownloadFile(url, dst string) error {
if err != nil {
return err
}
defer resp.Body.Close()
out, err := os.Create(dst)
if err != nil {
@@ -292,8 +324,6 @@ func (f FileOp) DownloadFile(url, dst string) error {
if _, err = io.Copy(out, resp.Body); err != nil {
return fmt.Errorf("save download file [%s] error, err %s", dst, err.Error())
}
out.Close()
resp.Body.Close()
return nil
}
@@ -314,7 +344,7 @@ func (f FileOp) Cut(oldPaths []string, dst, name string, cover bool) error {
coverFlag = "-f"
}
cmdStr := fmt.Sprintf(`mv %s "%s" "%s"`, coverFlag, p, dstPath)
cmdStr := fmt.Sprintf(`mv %s '%s' '%s'`, coverFlag, p, dstPath)
if err := cmd.ExecCmd(cmdStr); err != nil {
return err
}
@@ -323,7 +353,7 @@ func (f FileOp) Cut(oldPaths []string, dst, name string, cover bool) error {
}
func (f FileOp) Mv(oldPath, dstPath string) error {
cmdStr := fmt.Sprintf(`mv "%s" "%s"`, oldPath, dstPath)
cmdStr := fmt.Sprintf(`mv '%s' '%s'`, oldPath, dstPath)
if err := cmd.ExecCmd(cmdStr); err != nil {
return err
}
@@ -377,13 +407,13 @@ func (f FileOp) CopyAndReName(src, dst, name string, cover bool) error {
if name != "" && !cover {
dstPath = filepath.Join(dst, name)
}
return cmd.ExecCmd(fmt.Sprintf(`cp -rf "%s" "%s"`, src, dstPath))
return cmd.ExecCmd(fmt.Sprintf(`cp -rf '%s' '%s'`, src, dstPath))
} else {
dstPath := filepath.Join(dst, name)
if cover {
dstPath = dst
}
return cmd.ExecCmd(fmt.Sprintf(`cp -f "%s" "%s"`, src, dstPath))
return cmd.ExecCmd(fmt.Sprintf(`cp -f '%s' '%s'`, src, dstPath))
}
}
@@ -396,29 +426,29 @@ func (f FileOp) CopyDir(src, dst string) error {
if err = f.Fs.MkdirAll(dstDir, srcInfo.Mode()); err != nil {
return err
}
return cmd.ExecCmd(fmt.Sprintf(`cp -rf "%s" "%s"`, src, dst+"/"))
return cmd.ExecCmd(fmt.Sprintf(`cp -rf '%s' '%s'`, src, dst+"/"))
}
func (f FileOp) CopyFile(src, dst string) error {
dst = filepath.Clean(dst) + string(filepath.Separator)
return cmd.ExecCmd(fmt.Sprintf(`cp -f "%s" "%s"`, src, dst+"/"))
return cmd.ExecCmd(fmt.Sprintf(`cp -f '%s' '%s'`, src, dst+"/"))
}
func (f FileOp) GetDirSize(path string) (float64, error) {
var m sync.Map
var wg sync.WaitGroup
wg.Add(1)
go ScanDir(f.Fs, path, &m, &wg)
wg.Wait()
var dirSize float64
m.Range(func(k, v interface{}) bool {
dirSize = dirSize + v.(float64)
return true
var size int64
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
size += info.Size()
}
return nil
})
return dirSize, nil
if err != nil {
return 0, err
}
return float64(size), nil
}
func getFormat(cType CompressType) archiver.CompressedArchive {
+14 -12
View File
@@ -311,20 +311,22 @@ func (f *FileInfo) listChildren(option FileOption) error {
}
func (f *FileInfo) getContent() error {
if f.Size <= 10*1024*1024 {
afs := &afero.Afero{Fs: f.Fs}
cByte, err := afs.ReadFile(f.Path)
if err != nil {
return nil
}
if len(cByte) > 0 && DetectBinary(cByte) {
return buserr.New(constant.ErrFileCanNotRead)
}
f.Content = string(cByte)
return nil
} else {
if IsBlockDevice(f.FileMode) {
return buserr.New(constant.ErrFileCanNotRead)
}
if f.Size > 10*1024*1024 {
return buserr.New("ErrFileToLarge")
}
afs := &afero.Afero{Fs: f.Fs}
cByte, err := afs.ReadFile(f.Path)
if err != nil {
return nil
}
if len(cByte) > 0 && DetectBinary(cByte) {
return buserr.New(constant.ErrFileCanNotRead)
}
f.Content = string(cByte)
return nil
}
func DetectBinary(buf []byte) bool {
+33 -18
View File
@@ -2,20 +2,24 @@ package files
import (
"bufio"
"github.com/spf13/afero"
"fmt"
"io"
"net/http"
"os"
"os/user"
"path/filepath"
"strconv"
"sync"
"strings"
)
func IsSymlink(mode os.FileMode) bool {
return mode&os.ModeSymlink != 0
}
func IsBlockDevice(mode os.FileMode) bool {
return mode&os.ModeDevice != 0 && mode&os.ModeCharDevice == 0
}
func GetMimeType(path string) string {
file, err := os.Open(path)
if err != nil {
@@ -56,22 +60,6 @@ func GetGroup(gid uint32) string {
return usr.Name
}
func ScanDir(fs afero.Fs, path string, dirMap *sync.Map, wg *sync.WaitGroup) {
afs := &afero.Afero{Fs: fs}
files, _ := afs.ReadDir(path)
for _, f := range files {
if f.IsDir() {
wg.Add(1)
go ScanDir(fs, filepath.Join(path, f.Name()), dirMap, wg)
} else {
if f.Size() > 0 {
dirMap.Store(filepath.Join(path, f.Name()), float64(f.Size()))
}
}
}
defer wg.Done()
}
const dotCharacter = 46
func IsHidden(path string) bool {
@@ -113,3 +101,30 @@ func ReadFileByLine(filename string, page, pageSize int) ([]string, bool, error)
return lines, isEndOfFile, nil
}
func GetParentMode(path string) (os.FileMode, error) {
absPath, err := filepath.Abs(path)
if err != nil {
return 0, err
}
for {
fileInfo, err := os.Stat(absPath)
if err == nil {
return fileInfo.Mode() & os.ModePerm, nil
}
if !os.IsNotExist(err) {
return 0, err
}
parentDir := filepath.Dir(absPath)
if parentDir == absPath {
return 0, fmt.Errorf("no existing directory found in the path: %s", path)
}
absPath = parentDir
}
}
func IsInvalidChar(name string) bool {
return strings.Contains(name, "&")
}
+2 -1
View File
@@ -4,11 +4,12 @@ import (
"context"
"crypto/tls"
"errors"
"github.com/1Panel-dev/1Panel/backend/buserr"
"net"
"net/http"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/buserr"
)
func GetHttpRes(url string) (*http.Response, error) {

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