Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d5797fe68 | ||
|
|
bbe08ed218 | ||
|
|
6e12eba356 | ||
|
|
3457b99df6 | ||
|
|
4ad3b82c84 | ||
|
|
85fc07c900 | ||
|
|
d71e2a74b4 | ||
|
|
a18105349b | ||
|
|
6472227b6b | ||
|
|
c927132aa6 | ||
|
|
b06058ec18 | ||
|
|
57329a26c8 | ||
|
|
4a1aa84fa8 | ||
|
|
cbe9c83515 | ||
|
|
67479e7060 | ||
|
|
b454c959b4 | ||
|
|
e2d39b9ed0 | ||
|
|
b9fbcb0e73 | ||
|
|
30cb471629 | ||
|
|
d70c22dde8 | ||
|
|
01bb6b7c01 | ||
|
|
4f4879759e | ||
|
|
92a410fcea | ||
|
|
5d1fced8e9 | ||
|
|
a56e5a8abe | ||
|
|
28ae7f3a0c | ||
|
|
8d675c81c5 | ||
|
|
66a345364f | ||
|
|
a3cb8be08f | ||
|
|
0861b30a7b | ||
|
|
36f2a3eb4b | ||
|
|
092cbbf8da | ||
|
|
39e3e8f214 | ||
|
|
fa983bdcc9 | ||
|
|
67bb30c10c | ||
|
|
e85340ca5d | ||
|
|
a3a1e17849 | ||
|
|
2601135225 | ||
|
|
c556affc91 | ||
|
|
6ee9789a2f | ||
|
|
68a457ae89 | ||
|
|
72237596f3 | ||
|
|
f516333682 | ||
|
|
873af25684 | ||
|
|
8b058a873e | ||
|
|
0c5a5a6454 | ||
|
|
2096049708 | ||
|
|
1095aa2b65 | ||
|
|
13679ff301 | ||
|
|
89b7a06662 | ||
|
|
e8582bea75 | ||
|
|
9af7926eb9 | ||
|
|
bdcdf7e181 | ||
|
|
887db0aff7 | ||
|
|
4a974b7e0a | ||
|
|
fb286d2def | ||
|
|
89cb9e6693 | ||
|
|
927def4472 | ||
|
|
84fcd31704 | ||
|
|
005e5cc01f | ||
|
|
2896409b3a | ||
|
|
791641f3e1 | ||
|
|
79f266bbda | ||
|
|
c9edaf0d1d | ||
|
|
ac5f73c687 | ||
|
|
cc0667429a | ||
|
|
92a5d6faeb | ||
|
|
1111b6b494 | ||
|
|
be5a7c99e1 | ||
|
|
d6a963c087 | ||
|
|
af753bdffe | ||
|
|
59b025353f | ||
|
|
355a6b0205 | ||
|
|
7de80e9d5a | ||
|
|
4c6d8cd20c | ||
|
|
31da89d63a | ||
|
|
e044ca7d12 | ||
|
|
7c037b68cd | ||
|
|
9080824a59 | ||
|
|
11f4bc2c89 | ||
|
|
a64ddd1eb8 | ||
|
|
2fdaecfafe | ||
|
|
6d1fe20736 | ||
|
|
f61bc047cd | ||
|
|
4f52580938 | ||
|
|
281d0cf880 | ||
|
|
fdf9215d43 | ||
|
|
8c182e907d | ||
|
|
e55af04568 | ||
|
|
2462ffdbab | ||
|
|
bfeb57e24f | ||
|
|
9bb28cda27 |
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -25,7 +25,7 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: "1Panel 版本"
|
||||
description: "可通过系统右上角下拉菜单中的`关于`选项,或查看安装目录中的 version 文件获取。"
|
||||
description: "登录 1Panel Web 控制台,在页面右下角查看当前版本。"
|
||||
- type: markdown
|
||||
id: details
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature.yml
vendored
2
.github/ISSUE_TEMPLATE/feature.yml
vendored
@@ -14,7 +14,7 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: "1Panel 版本"
|
||||
description: "可通过系统右上角下拉菜单中的`关于`选项,或查看安装目录中的 version 文件获取。"
|
||||
description: "登录 1Panel Web 控制台,在页面右下角查看当前版本。"
|
||||
- type: markdown
|
||||
id: details
|
||||
attributes:
|
||||
|
||||
17
.github/workflows/add-labels-for-pr.yml
vendored
Normal file
17
.github/workflows/add-labels-for-pr.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
on: pull_request
|
||||
|
||||
name: 1Panel 通用 PR 处理
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
generic_handler:
|
||||
name: 为 PR 添加标签
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUBTOKEN }}
|
||||
labels: ${{ github.base_ref }}
|
||||
17
.github/workflows/issue-recent-alert.yml
vendored
Normal file
17
.github/workflows/issue-recent-alert.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
|
||||
name: Check recent handle issues
|
||||
|
||||
jobs:
|
||||
check-recent-issues-not-handle:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check recent issues and send msg
|
||||
uses: jumpserver/action-issues-alert@master
|
||||
with:
|
||||
hook: ${{ secrets.WECHAT_GROUP_WEB_HOOK }}
|
||||
type: recent
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
17
.github/workflows/issue-untimely-alert.yml
vendored
Normal file
17
.github/workflows/issue-untimely-alert.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 9 * * 1-5"
|
||||
|
||||
name: Check untimely handle issues
|
||||
|
||||
jobs:
|
||||
check-untimely-handle-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check untimely issues and send msg
|
||||
uses: jumpserver/action-issues-alert@master
|
||||
with:
|
||||
hook: ${{ secrets.WECHAT_GROUP_WEB_HOOK }}
|
||||
type: untimely
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
16
.github/workflows/sync2gitee.yml
vendored
Normal file
16
.github/workflows/sync2gitee.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: sync2gitee
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
repo-sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Mirror the Github organization repos to Gitee.
|
||||
uses: Yikun/hub-mirror-action@master
|
||||
with:
|
||||
src: 'github/1Panel-dev'
|
||||
dst: 'gitee/fit2cloud-xlab'
|
||||
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
|
||||
dst_token: ${{ secrets.GITEE_TOKEN }}
|
||||
static_list: "1Panel"
|
||||
force_update: true
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,5 +22,4 @@ cmd/server/__debug_bin
|
||||
cmd/server/web/assets
|
||||
cmd/server/web/monacoeditorwork
|
||||
cmd/server/web/index.html
|
||||
cmd/server/web/favicon.png
|
||||
frontend/auto-imports.d.ts
|
||||
|
||||
2
Makefile
2
Makefile
@@ -16,7 +16,7 @@ build_web:
|
||||
|
||||
build_bin:
|
||||
cd $(SERVER_PATH) \
|
||||
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -tags osusergo -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -tags 'osusergo,netgo' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||
|
||||
build_linux_on_mac:
|
||||
cd $(SERVER_PATH) \
|
||||
|
||||
11
OWNERS
Normal file
11
OWNERS
Normal file
@@ -0,0 +1,11 @@
|
||||
reviewers:
|
||||
- zhengkunwang223
|
||||
- ssongliu
|
||||
- wanghe-fit2cloud
|
||||
- wangdan-fit2cloud
|
||||
|
||||
approvers:
|
||||
- zhengkunwang223
|
||||
- ssongliu
|
||||
- wanghe-fit2cloud
|
||||
- wangdan-fit2cloud
|
||||
23
README.md
23
README.md
@@ -1,3 +1,4 @@
|
||||
[README_EN.md](README_EN.md)
|
||||
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
|
||||
<p align="center"><b>现代化、开源的 Linux 服务器运维管理面板</b></p>
|
||||
<p align="center">
|
||||
@@ -11,14 +12,14 @@
|
||||
|
||||
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
|
||||
|
||||
- **快速建站**:深度集成 Wordpress 和 Halo,域名绑定、SSL 证书配置等一键搞定;
|
||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理及常用应用软件管理;
|
||||
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等一键搞定;
|
||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括应用管理、主机监控、文件管理、数据库管理、容器管理等;
|
||||
- **安全可靠**:最小漏洞暴露面,提供防火墙和安全审计等功能;
|
||||
- **一键备份**:支持一键备份和恢复,备份数据云端存储,永不丢失。
|
||||
|
||||
## UI 展示
|
||||
|
||||

|
||||

|
||||
|
||||
## 快速开始
|
||||
|
||||
@@ -30,16 +31,16 @@
|
||||
|
||||
**一键安装**
|
||||
|
||||
以 root 用户执行如下命令一键安装 1Panel:
|
||||
执行如下命令一键安装 1Panel:
|
||||
|
||||
```sh
|
||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh
|
||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
|
||||
```
|
||||
|
||||
**学习资料**
|
||||
|
||||
- [在线文档](https://1panel.cn/docs/)
|
||||
- [入门视频](https://1panel.cn/video.html)
|
||||
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||
|
||||
## 社区
|
||||
|
||||
@@ -47,18 +48,22 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
|
||||
**微信交流群**
|
||||
|
||||
<img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/wechat-group.jpg" width="156" height="156"/>
|
||||
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
|
||||
|
||||
## 安全说明
|
||||
|
||||
如果您在使用过程中发现任何安全问题,请通过以下方式直接联系我们:
|
||||
|
||||
- 邮箱:support@fit2cloud.com
|
||||
- 邮箱:support@fit2cloud.com
|
||||
- 电话:400-052-0755
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved.
|
||||
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
|
||||
72
README_EN.md
Normal file
72
README_EN.md
Normal file
@@ -0,0 +1,72 @@
|
||||
[中文 README.md](README.md)
|
||||
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
|
||||
<p align="center"><b>Modern and Open-Source Linux Server Operation and Management Panel</b></p>
|
||||
<p align="center">
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel" alt="License: GPL v3"></a>
|
||||
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
|
||||
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
|
||||
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
|
||||
</p>
|
||||
|
||||
------------------------------
|
||||
|
||||
1Panel is a modern and Open-Source linux server operation and management panel, the functions and advantages of 1Panel include:
|
||||
|
||||
- **Quick website building**: Deeply integrated with Wordpress and [Halo](https://github.com/halo-dev/halo/), with one-click solutions for domain name binding, SSL certificate configuration, and more;
|
||||
- **Efficient management**: Easily manage Linux servers through the web interface, including application management, host monitoring, file management, database management, container management, and more;
|
||||
- **Secure and reliable**: Minimal vulnerability exposure, with firewall and security audit functions provided;
|
||||
- **One-click backup**: Support for one-click backup and restore, with backup data stored in the cloud and never lost.
|
||||
|
||||
## UI Display
|
||||
|
||||

|
||||
|
||||
## Quick Start
|
||||
|
||||
**Online Demo**
|
||||
|
||||
- Address: <https://demo.1panel.cn/>
|
||||
- Username: demo
|
||||
- Password: 1panel
|
||||
|
||||
**One-Click Installation**
|
||||
|
||||
Execute the following command to install 1Panel with one click:
|
||||
|
||||
```sh
|
||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
|
||||
```
|
||||
|
||||
**Learning Materials**
|
||||
|
||||
- [Online Documentation](https://1panel.cn/docs/)
|
||||
- [Teaching Videos](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||
|
||||
## Community
|
||||
|
||||
If you have any questions or suggestions, please submit a GitHub Issue or join our WeChat group for communication.
|
||||
|
||||
**WeChat Group**
|
||||
|
||||
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
|
||||
|
||||
## Security Information
|
||||
|
||||
If you discover any security issues, please contact us through:
|
||||
|
||||
- Email: support@fit2cloud.com
|
||||
- Phone: 400-052-0755
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
<https://www.gnu.org/licenses/gpl-3.0.html>
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
19
SECURITY.md
Normal file
19
SECURITY.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# 安全说明
|
||||
|
||||
如果您发现安全问题,请直接联系我们:
|
||||
|
||||
- wanghe@fit2cloud.com
|
||||
- support@fit2cloud.com
|
||||
- 400-052-0755
|
||||
|
||||
感谢您的支持!
|
||||
|
||||
# Security Policy
|
||||
|
||||
All security bugs should be reported to the contact as below:
|
||||
|
||||
- wanghe@fit2cloud.com
|
||||
- support@fit2cloud.com
|
||||
- 400-052-0755
|
||||
|
||||
Thanks for your support!
|
||||
@@ -144,7 +144,7 @@ func (b *BaseApi) DeleteCheck(c *gin.Context) {
|
||||
// @Router /apps/installed/sync [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"同步已安装应用列表","formatEN":"Sync the list of installed apps"}
|
||||
func (b *BaseApi) SyncInstalled(c *gin.Context) {
|
||||
if err := appInstallService.SyncAll(); err != nil {
|
||||
if err := appInstallService.SyncAll(false); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28,9 +28,11 @@ func (b *BaseApi) Login(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
if req.AuthMethod != "jwt" {
|
||||
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
user, err := authService.Login(c, req)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -27,6 +29,23 @@ func (b *BaseApi) CreateBackup(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Credential) != 0 {
|
||||
credential, err := base64.StdEncoding.DecodeString(req.Credential)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Credential = string(credential)
|
||||
}
|
||||
if len(req.AccessKey) != 0 {
|
||||
accessKey, err := base64.StdEncoding.DecodeString(req.AccessKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.AccessKey = string(accessKey)
|
||||
}
|
||||
|
||||
if err := backupService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -52,6 +71,23 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Credential) != 0 {
|
||||
credential, err := base64.StdEncoding.DecodeString(req.Credential)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Credential = string(credential)
|
||||
}
|
||||
if len(req.AccessKey) != 0 {
|
||||
accessKey, err := base64.StdEncoding.DecodeString(req.AccessKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.AccessKey = string(accessKey)
|
||||
}
|
||||
|
||||
buckets, err := backupService.GetBuckets(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -139,7 +175,7 @@ func (b *BaseApi) DownloadRecord(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
c.File(filePath)
|
||||
helper.SuccessWithData(c, filePath)
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
@@ -188,6 +224,23 @@ func (b *BaseApi) UpdateBackup(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Credential) != 0 {
|
||||
credential, err := base64.StdEncoding.DecodeString(req.Credential)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Credential = string(credential)
|
||||
}
|
||||
if len(req.AccessKey) != 0 {
|
||||
accessKey, err := base64.StdEncoding.DecodeString(req.AccessKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.AccessKey = string(accessKey)
|
||||
}
|
||||
|
||||
if err := backupService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -70,6 +70,34 @@ func (b *BaseApi) SearchCompose(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Container Compose
|
||||
// @Summary Test compose
|
||||
// @Description 测试 compose 是否可用
|
||||
// @Accept json
|
||||
// @Param request body dto.ComposeCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /containers/compose/test [post]
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测 compose [name] 格式","formatEN":"check compose [name]"}
|
||||
func (b *BaseApi) TestCompose(c *gin.Context) {
|
||||
var req dto.ComposeCreate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
isOK, err := containerService.TestCompose(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, isOK)
|
||||
}
|
||||
|
||||
// @Tags Container Compose
|
||||
// @Summary Create compose
|
||||
// @Description 创建容器编排
|
||||
@@ -90,11 +118,12 @@ func (b *BaseApi) CreateCompose(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := containerService.CreateCompose(req); err != nil {
|
||||
log, err := containerService.CreateCompose(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
helper.SuccessWithData(c, log)
|
||||
}
|
||||
|
||||
// @Tags Container Compose
|
||||
|
||||
@@ -198,7 +198,7 @@ func (b *BaseApi) TargetDownload(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
c.File(filePath)
|
||||
helper.SuccessWithData(c, filePath)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -29,6 +30,15 @@ func (b *BaseApi) CreateMysql(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
|
||||
if _, err := mysqlService.Create(context.Background(), req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -81,6 +91,15 @@ func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Value) != 0 {
|
||||
value, err := base64.StdEncoding.DecodeString(req.Value)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Value = string(value)
|
||||
}
|
||||
|
||||
if err := mysqlService.ChangePassword(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@@ -106,6 +107,15 @@ func (b *BaseApi) ChangeRedisPassword(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Value) != 0 {
|
||||
value, err := base64.StdEncoding.DecodeString(req.Value)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Value = string(value)
|
||||
}
|
||||
|
||||
if err := redisService.ChangePassword(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -35,7 +35,6 @@ var (
|
||||
|
||||
commandService = service.ServiceGroupApp.CommandService
|
||||
|
||||
websiteGroupService = service.ServiceGroupApp.WebsiteGroupService
|
||||
websiteService = service.ServiceGroupApp.WebsiteService
|
||||
websiteDnsAccountService = service.ServiceGroupApp.WebsiteDnsAccountService
|
||||
websiteSSLService = service.ServiceGroupApp.WebsiteSSLService
|
||||
|
||||
@@ -3,6 +3,14 @@ package v1
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
@@ -14,13 +22,6 @@ import (
|
||||
websocket2 "github.com/1Panel-dev/1Panel/backend/utils/websocket"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// @Tags File
|
||||
@@ -444,6 +445,28 @@ func (b *BaseApi) Download(c *gin.Context) {
|
||||
c.File(filePath)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Download file with path
|
||||
// @Description 下载指定文件
|
||||
// @Accept json
|
||||
// @Param request body dto.FilePath true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/download/bypath [post]
|
||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [path]","formatEN":"Download file [path]"}
|
||||
func (b *BaseApi) DownloadFile(c *gin.Context) {
|
||||
var req dto.FilePath
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
c.File(req.Path)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Load file size
|
||||
// @Description 获取文件夹大小
|
||||
@@ -496,6 +519,12 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
||||
}
|
||||
|
||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
|
||||
if _, err := os.Stat(path.Dir(dstDir)); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path.Dir(dstDir), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -524,7 +553,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/chunkupload [post]
|
||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
|
||||
func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
fileForm, err := c.FormFile("chunk")
|
||||
if err != nil {
|
||||
@@ -550,15 +578,18 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
}
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
if err := fileOp.CreateDir("uploads", 0755); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
tmpDir := path.Join(global.CONF.System.TmpDir, "upload")
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
if err := fileOp.CreateDir(tmpDir, 0755); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
//fileID := uuid.New().String()
|
||||
filename := c.PostForm("filename")
|
||||
fileDir := filepath.Join(global.CONF.System.DataDir, "upload", filename)
|
||||
|
||||
os.MkdirAll(fileDir, 0755)
|
||||
filename := c.PostForm("filename")
|
||||
fileDir := filepath.Join(tmpDir, filename)
|
||||
|
||||
_ = os.MkdirAll(fileDir, 0755)
|
||||
filePath := filepath.Join(fileDir, filename)
|
||||
|
||||
emptyFile, err := os.Create(filePath)
|
||||
@@ -566,26 +597,25 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
emptyFile.Close()
|
||||
defer emptyFile.Close()
|
||||
|
||||
chunkData, err := ioutil.ReadAll(uploadFile)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrFileUpload, err)
|
||||
return
|
||||
}
|
||||
|
||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
|
||||
err = ioutil.WriteFile(chunkPath, chunkData, 0644)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
|
||||
return
|
||||
}
|
||||
|
||||
if chunkIndex+1 == chunkCount {
|
||||
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrAppDelete, err)
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, true)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -29,6 +31,23 @@ func (b *BaseApi) CreateHost(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
|
||||
host, err := hostService.Create(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -55,6 +74,22 @@ func (b *BaseApi) TestByInfo(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
|
||||
var connInfo ssh.ConnInfo
|
||||
_ = copier.Copy(&connInfo, &req)
|
||||
@@ -211,6 +246,22 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["name"] = req.Name
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
@@ -88,6 +89,7 @@ func (b *BaseApi) GetNetworkOptions(c *gin.Context) {
|
||||
for _, net := range netStat {
|
||||
options = append(options, net.Name)
|
||||
}
|
||||
sort.Strings(options)
|
||||
helper.SuccessWithData(c, options)
|
||||
}
|
||||
|
||||
@@ -98,5 +100,6 @@ func (b *BaseApi) GetIOOptions(c *gin.Context) {
|
||||
for _, net := range diskStat {
|
||||
options = append(options, net.Name)
|
||||
}
|
||||
sort.Strings(options)
|
||||
helper.SuccessWithData(c, options)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,28 @@ func (b *BaseApi) GetUpgradeInfo(c *gin.Context) {
|
||||
helper.SuccessWithData(c, info)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load release notes by version
|
||||
// @Description 获取版本 release notes
|
||||
// @Accept json
|
||||
// @Param request body dto.Upgrade true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/upgrade [get]
|
||||
func (b *BaseApi) GetNotesByVersion(c *gin.Context) {
|
||||
var req dto.Upgrade
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
notes, err := upgradeService.LoadNotes(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, notes)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Upgrade
|
||||
// @Description 系统更新
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Website Group
|
||||
// @Summary List website groups
|
||||
// @Description 获取网站组
|
||||
// @Success 200 {anrry} model.WebsiteGroup
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/groups [get]
|
||||
func (b *BaseApi) GetWebGroups(c *gin.Context) {
|
||||
list, err := websiteGroupService.GetGroups()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Website Group
|
||||
// @Summary Create website group
|
||||
// @Description 创建网站组
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteGroupCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/groups [post]
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建网站组 [name]","formatEN":"Create website groups [name]"}
|
||||
func (b *BaseApi) CreateWebGroup(c *gin.Context) {
|
||||
var req request.WebsiteGroupCreate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteGroupService.CreateGroup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Website Group
|
||||
// @Summary Update website group
|
||||
// @Description 更新网站组
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteGroupUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/groups/update [post]
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新网站组 [name]","formatEN":"Update website groups [name]"}
|
||||
func (b *BaseApi) UpdateWebGroup(c *gin.Context) {
|
||||
var req request.WebsiteGroupUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteGroupService.UpdateGroup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Website Group
|
||||
// @Summary Delete website group
|
||||
// @Description 删除网站组
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteResourceReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/groups/del [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_groups","output_colume":"name","output_value":"name"}],"formatZH":"删除网站组 [name]","formatEN":"Delete website group [name]"}
|
||||
func (b *BaseApi) DeleteWebGroup(c *gin.Context) {
|
||||
var req request.WebsiteResourceReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteGroupService.DeleteGroup(req.ID); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
@@ -176,3 +176,25 @@ func (b *BaseApi) GetWebsiteSSLById(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, websiteSSL)
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
// @Summary Update ssl
|
||||
// @Description 更新 ssl
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteSSLUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ssl/update [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_ssls","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新证书设置 [domain]","formatEN":"Update ssl config [domain]"}
|
||||
func (b *BaseApi) UpdateWebsiteSSL(c *gin.Context) {
|
||||
var req request.WebsiteSSLUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteSSLService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
@@ -69,15 +69,21 @@ type AppForm struct {
|
||||
}
|
||||
|
||||
type AppFormFields struct {
|
||||
Type string `json:"type"`
|
||||
LabelZh string `json:"labelZh"`
|
||||
LabelEn string `json:"labelEn"`
|
||||
Required bool `json:"required"`
|
||||
Default interface{} `json:"default"`
|
||||
EnvKey string `json:"envKey"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Edit bool `json:"edit"`
|
||||
Rule string `json:"rule"`
|
||||
Type string `json:"type"`
|
||||
LabelZh string `json:"labelZh"`
|
||||
LabelEn string `json:"labelEn"`
|
||||
Required bool `json:"required"`
|
||||
Default interface{} `json:"default"`
|
||||
EnvKey string `json:"envKey"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Edit bool `json:"edit"`
|
||||
Rule string `json:"rule"`
|
||||
Values []AppFormValue `json:"values"`
|
||||
}
|
||||
|
||||
type AppFormValue struct {
|
||||
Label string `json:"label"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type AppResource struct {
|
||||
|
||||
@@ -9,7 +9,6 @@ type UserLoginInfo struct {
|
||||
Name string `json:"name"`
|
||||
Token string `json:"token"`
|
||||
MfaStatus string `json:"mfaStatus"`
|
||||
MfaSecret string `json:"mfaSecret"`
|
||||
}
|
||||
|
||||
type MfaCredential struct {
|
||||
@@ -28,7 +27,6 @@ type Login struct {
|
||||
type MFALogin struct {
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
Secret string `json:"secret"`
|
||||
Code string `json:"code"`
|
||||
AuthMethod string `json:"authMethod"`
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type ContainerInfo struct {
|
||||
State string `json:"state"`
|
||||
RunTime string `json:"runTime"`
|
||||
|
||||
IsFromApp bool `json:"isFromApp"`
|
||||
IsFromCompose bool `json:"isFromCompose"`
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,6 @@ package dto
|
||||
import "time"
|
||||
|
||||
type DashboardBase struct {
|
||||
HaloID uint `json:"haloID"`
|
||||
DateeaseID uint `json:"dateeaseID"`
|
||||
JumpServerID uint `json:"jumpserverID"`
|
||||
MeterSphereID uint `json:"metersphereID"`
|
||||
KubeoperatorID uint `json:"kubeoperatorID"`
|
||||
KubepiID uint `json:"kubepiID"`
|
||||
|
||||
WebsiteNumber int `json:"websiteNumber"`
|
||||
DatabaseNumber int `json:"databaseNumber"`
|
||||
CronjobNumber int `json:"cronjobNumber"`
|
||||
@@ -55,8 +48,21 @@ type DashboardCurrent struct {
|
||||
IOReadBytes uint64 `json:"ioReadBytes"`
|
||||
IOWriteBytes uint64 `json:"ioWriteBytes"`
|
||||
IOCount uint64 `json:"ioCount"`
|
||||
IOTime uint64 `json:"ioTime"`
|
||||
IOReadTime uint64 `json:"ioReadTime"`
|
||||
IOWriteTime uint64 `json:"ioWriteTime"`
|
||||
|
||||
DiskData []DiskInfo `json:"diskData"`
|
||||
|
||||
NetBytesSent uint64 `json:"netBytesSent"`
|
||||
NetBytesRecv uint64 `json:"netBytesRecv"`
|
||||
|
||||
ShotTime time.Time `json:"shotTime"`
|
||||
}
|
||||
|
||||
type DiskInfo struct {
|
||||
Path string `json:"path"`
|
||||
Type string `json:"type"`
|
||||
Device string `json:"device"`
|
||||
Total uint64 `json:"total"`
|
||||
Free uint64 `json:"free"`
|
||||
Used uint64 `json:"used"`
|
||||
@@ -66,9 +72,4 @@ type DashboardCurrent struct {
|
||||
InodesUsed uint64 `json:"inodesUsed"`
|
||||
InodesFree uint64 `json:"inodesFree"`
|
||||
InodesUsedPercent float64 `json:"inodesUsedPercent"`
|
||||
|
||||
NetBytesSent uint64 `json:"netBytesSent"`
|
||||
NetBytesRecv uint64 `json:"netBytesRecv"`
|
||||
|
||||
ShotTime time.Time `json:"shotTime"`
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ type GroupSearch struct {
|
||||
type GroupUpdate struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
}
|
||||
|
||||
|
||||
@@ -44,3 +44,8 @@ type WebsiteDnsAccountUpdate struct {
|
||||
type WebsiteResourceReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteSSLUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
AutoRenew bool `json:"autoRenew" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -61,11 +61,13 @@ type AppService struct {
|
||||
}
|
||||
|
||||
type AppParam struct {
|
||||
Value interface{} `json:"value"`
|
||||
Edit bool `json:"edit"`
|
||||
Key string `json:"key"`
|
||||
Rule string `json:"rule"`
|
||||
LabelZh string `json:"labelZh"`
|
||||
LabelEn string `json:"labelEn"`
|
||||
Type string `json:"type"`
|
||||
Value interface{} `json:"value"`
|
||||
Edit bool `json:"edit"`
|
||||
Key string `json:"key"`
|
||||
Rule string `json:"rule"`
|
||||
LabelZh string `json:"labelZh"`
|
||||
LabelEn string `json:"labelEn"`
|
||||
Type string `json:"type"`
|
||||
Values interface{} `json:"values"`
|
||||
ShowValue string `json:"showValue"`
|
||||
}
|
||||
|
||||
@@ -82,9 +82,11 @@ type SnapshotInfo struct {
|
||||
}
|
||||
|
||||
type UpgradeInfo struct {
|
||||
NewVersion string `json:"newVersion"`
|
||||
ReleaseNote string `json:"releaseNote"`
|
||||
NewVersion string `json:"newVersion"`
|
||||
LatestVersion string `json:"latestVersion"`
|
||||
ReleaseNote string `json:"releaseNote"`
|
||||
}
|
||||
|
||||
type Upgrade struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package model
|
||||
|
||||
type WebsiteGroup struct {
|
||||
BaseModel
|
||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||
Default bool `json:"default"`
|
||||
}
|
||||
|
||||
func (w WebsiteGroup) TableName() string {
|
||||
return "website_groups"
|
||||
}
|
||||
@@ -113,6 +113,7 @@ type RootInfo struct {
|
||||
Name string `json:"name"`
|
||||
Port int64 `json:"port"`
|
||||
Password string `json:"password"`
|
||||
UserPassword string `json:"userPassword"`
|
||||
ContainerName string `json:"containerName"`
|
||||
Param string `json:"param"`
|
||||
Env string `json:"env"`
|
||||
@@ -146,6 +147,10 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
||||
if ok {
|
||||
info.Password = password
|
||||
}
|
||||
userPassword, ok := envMap["PANEL_DB_USER_PASSWORD"].(string)
|
||||
if ok {
|
||||
info.UserPassword = userPassword
|
||||
}
|
||||
info.Port = int64(appInstall.HttpPort)
|
||||
info.ID = appInstall.ID
|
||||
info.ContainerName = appInstall.ContainerName
|
||||
|
||||
@@ -24,7 +24,7 @@ type ICronjobRepo interface {
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
Delete(opts ...DBOption) error
|
||||
DeleteRecord(opts ...DBOption) error
|
||||
StartRecords(cronjobID uint, targetPath string) model.JobRecords
|
||||
StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords
|
||||
EndRecords(record model.JobRecords, status, message, records string)
|
||||
}
|
||||
|
||||
@@ -112,10 +112,11 @@ func (c *CronjobRepo) WithByJobID(id int) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *CronjobRepo) StartRecords(cronjobID uint, targetPath string) model.JobRecords {
|
||||
func (u *CronjobRepo) StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords {
|
||||
var record model.JobRecords
|
||||
record.StartTime = time.Now()
|
||||
record.CronjobID = cronjobID
|
||||
record.FromLocal = fromLocal
|
||||
record.Status = constant.StatusWaiting
|
||||
if err := global.DB.Create(&record).Error; err != nil {
|
||||
global.LOG.Errorf("create record status failed, err: %v", err)
|
||||
|
||||
@@ -19,7 +19,6 @@ type RepoGroup struct {
|
||||
BackupRepo
|
||||
WebsiteRepo
|
||||
WebsiteDomainRepo
|
||||
WebsiteGroupRepo
|
||||
WebsiteDnsAccountRepo
|
||||
WebsiteSSLRepo
|
||||
WebsiteAcmeAccountRepo
|
||||
|
||||
@@ -14,7 +14,7 @@ type IGroupRepo interface {
|
||||
Create(group *model.Group) error
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
Delete(opts ...DBOption) error
|
||||
CancelDefault() error
|
||||
CancelDefault(groupType string) error
|
||||
WithByIsDefault(isDefault bool) DBOption
|
||||
}
|
||||
|
||||
@@ -64,6 +64,6 @@ func (u *GroupRepo) Delete(opts ...DBOption) error {
|
||||
return db.Delete(&model.Group{}).Error
|
||||
}
|
||||
|
||||
func (w GroupRepo) CancelDefault() error {
|
||||
return global.DB.Model(&model.Group{}).Where("`is_default` = 1").Updates(map[string]interface{}{"is_default": 0}).Error
|
||||
func (u *GroupRepo) CancelDefault(groupType string) error {
|
||||
return global.DB.Model(&model.Group{}).Where("is_default = ? AND type = ?", 1, groupType).Updates(map[string]interface{}{"is_default": 0}).Error
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type WebsiteGroupRepo struct {
|
||||
}
|
||||
|
||||
func (w WebsiteGroupRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteGroup, error) {
|
||||
var groups []model.WebsiteGroup
|
||||
db := getDb(opts...).Model(&model.WebsiteGroup{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Order("`default` desc").Find(&groups).Error
|
||||
return count, groups, err
|
||||
}
|
||||
|
||||
func (w WebsiteGroupRepo) GetBy(opts ...DBOption) ([]model.WebsiteGroup, error) {
|
||||
var groups []model.WebsiteGroup
|
||||
db := getDb(opts...).Model(&model.WebsiteGroup{})
|
||||
if err := db.Order("`default` desc").Find(&groups).Error; err != nil {
|
||||
return groups, err
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func (w WebsiteGroupRepo) Create(app *model.WebsiteGroup) error {
|
||||
return getDb().Omit(clause.Associations).Create(app).Error
|
||||
}
|
||||
|
||||
func (w WebsiteGroupRepo) Save(app *model.WebsiteGroup) error {
|
||||
return getDb().Omit(clause.Associations).Save(app).Error
|
||||
}
|
||||
|
||||
func (w WebsiteGroupRepo) DeleteBy(opts ...DBOption) error {
|
||||
return getDb(opts...).Delete(&model.WebsiteGroup{}).Error
|
||||
}
|
||||
|
||||
func (w WebsiteGroupRepo) CancelDefault() error {
|
||||
return global.DB.Model(&model.WebsiteGroup{}).Where("`default` = 1").Updates(map[string]interface{}{"default": 0}).Error
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -166,6 +167,9 @@ func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetail
|
||||
}
|
||||
|
||||
func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error) {
|
||||
if err := docker.CreateDefaultDockerNetwork(); err != nil {
|
||||
return nil, buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
|
||||
}
|
||||
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
|
||||
return nil, buserr.New(constant.ErrNameIsExist)
|
||||
}
|
||||
@@ -253,6 +257,9 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
if err := createLink(ctx, app, &appInstall, req.Params); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := upAppPre(app, appInstall); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go upApp(appInstall.GetComposePath(), appInstall)
|
||||
go updateToolApp(appInstall)
|
||||
return &appInstall, nil
|
||||
|
||||
@@ -3,9 +3,6 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/env"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||
"github.com/joho/godotenv"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
@@ -14,6 +11,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/env"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
@@ -33,7 +34,28 @@ import (
|
||||
type AppInstallService struct {
|
||||
}
|
||||
|
||||
func (a AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
|
||||
type IAppInstallService interface {
|
||||
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
|
||||
CheckExist(key string) (*response.AppInstalledCheck, error)
|
||||
LoadPort(key string) (int64, error)
|
||||
LoadPassword(key string) (string, error)
|
||||
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
|
||||
Operate(req request.AppInstalledOperate) error
|
||||
Update(req request.AppInstalledUpdate) error
|
||||
SyncAll(systemInit bool) error
|
||||
GetServices(key string) ([]response.AppService, error)
|
||||
GetUpdateVersions(installId uint) ([]dto.AppVersion, error)
|
||||
GetParams(id uint) ([]response.AppParam, error)
|
||||
ChangeAppPort(req request.PortUpdate) error
|
||||
GetDefaultConfigByKey(key string) (string, error)
|
||||
DeleteCheck(installId uint) ([]dto.AppResource, error)
|
||||
}
|
||||
|
||||
func NewIAppInstalledService() IAppInstallService {
|
||||
return &AppInstallService{}
|
||||
}
|
||||
|
||||
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
|
||||
var opts []repo.DBOption
|
||||
|
||||
if req.Name != "" {
|
||||
@@ -73,7 +95,7 @@ func (a AppInstallService) Page(req request.AppInstalledSearch) (int64, []respon
|
||||
return total, installDTOs, nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) CheckExist(key string) (*response.AppInstalledCheck, error) {
|
||||
func (a *AppInstallService) CheckExist(key string) (*response.AppInstalledCheck, error) {
|
||||
res := &response.AppInstalledCheck{
|
||||
IsExist: false,
|
||||
}
|
||||
@@ -103,7 +125,7 @@ func (a AppInstallService) CheckExist(key string) (*response.AppInstalledCheck,
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) LoadPort(key string) (int64, error) {
|
||||
func (a *AppInstallService) LoadPort(key string) (int64, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
||||
if err != nil {
|
||||
return int64(0), nil
|
||||
@@ -111,7 +133,7 @@ func (a AppInstallService) LoadPort(key string) (int64, error) {
|
||||
return app.Port, nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) LoadPassword(key string) (string, error) {
|
||||
func (a *AppInstallService) LoadPassword(key string) (string, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
||||
if err != nil {
|
||||
return "", nil
|
||||
@@ -119,7 +141,7 @@ func (a AppInstallService) LoadPassword(key string) (string, error) {
|
||||
return app.Password, nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
||||
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
||||
var (
|
||||
installs []model.AppInstall
|
||||
err error
|
||||
@@ -152,7 +174,7 @@ func (a AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]r
|
||||
return handleInstalled(installs, false)
|
||||
}
|
||||
|
||||
func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -196,7 +218,7 @@ func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
|
||||
func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
|
||||
installed, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -270,13 +292,18 @@ func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) SyncAll() error {
|
||||
func (a *AppInstallService) SyncAll(systemInit bool) error {
|
||||
allList, err := appInstallRepo.ListBy()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, i := range allList {
|
||||
if i.Status == constant.Installing {
|
||||
if systemInit {
|
||||
i.Status = constant.Error
|
||||
i.Message = "System restart causes application exception"
|
||||
_ = appInstallRepo.Save(&i)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err := syncById(i.ID); err != nil {
|
||||
@@ -286,7 +313,7 @@ func (a AppInstallService) SyncAll() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
||||
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -310,7 +337,7 @@ func (a AppInstallService) GetServices(key string) ([]response.AppService, error
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion, error) {
|
||||
func (a *AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion, error) {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||
var versions []dto.AppVersion
|
||||
if err != nil {
|
||||
@@ -335,7 +362,7 @@ func (a AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion,
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) ChangeAppPort(req request.PortUpdate) error {
|
||||
func (a *AppInstallService) ChangeAppPort(req request.PortUpdate) error {
|
||||
if common.ScanPort(int(req.Port)) {
|
||||
return buserr.WithDetail(constant.ErrPortInUsed, req.Port, nil)
|
||||
}
|
||||
@@ -363,7 +390,7 @@ func (a AppInstallService) ChangeAppPort(req request.PortUpdate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error) {
|
||||
func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error) {
|
||||
var res []dto.AppResource
|
||||
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||
if err != nil {
|
||||
@@ -404,7 +431,7 @@ func (a AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
|
||||
func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
|
||||
appInstall, err := getAppInstallByKey(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -426,7 +453,7 @@ func (a AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
|
||||
return string(contentByte), nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
|
||||
func (a *AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
|
||||
var (
|
||||
res []response.AppParam
|
||||
appForm dto.AppForm
|
||||
@@ -459,14 +486,20 @@ func (a AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
|
||||
}
|
||||
appParam.LabelZh = form.LabelZh
|
||||
appParam.LabelEn = form.LabelEn
|
||||
appParam.Value = v
|
||||
if form.Type == "service" {
|
||||
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
||||
appParam.Value = appInstall.Name
|
||||
res = append(res, appParam)
|
||||
} else {
|
||||
appParam.Value = v
|
||||
res = append(res, appParam)
|
||||
appParam.ShowValue = appInstall.Name
|
||||
} else if form.Type == "select" {
|
||||
for _, fv := range form.Values {
|
||||
if fv.Value == v {
|
||||
appParam.ShowValue = fv.Label
|
||||
break
|
||||
}
|
||||
}
|
||||
appParam.Values = form.Values
|
||||
}
|
||||
res = append(res, appParam)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
@@ -622,7 +655,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
|
||||
}, commonRepo.WithByID(appInstall.ID))
|
||||
}
|
||||
if param == "user-password" {
|
||||
oldVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", appInstall.Password)
|
||||
oldVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", appInstall.UserPassword)
|
||||
newVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", value)
|
||||
_ = appInstallRepo.BatchUpdateBy(map[string]interface{}{
|
||||
"param": strings.ReplaceAll(appInstall.Param, oldVal, newVal),
|
||||
|
||||
@@ -339,6 +339,17 @@ func copyAppData(key, version, installName string, params map[string]interface{}
|
||||
return
|
||||
}
|
||||
|
||||
// 处理文件夹权限等问题
|
||||
func upAppPre(app model.App, appInstall model.AppInstall) error {
|
||||
if app.Key == "nexus" {
|
||||
dataPath := path.Join(appInstall.GetPath(), "data")
|
||||
if err := files.NewFileOp().Chown(dataPath, 200, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func upApp(composeFilePath string, appInstall model.AppInstall) {
|
||||
out, err := compose.Up(composeFilePath)
|
||||
if err != nil {
|
||||
|
||||
@@ -86,9 +86,9 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
|
||||
}
|
||||
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
|
||||
if err != nil {
|
||||
return nil, constant.ErrAuth
|
||||
return nil, err
|
||||
}
|
||||
if info.Password != pass && nameSetting.Value != info.Name {
|
||||
if info.Password != pass || nameSetting.Value != info.Name {
|
||||
return nil, constant.ErrAuth
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
|
||||
j := jwt.NewJWT()
|
||||
claims := j.CreateClaims(jwt.BaseClaims{
|
||||
Name: name,
|
||||
}, lifeTime)
|
||||
})
|
||||
token, err := j.CreateToken(claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -134,7 +134,7 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
|
||||
tempPath := fmt.Sprintf("%sdownload%s", constant.DataDir, info.FileDir)
|
||||
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(tempPath, os.ModePerm); err != nil {
|
||||
fmt.Println(err)
|
||||
global.LOG.Errorf("mkdir %s failed, err: %v", tempPath, err)
|
||||
}
|
||||
}
|
||||
targetPath := tempPath + info.FileName
|
||||
|
||||
@@ -181,16 +181,19 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
if err := handleMysqlRecover(mysqlInfo, tmpPath, db.Name, fmt.Sprintf("%s.sql.gz", install.Name), true); err != nil {
|
||||
global.LOG.Errorf("handle recover from sql.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := handleUnTar(tmpPath+"/app.tar.gz", fmt.Sprintf("%s/%s", constant.AppInstallDir, install.App.Key)); err != nil {
|
||||
global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
oldInstall.Status = constant.Running
|
||||
if err := appInstallRepo.Save(install); err != nil {
|
||||
global.LOG.Errorf("save db app install failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
isOk = true
|
||||
|
||||
@@ -106,8 +106,8 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
|
||||
}
|
||||
defer func() {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if !isOk {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := handleWebsiteRecover(website, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback website %s from %s failed, err: %v", website.Alias, rollbackFile, err)
|
||||
return
|
||||
@@ -126,6 +126,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
}
|
||||
nginxConfPath := fmt.Sprintf("%s/openresty/%s/conf/conf.d", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := fileOp.CopyFile(fmt.Sprintf("%s/%s.conf", tmpPath, website.Alias), nginxConfPath); err != nil {
|
||||
global.LOG.Errorf("handle recover from conf.d failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -135,22 +136,27 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true); err != nil {
|
||||
global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, app.App.Key, app.Name)); err != nil {
|
||||
global.LOG.Errorf("docker-compose restart failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
siteDir := fmt.Sprintf("%s/openresty/%s/www/sites", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir); err != nil {
|
||||
global.LOG.Errorf("handle recover from web.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
stdout, err := cmd.Execf("docker exec -i %s nginx -s reload", nginxInfo.ContainerName)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("nginx -s reload failed, err: %s", stdout)
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
if err := websiteRepo.SaveWithoutCtx(&oldWebsite); err != nil {
|
||||
global.LOG.Errorf("handle save website data failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
isOk = true
|
||||
|
||||
@@ -3,7 +3,9 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"sort"
|
||||
@@ -21,6 +23,7 @@ import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
@@ -33,7 +36,7 @@ type IContainerService interface {
|
||||
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
ListVolume() ([]dto.Options, error)
|
||||
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
CreateCompose(req dto.ComposeCreate) error
|
||||
CreateCompose(req dto.ComposeCreate) (string, error)
|
||||
ComposeOperation(req dto.ComposeOperation) error
|
||||
ContainerCreate(req dto.ContainerCreate) error
|
||||
ContainerOperation(req dto.ContainerOperation) error
|
||||
@@ -98,6 +101,10 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
if _, ok := container.Labels[composeProjectLabel]; ok {
|
||||
IsFromCompose = true
|
||||
}
|
||||
IsFromApp := false
|
||||
if created, ok := container.Labels[composeCreatedBy]; ok && created == "Apps" {
|
||||
IsFromApp = true
|
||||
}
|
||||
backDatas = append(backDatas, dto.ContainerInfo{
|
||||
ContainerID: container.ID,
|
||||
CreateTime: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
|
||||
@@ -106,6 +113,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
ImageName: container.Image,
|
||||
State: container.State,
|
||||
RunTime: container.Status,
|
||||
IsFromApp: IsFromApp,
|
||||
IsFromCompose: IsFromCompose,
|
||||
})
|
||||
}
|
||||
@@ -150,10 +158,12 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
||||
return err
|
||||
}
|
||||
config := &container.Config{
|
||||
Image: req.Image,
|
||||
Cmd: req.Cmd,
|
||||
Env: req.Env,
|
||||
Labels: stringsToMap(req.Labels),
|
||||
Image: req.Image,
|
||||
Cmd: req.Cmd,
|
||||
Env: req.Env,
|
||||
Labels: stringsToMap(req.Labels),
|
||||
Tty: true,
|
||||
OpenStdin: true,
|
||||
}
|
||||
hostConf := &container.HostConfig{
|
||||
AutoRemove: req.AutoRemove,
|
||||
@@ -185,14 +195,19 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
||||
}
|
||||
|
||||
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
|
||||
container, err := client.ContainerCreate(context.TODO(), config, hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name)
|
||||
|
||||
ctx := context.Background()
|
||||
if err := pullImages(ctx, client, req.Image); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := client.ContainerCreate(ctx, config, hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name)
|
||||
if err != nil {
|
||||
_ = client.ContainerRemove(context.Background(), req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
|
||||
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{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(context.TODO(), container.ID, types.ContainerStartOptions{}); err != nil {
|
||||
_ = client.ContainerRemove(context.Background(), req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
|
||||
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
|
||||
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
|
||||
return fmt.Errorf("create successful but start failed, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
@@ -234,7 +249,7 @@ func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) {
|
||||
}
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.New(string(stdout))
|
||||
}
|
||||
return string(stdout), nil
|
||||
}
|
||||
@@ -315,3 +330,16 @@ func calculateNetwork(network map[string]types.NetworkStats) (float64, float64)
|
||||
}
|
||||
return rx, tx
|
||||
}
|
||||
|
||||
func pullImages(ctx context.Context, client *client.Client, image string) error {
|
||||
out, err := client.ImagePull(ctx, image, types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
_, err = io.Copy(ioutil.Discard, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -123,41 +125,49 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
|
||||
return int64(total), BackDatas, nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
|
||||
if req.From == "template" {
|
||||
template, err := composeRepo.Get(commonRepo.WithByID(req.Template))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.From = "edit"
|
||||
req.File = template.Content
|
||||
func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
|
||||
if err := u.loadPath(&req); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cmd := exec.Command("docker-compose", "-f", req.Path, "config")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return false, errors.New(string(stdout))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/docker-compose.yml", dir)
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(string(req.File))
|
||||
write.Flush()
|
||||
req.Path = path
|
||||
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error) {
|
||||
if err := u.loadPath(&req); err != nil {
|
||||
return "", err
|
||||
}
|
||||
global.LOG.Infof("docker-compose.yml %s create successful, start to docker-compose up", req.Name)
|
||||
if stdout, err := compose.Up(req.Path); err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name})
|
||||
return nil
|
||||
if req.From == "path" {
|
||||
req.Name = path.Base(strings.ReplaceAll(req.Path, "/"+path.Base(req.Path), ""))
|
||||
}
|
||||
logName := path.Dir(req.Path) + "/compose.log"
|
||||
file, err := os.OpenFile(logName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
go func() {
|
||||
defer file.Close()
|
||||
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
_, _ = file.Write(stdout)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err)
|
||||
_, _ = compose.Down(req.Path)
|
||||
_, _ = file.WriteString("docker-compose up failed!")
|
||||
return
|
||||
}
|
||||
global.LOG.Infof("docker-compose up %s successful!", req.Name)
|
||||
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name})
|
||||
_, _ = file.WriteString("docker-compose up successful!")
|
||||
}()
|
||||
|
||||
return logName, nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
||||
@@ -199,3 +209,34 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
|
||||
if req.From == "template" {
|
||||
template, err := composeRepo.Get(commonRepo.WithByID(req.Template))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.From = "edit"
|
||||
req.File = template.Content
|
||||
}
|
||||
if req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/docker-compose.yml", dir)
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(string(req.File))
|
||||
write.Flush()
|
||||
req.Path = path
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
@@ -80,6 +82,9 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
|
||||
}
|
||||
for _, id := range req.Names {
|
||||
if err := client.NetworkRemove(context.TODO(), id); err != nil {
|
||||
if strings.Contains(err.Error(), "has active endpoints") {
|
||||
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"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/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -96,6 +96,9 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
|
||||
}
|
||||
for _, id := range req.Names {
|
||||
if err := client.VolumeRemove(context.TODO(), id, true); err != nil {
|
||||
if strings.Contains(err.Error(), "volume is in use") {
|
||||
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -122,12 +125,8 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreat) error {
|
||||
DriverOpts: stringsToMap(req.Options),
|
||||
Labels: stringsToMap(req.Labels),
|
||||
}
|
||||
stat, err := client.VolumeCreate(context.TODO(), options)
|
||||
if err != nil {
|
||||
if _, err := client.VolumeCreate(context.TODO(), options); err != nil {
|
||||
return err
|
||||
}
|
||||
// if len(stat.CreatedAt) != 0 {
|
||||
fmt.Println(stat)
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,17 +2,14 @@ package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"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/cloud_storage"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/robfig/cron/v3"
|
||||
@@ -92,69 +89,28 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
||||
if cronjob.ID == 0 {
|
||||
return "", constant.ErrRecordNotFound
|
||||
}
|
||||
|
||||
global.LOG.Infof("start to download records %s from %s", cronjob.Type, backup.Type)
|
||||
varMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
||||
if backup.Type == "LOCAL" {
|
||||
if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) {
|
||||
return "", constant.ErrRecordNotFound
|
||||
}
|
||||
return record.File, nil
|
||||
}
|
||||
if record.FromLocal {
|
||||
local, _ := loadLocalDir()
|
||||
if _, err := os.Stat(local + "/" + record.File); err == nil {
|
||||
return local + "/" + record.File, nil
|
||||
}
|
||||
}
|
||||
client, err := NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
varMap["type"] = backup.Type
|
||||
if backup.Type != "LOCAL" {
|
||||
varMap["bucket"] = backup.Bucket
|
||||
switch backup.Type {
|
||||
case constant.Sftp:
|
||||
varMap["username"] = backup.AccessKey
|
||||
varMap["password"] = backup.Credential
|
||||
case constant.OSS, constant.S3, constant.MinIo:
|
||||
varMap["accessKey"] = backup.AccessKey
|
||||
varMap["secretKey"] = backup.Credential
|
||||
}
|
||||
backClient, err := cloud_storage.NewCloudStorageClient(varMap)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new cloud storage client failed, err: %v", err)
|
||||
}
|
||||
global.LOG.Info("new backup client successful")
|
||||
commonDir := fmt.Sprintf("%s/%s/", cronjob.Type, cronjob.Name)
|
||||
name := fmt.Sprintf("%s%s.tar.gz", commonDir, record.StartTime.Format("20060102150405"))
|
||||
if cronjob.Type == "database" {
|
||||
name = fmt.Sprintf("%s%s.gz", commonDir, record.StartTime.Format("20060102150405"))
|
||||
}
|
||||
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, commonDir)
|
||||
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(tempPath, os.ModePerm); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
global.LOG.Infof("download records %s from %s to %s", name, commonDir, tempPath)
|
||||
targetPath := tempPath + strings.ReplaceAll(name, commonDir, "")
|
||||
if _, err = os.Stat(targetPath); err != nil && os.IsNotExist(err) {
|
||||
isOK, err := backClient.Download(name, targetPath)
|
||||
if !isOK {
|
||||
return "", fmt.Errorf("cloud storage download failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return targetPath, nil
|
||||
}
|
||||
if _, ok := varMap["dir"]; !ok {
|
||||
return "", errors.New("load local backup dir failed")
|
||||
}
|
||||
global.LOG.Infof("record is save in local dir %s", varMap["dir"])
|
||||
|
||||
switch cronjob.Type {
|
||||
case "website":
|
||||
return fmt.Sprintf("%v/website/%s/website_%s_%s.tar.gz", varMap["dir"], cronjob.Website, cronjob.Website, record.StartTime.Format("20060102150405")), nil
|
||||
case "database":
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load mysqlInfo failed, err: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("%v/database/mysql/%s/%s/db_%s_%s.sql.gz", varMap["dir"], mysqlInfo.Name, cronjob.DBName, cronjob.DBName, record.StartTime.Format("20060102150405")), nil
|
||||
case "directory":
|
||||
return fmt.Sprintf("%v/%s/%s/directory%s_%s.tar.gz", varMap["dir"], cronjob.Type, cronjob.Name, strings.ReplaceAll(cronjob.SourceDir, "/", "_"), record.StartTime.Format("20060102150405")), nil
|
||||
default:
|
||||
return "", fmt.Errorf("not support type %s", cronjob.Type)
|
||||
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, record.File)
|
||||
isOK, _ := client.Download(record.File, tempPath)
|
||||
if !isOK || err != nil {
|
||||
return "", constant.ErrRecordNotFound
|
||||
}
|
||||
return tempPath, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) HandleOnce(id uint) error {
|
||||
@@ -238,6 +194,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["entry_id"] = newEntryID
|
||||
upMap["name"] = req.Name
|
||||
upMap["spec"] = cronjob.Spec
|
||||
upMap["script"] = req.Script
|
||||
upMap["spec_type"] = req.SpecType
|
||||
upMap["week"] = req.Week
|
||||
|
||||
@@ -22,8 +22,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
message []byte
|
||||
err error
|
||||
)
|
||||
record := cronjobRepo.StartRecords(cronjob.ID, "")
|
||||
record.FromLocal = cronjob.KeepLocal
|
||||
record := cronjobRepo.StartRecords(cronjob.ID, cronjob.KeepLocal, "")
|
||||
go func() {
|
||||
switch cronjob.Type {
|
||||
case "shell":
|
||||
@@ -118,6 +117,8 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||
if len(record.Name) != 0 {
|
||||
record.FileName = fileName
|
||||
record.FileDir = backupDir
|
||||
@@ -125,7 +126,7 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
record.BackupType = backup.Type
|
||||
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||
record.Source = backup.Type
|
||||
record.FileDir = strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||
record.FileDir = itemFileDir
|
||||
}
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
@@ -133,7 +134,10 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
}
|
||||
}
|
||||
|
||||
fullPath := fmt.Sprintf("%s/%s", record.FileDir, fileName)
|
||||
fullPath := fmt.Sprintf("%s/%s", backupDir, fileName)
|
||||
if backup.Type != "LOCAL" {
|
||||
fullPath = fmt.Sprintf("%s/%s", itemFileDir, fileName)
|
||||
}
|
||||
if backup.Type == "LOCAL" {
|
||||
u.HandleRmExpired(backup.Type, backupDir, cronjob, nil)
|
||||
return fullPath, nil
|
||||
@@ -148,10 +152,13 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
if err != nil {
|
||||
return fullPath, err
|
||||
}
|
||||
if _, err = client.Upload(backupDir+"/"+fileName, fullPath); err != nil {
|
||||
if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil {
|
||||
return fullPath, err
|
||||
}
|
||||
u.HandleRmExpired(backup.Type, backupDir, cronjob, client)
|
||||
u.HandleRmExpired(backup.Type, itemFileDir, cronjob, client)
|
||||
if cronjob.KeepLocal {
|
||||
u.HandleRmExpired("LOCAL", backupDir, cronjob, client)
|
||||
}
|
||||
return fullPath, nil
|
||||
}
|
||||
|
||||
@@ -185,9 +192,7 @@ func (u *CronjobService) HandleRmExpired(backType, backupDir string, cronjob *mo
|
||||
for i := 0; i < len(currentObjs)-int(cronjob.RetainCopies); i++ {
|
||||
_, _ = backClient.Delete(currentObjs[i].(string))
|
||||
}
|
||||
if !cronjob.KeepLocal {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
files, err := ioutil.ReadDir(backupDir)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,9 +2,11 @@ package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
@@ -39,27 +41,6 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
|
||||
ss, _ := json.Marshal(hostInfo)
|
||||
baseInfo.VirtualizationSystem = string(ss)
|
||||
|
||||
apps, err := appRepo.GetBy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, app := range apps {
|
||||
switch app.Key {
|
||||
case "dateease":
|
||||
baseInfo.DateeaseID = app.ID
|
||||
case "halo":
|
||||
baseInfo.HaloID = app.ID
|
||||
case "metersphere":
|
||||
baseInfo.MeterSphereID = app.ID
|
||||
case "jumpserver":
|
||||
baseInfo.JumpServerID = app.ID
|
||||
case "kubeoperator":
|
||||
baseInfo.KubeoperatorID = app.ID
|
||||
case "kubepi":
|
||||
baseInfo.KubepiID = app.ID
|
||||
}
|
||||
}
|
||||
|
||||
appInstall, err := appInstallRepo.ListBy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -120,15 +101,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
currentInfo.MemoryUsed = memoryInfo.Used
|
||||
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
||||
|
||||
state, _ := disk.Usage("/")
|
||||
currentInfo.Total = state.Total
|
||||
currentInfo.Free = state.Free
|
||||
currentInfo.Used = state.Used
|
||||
currentInfo.UsedPercent = state.UsedPercent
|
||||
currentInfo.InodesTotal = state.InodesTotal
|
||||
currentInfo.InodesUsed = state.InodesUsed
|
||||
currentInfo.InodesFree = state.InodesFree
|
||||
currentInfo.InodesUsedPercent = state.InodesUsedPercent
|
||||
currentInfo.DiskData = loadDiskInfo()
|
||||
|
||||
if ioOption == "all" {
|
||||
diskInfo, _ := disk.IOCounters()
|
||||
@@ -136,20 +109,17 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
currentInfo.IOReadBytes += state.ReadBytes
|
||||
currentInfo.IOWriteBytes += state.WriteBytes
|
||||
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
|
||||
currentInfo.IOTime += state.ReadTime / 1000 / 1000
|
||||
if state.WriteTime > state.ReadTime {
|
||||
currentInfo.IOTime += state.WriteTime / 1000 / 1000
|
||||
}
|
||||
currentInfo.IOReadTime += state.ReadTime
|
||||
currentInfo.IOWriteTime += state.WriteTime
|
||||
}
|
||||
} else {
|
||||
diskInfo, _ := disk.IOCounters(ioOption)
|
||||
for _, state := range diskInfo {
|
||||
currentInfo.IOReadBytes += state.ReadBytes
|
||||
currentInfo.IOWriteBytes += state.WriteBytes
|
||||
currentInfo.IOTime += state.ReadTime / 1000 / 1000
|
||||
if state.WriteTime > state.ReadTime {
|
||||
currentInfo.IOTime += state.WriteTime / 1000 / 1000
|
||||
}
|
||||
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
|
||||
currentInfo.IOReadTime += state.ReadTime
|
||||
currentInfo.IOWriteTime += state.WriteTime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,3 +142,64 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
currentInfo.ShotTime = time.Now()
|
||||
return ¤tInfo
|
||||
}
|
||||
|
||||
type diskInfo struct {
|
||||
Type string
|
||||
Mount string
|
||||
Device string
|
||||
}
|
||||
|
||||
func loadDiskInfo() []dto.DiskInfo {
|
||||
var datas []dto.DiskInfo
|
||||
stdout, err := cmd.Exec("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")
|
||||
if err != nil {
|
||||
return datas
|
||||
}
|
||||
lines := strings.Split(stdout, "\n")
|
||||
|
||||
var mounts []diskInfo
|
||||
var excludes = []string{"/mnt/cdrom", "/boot", "/boot/efi", "/dev", "/dev/shm", "/run/lock", "/run", "/run/shm", "/run/user"}
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 7 {
|
||||
continue
|
||||
}
|
||||
if fields[1] == "tmpfs" {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(fields[2], "M") || strings.Contains(fields[2], "K") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(fields[6], "docker") {
|
||||
continue
|
||||
}
|
||||
isExclude := false
|
||||
for _, exclude := range excludes {
|
||||
if exclude == fields[6] {
|
||||
isExclude = true
|
||||
}
|
||||
}
|
||||
if isExclude {
|
||||
continue
|
||||
}
|
||||
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: fields[6]})
|
||||
}
|
||||
|
||||
for i := 0; i < len(mounts); i++ {
|
||||
state, _ := disk.Usage(mounts[i].Mount)
|
||||
var itemData dto.DiskInfo
|
||||
itemData.Path = mounts[i].Mount
|
||||
itemData.Type = mounts[i].Type
|
||||
itemData.Device = mounts[i].Device
|
||||
itemData.Total = state.Total
|
||||
itemData.Free = state.Free
|
||||
itemData.Used = state.Used
|
||||
itemData.UsedPercent = state.UsedPercent
|
||||
itemData.InodesTotal = state.InodesTotal
|
||||
itemData.InodesUsed = state.InodesUsed
|
||||
itemData.InodesFree = state.InodesFree
|
||||
itemData.InodesUsedPercent = state.InodesUsedPercent
|
||||
datas = append(datas, itemData)
|
||||
}
|
||||
return datas
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
|
||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user if not exists '%s'@'%s' identified by '%s';", mysql.Username, info.Value, mysql.Password)); err != nil {
|
||||
return err
|
||||
}
|
||||
grantStr := fmt.Sprintf("grant all privileges on %s.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value)
|
||||
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value)
|
||||
if app.Version == "5.7.39" {
|
||||
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ type ServiceGroup struct {
|
||||
SettingService
|
||||
BackupService
|
||||
|
||||
WebsiteGroupService
|
||||
WebsiteService
|
||||
WebsiteDnsAccountService
|
||||
WebsiteSSLService
|
||||
@@ -68,7 +67,6 @@ var (
|
||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
||||
|
||||
websiteRepo = repo.NewIWebsiteRepo()
|
||||
websiteGroupRepo = repo.RepoGroupApp.WebsiteGroupRepo
|
||||
websiteDomainRepo = repo.RepoGroupApp.WebsiteDomainRepo
|
||||
websiteDnsRepo = repo.RepoGroupApp.WebsiteDnsAccountRepo
|
||||
websiteSSLRepo = repo.NewISSLRepo()
|
||||
|
||||
@@ -22,7 +22,7 @@ func NewIGroupService() IGroupService {
|
||||
}
|
||||
|
||||
func (u *GroupService) List(req dto.GroupSearch) ([]dto.GroupInfo, error) {
|
||||
groups, err := groupRepo.GetList(commonRepo.WithByType(req.Type))
|
||||
groups, err := groupRepo.GetList(commonRepo.WithByType(req.Type), commonRepo.WithOrderBy("is_default desc"), commonRepo.WithOrderBy("created_at desc"))
|
||||
if err != nil {
|
||||
return nil, constant.ErrRecordNotFound
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func (u *GroupService) List(req dto.GroupSearch) ([]dto.GroupInfo, error) {
|
||||
}
|
||||
|
||||
func (u *GroupService) Create(req dto.GroupCreate) error {
|
||||
group, _ := groupRepo.Get(commonRepo.WithByName(req.Name), commonRepo.WithByName(req.Name))
|
||||
group, _ := groupRepo.Get(commonRepo.WithByName(req.Name), commonRepo.WithByType(req.Type))
|
||||
if group.ID != 0 {
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func (u *GroupService) Delete(id uint) error {
|
||||
}
|
||||
switch group.Type {
|
||||
case "website":
|
||||
websites, _ := websiteRepo.GetBy(commonRepo.WithByGroupID(id))
|
||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithGroupID(id))
|
||||
if len(websites) > 0 {
|
||||
return buserr.New(constant.ErrGroupIsUsed)
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func (u *GroupService) Delete(id uint) error {
|
||||
|
||||
func (u *GroupService) Update(req dto.GroupUpdate) error {
|
||||
if req.IsDefault {
|
||||
if err := groupRepo.CancelDefault(); err != nil {
|
||||
if err := groupRepo.CancelDefault(req.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"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/docker"
|
||||
@@ -53,8 +54,8 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
return 0, nil, err
|
||||
}
|
||||
if len(req.Info) != 0 {
|
||||
lenth, count := len(list), 0
|
||||
for count < lenth {
|
||||
length, count := len(list), 0
|
||||
for count < length {
|
||||
hasTag := false
|
||||
for _, tag := range list[count].RepoTags {
|
||||
if strings.Contains(tag, req.Info) {
|
||||
@@ -64,7 +65,7 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
}
|
||||
if !hasTag {
|
||||
list = append(list[:count], list[(count+1):]...)
|
||||
lenth--
|
||||
length--
|
||||
} else {
|
||||
count++
|
||||
}
|
||||
@@ -121,6 +122,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fileName := "Dockerfile"
|
||||
if req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
@@ -140,7 +142,8 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
write.Flush()
|
||||
req.Dockerfile = dir
|
||||
} else {
|
||||
req.Dockerfile = strings.ReplaceAll(req.Dockerfile, "/Dockerfile", "")
|
||||
fileName = path.Base(req.Dockerfile)
|
||||
req.Dockerfile = path.Dir(req.Dockerfile)
|
||||
}
|
||||
tar, err := archive.TarWithOptions(req.Dockerfile+"/", &archive.TarOptions{})
|
||||
if err != nil {
|
||||
@@ -148,7 +151,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
}
|
||||
|
||||
opts := types.ImageBuildOptions{
|
||||
Dockerfile: "Dockerfile",
|
||||
Dockerfile: fileName,
|
||||
Tags: []string{req.Name},
|
||||
Remove: true,
|
||||
Labels: stringsToMap(req.Tags),
|
||||
@@ -178,14 +181,14 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(string(body), "error") && strings.Contains(string(body), "failed:") {
|
||||
if strings.Contains(string(body), "errorDetail") || strings.Contains(string(body), "error:") {
|
||||
global.LOG.Errorf("build image %s failed", req.Name)
|
||||
_, _ = file.Write(body)
|
||||
_, _ = file.WriteString("image build failed!")
|
||||
return
|
||||
}
|
||||
global.LOG.Infof("build image %s successful!", req.Name)
|
||||
_, _ = io.Copy(file, res.Body)
|
||||
_, _ = file.Write(body)
|
||||
_, _ = file.WriteString("image build successful!")
|
||||
}()
|
||||
|
||||
@@ -378,8 +381,14 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ids := range req.Names {
|
||||
if _, err := client.ImageRemove(context.TODO(), ids, types.ImageRemoveOptions{Force: true, PruneChildren: true}); err != nil {
|
||||
for _, id := range req.Names {
|
||||
if _, err := client.ImageRemove(context.TODO(), id, types.ImageRemoveOptions{Force: true, PruneChildren: true}); err != nil {
|
||||
if strings.Contains(err.Error(), "image is being used") {
|
||||
if strings.Contains(id, "sha256:") {
|
||||
return buserr.New(constant.ErrObjectInUsed)
|
||||
}
|
||||
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,15 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type LogService struct{}
|
||||
|
||||
const logs = "https://resource.fit2cloud.com/installation-log.sh"
|
||||
|
||||
type ILogService interface {
|
||||
CreateLoginLog(operation model.LoginLog) error
|
||||
PageLoginLog(search dto.SearchLgLogWithPage) (int64, interface{}, error)
|
||||
@@ -77,3 +80,7 @@ func (u *LogService) CleanLogs(logtype string) error {
|
||||
}
|
||||
return logRepo.CleanLogin()
|
||||
}
|
||||
|
||||
func writeLogs(version string) {
|
||||
_, _ = cmd.Execf("curl -sfL %s | sh -s 1p upgrade %s", logs, version)
|
||||
}
|
||||
|
||||
@@ -66,6 +66,9 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("incorrect snapshot name format of %s", snap)
|
||||
}
|
||||
if strings.HasSuffix(snap, ".tar.gz") {
|
||||
snap = strings.ReplaceAll(snap, ".tar.gz", "")
|
||||
}
|
||||
itemSnap := model.Snapshot{
|
||||
Name: snap,
|
||||
From: req.From,
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
@@ -20,6 +22,7 @@ type UpgradeService struct{}
|
||||
|
||||
type IUpgradeService interface {
|
||||
Upgrade(req dto.Upgrade) error
|
||||
LoadNotes(req dto.Upgrade) (string, error)
|
||||
SearchUpgrade() (*dto.UpgradeInfo, error)
|
||||
}
|
||||
|
||||
@@ -34,36 +37,50 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
versionRes, err := http.Get(fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode))
|
||||
latestVersion, err := u.loadVersion(true, currentVersion.Value)
|
||||
if err != nil {
|
||||
global.LOG.Infof("load latest version failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer versionRes.Body.Close()
|
||||
version, err := ioutil.ReadAll(versionRes.Body)
|
||||
if err != nil {
|
||||
if !common.CompareVersion(string(latestVersion), currentVersion.Value) {
|
||||
return nil, err
|
||||
}
|
||||
isNew, err := compareVersion(currentVersion.Value, string(version))
|
||||
if !isNew || err != nil {
|
||||
return nil, err
|
||||
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 != "" {
|
||||
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))
|
||||
|
||||
upgrade.NewVersion = string(version)
|
||||
|
||||
releaseNotes, err := http.Get(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, upgrade.NewVersion, upgrade.NewVersion))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("load relase-notes of version %s failed, err: %v", latestVersion, err)
|
||||
}
|
||||
defer releaseNotes.Body.Close()
|
||||
release, err := ioutil.ReadAll(releaseNotes.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upgrade.ReleaseNote = string(release)
|
||||
|
||||
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))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load relase-notes of version %s failed, err: %v", req.Version, err)
|
||||
}
|
||||
return notes, nil
|
||||
}
|
||||
|
||||
func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
global.LOG.Info("start to upgrade now...")
|
||||
fileOp := files.NewFileOp()
|
||||
@@ -128,6 +145,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
}
|
||||
|
||||
global.LOG.Info("upgrade successful!")
|
||||
go writeLogs(req.Version)
|
||||
_ = settingRepo.Update("SystemVersion", req.Version)
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
||||
@@ -173,45 +191,49 @@ func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string,
|
||||
if err := cpBinary(originalDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func compareVersion(version, newVersion string) (bool, error) {
|
||||
if version == newVersion {
|
||||
return false, nil
|
||||
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (string, error) {
|
||||
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode)
|
||||
if !isLatest {
|
||||
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, global.CONF.System.Mode)
|
||||
}
|
||||
if len(version) == 0 || len(newVersion) == 0 {
|
||||
return false, fmt.Errorf("incorrect version or new version entered %v -- %v", version, newVersion)
|
||||
latestVersionRes, err := http.Get(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
versions := strings.Split(strings.ReplaceAll(version, "v", ""), ".")
|
||||
if len(versions) != 3 {
|
||||
return false, fmt.Errorf("incorrect version input %v", version)
|
||||
defer latestVersionRes.Body.Close()
|
||||
version, err := ioutil.ReadAll(latestVersionRes.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
newVersions := strings.Split(strings.ReplaceAll(newVersion, "v", ""), ".")
|
||||
if len(newVersions) != 3 {
|
||||
return false, fmt.Errorf("incorrect newVersions input %v", version)
|
||||
if isLatest {
|
||||
return string(version), nil
|
||||
}
|
||||
version1, _ := strconv.Atoi(versions[0])
|
||||
newVersion1, _ := strconv.Atoi(newVersions[0])
|
||||
if newVersion1 > version1 {
|
||||
return true, nil
|
||||
} else if newVersion1 == version1 {
|
||||
version2, _ := strconv.Atoi(versions[1])
|
||||
newVersion2, _ := strconv.Atoi(newVersions[1])
|
||||
if newVersion2 > version2 {
|
||||
return true, nil
|
||||
} else if newVersion2 == version2 {
|
||||
version3, _ := strconv.Atoi(versions[2])
|
||||
newVersion3, _ := strconv.Atoi(newVersions[2])
|
||||
if newVersion3 > version3 {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
return false, nil
|
||||
|
||||
versionMap := make(map[string]string)
|
||||
if err := json.Unmarshal(version, &versionMap); err != nil {
|
||||
return "", fmt.Errorf("load version map failed, err: %v", err)
|
||||
}
|
||||
|
||||
if len(currentVersion) < 4 {
|
||||
return "", fmt.Errorf("current version is error format: %s", currentVersion)
|
||||
}
|
||||
if version, ok := versionMap[currentVersion[0:4]]; ok {
|
||||
return version, nil
|
||||
}
|
||||
return "", errors.New("load version failed in latest.current")
|
||||
}
|
||||
|
||||
func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
|
||||
releaseNotes, err := http.Get(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer releaseNotes.Body.Close()
|
||||
release, err := ioutil.ReadAll(releaseNotes.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(release), nil
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
)
|
||||
|
||||
type WebsiteGroupService struct {
|
||||
}
|
||||
|
||||
func (w WebsiteGroupService) CreateGroup(create request.WebsiteGroupCreate) error {
|
||||
groups, _ := websiteGroupRepo.GetBy(commonRepo.WithByName(create.Name))
|
||||
if len(groups) > 0 {
|
||||
return buserr.New(constant.ErrNameIsExist)
|
||||
}
|
||||
return websiteGroupRepo.Create(&model.WebsiteGroup{
|
||||
Name: create.Name,
|
||||
})
|
||||
}
|
||||
|
||||
func (w WebsiteGroupService) GetGroups() ([]model.WebsiteGroup, error) {
|
||||
return websiteGroupRepo.GetBy()
|
||||
}
|
||||
|
||||
func (w WebsiteGroupService) UpdateGroup(update request.WebsiteGroupUpdate) error {
|
||||
if update.Default {
|
||||
if err := websiteGroupRepo.CancelDefault(); err != nil {
|
||||
return err
|
||||
}
|
||||
return websiteGroupRepo.Save(&model.WebsiteGroup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: update.ID,
|
||||
},
|
||||
Name: update.Name,
|
||||
Default: true,
|
||||
})
|
||||
} else {
|
||||
exists, _ := websiteGroupRepo.GetBy(commonRepo.WithByName(update.Name))
|
||||
for _, exist := range exists {
|
||||
if exist.ID != update.ID {
|
||||
return buserr.New(constant.ErrNameIsExist)
|
||||
}
|
||||
}
|
||||
return websiteGroupRepo.Save(&model.WebsiteGroup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: update.ID,
|
||||
},
|
||||
Name: update.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (w WebsiteGroupService) DeleteGroup(id uint) error {
|
||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithGroupID(id))
|
||||
if len(websites) > 0 {
|
||||
return buserr.New(constant.ErrGroupIsUsed)
|
||||
}
|
||||
return websiteGroupRepo.DeleteBy(commonRepo.WithByID(id))
|
||||
}
|
||||
@@ -27,6 +27,7 @@ type IWebsiteSSLService interface {
|
||||
GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error)
|
||||
GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error)
|
||||
Delete(id uint) error
|
||||
Update(update request.WebsiteSSLUpdate) error
|
||||
}
|
||||
|
||||
func NewIWebsiteSSLService() IWebsiteSSLService {
|
||||
@@ -99,6 +100,10 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
||||
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
|
||||
return res, err
|
||||
}
|
||||
case constant.DnsManual:
|
||||
if err := client.UseManualDns(); err != nil {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
domains := []string{create.PrimaryDomain}
|
||||
@@ -128,6 +133,7 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
||||
websiteSSL.StartDate = cert.NotBefore
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||
websiteSSL.AutoRenew = create.AutoRenew
|
||||
|
||||
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
|
||||
return res, err
|
||||
@@ -254,3 +260,12 @@ func (w WebsiteSSLService) Delete(id uint) error {
|
||||
}
|
||||
return websiteSSLRepo.DeleteBy(commonRepo.WithByID(id))
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
|
||||
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(update.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
websiteSSL.AutoRenew = update.AutoRenew
|
||||
return websiteSSLRepo.Save(websiteSSL)
|
||||
}
|
||||
|
||||
@@ -50,15 +50,16 @@ var (
|
||||
|
||||
// app
|
||||
var (
|
||||
ErrPortInUsed = "ErrPortInUsed"
|
||||
ErrAppLimit = "ErrAppLimit"
|
||||
ErrAppRequired = "ErrAppRequired"
|
||||
ErrFileCanNotRead = "ErrFileCanNotRead"
|
||||
ErrFileToLarge = "ErrFileToLarge"
|
||||
ErrNotInstall = "ErrNotInstall"
|
||||
ErrPortInOtherApp = "ErrPortInOtherApp"
|
||||
ErrDbUserNotValid = "ErrDbUserNotValid"
|
||||
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
|
||||
ErrPortInUsed = "ErrPortInUsed"
|
||||
ErrAppLimit = "ErrAppLimit"
|
||||
ErrAppRequired = "ErrAppRequired"
|
||||
ErrFileCanNotRead = "ErrFileCanNotRead"
|
||||
ErrFileToLarge = "ErrFileToLarge"
|
||||
ErrNotInstall = "ErrNotInstall"
|
||||
ErrPortInOtherApp = "ErrPortInOtherApp"
|
||||
ErrDbUserNotValid = "ErrDbUserNotValid"
|
||||
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
|
||||
Err1PanelNetworkFailed = "Err1PanelNetworkFailed"
|
||||
)
|
||||
|
||||
//website
|
||||
@@ -83,6 +84,7 @@ var (
|
||||
ErrMovePathFailed = "ErrMovePathFailed"
|
||||
ErrLinkPathNotFound = "ErrLinkPathNotFound"
|
||||
ErrFileIsExit = "ErrFileIsExit"
|
||||
ErrFileUpload = "ErrFileUpload"
|
||||
)
|
||||
|
||||
//mysql
|
||||
@@ -95,3 +97,9 @@ var (
|
||||
var (
|
||||
ErrTypeOfRedis = "ErrTypeOfRedis"
|
||||
)
|
||||
|
||||
//container
|
||||
var (
|
||||
ErrInUsed = "ErrInUsed"
|
||||
ErrObjectInUsed = "ErrObjectInUsed"
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ const (
|
||||
|
||||
AuthMethodJWT = "jwt"
|
||||
JWTHeaderName = "Authorization"
|
||||
JWTBufferTime = 86400
|
||||
JWTBufferTime = 3600
|
||||
JWTIssuer = "1Panel"
|
||||
|
||||
PasswordExpiredName = "expired"
|
||||
|
||||
@@ -4,8 +4,9 @@ const (
|
||||
WebRunning = "Running"
|
||||
WebStopped = "Stopped"
|
||||
|
||||
DateLayout = "2006-01-02"
|
||||
DefaultDate = "1970-01-01"
|
||||
DateLayout = "2006-01-02"
|
||||
DateTimeLayout = "2006-01-02 15:04:05"
|
||||
DefaultDate = "1970-01-01"
|
||||
|
||||
ProtocolHTTP = "HTTP"
|
||||
ProtocolHTTPS = "HTTPS"
|
||||
|
||||
@@ -44,13 +44,13 @@ func Run() {
|
||||
}).Error; err != nil {
|
||||
global.LOG.Errorf("start my cronjob failed, err: %v", err)
|
||||
}
|
||||
for _, cronjob := range cronJobs {
|
||||
entryID, err := service.ServiceGroupApp.StartJob(&cronjob)
|
||||
for i := 0; i < len(cronJobs); i++ {
|
||||
entryID, err := service.ServiceGroupApp.StartJob(&cronJobs[i])
|
||||
if err != nil {
|
||||
global.LOG.Errorf("start %s job %s failed, err: %v", cronjob.Type, cronjob.Name, err)
|
||||
global.LOG.Errorf("start %s job %s failed, err: %v", &cronJobs[i].Type, &cronJobs[i].Name, err)
|
||||
}
|
||||
if err := repo.NewICronjobRepo().Update(cronjob.ID, map[string]interface{}{"entry_id": entryID}); err != nil {
|
||||
global.LOG.Errorf("update cronjob %s %s failed, err: %v", cronjob.Type, cronjob.Name, err)
|
||||
if err := repo.NewICronjobRepo().Update(cronJobs[i].ID, map[string]interface{}{"entry_id": entryID}); err != nil {
|
||||
global.LOG.Errorf("update cronjob %s %s failed, err: %v", cronJobs[i].Type, cronJobs[i].Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +118,9 @@ func loadNetIO() {
|
||||
netStatAll2, _ := net.IOCounters(false)
|
||||
for _, net2 := range netStatAll2 {
|
||||
for _, net1 := range netStatAll {
|
||||
if net1.BytesSent == 0 || net1.BytesRecv == 0 {
|
||||
continue
|
||||
}
|
||||
if net2.Name == net1.Name {
|
||||
var itemNet model.MonitorNetwork
|
||||
itemNet.Name = net1.Name
|
||||
|
||||
@@ -3,6 +3,7 @@ package job
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"time"
|
||||
)
|
||||
@@ -19,18 +20,18 @@ func (ssl *ssl) Run() {
|
||||
sslService := service.NewIWebsiteSSLService()
|
||||
sslList, _ := sslRepo.List()
|
||||
global.LOG.Info("ssl renew cron job start...")
|
||||
now := time.Now()
|
||||
now := time.Now().Add(10 * time.Second)
|
||||
for _, s := range sslList {
|
||||
if !s.AutoRenew || s.Provider == "manual" || s.Provider == "dnsManual" {
|
||||
continue
|
||||
}
|
||||
sum := s.ExpireDate.Sub(now)
|
||||
if sum.Hours() < 168 {
|
||||
expireDate, _ := time.ParseInLocation(constant.DateTimeLayout, s.ExpireDate.String(), time.Now().Location())
|
||||
sum := expireDate.Sub(now)
|
||||
if sum.Hours() < 720 {
|
||||
if err := sslService.Renew(s.ID); err != nil {
|
||||
global.LOG.Errorf("renew doamin [%s] ssl failed err:%s", s.PrimaryDomain, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global.LOG.Info("ssl renew cron job end...")
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func NewWebsiteJob() *website {
|
||||
func (w *website) Run() {
|
||||
websites, _ := repo.NewIWebsiteRepo().List()
|
||||
global.LOG.Info("website cron job start...")
|
||||
now := time.Now()
|
||||
now := time.Now().Add(10 * time.Second)
|
||||
if len(websites) > 0 {
|
||||
neverExpireDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
||||
var wg sync.WaitGroup
|
||||
@@ -28,7 +28,8 @@ func (w *website) Run() {
|
||||
if site.Status != constant.WebRunning || neverExpireDate.Equal(site.ExpireDate) {
|
||||
continue
|
||||
}
|
||||
if site.ExpireDate.Before(now) {
|
||||
expireDate, _ := time.ParseInLocation(constant.DateTimeLayout, site.ExpireDate.String(), time.Now().Location())
|
||||
if expireDate.Before(now) {
|
||||
wg.Add(1)
|
||||
go func(ws model.Website) {
|
||||
stopWebsite(ws.ID, &wg)
|
||||
|
||||
@@ -11,35 +11,35 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func GetMsgWithMap(msg string, maps map[string]interface{}) string {
|
||||
func GetMsgWithMap(key string, maps map[string]interface{}) string {
|
||||
content := ""
|
||||
if maps == nil {
|
||||
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: msg,
|
||||
MessageID: key,
|
||||
})
|
||||
} else {
|
||||
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: msg,
|
||||
MessageID: key,
|
||||
TemplateData: maps,
|
||||
})
|
||||
}
|
||||
content = strings.ReplaceAll(content, ": <no value>", "")
|
||||
if content == "" {
|
||||
return msg
|
||||
return key
|
||||
} else {
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
||||
func GetErrMsg(msg string, maps map[string]interface{}) string {
|
||||
func GetErrMsg(key string, maps map[string]interface{}) string {
|
||||
content := ""
|
||||
if maps == nil {
|
||||
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: msg,
|
||||
MessageID: key,
|
||||
})
|
||||
} else {
|
||||
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
|
||||
MessageID: msg,
|
||||
MessageID: key,
|
||||
TemplateData: maps,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ ErrPortInOtherApp: "{{ .port }} port already in use by {{ .apps }}"
|
||||
ErrDbUserNotValid: "Stock database, username and password do not match!"
|
||||
ErrDockerComposeNotValid: "docker-compose file format error!"
|
||||
ErrUpdateBuWebsite: 'The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!'
|
||||
Err1PanelNetworkFailed: 'Default container network creation failed! {{ .detail }}'
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "File can not read"
|
||||
@@ -34,6 +35,7 @@ ErrPathNotFound: "Path is not found"
|
||||
ErrMovePathFailed: "The target path cannot contain the original path!"
|
||||
ErrLinkPathNotFound: "Target path does not exist!"
|
||||
ErrFileIsExit: "File already exists!"
|
||||
ErrFileUpload: "Failed to upload file"
|
||||
|
||||
#website
|
||||
ErrDomainIsExist: "Domain is already exist"
|
||||
@@ -52,4 +54,8 @@ ErrUserIsExist: "The current user already exists. Please enter a new user"
|
||||
ErrDatabaseIsExist: "The current database already exists. Please enter a new database"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again"
|
||||
ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again"
|
||||
|
||||
#container
|
||||
ErrInUsed: "{{ .detail }} is in use and cannot be deleted"
|
||||
ErrObjectInUsed: "This object is in use and cannot be deleted"
|
||||
@@ -26,6 +26,7 @@ ErrPortInOtherApp: "{{ .port }} 端口已被 {{ .apps }}占用!"
|
||||
ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
|
||||
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
|
||||
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
|
||||
Err1PanelNetworkFailed: '默认容器网络创建失败!{{ .detail }}'
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持预览"
|
||||
@@ -34,6 +35,7 @@ ErrPathNotFound: "目录不存在"
|
||||
ErrMovePathFailed: "目标路径不能包含原路径!"
|
||||
ErrLinkPathNotFound: "目标路径不存在!"
|
||||
ErrFileIsExit: "文件已存在!"
|
||||
ErrFileUpload: "上传文件失败"
|
||||
|
||||
#website
|
||||
ErrDomainIsExist: "域名已存在"
|
||||
@@ -52,4 +54,8 @@ ErrUserIsExist: "当前用户已存在,请重新输入"
|
||||
ErrDatabaseIsExist: "当前数据库已存在,请重新输入"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
|
||||
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
|
||||
|
||||
#container
|
||||
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
|
||||
ErrObjectInUsed: "该对象正被使用,无法删除"
|
||||
@@ -1,12 +1,11 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
@@ -23,7 +22,7 @@ func Init() {
|
||||
createDir(fileOp, dir)
|
||||
}
|
||||
|
||||
createDefaultDockerNetwork()
|
||||
_ = docker.CreateDefaultDockerNetwork()
|
||||
}
|
||||
|
||||
func createDir(fileOp files.FileOp, dirPath string) {
|
||||
@@ -31,17 +30,3 @@ func createDir(fileOp files.FileOp, dirPath string) {
|
||||
_ = fileOp.CreateDir(dirPath, 0755)
|
||||
}
|
||||
}
|
||||
|
||||
func createDefaultDockerNetwork() {
|
||||
cli, err := docker.NewClient()
|
||||
if err != nil {
|
||||
fmt.Println("init docker client error", err.Error())
|
||||
return
|
||||
}
|
||||
if !cli.NetworkExist("1panel-network") {
|
||||
if err := cli.CreateNetwork("1panel-network"); err != nil {
|
||||
fmt.Println("init docker client error", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,35 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
syncApp()
|
||||
syncInstalledApp()
|
||||
}
|
||||
|
||||
func syncApp() {
|
||||
setting, err := service.NewISettingService().GetSettingInfo()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("sync app error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
if setting.AppStoreVersion != "" {
|
||||
fmt.Println(setting.AppStoreVersion)
|
||||
global.LOG.Info("do not sync")
|
||||
global.LOG.Info("no need to sync")
|
||||
return
|
||||
}
|
||||
global.LOG.Info("sync app start...")
|
||||
if err := service.NewIAppService().SyncAppList(); err != nil {
|
||||
global.LOG.Errorf("sync app error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
global.LOG.Info("sync app successful")
|
||||
}
|
||||
|
||||
func syncInstalledApp() {
|
||||
if err := service.NewIAppInstalledService().SyncAll(true); err != nil {
|
||||
global.LOG.Errorf("sync instaled app error: %s", err.Error())
|
||||
}
|
||||
global.LOG.Info("sync app success")
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"os"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
)
|
||||
@@ -28,6 +30,15 @@ func Init() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = db.Exec("PRAGMA journal_mode = WAL;")
|
||||
sqlDB, dbError := db.DB()
|
||||
if dbError != nil {
|
||||
panic(err)
|
||||
}
|
||||
sqlDB.SetConnMaxIdleTime(10)
|
||||
sqlDB.SetMaxOpenConns(100)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||
|
||||
global.DB = db
|
||||
global.LOG.Info("init db successfully")
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ func Init() {
|
||||
migrations.AddTableWebsite,
|
||||
migrations.AddTableDatabaseMysql,
|
||||
migrations.AddTableSnap,
|
||||
migrations.AddDefaultGroup,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -140,7 +140,6 @@ var AddTableSetting = &gormigrate.Migration{
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "SystemStatus", Value: "Free"}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "AppStoreVersion", Value: ""}).Error; err != nil {
|
||||
@@ -211,14 +210,7 @@ var AddTableDatabaseMysql = &gormigrate.Migration{
|
||||
var AddTableWebsite = &gormigrate.Migration{
|
||||
ID: "20201009-add-table-website",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.Website{}, &model.WebsiteDomain{}, &model.WebsiteGroup{}, &model.WebsiteDnsAccount{}, &model.WebsiteSSL{}, &model.WebsiteAcmeAccount{}); err != nil {
|
||||
return err
|
||||
}
|
||||
item := &model.WebsiteGroup{
|
||||
Name: "默认",
|
||||
Default: true,
|
||||
}
|
||||
if err := tx.Create(item).Error; err != nil {
|
||||
if err := tx.AutoMigrate(&model.Website{}, &model.WebsiteDomain{}, &model.WebsiteDnsAccount{}, &model.WebsiteSSL{}, &model.WebsiteAcmeAccount{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -234,3 +226,24 @@ var AddTableSnap = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddDefaultGroup = &gormigrate.Migration{
|
||||
ID: "2023022-change-default-group",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
defaultGroup := &model.Group{
|
||||
Name: "默认",
|
||||
IsDefault: true,
|
||||
Type: "website",
|
||||
}
|
||||
if err := tx.Create(defaultGroup).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Model(&model.Group{}).Where("name = ? AND type = ?", "default", "host").Update("name", "默认").Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Model(&model.Website{}).Where("1 = 1").Update("website_group_id", defaultGroup.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Migrator().DropTable("website_groups")
|
||||
},
|
||||
}
|
||||
|
||||
@@ -63,6 +63,10 @@ func Routers() *gin.Engine {
|
||||
|
||||
systemRouter := rou.RouterGroupApp
|
||||
|
||||
swaggerRouter := Router.Group("1panel")
|
||||
docs.SwaggerInfo.BasePath = "/api/v1"
|
||||
swaggerRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
|
||||
|
||||
PublicGroup := Router.Group("")
|
||||
{
|
||||
PublicGroup.GET("/health", func(c *gin.Context) {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@@ -14,6 +11,9 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
type Writer struct {
|
||||
@@ -261,7 +261,6 @@ func (w *Writer) CompressFile(logFile string) error {
|
||||
comFileName := path.Base(logFile) + ".gz"
|
||||
filePath := path.Dir(logFile)
|
||||
|
||||
fmt.Println(path.Dir(logFile))
|
||||
if err := op.Compress([]string{logFile}, filePath, comFileName, files.Gz); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
jwtUtils "github.com/1Panel-dev/1Panel/backend/utils/jwt"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func JwtAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Set("authMethod", "")
|
||||
token := c.Request.Header.Get(constant.JWTHeaderName)
|
||||
if token == "" {
|
||||
c.Next()
|
||||
@@ -28,15 +21,6 @@ func JwtAuth() gin.HandlerFunc {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrUnauthorized, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
if claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("SessionTimeout"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("create operation record failed, err: %v", err)
|
||||
}
|
||||
lifeTime, _ := strconv.Atoi(setting.Value)
|
||||
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Second * time.Duration(lifeTime)))
|
||||
}
|
||||
c.Set("claims", claims)
|
||||
c.Set("authMethod", constant.AuthMethodJWT)
|
||||
c.Next()
|
||||
|
||||
@@ -96,7 +96,6 @@ func OperationLog() gin.HandlerFunc {
|
||||
var names []string
|
||||
if funcs.IsList {
|
||||
sql := fmt.Sprintf("SELECT %s FROM %s where %s in (?);", funcs.OutputColume, funcs.DB, funcs.InputColume)
|
||||
fmt.Println(value)
|
||||
_ = global.DB.Raw(sql, value).Scan(&names)
|
||||
} else {
|
||||
_ = global.DB.Raw(fmt.Sprintf("select %s from %s where %s = ?;", funcs.OutputColume, funcs.DB, funcs.InputColume), value).Scan(&names)
|
||||
|
||||
@@ -14,6 +14,7 @@ func SessionAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if method, exist := c.Get("authMethod"); exist && method == constant.AuthMethodJWT {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
sId, err := c.Cookie(constant.SessionName)
|
||||
if err != nil {
|
||||
|
||||
@@ -33,6 +33,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
|
||||
|
||||
baRouter.POST("/compose/search", baseApi.SearchCompose)
|
||||
baRouter.POST("/compose", baseApi.CreateCompose)
|
||||
baRouter.POST("/compose/test", baseApi.TestCompose)
|
||||
baRouter.POST("/compose/operate", baseApi.OperatorCompose)
|
||||
baRouter.POST("/compose/update", baseApi.ComposeUpdate)
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
||||
fileRouter.POST("/wget", baseApi.WgetFile)
|
||||
fileRouter.POST("/move", baseApi.MoveFile)
|
||||
fileRouter.POST("/download", baseApi.Download)
|
||||
fileRouter.POST("/download/bypath", baseApi.DownloadFile)
|
||||
fileRouter.POST("/size", baseApi.Size)
|
||||
fileRouter.GET("/ws", baseApi.Ws)
|
||||
fileRouter.GET("/keys", baseApi.Keys)
|
||||
|
||||
@@ -10,14 +10,14 @@ type WebsiteGroupRouter struct {
|
||||
}
|
||||
|
||||
func (a *WebsiteGroupRouter) InitWebsiteGroupRouter(Router *gin.RouterGroup) {
|
||||
groupRouter := Router.Group("websites/groups")
|
||||
groupRouter := Router.Group("groups")
|
||||
groupRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.PasswordExpired())
|
||||
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
groupRouter.GET("", baseApi.GetWebGroups)
|
||||
groupRouter.POST("", baseApi.CreateWebGroup)
|
||||
groupRouter.POST("/update", baseApi.UpdateWebGroup)
|
||||
groupRouter.POST("/del", baseApi.DeleteWebGroup)
|
||||
groupRouter.POST("", baseApi.CreateGroup)
|
||||
groupRouter.POST("/del", baseApi.DeleteGroup)
|
||||
groupRouter.POST("/update", baseApi.UpdateGroup)
|
||||
groupRouter.POST("/search", baseApi.ListGroup)
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,6 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
|
||||
hostRouter.POST("/test/byid/:id", baseApi.TestByID)
|
||||
hostRouter.GET(":id", baseApi.GetHostInfo)
|
||||
|
||||
hostRouter.POST("/group", baseApi.CreateGroup)
|
||||
hostRouter.POST("/group/del", baseApi.DeleteGroup)
|
||||
hostRouter.POST("/group/update", baseApi.UpdateGroup)
|
||||
hostRouter.POST("/group/search", baseApi.ListGroup)
|
||||
|
||||
hostRouter.GET("/command", baseApi.ListCommand)
|
||||
hostRouter.POST("/command", baseApi.CreateCommand)
|
||||
hostRouter.POST("/command/del", baseApi.DeleteCommand)
|
||||
|
||||
@@ -51,6 +51,7 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
|
||||
settingRouter.POST("/backup/record/del", baseApi.DeleteBackupRecord)
|
||||
|
||||
settingRouter.POST("/upgrade", baseApi.Upgrade)
|
||||
settingRouter.POST("/upgrade/notes", baseApi.GetNotesByVersion)
|
||||
settingRouter.GET("/upgrade", baseApi.GetUpgradeInfo)
|
||||
settingRouter.GET("/basedir", baseApi.LoadBaseDir)
|
||||
}
|
||||
|
||||
@@ -22,5 +22,6 @@ func (a *WebsiteSSLRouter) InitWebsiteSSLRouter(Router *gin.RouterGroup) {
|
||||
groupRouter.POST("/del", baseApi.DeleteWebsiteSSL)
|
||||
groupRouter.GET("/website/:websiteId", baseApi.GetWebsiteSSLByWebsiteId)
|
||||
groupRouter.GET("/:id", baseApi.GetWebsiteSSLById)
|
||||
groupRouter.POST("/update", baseApi.UpdateWebsiteSSL)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func (oss ossClient) Upload(src, target string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = bucket.PutObjectFromFile(target, src)
|
||||
err = bucket.UploadFile(target, src, 200*1024*1024, osssdk.Routines(5), osssdk.Checkpoint(true, ""))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (oss ossClient) Download(src, target string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = bucket.GetObjectToFile(src, target)
|
||||
err = bucket.DownloadFile(src, target, 200*1024*1024, osssdk.Routines(5), osssdk.Checkpoint(true, ""))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
@@ -73,3 +74,18 @@ func (c Client) NetworkExist(name string) bool {
|
||||
}
|
||||
return len(networks) > 0
|
||||
}
|
||||
|
||||
func CreateDefaultDockerNetwork() error {
|
||||
cli, err := NewClient()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("init docker client error %s", err.Error())
|
||||
return err
|
||||
}
|
||||
if !cli.NetworkExist("1panel-network") {
|
||||
if err := cli.CreateNetwork("1panel-network"); err != nil {
|
||||
global.LOG.Errorf("create default docker network error %s", err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -106,6 +106,10 @@ func (f FileOp) Chmod(dst string, mode fs.FileMode) error {
|
||||
return f.Fs.Chmod(dst, mode)
|
||||
}
|
||||
|
||||
func (f FileOp) Chown(dst string, uid int, gid int) error {
|
||||
return f.Fs.Chown(dst, uid, gid)
|
||||
}
|
||||
|
||||
func (f FileOp) Rename(oldName string, newName string) error {
|
||||
return f.Fs.Rename(oldName, newName)
|
||||
}
|
||||
|
||||
@@ -38,12 +38,12 @@ func NewJWT() *JWT {
|
||||
}
|
||||
}
|
||||
|
||||
func (j *JWT) CreateClaims(baseClaims BaseClaims, ttl int) CustomClaims {
|
||||
func (j *JWT) CreateClaims(baseClaims BaseClaims) CustomClaims {
|
||||
claims := CustomClaims{
|
||||
BaseClaims: baseClaims,
|
||||
BufferTime: constant.JWTBufferTime,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Second * time.Duration(ttl))),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Second * time.Duration(constant.JWTBufferTime))),
|
||||
Issuer: constant.JWTIssuer,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSSH(t *testing.T) {
|
||||
ss := ConnInfo{
|
||||
Addr: "172.16.10.111",
|
||||
Port: 22,
|
||||
User: "root",
|
||||
AuthMode: "password",
|
||||
Password: "Calong@2015",
|
||||
}
|
||||
_, err := ss.NewClient()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(ss.Run("ip a"))
|
||||
}
|
||||
@@ -89,6 +89,7 @@ func NewPrivateKeyClient(email string, privateKey string) (*AcmeClient, error) {
|
||||
func newConfig(user *AcmeUser) *lego.Config {
|
||||
config := lego.NewConfig(user)
|
||||
config.CADirURL = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
//config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
config.UserAgent = "acm_go/0.0.1"
|
||||
config.Certificate.KeyType = certcrypto.RSA2048
|
||||
return config
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme/api"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
@@ -154,10 +155,10 @@ func TestSSL(t *testing.T) {
|
||||
// panic(err)
|
||||
//}
|
||||
|
||||
// err = client.Challenge.SetDNS01Provider(&plainDnsProvider{}, dns01.AddDNSTimeout(6*time.Minute))
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
err = client.Challenge.SetDNS01Provider(&manualDnsProvider{}, dns01.AddDNSTimeout(6*time.Minute))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
core, err := api.New(config.HTTPClient, config.UserAgent, config.CADirURL, reg.URI, priKey)
|
||||
if err != nil {
|
||||
|
||||
@@ -115,22 +115,12 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string) error {
|
||||
return c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute))
|
||||
}
|
||||
|
||||
func (c *AcmeClient) UseManualDns(domains []string) (*Resolve, error) {
|
||||
func (c *AcmeClient) UseManualDns() error {
|
||||
p := &manualDnsProvider{}
|
||||
if err := c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute)); err != nil {
|
||||
return nil, nil
|
||||
return err
|
||||
}
|
||||
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: domains,
|
||||
Bundle: true,
|
||||
}
|
||||
|
||||
_, err := c.Client.Certificate.Obtain(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.Resolve, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *AcmeClient) UseHTTP(path string) error {
|
||||
|
||||
@@ -62,6 +62,25 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/checkupdate": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取应用更新版本",
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Get app list update",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/detail/:appId/:version": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -470,6 +489,48 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/params/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改应用参数",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Change app params",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.AppInstalledUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"installId"
|
||||
],
|
||||
"formatEN": "Application param update [installId]",
|
||||
"formatZH": "应用参数修改 [installId]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/port/change": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -683,6 +744,20 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/demo": {
|
||||
"get": {
|
||||
"description": "判断是否为demo环境",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Check System isDemo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/init": {
|
||||
"post": {
|
||||
"description": "初始化用户",
|
||||
@@ -970,6 +1045,48 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/containers/compose/test": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "测试 compose 是否可用",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Container Compose"
|
||||
],
|
||||
"summary": "Test compose",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ComposeCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "check compose [name]",
|
||||
"formatZH": "检测 compose [name] 格式",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/containers/compose/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -3899,6 +4016,34 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/chunkupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "分片上传文件",
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "ChunkUpload file",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "file",
|
||||
"description": "request",
|
||||
"name": "file",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/compress": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -4112,6 +4257,48 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/download/bypath": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "下载指定文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Download file with path",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilePath"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path"
|
||||
],
|
||||
"formatEN": "Download file [path]",
|
||||
"formatZH": "下载文件 [path]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/loadfile": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -6706,17 +6893,28 @@ var doc = `{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "系统更新信息",
|
||||
"description": "获取版本 release notes",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load upgrade info",
|
||||
"summary": "Load release notes by version",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.Upgrade"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpgradeInfo"
|
||||
}
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -7616,161 +7814,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/groups": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取网站组",
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "List website groups",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "创建网站组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "Create website group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteGroupCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "Create website groups [name]",
|
||||
"formatZH": "创建网站组 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/groups/del": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "删除网站组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "Delete website group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteResourceReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "website_groups",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Delete website group [name]",
|
||||
"formatZH": "删除网站组 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/groups/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新网站组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "Update website group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteGroupUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "Update website groups [name]",
|
||||
"formatZH": "更新网站组 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -8256,6 +8299,57 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/ssl/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新 ssl",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website SSL"
|
||||
],
|
||||
"summary": "Update ssl",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteSSLUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "website_ssls",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update ssl config [domain]",
|
||||
"formatZH": "更新证书设置 [domain]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/ssl/website/:websiteId": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -8623,8 +8717,7 @@ var doc = `{
|
||||
"dto.ComposeCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"from",
|
||||
"name"
|
||||
"from"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
@@ -8860,9 +8953,7 @@ var doc = `{
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8871,17 +8962,13 @@ var doc = `{
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -8942,9 +9029,7 @@ var doc = `{
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8953,9 +9038,7 @@ var doc = `{
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -8964,9 +9047,7 @@ var doc = `{
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -9060,15 +9141,9 @@ var doc = `{
|
||||
},
|
||||
"dto.DaemonJsonUpdateByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9096,33 +9171,15 @@ var doc = `{
|
||||
"databaseNumber": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dateeaseID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"haloID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
"jumpserverID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"kernelArch": {
|
||||
"type": "string"
|
||||
},
|
||||
"kernelVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"kubeoperatorID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"kubepiID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"metersphereID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"os": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -9164,20 +9221,11 @@ var doc = `{
|
||||
"cpuUsedPercent": {
|
||||
"type": "number"
|
||||
},
|
||||
"free": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesFree": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesTotal": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsed": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsedPercent": {
|
||||
"type": "number"
|
||||
"diskData": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.DiskInfo"
|
||||
}
|
||||
},
|
||||
"ioCount": {
|
||||
"type": "integer"
|
||||
@@ -9185,12 +9233,15 @@ var doc = `{
|
||||
"ioReadBytes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ioTime": {
|
||||
"ioReadTime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ioWriteBytes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ioWriteTime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"load1": {
|
||||
"type": "number"
|
||||
},
|
||||
@@ -9227,11 +9278,40 @@ var doc = `{
|
||||
"timeSinceUptime": {
|
||||
"type": "string"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.DiskInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device": {
|
||||
"type": "string"
|
||||
},
|
||||
"free": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesFree": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesTotal": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsed": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsedPercent": {
|
||||
"type": "number"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"used": {
|
||||
"type": "integer"
|
||||
@@ -9254,6 +9334,12 @@ var doc = `{
|
||||
"restart",
|
||||
"stop"
|
||||
]
|
||||
},
|
||||
"stopService": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"stopSocket": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9347,6 +9433,9 @@ var doc = `{
|
||||
},
|
||||
"dto.GroupUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -9356,6 +9445,9 @@ var doc = `{
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9677,9 +9769,6 @@ var doc = `{
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10511,6 +10600,9 @@ var doc = `{
|
||||
"dto.UpgradeInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"latestVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"newVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -10522,9 +10614,6 @@ var doc = `{
|
||||
"dto.UserLoginInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mfaSecret": {
|
||||
"type": "string"
|
||||
},
|
||||
"mfaStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11042,6 +11131,22 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppInstalledUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"installId",
|
||||
"params"
|
||||
],
|
||||
"properties": {
|
||||
"installId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11614,34 +11719,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteGroupCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteGroupUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"default": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteHTTPSOp": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11819,6 +11896,21 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteSSLUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"autoRenew",
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"autoRenew": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12042,10 +12134,29 @@ var doc = `{
|
||||
"response.AppParam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"edit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {}
|
||||
"labelEn": {
|
||||
"type": "string"
|
||||
},
|
||||
"labelZh": {
|
||||
"type": "string"
|
||||
},
|
||||
"rule": {
|
||||
"type": "string"
|
||||
},
|
||||
"showValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {},
|
||||
"values": {}
|
||||
}
|
||||
},
|
||||
"response.FileInfo": {
|
||||
@@ -12185,6 +12296,9 @@ var doc = `{
|
||||
"appInstallId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"appName": {
|
||||
"type": "string"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -48,6 +48,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/checkupdate": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取应用更新版本",
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Get app list update",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/detail/:appId/:version": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -456,6 +475,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/params/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改应用参数",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Change app params",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.AppInstalledUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"installId"
|
||||
],
|
||||
"formatEN": "Application param update [installId]",
|
||||
"formatZH": "应用参数修改 [installId]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/port/change": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -669,6 +730,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/demo": {
|
||||
"get": {
|
||||
"description": "判断是否为demo环境",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Check System isDemo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/init": {
|
||||
"post": {
|
||||
"description": "初始化用户",
|
||||
@@ -956,6 +1031,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/containers/compose/test": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "测试 compose 是否可用",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Container Compose"
|
||||
],
|
||||
"summary": "Test compose",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ComposeCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "check compose [name]",
|
||||
"formatZH": "检测 compose [name] 格式",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/containers/compose/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -3885,6 +4002,34 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/chunkupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "分片上传文件",
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "ChunkUpload file",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "file",
|
||||
"description": "request",
|
||||
"name": "file",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/compress": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -4098,6 +4243,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/download/bypath": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "下载指定文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Download file with path",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilePath"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path"
|
||||
],
|
||||
"formatEN": "Download file [path]",
|
||||
"formatZH": "下载文件 [path]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/loadfile": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -6692,17 +6879,28 @@
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "系统更新信息",
|
||||
"description": "获取版本 release notes",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load upgrade info",
|
||||
"summary": "Load release notes by version",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.Upgrade"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpgradeInfo"
|
||||
}
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -7602,161 +7800,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/groups": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取网站组",
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "List website groups",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "创建网站组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "Create website group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteGroupCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "Create website groups [name]",
|
||||
"formatZH": "创建网站组 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/groups/del": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "删除网站组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "Delete website group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteResourceReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "website_groups",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Delete website group [name]",
|
||||
"formatZH": "删除网站组 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/groups/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新网站组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website Group"
|
||||
],
|
||||
"summary": "Update website group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteGroupUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name"
|
||||
],
|
||||
"formatEN": "Update website groups [name]",
|
||||
"formatZH": "更新网站组 [name]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -8242,6 +8285,57 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/ssl/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新 ssl",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website SSL"
|
||||
],
|
||||
"summary": "Update ssl",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteSSLUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "website_ssls",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Update ssl config [domain]",
|
||||
"formatZH": "更新证书设置 [domain]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/ssl/website/:websiteId": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -8609,8 +8703,7 @@
|
||||
"dto.ComposeCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"from",
|
||||
"name"
|
||||
"from"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
@@ -8846,9 +8939,7 @@
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8857,17 +8948,13 @@
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -8928,9 +9015,7 @@
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8939,9 +9024,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -8950,9 +9033,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -9046,15 +9127,9 @@
|
||||
},
|
||||
"dto.DaemonJsonUpdateByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9082,33 +9157,15 @@
|
||||
"databaseNumber": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dateeaseID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"haloID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
"jumpserverID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"kernelArch": {
|
||||
"type": "string"
|
||||
},
|
||||
"kernelVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"kubeoperatorID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"kubepiID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"metersphereID": {
|
||||
"type": "integer"
|
||||
},
|
||||
"os": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -9150,20 +9207,11 @@
|
||||
"cpuUsedPercent": {
|
||||
"type": "number"
|
||||
},
|
||||
"free": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesFree": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesTotal": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsed": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsedPercent": {
|
||||
"type": "number"
|
||||
"diskData": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.DiskInfo"
|
||||
}
|
||||
},
|
||||
"ioCount": {
|
||||
"type": "integer"
|
||||
@@ -9171,12 +9219,15 @@
|
||||
"ioReadBytes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ioTime": {
|
||||
"ioReadTime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ioWriteBytes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ioWriteTime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"load1": {
|
||||
"type": "number"
|
||||
},
|
||||
@@ -9213,11 +9264,40 @@
|
||||
"timeSinceUptime": {
|
||||
"type": "string"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.DiskInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device": {
|
||||
"type": "string"
|
||||
},
|
||||
"free": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesFree": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesTotal": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsed": {
|
||||
"type": "integer"
|
||||
},
|
||||
"inodesUsedPercent": {
|
||||
"type": "number"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"used": {
|
||||
"type": "integer"
|
||||
@@ -9240,6 +9320,12 @@
|
||||
"restart",
|
||||
"stop"
|
||||
]
|
||||
},
|
||||
"stopService": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"stopSocket": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9333,6 +9419,9 @@
|
||||
},
|
||||
"dto.GroupUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -9342,6 +9431,9 @@
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9663,9 +9755,6 @@
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10497,6 +10586,9 @@
|
||||
"dto.UpgradeInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"latestVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"newVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -10508,9 +10600,6 @@
|
||||
"dto.UserLoginInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mfaSecret": {
|
||||
"type": "string"
|
||||
},
|
||||
"mfaStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -11028,6 +11117,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppInstalledUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"installId",
|
||||
"params"
|
||||
],
|
||||
"properties": {
|
||||
"installId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11600,34 +11705,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteGroupCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteGroupUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"default": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteHTTPSOp": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11805,6 +11882,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteSSLUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"autoRenew",
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"autoRenew": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12028,10 +12120,29 @@
|
||||
"response.AppParam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"edit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {}
|
||||
"labelEn": {
|
||||
"type": "string"
|
||||
},
|
||||
"labelZh": {
|
||||
"type": "string"
|
||||
},
|
||||
"rule": {
|
||||
"type": "string"
|
||||
},
|
||||
"showValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {},
|
||||
"values": {}
|
||||
}
|
||||
},
|
||||
"response.FileInfo": {
|
||||
@@ -12171,6 +12282,9 @@
|
||||
"appInstallId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"appName": {
|
||||
"type": "string"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -152,7 +152,6 @@ definitions:
|
||||
type: integer
|
||||
required:
|
||||
- from
|
||||
- name
|
||||
type: object
|
||||
dto.ComposeOperation:
|
||||
properties:
|
||||
@@ -294,22 +293,16 @@ definitions:
|
||||
dto.CronjobCreate:
|
||||
properties:
|
||||
day:
|
||||
maximum: 31
|
||||
minimum: 1
|
||||
type: integer
|
||||
dbName:
|
||||
type: string
|
||||
exclusionRules:
|
||||
type: string
|
||||
hour:
|
||||
maximum: 23
|
||||
minimum: 0
|
||||
type: integer
|
||||
keepLocal:
|
||||
type: boolean
|
||||
minute:
|
||||
maximum: 59
|
||||
minimum: 0
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
@@ -352,24 +345,18 @@ definitions:
|
||||
dto.CronjobUpdate:
|
||||
properties:
|
||||
day:
|
||||
maximum: 31
|
||||
minimum: 1
|
||||
type: integer
|
||||
dbName:
|
||||
type: string
|
||||
exclusionRules:
|
||||
type: string
|
||||
hour:
|
||||
maximum: 23
|
||||
minimum: 0
|
||||
type: integer
|
||||
id:
|
||||
type: integer
|
||||
keepLocal:
|
||||
type: boolean
|
||||
minute:
|
||||
maximum: 59
|
||||
minimum: 0
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
@@ -439,10 +426,6 @@ definitions:
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
type: object
|
||||
dto.DashboardBase:
|
||||
properties:
|
||||
@@ -460,24 +443,12 @@ definitions:
|
||||
$ref: '#/definitions/dto.DashboardCurrent'
|
||||
databaseNumber:
|
||||
type: integer
|
||||
dateeaseID:
|
||||
type: integer
|
||||
haloID:
|
||||
type: integer
|
||||
hostname:
|
||||
type: string
|
||||
jumpserverID:
|
||||
type: integer
|
||||
kernelArch:
|
||||
type: string
|
||||
kernelVersion:
|
||||
type: string
|
||||
kubeoperatorID:
|
||||
type: integer
|
||||
kubepiID:
|
||||
type: integer
|
||||
metersphereID:
|
||||
type: integer
|
||||
os:
|
||||
type: string
|
||||
platform:
|
||||
@@ -505,24 +476,20 @@ definitions:
|
||||
type: number
|
||||
cpuUsedPercent:
|
||||
type: number
|
||||
free:
|
||||
type: integer
|
||||
inodesFree:
|
||||
type: integer
|
||||
inodesTotal:
|
||||
type: integer
|
||||
inodesUsed:
|
||||
type: integer
|
||||
inodesUsedPercent:
|
||||
type: number
|
||||
diskData:
|
||||
items:
|
||||
$ref: '#/definitions/dto.DiskInfo'
|
||||
type: array
|
||||
ioCount:
|
||||
type: integer
|
||||
ioReadBytes:
|
||||
type: integer
|
||||
ioTime:
|
||||
ioReadTime:
|
||||
type: integer
|
||||
ioWriteBytes:
|
||||
type: integer
|
||||
ioWriteTime:
|
||||
type: integer
|
||||
load1:
|
||||
type: number
|
||||
load5:
|
||||
@@ -547,10 +514,29 @@ definitions:
|
||||
type: string
|
||||
timeSinceUptime:
|
||||
type: string
|
||||
total:
|
||||
type: integer
|
||||
uptime:
|
||||
type: integer
|
||||
type: object
|
||||
dto.DiskInfo:
|
||||
properties:
|
||||
device:
|
||||
type: string
|
||||
free:
|
||||
type: integer
|
||||
inodesFree:
|
||||
type: integer
|
||||
inodesTotal:
|
||||
type: integer
|
||||
inodesUsed:
|
||||
type: integer
|
||||
inodesUsedPercent:
|
||||
type: number
|
||||
path:
|
||||
type: string
|
||||
total:
|
||||
type: integer
|
||||
type:
|
||||
type: string
|
||||
used:
|
||||
type: integer
|
||||
usedPercent:
|
||||
@@ -564,6 +550,10 @@ definitions:
|
||||
- restart
|
||||
- stop
|
||||
type: string
|
||||
stopService:
|
||||
type: boolean
|
||||
stopSocket:
|
||||
type: boolean
|
||||
required:
|
||||
- operation
|
||||
type: object
|
||||
@@ -635,6 +625,10 @@ definitions:
|
||||
type: boolean
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
dto.HostConnTest:
|
||||
properties:
|
||||
@@ -850,8 +844,6 @@ definitions:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
secret:
|
||||
type: string
|
||||
type: object
|
||||
dto.MfaCredential:
|
||||
properties:
|
||||
@@ -1402,6 +1394,8 @@ definitions:
|
||||
type: object
|
||||
dto.UpgradeInfo:
|
||||
properties:
|
||||
latestVersion:
|
||||
type: string
|
||||
newVersion:
|
||||
type: string
|
||||
releaseNote:
|
||||
@@ -1409,8 +1403,6 @@ definitions:
|
||||
type: object
|
||||
dto.UserLoginInfo:
|
||||
properties:
|
||||
mfaSecret:
|
||||
type: string
|
||||
mfaStatus:
|
||||
type: string
|
||||
name:
|
||||
@@ -1752,6 +1744,17 @@ definitions:
|
||||
- page
|
||||
- pageSize
|
||||
type: object
|
||||
request.AppInstalledUpdate:
|
||||
properties:
|
||||
installId:
|
||||
type: integer
|
||||
params:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
required:
|
||||
- installId
|
||||
- params
|
||||
type: object
|
||||
request.AppSearch:
|
||||
properties:
|
||||
name:
|
||||
@@ -2135,24 +2138,6 @@ definitions:
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
request.WebsiteGroupCreate:
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
request.WebsiteGroupUpdate:
|
||||
properties:
|
||||
default:
|
||||
type: boolean
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
request.WebsiteHTTPSOp:
|
||||
properties:
|
||||
HttpConfig:
|
||||
@@ -2272,6 +2257,16 @@ definitions:
|
||||
- page
|
||||
- pageSize
|
||||
type: object
|
||||
request.WebsiteSSLUpdate:
|
||||
properties:
|
||||
autoRenew:
|
||||
type: boolean
|
||||
id:
|
||||
type: integer
|
||||
required:
|
||||
- autoRenew
|
||||
- id
|
||||
type: object
|
||||
request.WebsiteSearch:
|
||||
properties:
|
||||
name:
|
||||
@@ -2421,9 +2416,22 @@ definitions:
|
||||
type: object
|
||||
response.AppParam:
|
||||
properties:
|
||||
label:
|
||||
edit:
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
labelEn:
|
||||
type: string
|
||||
labelZh:
|
||||
type: string
|
||||
rule:
|
||||
type: string
|
||||
showValue:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
value: {}
|
||||
values: {}
|
||||
type: object
|
||||
response.FileInfo:
|
||||
properties:
|
||||
@@ -2515,6 +2523,8 @@ definitions:
|
||||
type: string
|
||||
appInstallId:
|
||||
type: integer
|
||||
appName:
|
||||
type: string
|
||||
createdAt:
|
||||
type: string
|
||||
defaultServer:
|
||||
@@ -2628,6 +2638,17 @@ paths:
|
||||
summary: Search app by key
|
||||
tags:
|
||||
- App
|
||||
/apps/checkupdate:
|
||||
get:
|
||||
description: 获取应用更新版本
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get app list update
|
||||
tags:
|
||||
- App
|
||||
/apps/detail/:appId/:version:
|
||||
get:
|
||||
consumes:
|
||||
@@ -2887,6 +2908,33 @@ paths:
|
||||
summary: Search params by appInstallId
|
||||
tags:
|
||||
- App
|
||||
/apps/installed/params/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改应用参数
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.AppInstalledUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Change app params
|
||||
tags:
|
||||
- App
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- installId
|
||||
formatEN: Application param update [installId]
|
||||
formatZH: 应用参数修改 [installId]
|
||||
paramKeys: []
|
||||
/apps/installed/port/change:
|
||||
post:
|
||||
consumes:
|
||||
@@ -3022,6 +3070,15 @@ paths:
|
||||
summary: Load captcha
|
||||
tags:
|
||||
- Auth
|
||||
/auth/demo:
|
||||
get:
|
||||
description: 判断是否为demo环境
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
summary: Check System isDemo
|
||||
tags:
|
||||
- Auth
|
||||
/auth/init:
|
||||
post:
|
||||
consumes:
|
||||
@@ -3205,6 +3262,33 @@ paths:
|
||||
summary: Page composes
|
||||
tags:
|
||||
- Container Compose
|
||||
/containers/compose/test:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 测试 compose 是否可用
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.ComposeCreate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Test compose
|
||||
tags:
|
||||
- Container Compose
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- name
|
||||
formatEN: check compose [name]
|
||||
formatZH: 检测 compose [name] 格式
|
||||
paramKeys: []
|
||||
/containers/compose/update:
|
||||
post:
|
||||
consumes:
|
||||
@@ -5065,6 +5149,23 @@ paths:
|
||||
formatEN: Check whether file [path] exists
|
||||
formatZH: 检测文件 [path] 是否存在
|
||||
paramKeys: []
|
||||
/files/chunkupload:
|
||||
post:
|
||||
description: 分片上传文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: formData
|
||||
name: file
|
||||
required: true
|
||||
type: file
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: ChunkUpload file
|
||||
tags:
|
||||
- File
|
||||
/files/compress:
|
||||
post:
|
||||
consumes:
|
||||
@@ -5202,6 +5303,33 @@ paths:
|
||||
formatEN: Download file [name]
|
||||
formatZH: 下载文件 [name]
|
||||
paramKeys: []
|
||||
/files/download/bypath:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 下载指定文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.FilePath'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Download file with path
|
||||
tags:
|
||||
- File
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- path
|
||||
formatEN: Download file [path]
|
||||
formatZH: 下载文件 [path]
|
||||
paramKeys: []
|
||||
/files/loadfile:
|
||||
post:
|
||||
consumes:
|
||||
@@ -6853,15 +6981,22 @@ paths:
|
||||
paramKeys: []
|
||||
/settings/upgrade:
|
||||
get:
|
||||
description: 系统更新信息
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取版本 release notes
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.Upgrade'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UpgradeInfo'
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load upgrade info
|
||||
summary: Load release notes by version
|
||||
tags:
|
||||
- System Setting
|
||||
post:
|
||||
@@ -7434,105 +7569,6 @@ paths:
|
||||
formatEN: Delete domain [domain]
|
||||
formatZH: 删除域名 [domain]
|
||||
paramKeys: []
|
||||
/websites/groups:
|
||||
get:
|
||||
description: 获取网站组
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: anrry
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: List website groups
|
||||
tags:
|
||||
- Website Group
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建网站组
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteGroupCreate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Create website group
|
||||
tags:
|
||||
- Website Group
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- name
|
||||
formatEN: Create website groups [name]
|
||||
formatZH: 创建网站组 [name]
|
||||
paramKeys: []
|
||||
/websites/groups/del:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除网站组
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteResourceReq'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Delete website group
|
||||
tags:
|
||||
- Website Group
|
||||
x-panel-log:
|
||||
BeforeFuntions:
|
||||
- db: website_groups
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_colume: name
|
||||
output_value: name
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: Delete website group [name]
|
||||
formatZH: 删除网站组 [name]
|
||||
paramKeys: []
|
||||
/websites/groups/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新网站组
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteGroupUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update website group
|
||||
tags:
|
||||
- Website Group
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- name
|
||||
formatEN: Update website groups [name]
|
||||
formatZH: 更新网站组 [name]
|
||||
paramKeys: []
|
||||
/websites/list:
|
||||
get:
|
||||
description: 获取网站列表
|
||||
@@ -7840,6 +7876,39 @@ paths:
|
||||
summary: Page website ssl
|
||||
tags:
|
||||
- Website SSL
|
||||
/websites/ssl/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新 ssl
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteSSLUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update ssl
|
||||
tags:
|
||||
- Website SSL
|
||||
x-panel-log:
|
||||
BeforeFuntions:
|
||||
- db: website_ssls
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_colume: primary_domain
|
||||
output_value: domain
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: Update ssl config [domain]
|
||||
formatZH: 更新证书设置 [domain]
|
||||
paramKeys: []
|
||||
/websites/ssl/website/:websiteId:
|
||||
get:
|
||||
consumes:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user