mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-23 18:49:21 +08:00
Merge branch 'dev'
This commit is contained in:
commit
ce3d4b16d7
17
.github/workflows/create-pr-from-push.yml
vendored
17
.github/workflows/create-pr-from-push.yml
vendored
@ -1,17 +0,0 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'pr@**'
|
|
||||||
- 'repr@**'
|
|
||||||
|
|
||||||
name: 针对特定分支名自动创建 PR
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
generic_handler:
|
|
||||||
name: 自动创建 PR
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Create pull request
|
|
||||||
uses: jumpserver/action-generic-handler@master
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUBTOKEN }}
|
|
16
.github/workflows/issue-close.yml
vendored
16
.github/workflows/issue-close.yml
vendored
@ -1,16 +0,0 @@
|
|||||||
name: Issue Close Check
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [closed]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
issue-close-remove-labels:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Remove labels
|
|
||||||
uses: actions-cool/issues-helper@v2
|
|
||||||
if: ${{ !github.event.issue.pull_request }}
|
|
||||||
with:
|
|
||||||
actions: 'remove-labels'
|
|
||||||
labels: '状态:待处理'
|
|
38
.github/workflows/issue-comment.yml
vendored
38
.github/workflows/issue-comment.yml
vendored
@ -1,38 +0,0 @@
|
|||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
name: Add issues workflow labels
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
add-label-if-is-author:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ (github.event.issue.user.id == github.event.comment.user.id) && (!github.event.issue.pull_request) }}
|
|
||||||
steps:
|
|
||||||
- name: Add require handle label
|
|
||||||
uses: actions-cool/issues-helper@v2
|
|
||||||
with:
|
|
||||||
actions: 'add-labels'
|
|
||||||
labels: '状态:待处理'
|
|
||||||
|
|
||||||
- name: Remove require reply label
|
|
||||||
uses: actions-cool/issues-helper@v2
|
|
||||||
with:
|
|
||||||
actions: 'remove-labels'
|
|
||||||
labels: '状态:待用户反馈'
|
|
||||||
|
|
||||||
add-label-if-not-author:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ (github.event.issue.user.id != github.event.comment.user.id) && (!github.event.issue.pull_request) && (github.event.issue.state == 'open') }}
|
|
||||||
steps:
|
|
||||||
- name: Add require replay label
|
|
||||||
uses: actions-cool/issues-helper@v2
|
|
||||||
with:
|
|
||||||
actions: 'add-labels'
|
|
||||||
labels: '状态:待用户反馈'
|
|
||||||
|
|
||||||
- name: Remove require handle label
|
|
||||||
uses: actions-cool/issues-helper@v2
|
|
||||||
with:
|
|
||||||
actions: 'remove-labels'
|
|
||||||
labels: '状态:待处理'
|
|
16
.github/workflows/issue-open.yml
vendored
16
.github/workflows/issue-open.yml
vendored
@ -1,16 +0,0 @@
|
|||||||
name: Issue Open Check
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
issue-open-add-labels:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Add labels
|
|
||||||
uses: actions-cool/issues-helper@v2
|
|
||||||
if: ${{ !github.event.issue.pull_request }}
|
|
||||||
with:
|
|
||||||
actions: 'add-labels'
|
|
||||||
labels: '状态:待处理'
|
|
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
|
14
Makefile
14
Makefile
@ -11,15 +11,19 @@ SERVER_PATH=$(BASE_PAH)/backend
|
|||||||
MAIN= $(BASE_PAH)/cmd/server/main.go
|
MAIN= $(BASE_PAH)/cmd/server/main.go
|
||||||
APP_NAME=1panel
|
APP_NAME=1panel
|
||||||
|
|
||||||
build_web:
|
build_frontend:
|
||||||
cd $(WEB_PATH) && npm install && npm run build:dev
|
cd $(WEB_PATH) && npm install && npm run build:dev
|
||||||
|
|
||||||
build_bin:
|
build_backend_on_linux:
|
||||||
cd $(SERVER_PATH) \
|
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:
|
build_backend_on_darwin:
|
||||||
cd $(SERVER_PATH) \
|
cd $(SERVER_PATH) \
|
||||||
&& CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
&& CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||||
|
|
||||||
build_all: build_web build_bin
|
build_backend_on_archlinux:
|
||||||
|
cd $(SERVER_PATH) \
|
||||||
|
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-fpic"' -tags osusergo -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||||
|
|
||||||
|
build_all: build_frontend build_backend_on_linux
|
||||||
|
@ -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"><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"><b>现代化、开源的 Linux 服务器运维管理面板</b></p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@ -18,7 +19,7 @@
|
|||||||
|
|
||||||
## UI 展示
|
## UI 展示
|
||||||
|
|
||||||
![UI展示](https://1panel.oss-cn-hangzhou.aliyuncs.com/img/overview.png)
|
![UI展示](https://resource.fit2cloud.com/1panel/img/overview.png)
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
@ -47,13 +48,13 @@ 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
|
- 电话:400-052-0755
|
||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
@ -62,7 +63,7 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
|||||||
|
|
||||||
## License
|
## 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
|
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
|
||||||
|
|
||||||
|
![UI Display](https://resource.fit2cloud.com/1panel/img/overview_en.png)
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](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!
|
@ -38,8 +38,9 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
|
|||||||
// @Router /apps/sync [post]
|
// @Router /apps/sync [post]
|
||||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
|
||||||
func (b *BaseApi) SyncApp(c *gin.Context) {
|
func (b *BaseApi) SyncApp(c *gin.Context) {
|
||||||
|
appService.SyncAppListFromLocal()
|
||||||
global.LOG.Infof("sync app list start ...")
|
global.LOG.Infof("sync app list start ...")
|
||||||
if err := appService.SyncAppList(); err != nil {
|
if err := appService.SyncAppListFromRemote(); err != nil {
|
||||||
global.LOG.Errorf("sync app list error [%s]", err.Error())
|
global.LOG.Errorf("sync app list error [%s]", err.Error())
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@ -71,14 +72,15 @@ func (b *BaseApi) GetApp(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary Search app detail by id
|
// @Summary Search app detail by appid
|
||||||
// @Description 通过 id 获取应用详情
|
// @Description 通过 appid 获取应用详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param appId path integer true "app id"
|
// @Param appId path integer true "app id"
|
||||||
// @Param version path string true "app 版本"
|
// @Param version path string true "app 版本"
|
||||||
|
// @Param version path string true "app 类型"
|
||||||
// @Success 200 {object} response.AppDetailDTO
|
// @Success 200 {object} response.AppDetailDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /apps/detail/:appId/:version [get]
|
// @Router /apps/detail/:appId/:version/:type [get]
|
||||||
func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
||||||
appId, err := helper.GetIntParamByKey(c, "appId")
|
appId, err := helper.GetIntParamByKey(c, "appId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -86,7 +88,30 @@ func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
version := c.Param("version")
|
version := c.Param("version")
|
||||||
appDetailDTO, err := appService.GetAppDetail(appId, version)
|
appType := c.Param("type")
|
||||||
|
appDetailDTO, err := appService.GetAppDetail(appId, version, appType)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, appDetailDTO)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags App
|
||||||
|
// @Summary Get app detail by id
|
||||||
|
// @Description 通过 id 获取应用详情
|
||||||
|
// @Accept json
|
||||||
|
// @Param appId path integer true "id"
|
||||||
|
// @Success 200 {object} response.AppDetailDTO
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /apps/details/:id [get]
|
||||||
|
func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
|
||||||
|
appDetailID, err := helper.GetIntParamByKey(c, "id")
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appDetailDTO, err := appService.GetAppDetailByID(appDetailID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
|
@ -93,24 +93,24 @@ func (b *BaseApi) LoadPort(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary Search app password by key
|
// @Summary Search app password by key
|
||||||
// @Description 获取应用密码
|
// @Description 获取应用连接信息
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param key path string true "request"
|
// @Param key path string true "request"
|
||||||
// @Success 200 {string} password
|
// @Success 200 {string} response.DatabaseConn
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /apps/installed/loadpassword/:key [get]
|
// @Router /apps/installed/conninfo/:key [get]
|
||||||
func (b *BaseApi) LoadPassword(c *gin.Context) {
|
func (b *BaseApi) LoadConnInfo(c *gin.Context) {
|
||||||
key, ok := c.Params.Get("key")
|
key, ok := c.Params.Get("key")
|
||||||
if !ok {
|
if !ok {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
password, err := appInstallService.LoadPassword(key)
|
conn, err := appInstallService.LoadConnInfo(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, password)
|
helper.SuccessWithData(c, conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags App
|
// @Tags App
|
||||||
@ -144,7 +144,7 @@ func (b *BaseApi) DeleteCheck(c *gin.Context) {
|
|||||||
// @Router /apps/installed/sync [post]
|
// @Router /apps/installed/sync [post]
|
||||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"同步已安装应用列表","formatEN":"Sync the list of installed apps"}
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"同步已安装应用列表","formatEN":"Sync the list of installed apps"}
|
||||||
func (b *BaseApi) SyncInstalled(c *gin.Context) {
|
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)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,11 @@ func (b *BaseApi) Login(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
if req.AuthMethod != "jwt" {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
||||||
return
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := authService.Login(c, req)
|
user, err := authService.Login(c, req)
|
||||||
|
@ -104,9 +104,9 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /settings/backup/del [post]
|
// @Router /settings/backup/del [post]
|
||||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"backup_accounts","output_colume":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":true,"db":"backup_accounts","output_colume":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
|
||||||
func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
||||||
var req dto.BatchDeleteReq
|
var req dto.OperateByID
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
@ -116,7 +116,7 @@ func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := backupService.BatchDelete(req.Ids); err != nil {
|
if err := backupService.Delete(req.ID); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ func (b *BaseApi) DownloadRecord(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.File(filePath)
|
helper.SuccessWithData(c, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Backup Account
|
// @Tags Backup Account
|
||||||
|
@ -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
|
// @Tags Container Compose
|
||||||
// @Summary Create compose
|
// @Summary Create compose
|
||||||
// @Description 创建容器编排
|
// @Description 创建容器编排
|
||||||
@ -90,11 +118,12 @@ func (b *BaseApi) CreateCompose(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := containerService.CreateCompose(req); err != nil {
|
log, err := containerService.CreateCompose(req)
|
||||||
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container Compose
|
// @Tags Container Compose
|
||||||
|
@ -92,17 +92,41 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Cronjob
|
||||||
|
// @Summary Clean job records
|
||||||
|
// @Description 清空计划任务记录
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.CronjobClean true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /cronjobs/records/clean [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"清空计划任务记录 [name]","formatEN":"clean cronjob [name] records"}
|
||||||
|
func (b *BaseApi) CleanRecord(c *gin.Context) {
|
||||||
|
var req dto.CronjobClean
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cronjobService.CleanRecord(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Cronjob
|
// @Tags Cronjob
|
||||||
// @Summary Delete cronjob
|
// @Summary Delete cronjob
|
||||||
// @Description 删除计划任务
|
// @Description 删除计划任务
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.BatchDeleteReq true "request"
|
// @Param request body dto.CronjobBatchDelete true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /cronjobs/del [post]
|
// @Router /cronjobs/del [post]
|
||||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"cronjobs","output_colume":"name","output_value":"names"}],"formatZH":"删除计划任务 [names]","formatEN":"delete cronjob [names]"}
|
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"cronjobs","output_colume":"name","output_value":"names"}],"formatZH":"删除计划任务 [names]","formatEN":"delete cronjob [names]"}
|
||||||
func (b *BaseApi) DeleteCronjob(c *gin.Context) {
|
func (b *BaseApi) DeleteCronjob(c *gin.Context) {
|
||||||
var req dto.BatchDeleteReq
|
var req dto.CronjobBatchDelete
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
@ -112,7 +136,7 @@ func (b *BaseApi) DeleteCronjob(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cronjobService.Delete(req.Ids); err != nil {
|
if err := cronjobService.Delete(req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -198,7 +222,7 @@ func (b *BaseApi) TargetDownload(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.File(filePath)
|
helper.SuccessWithData(c, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Cronjob
|
// @Tags Cronjob
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
@ -35,7 +34,7 @@ func (b *BaseApi) LoadDaemonJsonFile(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, "daemon.json is not find in path")
|
helper.SuccessWithData(c, "daemon.json is not find in path")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
content, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
|
@ -9,41 +9,43 @@ type ApiGroup struct {
|
|||||||
var ApiGroupApp = new(ApiGroup)
|
var ApiGroupApp = new(ApiGroup)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
authService = service.ServiceGroupApp.AuthService
|
authService = service.NewIAuthService()
|
||||||
dashboardService = service.ServiceGroupApp.DashboardService
|
dashboardService = service.NewIDashboardService()
|
||||||
|
|
||||||
appService = service.NewIAppService()
|
appService = service.NewIAppService()
|
||||||
appInstallService = service.ServiceGroupApp.AppInstallService
|
appInstallService = service.NewIAppInstalledService()
|
||||||
|
|
||||||
containerService = service.ServiceGroupApp.ContainerService
|
containerService = service.NewIContainerService()
|
||||||
composeTemplateService = service.ServiceGroupApp.ComposeTemplateService
|
composeTemplateService = service.NewIComposeTemplateService()
|
||||||
imageRepoService = service.ServiceGroupApp.ImageRepoService
|
imageRepoService = service.NewIImageRepoService()
|
||||||
imageService = service.ServiceGroupApp.ImageService
|
imageService = service.NewIImageService()
|
||||||
dockerService = service.ServiceGroupApp.DockerService
|
dockerService = service.NewIDockerService()
|
||||||
|
|
||||||
mysqlService = service.ServiceGroupApp.MysqlService
|
mysqlService = service.NewIMysqlService()
|
||||||
redisService = service.ServiceGroupApp.RedisService
|
redisService = service.NewIRedisService()
|
||||||
|
|
||||||
cronjobService = service.ServiceGroupApp.CronjobService
|
cronjobService = service.NewICronjobService()
|
||||||
|
|
||||||
hostService = service.ServiceGroupApp.HostService
|
hostService = service.NewIHostService()
|
||||||
groupService = service.ServiceGroupApp.GroupService
|
groupService = service.NewIGroupService()
|
||||||
fileService = service.ServiceGroupApp.FileService
|
fileService = service.NewIFileService()
|
||||||
|
firewallService = service.NewIFirewallService()
|
||||||
|
|
||||||
settingService = service.ServiceGroupApp.SettingService
|
settingService = service.NewISettingService()
|
||||||
backupService = service.ServiceGroupApp.BackupService
|
backupService = service.NewIBackupService()
|
||||||
|
|
||||||
commandService = service.ServiceGroupApp.CommandService
|
commandService = service.NewICommandService()
|
||||||
|
|
||||||
websiteGroupService = service.ServiceGroupApp.WebsiteGroupService
|
websiteService = service.NewIWebsiteService()
|
||||||
websiteService = service.ServiceGroupApp.WebsiteService
|
websiteDnsAccountService = service.NewIWebsiteDnsAccountService()
|
||||||
websiteDnsAccountService = service.ServiceGroupApp.WebsiteDnsAccountService
|
websiteSSLService = service.NewIWebsiteSSLService()
|
||||||
websiteSSLService = service.ServiceGroupApp.WebsiteSSLService
|
websiteAcmeAccountService = service.NewIWebsiteAcmeAccountService()
|
||||||
websiteAcmeAccountService = service.ServiceGroupApp.WebsiteAcmeAccountService
|
|
||||||
|
|
||||||
nginxService = service.ServiceGroupApp.NginxService
|
nginxService = service.NewINginxService()
|
||||||
|
|
||||||
logService = service.ServiceGroupApp.LogService
|
logService = service.NewILogService()
|
||||||
snapshotService = service.ServiceGroupApp.SnapshotService
|
snapshotService = service.NewISnapshotService()
|
||||||
upgradeService = service.ServiceGroupApp.UpgradeService
|
upgradeService = service.NewIUpgradeService()
|
||||||
|
|
||||||
|
runtimeService = service.NewRuntimeService()
|
||||||
)
|
)
|
||||||
|
@ -3,7 +3,7 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -445,6 +445,28 @@ func (b *BaseApi) Download(c *gin.Context) {
|
|||||||
c.File(filePath)
|
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
|
// @Tags File
|
||||||
// @Summary Load file size
|
// @Summary Load file size
|
||||||
// @Description 获取文件夹大小
|
// @Description 获取文件夹大小
|
||||||
@ -488,7 +510,7 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := ioutil.ReadFile(req.Path)
|
content, err := os.ReadFile(req.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@ -497,6 +519,12 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
|
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))
|
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -505,7 +533,7 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
|
|||||||
|
|
||||||
for i := 0; i < chunkCount; i++ {
|
for i := 0; i < chunkCount; i++ {
|
||||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
||||||
chunkData, err := ioutil.ReadFile(chunkPath)
|
chunkData, err := os.ReadFile(chunkPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -525,7 +553,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /files/chunkupload [post]
|
// @Router /files/chunkupload [post]
|
||||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
|
|
||||||
func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||||
fileForm, err := c.FormFile("chunk")
|
fileForm, err := c.FormFile("chunk")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -551,13 +578,16 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
if err := fileOp.CreateDir("uploads", 0755); err != nil {
|
tmpDir := path.Join(global.CONF.System.TmpDir, "upload")
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
if !fileOp.Stat(tmpDir) {
|
||||||
return
|
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")
|
filename := c.PostForm("filename")
|
||||||
fileDir := filepath.Join(global.CONF.System.DataDir, "upload", filename)
|
fileDir := filepath.Join(tmpDir, filename)
|
||||||
|
|
||||||
_ = os.MkdirAll(fileDir, 0755)
|
_ = os.MkdirAll(fileDir, 0755)
|
||||||
filePath := filepath.Join(fileDir, filename)
|
filePath := filepath.Join(fileDir, filename)
|
||||||
@ -567,25 +597,25 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
emptyFile.Close()
|
defer emptyFile.Close()
|
||||||
|
|
||||||
chunkData, err := ioutil.ReadAll(uploadFile)
|
chunkData, err := io.ReadAll(uploadFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrFileUpload, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
|
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
|
||||||
err = ioutil.WriteFile(chunkPath, chunkData, 0644)
|
err = os.WriteFile(chunkPath, chunkData, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if chunkIndex+1 == chunkCount {
|
if chunkIndex+1 == chunkCount {
|
||||||
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount)
|
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrAppDelete, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, true)
|
helper.SuccessWithData(c, true)
|
||||||
|
207
backend/app/api/v1/firewall.go
Normal file
207
backend/app/api/v1/firewall.go
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Load firewall base info
|
||||||
|
// @Description 获取防火墙基础信息
|
||||||
|
// @Success 200 {object} dto.FirewallBaseInfo
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/base [get]
|
||||||
|
func (b *BaseApi) LoadFirewallBaseInfo(c *gin.Context) {
|
||||||
|
data, err := firewallService.LoadBaseInfo()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Page firewall rules
|
||||||
|
// @Description 获取防火墙规则列表分页
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.SearchWithPage true "request"
|
||||||
|
// @Success 200 {object} dto.PageResult
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/search [post]
|
||||||
|
func (b *BaseApi) SearchFirewallRule(c *gin.Context) {
|
||||||
|
var req dto.RuleSearch
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
total, list, err := firewallService.SearchWithPage(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Items: list,
|
||||||
|
Total: total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Page firewall status
|
||||||
|
// @Description 修改防火墙状态
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.FirewallOperation true "request"
|
||||||
|
// @Success 200 {object} dto.PageResult
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/operate [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operation] 防火墙","formatEN":"[operation] firewall"}
|
||||||
|
func (b *BaseApi) OperateFirewall(c *gin.Context) {
|
||||||
|
var req dto.FirewallOperation
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := firewallService.OperateFirewall(req.Operation); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 创建防火墙端口规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.PortRuleOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/port [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["port","strategy"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加端口规则 [strategy] [port]","formatEN":"create port rules [strategy][port]"}
|
||||||
|
func (b *BaseApi) OperatePortRule(c *gin.Context) {
|
||||||
|
var req dto.PortRuleOperate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := firewallService.OperatePortRule(req, true); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 创建防火墙 IP 规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.AddrRuleOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/ip [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["strategy","address"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加 ip 规则 [strategy] [address]","formatEN":"create address rules [strategy][address]"}
|
||||||
|
func (b *BaseApi) OperateIPRule(c *gin.Context) {
|
||||||
|
var req dto.AddrRuleOperate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := firewallService.OperateAddressRule(req, true); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 批量删除防火墙规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.BatchRuleOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/ip [post]
|
||||||
|
func (b *BaseApi) BatchOperateRule(c *gin.Context) {
|
||||||
|
var req dto.BatchRuleOperate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := firewallService.BacthOperateRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 更新端口防火墙规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.PortRuleUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/update/port [post]
|
||||||
|
func (b *BaseApi) UpdatePortRule(c *gin.Context) {
|
||||||
|
var req dto.PortRuleUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := firewallService.UpdatePortRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 更新 ip 防火墙规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.AddrRuleUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/update/ip [post]
|
||||||
|
func (b *BaseApi) UpdateAddrRule(c *gin.Context) {
|
||||||
|
var req dto.AddrRuleUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := firewallService.UpdateAddrRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
@ -15,7 +15,7 @@ import (
|
|||||||
// @Param request body dto.GroupCreate true "request"
|
// @Param request body dto.GroupCreate true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group [post]
|
// @Router /groups [post]
|
||||||
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
|
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
|
||||||
func (b *BaseApi) CreateGroup(c *gin.Context) {
|
func (b *BaseApi) CreateGroup(c *gin.Context) {
|
||||||
var req dto.GroupCreate
|
var req dto.GroupCreate
|
||||||
@ -41,7 +41,7 @@ func (b *BaseApi) CreateGroup(c *gin.Context) {
|
|||||||
// @Param request body dto.OperateByID true "request"
|
// @Param request body dto.OperateByID true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group/del [post]
|
// @Router /groups/del [post]
|
||||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"groups","output_colume":"name","output_value":"name"},{"input_colume":"id","input_value":"id","isList":false,"db":"groups","output_colume":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"groups","output_colume":"name","output_value":"name"},{"input_colume":"id","input_value":"id","isList":false,"db":"groups","output_colume":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
|
||||||
func (b *BaseApi) DeleteGroup(c *gin.Context) {
|
func (b *BaseApi) DeleteGroup(c *gin.Context) {
|
||||||
var req dto.OperateByID
|
var req dto.OperateByID
|
||||||
@ -68,7 +68,7 @@ func (b *BaseApi) DeleteGroup(c *gin.Context) {
|
|||||||
// @Param request body dto.GroupUpdate true "request"
|
// @Param request body dto.GroupUpdate true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group/update [post]
|
// @Router /groups/update [post]
|
||||||
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
|
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
|
||||||
func (b *BaseApi) UpdateGroup(c *gin.Context) {
|
func (b *BaseApi) UpdateGroup(c *gin.Context) {
|
||||||
var req dto.GroupUpdate
|
var req dto.GroupUpdate
|
||||||
@ -94,7 +94,7 @@ func (b *BaseApi) UpdateGroup(c *gin.Context) {
|
|||||||
// @Param request body dto.GroupSearch true "request"
|
// @Param request body dto.GroupSearch true "request"
|
||||||
// @Success 200 {anrry} dto.GroupInfo
|
// @Success 200 {anrry} dto.GroupInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group/search [post]
|
// @Router /groups/search [post]
|
||||||
func (b *BaseApi) ListGroup(c *gin.Context) {
|
func (b *BaseApi) ListGroup(c *gin.Context) {
|
||||||
var req dto.GroupSearch
|
var req dto.GroupSearch
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
@ -83,6 +83,15 @@ func SuccessWithData(ctx *gin.Context, data interface{}) {
|
|||||||
ctx.Abort()
|
ctx.Abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SuccessWithOutData(ctx *gin.Context) {
|
||||||
|
res := dto.Response{
|
||||||
|
Code: constant.CodeSuccess,
|
||||||
|
Message: "success",
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
|
ctx.Abort()
|
||||||
|
}
|
||||||
|
|
||||||
func SuccessWithMsg(ctx *gin.Context, msg string) {
|
func SuccessWithMsg(ctx *gin.Context, msg string) {
|
||||||
res := dto.Response{
|
res := dto.Response{
|
||||||
Code: constant.CodeSuccess,
|
Code: constant.CodeSuccess,
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/ssh"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,33 +73,9 @@ func (b *BaseApi) TestByInfo(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
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
|
connStatus := hostService.TestByInfo(req)
|
||||||
_ = copier.Copy(&connInfo, &req)
|
helper.SuccessWithData(c, connStatus)
|
||||||
connInfo.PrivateKey = []byte(req.PrivateKey)
|
|
||||||
client, err := connInfo.NewClient()
|
|
||||||
if err != nil {
|
|
||||||
helper.SuccessWithData(c, false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
helper.SuccessWithData(c, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Host
|
// @Tags Host
|
||||||
@ -270,11 +245,13 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
|||||||
upMap["port"] = req.Port
|
upMap["port"] = req.Port
|
||||||
upMap["user"] = req.User
|
upMap["user"] = req.User
|
||||||
upMap["auth_mode"] = req.AuthMode
|
upMap["auth_mode"] = req.AuthMode
|
||||||
|
upMap["remember_password"] = req.RememberPassword
|
||||||
if len(req.Password) != 0 {
|
if len(req.Password) != 0 {
|
||||||
upMap["password"] = req.Password
|
upMap["password"] = req.Password
|
||||||
}
|
}
|
||||||
if len(req.PrivateKey) != 0 {
|
if len(req.PrivateKey) != 0 {
|
||||||
upMap["private_key"] = req.PrivateKey
|
upMap["private_key"] = req.PrivateKey
|
||||||
|
upMap["pass_phrase"] = req.PassPhrase
|
||||||
}
|
}
|
||||||
upMap["description"] = req.Description
|
upMap["description"] = req.Description
|
||||||
if err := hostService.Update(req.ID, upMap); err != nil {
|
if err := hostService.Update(req.ID, upMap); err != nil {
|
||||||
@ -291,7 +268,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
|||||||
// @Param request body dto.ChangeHostGroup true "request"
|
// @Param request body dto.ChangeHostGroup true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/update [post]
|
// @Router /hosts/update/group [post]
|
||||||
// @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"hosts","output_colume":"addr","output_value":"addr"}],"formatZH":"切换主机[addr]分组 => [group]","formatEN":"change host [addr] group => [group]"}
|
// @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"hosts","output_colume":"addr","output_value":"addr"}],"formatZH":"切换主机[addr]分组 => [group]","formatEN":"change host [addr] group => [group]"}
|
||||||
func (b *BaseApi) UpdateHostGroup(c *gin.Context) {
|
func (b *BaseApi) UpdateHostGroup(c *gin.Context) {
|
||||||
var req dto.ChangeHostGroup
|
var req dto.ChangeHostGroup
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"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 {
|
for _, net := range netStat {
|
||||||
options = append(options, net.Name)
|
options = append(options, net.Name)
|
||||||
}
|
}
|
||||||
|
sort.Strings(options)
|
||||||
helper.SuccessWithData(c, options)
|
helper.SuccessWithData(c, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,5 +100,6 @@ func (b *BaseApi) GetIOOptions(c *gin.Context) {
|
|||||||
for _, net := range diskStat {
|
for _, net := range diskStat {
|
||||||
options = append(options, net.Name)
|
options = append(options, net.Name)
|
||||||
}
|
}
|
||||||
|
sort.Strings(options)
|
||||||
helper.SuccessWithData(c, options)
|
helper.SuccessWithData(c, options)
|
||||||
}
|
}
|
||||||
|
123
backend/app/api/v1/runtime.go
Normal file
123
backend/app/api/v1/runtime.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary List runtimes
|
||||||
|
// @Description 获取运行环境列表
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeSearch true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/search [post]
|
||||||
|
func (b *BaseApi) SearchRuntimes(c *gin.Context) {
|
||||||
|
var req request.RuntimeSearch
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
total, items, err := runtimeService.Page(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Total: total,
|
||||||
|
Items: items,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary Create runtime
|
||||||
|
// @Description 创建运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeCreate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建运行环境 [name]","formatEN":"Create runtime [name]"}
|
||||||
|
func (b *BaseApi) CreateRuntime(c *gin.Context) {
|
||||||
|
var req request.RuntimeCreate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := runtimeService.Create(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Delete runtime
|
||||||
|
// @Description 删除运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeDelete true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/del [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除网站 [name]","formatEN":"Delete website [name]"}
|
||||||
|
func (b *BaseApi) DeleteRuntime(c *gin.Context) {
|
||||||
|
var req request.RuntimeDelete
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := runtimeService.Delete(req.ID)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary Update runtime
|
||||||
|
// @Description 更新运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新运行环境 [name]","formatEN":"Update runtime [name]"}
|
||||||
|
func (b *BaseApi) UpdateRuntime(c *gin.Context) {
|
||||||
|
var req request.RuntimeUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := runtimeService.Update(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary Get runtime
|
||||||
|
// @Description 获取运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param id path string true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/:id [get]
|
||||||
|
func (b *BaseApi) GetRuntime(c *gin.Context) {
|
||||||
|
id, err := helper.GetIntParamByKey(c, "id")
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := runtimeService.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -42,6 +44,9 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
|
|||||||
var connInfo ssh.ConnInfo
|
var connInfo ssh.ConnInfo
|
||||||
_ = copier.Copy(&connInfo, &host)
|
_ = copier.Copy(&connInfo, &host)
|
||||||
connInfo.PrivateKey = []byte(host.PrivateKey)
|
connInfo.PrivateKey = []byte(host.PrivateKey)
|
||||||
|
if len(host.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(host.PassPhrase)
|
||||||
|
}
|
||||||
|
|
||||||
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -196,7 +201,15 @@ func wshandleError(ws *websocket.Conn, err error) bool {
|
|||||||
global.LOG.Errorf("handler ws faled:, err: %v", err)
|
global.LOG.Errorf("handler ws faled:, err: %v", err)
|
||||||
dt := time.Now().Add(time.Second)
|
dt := time.Now().Add(time.Second)
|
||||||
if ctlerr := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); ctlerr != nil {
|
if ctlerr := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); ctlerr != nil {
|
||||||
_ = ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))
|
wsData, err := json.Marshal(terminal.WsMsg{
|
||||||
|
Type: terminal.WsMsgCmd,
|
||||||
|
Data: base64.StdEncoding.EncodeToString([]byte(err.Error())),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
_ = ws.WriteMessage(websocket.TextMessage, []byte("{\"type\":\"cmd\",\"data\":\"failed to encoding to json\"}"))
|
||||||
|
} else {
|
||||||
|
_ = ws.WriteMessage(websocket.TextMessage, wsData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,28 @@ func (b *BaseApi) GetUpgradeInfo(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, info)
|
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
|
// @Tags System Setting
|
||||||
// @Summary Upgrade
|
// @Summary Upgrade
|
||||||
// @Description 系统更新
|
// @Description 系统更新
|
||||||
|
@ -78,14 +78,12 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx, ctx := helper.GetTxAndContext()
|
|
||||||
err := websiteService.CreateWebsite(ctx, req)
|
err := websiteService.CreateWebsite(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx.Commit()
|
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,14 +125,12 @@ func (b *BaseApi) DeleteWebsite(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx, ctx := helper.GetTxAndContext()
|
|
||||||
err := websiteService.DeleteWebsite(ctx, req)
|
err := websiteService.DeleteWebsite(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx.Commit()
|
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,14 +185,16 @@ func (b *BaseApi) GetWebsite(c *gin.Context) {
|
|||||||
// @Param id path integer true "request"
|
// @Param id path integer true "request"
|
||||||
// @Success 200 {object} response.FileInfo
|
// @Success 200 {object} response.FileInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /websites/:id/nginx [get]
|
// @Router /websites/:id/config/:type [get]
|
||||||
func (b *BaseApi) GetWebsiteNginx(c *gin.Context) {
|
func (b *BaseApi) GetWebsiteNginx(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fileInfo, err := websiteService.GetWebsiteNginxConfig(id)
|
configType := c.Param("type")
|
||||||
|
|
||||||
|
fileInfo, err := websiteService.GetWebsiteNginxConfig(id, configType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@ -496,3 +494,157 @@ func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Load websit php conf
|
||||||
|
// @Description 获取网站 php 配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param id path integer true "request"
|
||||||
|
// @Success 200 {object} response.PHPConfig
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/php/config/:id [get]
|
||||||
|
func (b *BaseApi) GetWebsitePHPConfig(c *gin.Context) {
|
||||||
|
id, err := helper.GetParamID(c)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := websiteService.GetPHPConfig(id)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website PHP
|
||||||
|
// @Summary Update website php conf
|
||||||
|
// @Description 更新 网站 PHP 配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsitePHPConfigUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/php/config [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[domain] PHP 配置修改","formatEN":"[domain] PHP conf update"}
|
||||||
|
func (b *BaseApi) UpdateWebsitePHPConfig(c *gin.Context) {
|
||||||
|
var req request.WebsitePHPConfigUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdatePHPConfig(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website PHP
|
||||||
|
// @Summary Update php conf
|
||||||
|
// @Description 更新 php 配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsitePHPFileUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/php/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"php 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
|
||||||
|
func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
|
||||||
|
var req request.WebsitePHPFileUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdatePHPConfigFile(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Get rewrite conf
|
||||||
|
// @Description 获取伪静态配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxRewriteReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/rewrite [post]
|
||||||
|
func (b *BaseApi) GetRewriteConfig(c *gin.Context) {
|
||||||
|
var req request.NginxRewriteReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := websiteService.GetRewriteConfig(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update rewrite conf
|
||||||
|
// @Description 更新伪静态配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxRewriteUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/rewrite/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteID","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"伪静态配置修改 [domain]","formatEN":"Nginx conf rewrite update [domain]"}
|
||||||
|
func (b *BaseApi) UpdateRewriteConfig(c *gin.Context) {
|
||||||
|
var req request.NginxRewriteUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateRewriteConfig(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update Site Dir
|
||||||
|
// @Description 更新网站目录
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteUpdateDir true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/dir/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录","formatEN":"Update domain [domain] dir"}
|
||||||
|
func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
|
||||||
|
var req request.WebsiteUpdateDir
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateSiteDir(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update Site Dir permission
|
||||||
|
// @Description 更新网站目录权限
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteUpdateDirPermission true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/dir/permission [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录权限","formatEN":"Update domain [domain] dir permission"}
|
||||||
|
func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
|
||||||
|
var req request.WebsiteUpdateDirPermission
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateSitePermission(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
@ -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)
|
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,22 @@ type AppForm struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AppFormFields struct {
|
type AppFormFields struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
LabelZh string `json:"labelZh"`
|
LabelZh string `json:"labelZh"`
|
||||||
LabelEn string `json:"labelEn"`
|
LabelEn string `json:"labelEn"`
|
||||||
Required bool `json:"required"`
|
Required bool `json:"required"`
|
||||||
Default interface{} `json:"default"`
|
Default interface{} `json:"default"`
|
||||||
EnvKey string `json:"envKey"`
|
EnvKey string `json:"envKey"`
|
||||||
Disabled bool `json:"disabled"`
|
Disabled bool `json:"disabled"`
|
||||||
Edit bool `json:"edit"`
|
Edit bool `json:"edit"`
|
||||||
Rule string `json:"rule"`
|
Rule string `json:"rule"`
|
||||||
|
Multiple bool `json:"multiple"`
|
||||||
|
Values []AppFormValue `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppFormValue struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppResource struct {
|
type AppResource struct {
|
||||||
|
@ -9,7 +9,6 @@ type UserLoginInfo struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
MfaStatus string `json:"mfaStatus"`
|
MfaStatus string `json:"mfaStatus"`
|
||||||
MfaSecret string `json:"mfaSecret"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MfaCredential struct {
|
type MfaCredential struct {
|
||||||
@ -28,7 +27,6 @@ type Login struct {
|
|||||||
type MFALogin struct {
|
type MFALogin struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Secret string `json:"secret"`
|
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
AuthMethod string `json:"authMethod"`
|
AuthMethod string `json:"authMethod"`
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ type BackupRecords struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DownloadRecord struct {
|
type DownloadRecord struct {
|
||||||
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL"`
|
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO"`
|
||||||
FileDir string `json:"fileDir" validate:"required"`
|
FileDir string `json:"fileDir" validate:"required"`
|
||||||
FileName string `json:"fileName" validate:"required"`
|
FileName string `json:"fileName" validate:"required"`
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,16 @@ type CronjobDownload struct {
|
|||||||
BackupAccountID uint `json:"backupAccountID" validate:"required"`
|
BackupAccountID uint `json:"backupAccountID" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CronjobClean struct {
|
||||||
|
CleanData bool `json:"cleanData"`
|
||||||
|
CronjobID uint `json:"cronjobID" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CronjobBatchDelete struct {
|
||||||
|
CleanData bool `json:"cleanData"`
|
||||||
|
IDs []uint `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
type CronjobInfo struct {
|
type CronjobInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -3,13 +3,6 @@ package dto
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type DashboardBase struct {
|
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"`
|
WebsiteNumber int `json:"websiteNumber"`
|
||||||
DatabaseNumber int `json:"databaseNumber"`
|
DatabaseNumber int `json:"databaseNumber"`
|
||||||
CronjobNumber int `json:"cronjobNumber"`
|
CronjobNumber int `json:"cronjobNumber"`
|
||||||
@ -55,8 +48,21 @@ type DashboardCurrent struct {
|
|||||||
IOReadBytes uint64 `json:"ioReadBytes"`
|
IOReadBytes uint64 `json:"ioReadBytes"`
|
||||||
IOWriteBytes uint64 `json:"ioWriteBytes"`
|
IOWriteBytes uint64 `json:"ioWriteBytes"`
|
||||||
IOCount uint64 `json:"ioCount"`
|
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"`
|
Total uint64 `json:"total"`
|
||||||
Free uint64 `json:"free"`
|
Free uint64 `json:"free"`
|
||||||
Used uint64 `json:"used"`
|
Used uint64 `json:"used"`
|
||||||
@ -66,9 +72,4 @@ type DashboardCurrent struct {
|
|||||||
InodesUsed uint64 `json:"inodesUsed"`
|
InodesUsed uint64 `json:"inodesUsed"`
|
||||||
InodesFree uint64 `json:"inodesFree"`
|
InodesFree uint64 `json:"inodesFree"`
|
||||||
InodesUsedPercent float64 `json:"inodesUsedPercent"`
|
InodesUsedPercent float64 `json:"inodesUsedPercent"`
|
||||||
|
|
||||||
NetBytesSent uint64 `json:"netBytesSent"`
|
|
||||||
NetBytesRecv uint64 `json:"netBytesRecv"`
|
|
||||||
|
|
||||||
ShotTime time.Time `json:"shotTime"`
|
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,13 @@ type DaemonJsonUpdateByFile struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DaemonJsonConf struct {
|
type DaemonJsonConf struct {
|
||||||
|
IsSwarm bool `json:"isSwarm"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Mirrors []string `json:"registryMirrors"`
|
Mirrors []string `json:"registryMirrors"`
|
||||||
Registries []string `json:"insecureRegistries"`
|
Registries []string `json:"insecureRegistries"`
|
||||||
LiveRestore bool `json:"liveRestore"`
|
LiveRestore bool `json:"liveRestore"`
|
||||||
|
IPTables bool `json:"iptables"`
|
||||||
CgroupDriver string `json:"cgroupDriver"`
|
CgroupDriver string `json:"cgroupDriver"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
backend/app/dto/firewall.go
Normal file
47
backend/app/dto/firewall.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type FirewallBaseInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
PingStatus string `json:"pingStatus"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleSearch struct {
|
||||||
|
PageInfo
|
||||||
|
Info string `json:"info"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FirewallOperation struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=start stop disablePing enablePing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port string `json:"port" validate:"required"`
|
||||||
|
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddrRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address" validate:"required"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortRuleUpdate struct {
|
||||||
|
OldRule PortRuleOperate `json:"oldRule"`
|
||||||
|
NewRule PortRuleOperate `json:"newRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddrRuleUpdate struct {
|
||||||
|
OldRule AddrRuleOperate `json:"oldRule"`
|
||||||
|
NewRule AddrRuleOperate `json:"newRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchRuleOperate struct {
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
Rules []PortRuleOperate `json:"rules"`
|
||||||
|
}
|
@ -13,6 +13,7 @@ type GroupSearch struct {
|
|||||||
type GroupUpdate struct {
|
type GroupUpdate struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
IsDefault bool `json:"isDefault"`
|
IsDefault bool `json:"isDefault"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,15 +5,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HostOperate struct {
|
type HostOperate struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
GroupID uint `json:"groupID"`
|
GroupID uint `json:"groupID"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Addr string `json:"addr" validate:"required"`
|
Addr string `json:"addr" validate:"required"`
|
||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
User string `json:"user" validate:"required"`
|
User string `json:"user" validate:"required"`
|
||||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||||
PrivateKey string `json:"privateKey"`
|
Password string `json:"password"`
|
||||||
Password string `json:"password"`
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
@ -23,8 +25,9 @@ type HostConnTest struct {
|
|||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
User string `json:"user" validate:"required"`
|
User string `json:"user" validate:"required"`
|
||||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||||
PrivateKey string `json:"privateKey"`
|
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchHostWithPage struct {
|
type SearchHostWithPage struct {
|
||||||
@ -43,15 +46,19 @@ type ChangeHostGroup struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HostInfo struct {
|
type HostInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
GroupID uint `json:"groupID"`
|
GroupID uint `json:"groupID"`
|
||||||
GroupBelong string `json:"groupBelong"`
|
GroupBelong string `json:"groupBelong"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
Port uint `json:"port"`
|
Port uint `json:"port"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
AuthMode string `json:"authMode"`
|
AuthMode string `json:"authMode"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
@ -19,3 +19,14 @@ type NginxConfigUpdate struct {
|
|||||||
WebsiteID uint `json:"websiteId" validate:"required"`
|
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||||
Params interface{} `json:"params"`
|
Params interface{} `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NginxRewriteReq struct {
|
||||||
|
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NginxRewriteUpdate struct {
|
||||||
|
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required"`
|
||||||
|
}
|
||||||
|
32
backend/app/dto/request/runtime.go
Normal file
32
backend/app/dto/request/runtime.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
|
||||||
|
type RuntimeSearch struct {
|
||||||
|
dto.PageInfo
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeCreate struct {
|
||||||
|
AppDetailID uint `json:"appDetailId"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
Resource string `json:"resource"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeDelete struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeUpdate struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
@ -23,6 +23,14 @@ type WebsiteCreate struct {
|
|||||||
AppInstall NewAppInstall `json:"appInstall"`
|
AppInstall NewAppInstall `json:"appInstall"`
|
||||||
AppID uint `json:"appID"`
|
AppID uint `json:"appID"`
|
||||||
AppInstallID uint `json:"appInstallID"`
|
AppInstallID uint `json:"appInstallID"`
|
||||||
|
|
||||||
|
RuntimeID uint `json:"runtimeID"`
|
||||||
|
RuntimeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeConfig struct {
|
||||||
|
ProxyType string `json:"proxyType"`
|
||||||
|
Port int `json:"port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewAppInstall struct {
|
type NewAppInstall struct {
|
||||||
@ -126,3 +134,25 @@ type WebsiteLogReq struct {
|
|||||||
type WebsiteDefaultUpdate struct {
|
type WebsiteDefaultUpdate struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsitePHPConfigUpdate struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Params map[string]string `json:"params" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePHPFileUpdate struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteUpdateDir struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
SiteDir string `json:"siteDir" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteUpdateDirPermission struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
User string `json:"user" validate:"required"`
|
||||||
|
Group string `json:"group" validate:"required"`
|
||||||
|
}
|
||||||
|
@ -44,3 +44,8 @@ type WebsiteDnsAccountUpdate struct {
|
|||||||
type WebsiteResourceReq struct {
|
type WebsiteResourceReq struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsiteSSLUpdate struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
AutoRenew bool `json:"autoRenew" validate:"required"`
|
||||||
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package response
|
package response
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppRes struct {
|
type AppRes struct {
|
||||||
@ -43,6 +44,7 @@ type AppDetailDTO struct {
|
|||||||
model.AppDetail
|
model.AppDetail
|
||||||
Enable bool `json:"enable"`
|
Enable bool `json:"enable"`
|
||||||
Params interface{} `json:"params"`
|
Params interface{} `json:"params"`
|
||||||
|
Image string `json:"image"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppInstalledDTO struct {
|
type AppInstalledDTO struct {
|
||||||
@ -54,6 +56,12 @@ type AppInstalledDTO struct {
|
|||||||
CanUpdate bool `json:"canUpdate"`
|
CanUpdate bool `json:"canUpdate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DatabaseConn struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
Port int64 `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
type AppService struct {
|
type AppService struct {
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
@ -61,11 +69,15 @@ type AppService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AppParam struct {
|
type AppParam struct {
|
||||||
Value interface{} `json:"value"`
|
Value interface{} `json:"value"`
|
||||||
Edit bool `json:"edit"`
|
Edit bool `json:"edit"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Rule string `json:"rule"`
|
Rule string `json:"rule"`
|
||||||
LabelZh string `json:"labelZh"`
|
LabelZh string `json:"labelZh"`
|
||||||
LabelEn string `json:"labelEn"`
|
LabelEn string `json:"labelEn"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
Values interface{} `json:"values"`
|
||||||
|
ShowValue string `json:"showValue"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Multiple bool `json:"multiple"`
|
||||||
}
|
}
|
||||||
|
9
backend/app/dto/response/runtime.go
Normal file
9
backend/app/dto/response/runtime.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
|
||||||
|
type RuntimeRes struct {
|
||||||
|
model.Runtime
|
||||||
|
AppParams []AppParam `json:"appParams"`
|
||||||
|
AppID uint `json:"appId"`
|
||||||
|
}
|
@ -10,6 +10,7 @@ type WebsiteDTO struct {
|
|||||||
AccessLogPath string `json:"accessLogPath"`
|
AccessLogPath string `json:"accessLogPath"`
|
||||||
SitePath string `json:"sitePath"`
|
SitePath string `json:"sitePath"`
|
||||||
AppName string `json:"appName"`
|
AppName string `json:"appName"`
|
||||||
|
RuntimeName string `json:"runtimeName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebsitePreInstallCheck struct {
|
type WebsitePreInstallCheck struct {
|
||||||
@ -42,3 +43,11 @@ type WebsiteLog struct {
|
|||||||
Enable bool `json:"enable"`
|
Enable bool `json:"enable"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PHPConfig struct {
|
||||||
|
Params map[string]string `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NginxRewriteRes struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
@ -49,7 +49,7 @@ type PortUpdate struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SnapshotCreate struct {
|
type SnapshotCreate struct {
|
||||||
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO"`
|
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO COS KODO"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
type SnapshotRecover struct {
|
type SnapshotRecover struct {
|
||||||
@ -82,9 +82,11 @@ type SnapshotInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UpgradeInfo struct {
|
type UpgradeInfo struct {
|
||||||
NewVersion string `json:"newVersion"`
|
NewVersion string `json:"newVersion"`
|
||||||
ReleaseNote string `json:"releaseNote"`
|
LatestVersion string `json:"latestVersion"`
|
||||||
|
ReleaseNote string `json:"releaseNote"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Upgrade struct {
|
type Upgrade struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ type App struct {
|
|||||||
Github string `json:"github" gorm:"type:varchar(64);not null"`
|
Github string `json:"github" gorm:"type:varchar(64);not null"`
|
||||||
Document string `json:"document" gorm:"type:varchar(64);not null"`
|
Document string `json:"document" gorm:"type:varchar(64);not null"`
|
||||||
Recommend int `json:"recommend" gorm:"type:Integer;not null"`
|
Recommend int `json:"recommend" gorm:"type:Integer;not null"`
|
||||||
|
Resource string `json:"resource" gorm:"type:varchar;not null;default:remote"`
|
||||||
Details []AppDetail `json:"-" gorm:"-:migration"`
|
Details []AppDetail `json:"-" gorm:"-:migration"`
|
||||||
TagsKey []string `json:"-" gorm:"-"`
|
TagsKey []string `json:"-" gorm:"-"`
|
||||||
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
||||||
|
@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
)
|
)
|
||||||
@ -26,9 +27,21 @@ type AppInstall struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *AppInstall) GetPath() string {
|
func (i *AppInstall) GetPath() string {
|
||||||
return path.Join(constant.AppInstallDir, i.App.Key, i.Name)
|
return path.Join(i.getAppPath(), i.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *AppInstall) GetComposePath() string {
|
func (i *AppInstall) GetComposePath() string {
|
||||||
return path.Join(constant.AppInstallDir, i.App.Key, i.Name, "docker-compose.yml")
|
return path.Join(i.getAppPath(), i.Name, "docker-compose.yml")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *AppInstall) GetEnvPath() string {
|
||||||
|
return path.Join(i.getAppPath(), i.Name, ".env")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *AppInstall) getAppPath() string {
|
||||||
|
if i.App.Resource == constant.AppResourceLocal {
|
||||||
|
return path.Join(constant.LocalAppInstallDir, strings.TrimPrefix(i.App.Key, constant.AppResourceLocal))
|
||||||
|
} else {
|
||||||
|
return path.Join(constant.AppInstallDir, i.App.Key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,17 @@ package model
|
|||||||
|
|
||||||
type Host struct {
|
type Host struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
GroupID uint `gorm:"type:decimal;not null" json:"group_id"`
|
|
||||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
GroupID uint `gorm:"type:decimal;not null" json:"group_id"`
|
||||||
Addr string `gorm:"type:varchar(16);not null" json:"addr"`
|
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||||
Port int `gorm:"type:decimal;not null" json:"port"`
|
Addr string `gorm:"type:varchar(16);not null" json:"addr"`
|
||||||
User string `gorm:"type:varchar(64);not null" json:"user"`
|
Port int `gorm:"type:decimal;not null" json:"port"`
|
||||||
AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"`
|
User string `gorm:"type:varchar(64);not null" json:"user"`
|
||||||
Password string `gorm:"type:varchar(64)" json:"password"`
|
AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"`
|
||||||
PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"`
|
Password string `gorm:"type:varchar(64)" json:"password"`
|
||||||
|
PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"`
|
||||||
|
PassPhrase string `gorm:"type:varchar(256)" json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `gorm:"type:varchar(256)" json:"description"`
|
Description string `gorm:"type:varchar(256)" json:"description"`
|
||||||
}
|
}
|
||||||
|
17
backend/app/model/runtime.go
Normal file
17
backend/app/model/runtime.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Runtime struct {
|
||||||
|
BaseModel
|
||||||
|
Name string `gorm:"type:varchar;not null" json:"name"`
|
||||||
|
AppDetailID uint `gorm:"type:integer" json:"appDetailId"`
|
||||||
|
Image string `gorm:"type:varchar" json:"image"`
|
||||||
|
WorkDir string `gorm:"type:varchar" json:"workDir"`
|
||||||
|
DockerCompose string `gorm:"type:varchar" json:"dockerCompose"`
|
||||||
|
Env string `gorm:"type:varchar" json:"env"`
|
||||||
|
Params string `gorm:"type:varchar" json:"params"`
|
||||||
|
Version string `gorm:"type:varchar;not null" json:"version"`
|
||||||
|
Type string `gorm:"type:varchar;not null" json:"type"`
|
||||||
|
Status string `gorm:"type:varchar;not null" json:"status"`
|
||||||
|
Resource string `gorm:"type:varchar;not null" json:"resource"`
|
||||||
|
Message string `gorm:"type:longtext;" json:"message"`
|
||||||
|
}
|
@ -4,23 +4,33 @@ import "time"
|
|||||||
|
|
||||||
type Website struct {
|
type Website struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Protocol string `gorm:"type:varchar(64);not null" json:"protocol"`
|
Protocol string `gorm:"type:varchar;not null" json:"protocol"`
|
||||||
PrimaryDomain string `gorm:"type:varchar(128);not null" json:"primaryDomain"`
|
PrimaryDomain string `gorm:"type:varchar;not null" json:"primaryDomain"`
|
||||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
Type string `gorm:"type:varchar;not null" json:"type"`
|
||||||
Alias string `gorm:"type:varchar(128);not null" json:"alias"`
|
Alias string `gorm:"type:varchar;not null" json:"alias"`
|
||||||
Remark string `gorm:"type:longtext;" json:"remark"`
|
Remark string `gorm:"type:longtext;" json:"remark"`
|
||||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
Status string `gorm:"type:varchar;not null" json:"status"`
|
||||||
HttpConfig string `gorm:"type:varchar(64);not null" json:"httpConfig"`
|
HttpConfig string `gorm:"type:varchar;not null" json:"httpConfig"`
|
||||||
ExpireDate time.Time `json:"expireDate"`
|
ExpireDate time.Time `json:"expireDate"`
|
||||||
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
|
||||||
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
Proxy string `gorm:"type:varchar;" json:"proxy"`
|
||||||
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
ProxyType string `gorm:"type:varchar;" json:"proxyType"`
|
||||||
Proxy string `gorm:"type:varchar(128);not null" json:"proxy"`
|
SiteDir string `gorm:"type:varchar;" json:"siteDir"`
|
||||||
ErrorLog bool `json:"errorLog"`
|
ErrorLog bool `json:"errorLog"`
|
||||||
AccessLog bool `json:"accessLog"`
|
AccessLog bool `json:"accessLog"`
|
||||||
DefaultServer bool `json:"defaultServer"`
|
DefaultServer bool `json:"defaultServer"`
|
||||||
Domains []WebsiteDomain `json:"domains" gorm:"-:migration"`
|
Rewrite string `gorm:"type:varchar" json:"rewrite"`
|
||||||
WebsiteSSL WebsiteSSL `json:"webSiteSSL" gorm:"-:migration"`
|
|
||||||
|
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
||||||
|
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
||||||
|
RuntimeID uint `gorm:"type:integer" json:"runtimeID"`
|
||||||
|
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
||||||
|
|
||||||
|
User string `gorm:"type:varchar;" json:"user"`
|
||||||
|
Group string `gorm:"type:varchar;" json:"group"`
|
||||||
|
|
||||||
|
Domains []WebsiteDomain `json:"domains" gorm:"-:migration"`
|
||||||
|
WebsiteSSL WebsiteSSL `json:"webSiteSSL" gorm:"-:migration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Website) TableName() string {
|
func (w Website) TableName() string {
|
||||||
|
@ -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"
|
|
||||||
}
|
|
@ -11,6 +11,25 @@ import (
|
|||||||
type AppRepo struct {
|
type AppRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppRepo interface {
|
||||||
|
WithKey(key string) DBOption
|
||||||
|
WithType(typeStr string) DBOption
|
||||||
|
OrderByRecommend() DBOption
|
||||||
|
GetRecommend() DBOption
|
||||||
|
WithResource(resource string) DBOption
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.App, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.App, error)
|
||||||
|
GetBy(opts ...DBOption) ([]model.App, error)
|
||||||
|
BatchCreate(ctx context.Context, apps []model.App) error
|
||||||
|
GetByKey(ctx context.Context, key string) (model.App, error)
|
||||||
|
Create(ctx context.Context, app *model.App) error
|
||||||
|
Save(ctx context.Context, app *model.App) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppRepo() IAppRepo {
|
||||||
|
return &AppRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppRepo) WithKey(key string) DBOption {
|
func (a AppRepo) WithKey(key string) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("key = ?", key)
|
return db.Where("key = ?", key)
|
||||||
@ -35,12 +54,18 @@ func (a AppRepo) GetRecommend() DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppRepo) WithResource(resource string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("resource = ?", resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppRepo) Page(page, size int, opts ...DBOption) (int64, []model.App, error) {
|
func (a AppRepo) Page(page, size int, opts ...DBOption) (int64, []model.App, error) {
|
||||||
var apps []model.App
|
var apps []model.App
|
||||||
db := getDb(opts...).Model(&model.App{})
|
db := getDb(opts...).Model(&model.App{})
|
||||||
count := int64(0)
|
count := int64(0)
|
||||||
db = db.Count(&count)
|
db = db.Count(&count)
|
||||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
|
err := db.Debug().Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
|
||||||
return count, apps, err
|
return count, apps, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,21 @@ import (
|
|||||||
type AppDetailRepo struct {
|
type AppDetailRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppDetailRepo interface {
|
||||||
|
WithVersion(version string) DBOption
|
||||||
|
WithAppId(id uint) DBOption
|
||||||
|
GetFirst(opts ...DBOption) (model.AppDetail, error)
|
||||||
|
Update(ctx context.Context, detail model.AppDetail) error
|
||||||
|
BatchCreate(ctx context.Context, details []model.AppDetail) error
|
||||||
|
DeleteByAppIds(ctx context.Context, appIds []uint) error
|
||||||
|
GetBy(opts ...DBOption) ([]model.AppDetail, error)
|
||||||
|
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppDetailRepo() IAppDetailRepo {
|
||||||
|
return &AppDetailRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppDetailRepo) WithVersion(version string) DBOption {
|
func (a AppDetailRepo) WithVersion(version string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("version = ?", version)
|
return g.Where("version = ?", version)
|
||||||
|
@ -3,6 +3,7 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
@ -11,6 +12,31 @@ import (
|
|||||||
|
|
||||||
type AppInstallRepo struct{}
|
type AppInstallRepo struct{}
|
||||||
|
|
||||||
|
type IAppInstallRepo interface {
|
||||||
|
WithDetailIdsIn(detailIds []uint) DBOption
|
||||||
|
WithDetailIdNotIn(detailIds []uint) DBOption
|
||||||
|
WithAppId(appId uint) DBOption
|
||||||
|
WithAppIdsIn(appIds []uint) DBOption
|
||||||
|
WithStatus(status string) DBOption
|
||||||
|
WithServiceName(serviceName string) DBOption
|
||||||
|
WithPort(port int) DBOption
|
||||||
|
WithIdNotInWebsite() DBOption
|
||||||
|
ListBy(opts ...DBOption) ([]model.AppInstall, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.AppInstall, error)
|
||||||
|
Create(ctx context.Context, install *model.AppInstall) error
|
||||||
|
Save(ctx context.Context, install *model.AppInstall) error
|
||||||
|
DeleteBy(opts ...DBOption) error
|
||||||
|
Delete(ctx context.Context, install model.AppInstall) error
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.AppInstall, error)
|
||||||
|
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
||||||
|
LoadBaseInfo(key string, name string) (*RootInfo, error)
|
||||||
|
GetFirstByCtx(ctx context.Context, opts ...DBOption) (model.AppInstall, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppInstallRepo() IAppInstallRepo {
|
||||||
|
return &AppInstallRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) WithDetailIdsIn(detailIds []uint) DBOption {
|
func (a *AppInstallRepo) WithDetailIdsIn(detailIds []uint) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("app_detail_id in (?)", detailIds)
|
return g.Where("app_detail_id in (?)", detailIds)
|
||||||
@ -73,13 +99,20 @@ func (a *AppInstallRepo) GetFirst(opts ...DBOption) (model.AppInstall, error) {
|
|||||||
return install, err
|
return install, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) Create(ctx context.Context, install *model.AppInstall) error {
|
func (a *AppInstallRepo) GetFirstByCtx(ctx context.Context, opts ...DBOption) (model.AppInstall, error) {
|
||||||
db := getTx(ctx).Model(&model.AppInstall{})
|
var install model.AppInstall
|
||||||
return db.Create(&install).Error
|
db := getTx(ctx, opts...).Model(&model.AppInstall{})
|
||||||
|
err := db.Preload("App").First(&install).Error
|
||||||
|
return install, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) Save(install *model.AppInstall) error {
|
func (a *AppInstallRepo) Create(ctx context.Context, install *model.AppInstall) error {
|
||||||
return getDb().Save(&install).Error
|
db := getTx(ctx).Model(&model.AppInstall{})
|
||||||
|
return db.Omit(clause.Associations).Create(&install).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppInstallRepo) Save(ctx context.Context, install *model.AppInstall) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Save(&install).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
|
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
|
||||||
@ -112,8 +145,11 @@ type RootInfo struct {
|
|||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Port int64 `json:"port"`
|
Port int64 `json:"port"`
|
||||||
|
HttpsPort int64 `json:"httpsPort"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
UserPassword string `json:"userPassword"`
|
||||||
ContainerName string `json:"containerName"`
|
ContainerName string `json:"containerName"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
Param string `json:"param"`
|
Param string `json:"param"`
|
||||||
Env string `json:"env"`
|
Env string `json:"env"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
@ -146,8 +182,14 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
|||||||
if ok {
|
if ok {
|
||||||
info.Password = password
|
info.Password = password
|
||||||
}
|
}
|
||||||
|
userPassword, ok := envMap["PANEL_DB_USER_PASSWORD"].(string)
|
||||||
|
if ok {
|
||||||
|
info.UserPassword = userPassword
|
||||||
|
}
|
||||||
info.Port = int64(appInstall.HttpPort)
|
info.Port = int64(appInstall.HttpPort)
|
||||||
|
info.HttpsPort = int64(appInstall.HttpsPort)
|
||||||
info.ID = appInstall.ID
|
info.ID = appInstall.ID
|
||||||
|
info.ServiceName = appInstall.ServiceName
|
||||||
info.ContainerName = appInstall.ContainerName
|
info.ContainerName = appInstall.ContainerName
|
||||||
info.Name = appInstall.Name
|
info.Name = appInstall.Name
|
||||||
info.Env = appInstall.Env
|
info.Env = appInstall.Env
|
||||||
|
@ -11,6 +11,20 @@ import (
|
|||||||
type AppInstallResourceRpo struct {
|
type AppInstallResourceRpo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppInstallResourceRpo interface {
|
||||||
|
WithAppInstallId(appInstallId uint) DBOption
|
||||||
|
WithLinkId(linkId uint) DBOption
|
||||||
|
WithResourceId(resourceId uint) DBOption
|
||||||
|
GetBy(opts ...DBOption) ([]model.AppInstallResource, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.AppInstallResource, error)
|
||||||
|
Create(ctx context.Context, resource *model.AppInstallResource) error
|
||||||
|
DeleteBy(ctx context.Context, opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppInstallResourceRpo() IAppInstallResourceRpo {
|
||||||
|
return &AppInstallResourceRpo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppInstallResourceRpo) WithAppInstallId(appInstallId uint) DBOption {
|
func (a AppInstallResourceRpo) WithAppInstallId(appInstallId uint) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("app_install_id = ?", appInstallId)
|
return db.Where("app_install_id = ?", appInstallId)
|
||||||
|
@ -8,6 +8,18 @@ import (
|
|||||||
type AppTagRepo struct {
|
type AppTagRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppTagRepo interface {
|
||||||
|
BatchCreate(ctx context.Context, tags []*model.AppTag) error
|
||||||
|
DeleteByAppIds(ctx context.Context, appIds []uint) error
|
||||||
|
DeleteAll(ctx context.Context) error
|
||||||
|
GetByAppId(appId uint) ([]model.AppTag, error)
|
||||||
|
GetByTagIds(tagIds []uint) ([]model.AppTag, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppTagRepo() IAppTagRepo {
|
||||||
|
return &AppTagRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppTagRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
|
func (a AppTagRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
|
||||||
return getTx(ctx).Create(&tags).Error
|
return getTx(ctx).Create(&tags).Error
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ type IBackupRepo interface {
|
|||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
DeleteRecord(ctx context.Context, opts ...DBOption) error
|
DeleteRecord(ctx context.Context, opts ...DBOption) error
|
||||||
WithByDetailName(detailName string) DBOption
|
WithByDetailName(detailName string) DBOption
|
||||||
|
WithByFileName(fileName string) DBOption
|
||||||
|
WithByType(backupType string) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIBackupRepo() IBackupRepo {
|
func NewIBackupRepo() IBackupRepo {
|
||||||
|
@ -15,6 +15,7 @@ type ICommandRepo interface {
|
|||||||
Create(command *model.Command) error
|
Create(command *model.Command) error
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
|
Get(opts ...DBOption) (model.Command, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICommandRepo() ICommandRepo {
|
func NewICommandRepo() ICommandRepo {
|
||||||
|
@ -21,10 +21,15 @@ type ICommonRepo interface {
|
|||||||
WithIdsIn(ids []uint) DBOption
|
WithIdsIn(ids []uint) DBOption
|
||||||
WithByDate(startTime, endTime time.Time) DBOption
|
WithByDate(startTime, endTime time.Time) DBOption
|
||||||
WithByStartDate(startTime time.Time) DBOption
|
WithByStartDate(startTime time.Time) DBOption
|
||||||
|
WithByStatus(status string) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommonRepo struct{}
|
type CommonRepo struct{}
|
||||||
|
|
||||||
|
func NewCommonRepo() ICommonRepo {
|
||||||
|
return &CommonRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CommonRepo) WithByID(id uint) DBOption {
|
func (c *CommonRepo) WithByID(id uint) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("id = ?", id)
|
return g.Where("id = ?", id)
|
||||||
|
@ -17,6 +17,7 @@ type IComposeTemplateRepo interface {
|
|||||||
|
|
||||||
CreateRecord(compose *model.Compose) error
|
CreateRecord(compose *model.Compose) error
|
||||||
DeleteRecord(opts ...DBOption) error
|
DeleteRecord(opts ...DBOption) error
|
||||||
|
ListRecord() ([]model.Compose, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIComposeTemplateRepo() IComposeTemplateRepo {
|
func NewIComposeTemplateRepo() IComposeTemplateRepo {
|
||||||
|
@ -20,12 +20,15 @@ type ICronjobRepo interface {
|
|||||||
Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error)
|
Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error)
|
||||||
Create(cronjob *model.Cronjob) error
|
Create(cronjob *model.Cronjob) error
|
||||||
WithByJobID(id int) DBOption
|
WithByJobID(id int) DBOption
|
||||||
|
WithByBackupID(id uint) DBOption
|
||||||
|
WithByRecordDropID(id int) DBOption
|
||||||
Save(id uint, cronjob model.Cronjob) error
|
Save(id uint, cronjob model.Cronjob) error
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
DeleteRecord(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)
|
EndRecords(record model.JobRecords, status, message, records string)
|
||||||
|
PageRecords(page, size int, opts ...DBOption) (int64, []model.JobRecords, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICronjobRepo() ICronjobRepo {
|
func NewICronjobRepo() ICronjobRepo {
|
||||||
@ -112,10 +115,23 @@ func (c *CronjobRepo) WithByJobID(id int) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobRepo) StartRecords(cronjobID uint, targetPath string) model.JobRecords {
|
func (c *CronjobRepo) WithByBackupID(id uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("target_dir_id = ?", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CronjobRepo) WithByRecordDropID(id int) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("id < ?", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CronjobRepo) StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords {
|
||||||
var record model.JobRecords
|
var record model.JobRecords
|
||||||
record.StartTime = time.Now()
|
record.StartTime = time.Now()
|
||||||
record.CronjobID = cronjobID
|
record.CronjobID = cronjobID
|
||||||
|
record.FromLocal = fromLocal
|
||||||
record.Status = constant.StatusWaiting
|
record.Status = constant.StatusWaiting
|
||||||
if err := global.DB.Create(&record).Error; err != nil {
|
if err := global.DB.Create(&record).Error; err != nil {
|
||||||
global.LOG.Errorf("create record status failed, err: %v", err)
|
global.LOG.Errorf("create record status failed, err: %v", err)
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package repo
|
|
||||||
|
|
||||||
type RepoGroup struct {
|
|
||||||
CommonRepo
|
|
||||||
AppRepo
|
|
||||||
AppTagRepo
|
|
||||||
TagRepo
|
|
||||||
AppDetailRepo
|
|
||||||
AppInstallRepo
|
|
||||||
AppInstallResourceRpo
|
|
||||||
ImageRepoRepo
|
|
||||||
ComposeTemplateRepo
|
|
||||||
MysqlRepo
|
|
||||||
CronjobRepo
|
|
||||||
HostRepo
|
|
||||||
CommandRepo
|
|
||||||
GroupRepo
|
|
||||||
SettingRepo
|
|
||||||
BackupRepo
|
|
||||||
WebsiteRepo
|
|
||||||
WebsiteDomainRepo
|
|
||||||
WebsiteGroupRepo
|
|
||||||
WebsiteDnsAccountRepo
|
|
||||||
WebsiteSSLRepo
|
|
||||||
WebsiteAcmeAccountRepo
|
|
||||||
LogRepo
|
|
||||||
SnapshotRepo
|
|
||||||
}
|
|
||||||
|
|
||||||
var RepoGroupApp = new(RepoGroup)
|
|
@ -14,7 +14,7 @@ type IGroupRepo interface {
|
|||||||
Create(group *model.Group) error
|
Create(group *model.Group) error
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
CancelDefault() error
|
CancelDefault(groupType string) error
|
||||||
WithByIsDefault(isDefault bool) DBOption
|
WithByIsDefault(isDefault bool) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +64,6 @@ func (u *GroupRepo) Delete(opts ...DBOption) error {
|
|||||||
return db.Delete(&model.Group{}).Error
|
return db.Delete(&model.Group{}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w GroupRepo) CancelDefault() error {
|
func (u *GroupRepo) CancelDefault(groupType string) error {
|
||||||
return global.DB.Model(&model.Group{}).Where("`is_default` = 1").Updates(map[string]interface{}{"is_default": 0}).Error
|
return global.DB.Model(&model.Group{}).Where("is_default = ? AND type = ?", 1, groupType).Updates(map[string]interface{}{"is_default": 0}).Error
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ func NewIHostRepo() IHostRepo {
|
|||||||
return &HostRepo{}
|
return &HostRepo{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Get(opts ...DBOption) (model.Host, error) {
|
func (h *HostRepo) Get(opts ...DBOption) (model.Host, error) {
|
||||||
var host model.Host
|
var host model.Host
|
||||||
db := global.DB
|
db := global.DB
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@ -35,7 +35,7 @@ func (u *HostRepo) Get(opts ...DBOption) (model.Host, error) {
|
|||||||
return host, err
|
return host, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) GetList(opts ...DBOption) ([]model.Host, error) {
|
func (h *HostRepo) GetList(opts ...DBOption) ([]model.Host, error) {
|
||||||
var hosts []model.Host
|
var hosts []model.Host
|
||||||
db := global.DB.Model(&model.Host{})
|
db := global.DB.Model(&model.Host{})
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@ -45,7 +45,7 @@ func (u *HostRepo) GetList(opts ...DBOption) ([]model.Host, error) {
|
|||||||
return hosts, err
|
return hosts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Page(page, size int, opts ...DBOption) (int64, []model.Host, error) {
|
func (h *HostRepo) Page(page, size int, opts ...DBOption) (int64, []model.Host, error) {
|
||||||
var users []model.Host
|
var users []model.Host
|
||||||
db := global.DB.Model(&model.Host{})
|
db := global.DB.Model(&model.Host{})
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@ -57,7 +57,7 @@ func (u *HostRepo) Page(page, size int, opts ...DBOption) (int64, []model.Host,
|
|||||||
return count, users, err
|
return count, users, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HostRepo) WithByInfo(info string) DBOption {
|
func (h *HostRepo) WithByInfo(info string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
if len(info) == 0 {
|
if len(info) == 0 {
|
||||||
return g
|
return g
|
||||||
@ -67,22 +67,22 @@ func (c *HostRepo) WithByInfo(info string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) WithByPort(port uint) DBOption {
|
func (h *HostRepo) WithByPort(port uint) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("port = ?", port)
|
return g.Where("port = ?", port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (u *HostRepo) WithByUser(user string) DBOption {
|
func (h *HostRepo) WithByUser(user string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("user = ?", user)
|
return g.Where("user = ?", user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (u *HostRepo) WithByAddr(addr string) DBOption {
|
func (h *HostRepo) WithByAddr(addr string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("addr = ?", addr)
|
return g.Where("addr = ?", addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (u *HostRepo) WithByGroup(group string) DBOption {
|
func (h *HostRepo) WithByGroup(group string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
if len(group) == 0 {
|
if len(group) == 0 {
|
||||||
return g
|
return g
|
||||||
@ -91,15 +91,15 @@ func (u *HostRepo) WithByGroup(group string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Create(host *model.Host) error {
|
func (h *HostRepo) Create(host *model.Host) error {
|
||||||
return global.DB.Create(host).Error
|
return global.DB.Create(host).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Update(id uint, vars map[string]interface{}) error {
|
func (h *HostRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
return global.DB.Model(&model.Host{}).Where("id = ?", id).Updates(vars).Error
|
return global.DB.Model(&model.Host{}).Where("id = ?", id).Updates(vars).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Delete(opts ...DBOption) error {
|
func (h *HostRepo) Delete(opts ...DBOption) error {
|
||||||
db := global.DB
|
db := global.DB
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
db = opt(db)
|
db = opt(db)
|
||||||
|
80
backend/app/repo/runtime.go
Normal file
80
backend/app/repo/runtime.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RuntimeRepo struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type IRuntimeRepo interface {
|
||||||
|
WithName(name string) DBOption
|
||||||
|
WithImage(image string) DBOption
|
||||||
|
WithNotId(id uint) DBOption
|
||||||
|
WithStatus(status string) DBOption
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error)
|
||||||
|
Create(ctx context.Context, runtime *model.Runtime) error
|
||||||
|
Save(runtime *model.Runtime) error
|
||||||
|
DeleteBy(opts ...DBOption) error
|
||||||
|
GetFirst(opts ...DBOption) (*model.Runtime, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIRunTimeRepo() IRuntimeRepo {
|
||||||
|
return &RuntimeRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithName(name string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("name = ?", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithStatus(status string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("status = ?", status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithImage(image string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("image = ?", image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithNotId(id uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("id != ?", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error) {
|
||||||
|
var runtimes []model.Runtime
|
||||||
|
db := getDb(opts...).Model(&model.Runtime{})
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&runtimes).Error
|
||||||
|
return count, runtimes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) Create(ctx context.Context, runtime *model.Runtime) error {
|
||||||
|
db := getTx(ctx).Model(&model.Runtime{})
|
||||||
|
return db.Create(&runtime).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) Save(runtime *model.Runtime) error {
|
||||||
|
return getDb().Save(&runtime).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) DeleteBy(opts ...DBOption) error {
|
||||||
|
return getDb(opts...).Delete(&model.Runtime{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) GetFirst(opts ...DBOption) (*model.Runtime, error) {
|
||||||
|
var runtime model.Runtime
|
||||||
|
if err := getDb(opts...).First(&runtime).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &runtime, nil
|
||||||
|
}
|
@ -8,6 +8,19 @@ import (
|
|||||||
type TagRepo struct {
|
type TagRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ITagRepo interface {
|
||||||
|
BatchCreate(ctx context.Context, tags []*model.Tag) error
|
||||||
|
DeleteAll(ctx context.Context) error
|
||||||
|
All() ([]model.Tag, error)
|
||||||
|
GetByIds(ids []uint) ([]model.Tag, error)
|
||||||
|
GetByKeys(keys []string) ([]model.Tag, error)
|
||||||
|
GetByAppId(appId uint) ([]model.Tag, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewITagRepo() ITagRepo {
|
||||||
|
return &TagRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (t TagRepo) BatchCreate(ctx context.Context, tags []*model.Tag) error {
|
func (t TagRepo) BatchCreate(ctx context.Context, tags []*model.Tag) error {
|
||||||
return getTx(ctx).Create(&tags).Error
|
return getTx(ctx).Create(&tags).Error
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ type IWebsiteRepo interface {
|
|||||||
WithGroupID(groupId uint) DBOption
|
WithGroupID(groupId uint) DBOption
|
||||||
WithDefaultServer() DBOption
|
WithDefaultServer() DBOption
|
||||||
WithDomainLike(domain string) DBOption
|
WithDomainLike(domain string) DBOption
|
||||||
|
WithRuntimeID(runtimeID uint) DBOption
|
||||||
Page(page, size int, opts ...DBOption) (int64, []model.Website, error)
|
Page(page, size int, opts ...DBOption) (int64, []model.Website, error)
|
||||||
List(opts ...DBOption) ([]model.Website, error)
|
List(opts ...DBOption) ([]model.Website, error)
|
||||||
GetFirst(opts ...DBOption) (model.Website, error)
|
GetFirst(opts ...DBOption) (model.Website, error)
|
||||||
@ -40,6 +41,12 @@ func (w *WebsiteRepo) WithAppInstallId(appInstallId uint) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WebsiteRepo) WithRuntimeID(runtimeID uint) DBOption {
|
||||||
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Where("runtime_id = ?", runtimeID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (w *WebsiteRepo) WithDomain(domain string) DBOption {
|
func (w *WebsiteRepo) WithDomain(domain string) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("primary_domain = ?", domain)
|
return db.Where("primary_domain = ?", domain)
|
||||||
|
@ -7,6 +7,19 @@ import (
|
|||||||
type WebsiteDnsAccountRepo struct {
|
type WebsiteDnsAccountRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IWebsiteDnsAccountRepo interface {
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDnsAccount, error)
|
||||||
|
GetFirst(opts ...DBOption) (*model.WebsiteDnsAccount, error)
|
||||||
|
List(opts ...DBOption) ([]model.WebsiteDnsAccount, error)
|
||||||
|
Create(account model.WebsiteDnsAccount) error
|
||||||
|
Save(account model.WebsiteDnsAccount) error
|
||||||
|
DeleteBy(opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIWebsiteDnsAccountRepo() IWebsiteDnsAccountRepo {
|
||||||
|
return &WebsiteDnsAccountRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteDnsAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDnsAccount, error) {
|
func (w WebsiteDnsAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDnsAccount, error) {
|
||||||
var accounts []model.WebsiteDnsAccount
|
var accounts []model.WebsiteDnsAccount
|
||||||
db := getDb(opts...).Model(&model.WebsiteDnsAccount{})
|
db := getDb(opts...).Model(&model.WebsiteDnsAccount{})
|
||||||
|
@ -10,6 +10,23 @@ import (
|
|||||||
type WebsiteDomainRepo struct {
|
type WebsiteDomainRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IWebsiteDomainRepo interface {
|
||||||
|
WithWebsiteId(websiteId uint) DBOption
|
||||||
|
WithPort(port int) DBOption
|
||||||
|
WithDomain(domain string) DBOption
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDomain, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.WebsiteDomain, error)
|
||||||
|
GetBy(opts ...DBOption) ([]model.WebsiteDomain, error)
|
||||||
|
BatchCreate(ctx context.Context, domains []model.WebsiteDomain) error
|
||||||
|
Create(ctx context.Context, app *model.WebsiteDomain) error
|
||||||
|
Save(ctx context.Context, app *model.WebsiteDomain) error
|
||||||
|
DeleteBy(ctx context.Context, opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIWebsiteDomainRepo() IWebsiteDomainRepo {
|
||||||
|
return &WebsiteDomainRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteDomainRepo) WithWebsiteId(websiteId uint) DBOption {
|
func (w WebsiteDomainRepo) WithWebsiteId(websiteId uint) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("website_id = ?", websiteId)
|
return db.Where("website_id = ?", websiteId)
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -5,13 +5,15 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
@ -31,10 +33,12 @@ type IAppService interface {
|
|||||||
PageApp(req request.AppSearch) (interface{}, error)
|
PageApp(req request.AppSearch) (interface{}, error)
|
||||||
GetAppTags() ([]response.TagDTO, error)
|
GetAppTags() ([]response.TagDTO, error)
|
||||||
GetApp(key string) (*response.AppDTO, error)
|
GetApp(key string) (*response.AppDTO, error)
|
||||||
GetAppDetail(appId uint, version string) (response.AppDetailDTO, error)
|
GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error)
|
||||||
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
|
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
|
||||||
SyncAppList() error
|
SyncAppListFromRemote() error
|
||||||
GetAppUpdate() (*response.AppUpdateRes, error)
|
GetAppUpdate() (*response.AppUpdateRes, error)
|
||||||
|
GetAppDetailByID(id uint) (*response.AppDetailDTO, error)
|
||||||
|
SyncAppListFromLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAppService() IAppService {
|
func NewIAppService() IAppService {
|
||||||
@ -137,7 +141,7 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) {
|
|||||||
return &appDTO, nil
|
return &appDTO, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetailDTO, error) {
|
func (a AppService) GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error) {
|
||||||
var (
|
var (
|
||||||
appDetailDTO response.AppDetailDTO
|
appDetailDTO response.AppDetailDTO
|
||||||
opts []repo.DBOption
|
opts []repo.DBOption
|
||||||
@ -147,14 +151,55 @@ func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetail
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return appDetailDTO, err
|
return appDetailDTO, err
|
||||||
}
|
}
|
||||||
paramMap := make(map[string]interface{})
|
|
||||||
if err := json.Unmarshal([]byte(detail.Params), ¶mMap); err != nil {
|
|
||||||
return appDetailDTO, err
|
|
||||||
}
|
|
||||||
appDetailDTO.AppDetail = detail
|
appDetailDTO.AppDetail = detail
|
||||||
appDetailDTO.Params = paramMap
|
|
||||||
appDetailDTO.Enable = true
|
appDetailDTO.Enable = true
|
||||||
|
|
||||||
|
if appType == "runtime" {
|
||||||
|
app, err := appRepo.GetFirst(commonRepo.WithByID(appId))
|
||||||
|
if err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
buildPath := path.Join(constant.AppResourceDir, app.Key, "versions", detail.Version, "build")
|
||||||
|
paramsPath := path.Join(buildPath, "config.json")
|
||||||
|
if !fileOp.Stat(paramsPath) {
|
||||||
|
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
|
||||||
|
}
|
||||||
|
param, err := fileOp.GetContent(paramsPath)
|
||||||
|
if err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
paramMap := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal(param, ¶mMap); err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
appDetailDTO.Params = paramMap
|
||||||
|
composePath := path.Join(buildPath, "docker-compose.yml")
|
||||||
|
if !fileOp.Stat(composePath) {
|
||||||
|
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
|
||||||
|
}
|
||||||
|
compose, err := fileOp.GetContent(composePath)
|
||||||
|
if err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
composeMap := make(map[string]interface{})
|
||||||
|
if err := yaml.Unmarshal(compose, &composeMap); err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
if service, ok := composeMap["services"]; ok {
|
||||||
|
servicesMap := service.(map[string]interface{})
|
||||||
|
for k := range servicesMap {
|
||||||
|
appDetailDTO.Image = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramMap := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal([]byte(detail.Params), ¶mMap); err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
appDetailDTO.Params = paramMap
|
||||||
|
}
|
||||||
|
|
||||||
app, err := appRepo.GetFirst(commonRepo.WithByID(detail.AppId))
|
app, err := appRepo.GetFirst(commonRepo.WithByID(detail.AppId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return appDetailDTO, err
|
return appDetailDTO, err
|
||||||
@ -164,54 +209,75 @@ func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetail
|
|||||||
}
|
}
|
||||||
return appDetailDTO, nil
|
return appDetailDTO, nil
|
||||||
}
|
}
|
||||||
|
func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
|
||||||
|
res := &response.AppDetailDTO{}
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.AppDetail = appDetail
|
||||||
|
paramMap := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal([]byte(appDetail.Params), ¶mMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.Params = paramMap
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error) {
|
func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (appInstall *model.AppInstall, err error) {
|
||||||
|
if err = docker.CreateDefaultDockerNetwork(); err != nil {
|
||||||
|
err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
|
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
|
||||||
return nil, buserr.New(constant.ErrNameIsExist)
|
err = buserr.New(constant.ErrNameIsExist)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
var (
|
||||||
|
httpPort int
|
||||||
|
httpsPort int
|
||||||
|
appDetail model.AppDetail
|
||||||
|
app model.App
|
||||||
|
)
|
||||||
|
httpPort, err = checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpsPort, err = checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appDetail, err = appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
if err = checkRequiredAndLimit(app); err != nil {
|
||||||
if err != nil {
|
return
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := checkRequiredAndLimit(app); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
paramByte, err := json.Marshal(req.Params)
|
appInstall = &model.AppInstall{
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
appInstall := model.AppInstall{
|
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
AppId: appDetail.AppId,
|
AppId: appDetail.AppId,
|
||||||
AppDetailId: appDetail.ID,
|
AppDetailId: appDetail.ID,
|
||||||
Version: appDetail.Version,
|
Version: appDetail.Version,
|
||||||
Status: constant.Installing,
|
Status: constant.Installing,
|
||||||
Env: string(paramByte),
|
|
||||||
HttpPort: httpPort,
|
HttpPort: httpPort,
|
||||||
HttpsPort: httpsPort,
|
HttpsPort: httpsPort,
|
||||||
App: app,
|
App: app,
|
||||||
}
|
}
|
||||||
composeMap := make(map[string]interface{})
|
composeMap := make(map[string]interface{})
|
||||||
if err := yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
if err = yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
value, ok := composeMap["services"]
|
value, ok := composeMap["services"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, buserr.New("")
|
err = buserr.New("")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
servicesMap := value.(map[string]interface{})
|
servicesMap := value.(map[string]interface{})
|
||||||
changeKeys := make(map[string]string, len(servicesMap))
|
changeKeys := make(map[string]string, len(servicesMap))
|
||||||
@ -232,30 +298,59 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
servicesMap[v] = servicesMap[k]
|
servicesMap[v] = servicesMap[k]
|
||||||
delete(servicesMap, k)
|
delete(servicesMap, k)
|
||||||
}
|
}
|
||||||
composeByte, err := yaml.Marshal(composeMap)
|
|
||||||
|
var (
|
||||||
|
composeByte []byte
|
||||||
|
paramByte []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
composeByte, err = yaml.Marshal(composeMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
appInstall.DockerCompose = string(composeByte)
|
appInstall.DockerCompose = string(composeByte)
|
||||||
|
|
||||||
if err := copyAppData(app.Key, appDetail.Version, req.Name, req.Params); err != nil {
|
defer func() {
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
hErr := handleAppInstallErr(ctx, appInstall)
|
||||||
|
if hErr != nil {
|
||||||
|
global.LOG.Errorf("delete app dir error %s", hErr.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err = copyAppData(app.Key, appDetail.Version, req.Name, req.Params, app.Resource == constant.AppResourceLocal); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
if err := fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
|
if err = fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
paramByte, err = json.Marshal(req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appInstall.Env = string(paramByte)
|
||||||
|
|
||||||
if err := appInstallRepo.Create(ctx, &appInstall); err != nil {
|
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
if err := createLink(ctx, app, &appInstall, req.Params); err != nil {
|
if err = createLink(ctx, app, appInstall, req.Params); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
go upApp(appInstall.GetComposePath(), appInstall)
|
if err = upAppPre(app, appInstall); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go upApp(appInstall)
|
||||||
go updateToolApp(appInstall)
|
go updateToolApp(appInstall)
|
||||||
return &appInstall, nil
|
ports := []int{appInstall.HttpPort}
|
||||||
|
if appInstall.HttpsPort > 0 {
|
||||||
|
ports = append(ports, appInstall.HttpsPort)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
_ = OperateFirewallPort(nil, ports)
|
||||||
|
}()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||||
@ -268,12 +363,11 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
|||||||
}
|
}
|
||||||
versionUrl := fmt.Sprintf("%s/%s/%s/appstore/apps.json", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion)
|
versionUrl := fmt.Sprintf("%s/%s/%s/appstore/apps.json", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion)
|
||||||
versionRes, err := http.Get(versionUrl)
|
versionRes, err := http.Get(versionUrl)
|
||||||
global.LOG.Infof("get current version from [%s]", versionUrl)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer versionRes.Body.Close()
|
defer versionRes.Body.Close()
|
||||||
body, err := ioutil.ReadAll(versionRes.Body)
|
body, err := io.ReadAll(versionRes.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -290,7 +384,155 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) SyncAppList() error {
|
func (a AppService) SyncAppListFromLocal() {
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
appDir := constant.LocalAppResourceDir
|
||||||
|
listFile := path.Join(appDir, "list.json")
|
||||||
|
if !fileOp.Stat(listFile) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
global.LOG.Infof("start sync local apps...")
|
||||||
|
content, err := fileOp.GetContent(listFile)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("get list.json content failed %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list := &dto.AppList{}
|
||||||
|
if err := json.Unmarshal(content, list); err != nil {
|
||||||
|
global.LOG.Errorf("unmarshal list.json failed %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oldApps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceLocal))
|
||||||
|
appsMap := getApps(oldApps, list.Items, true)
|
||||||
|
for _, l := range list.Items {
|
||||||
|
localKey := "local" + l.Key
|
||||||
|
app := appsMap[localKey]
|
||||||
|
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
iconStr := base64.StdEncoding.EncodeToString(icon)
|
||||||
|
app.Icon = iconStr
|
||||||
|
app.TagsKey = append(l.Tags, "Local")
|
||||||
|
app.Recommend = 9999
|
||||||
|
versions := l.Versions
|
||||||
|
detailsMap := getAppDetails(app.Details, versions)
|
||||||
|
|
||||||
|
for _, v := range versions {
|
||||||
|
detail := detailsMap[v]
|
||||||
|
detailPath := path.Join(appDir, l.Key, "versions", v)
|
||||||
|
if _, err := os.Stat(detailPath); err != nil {
|
||||||
|
global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
readmeStr, err := os.ReadFile(path.Join(detailPath, "README.md"))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("get [%s] README error: %s", detailPath, err.Error())
|
||||||
|
}
|
||||||
|
detail.Readme = string(readmeStr)
|
||||||
|
dockerComposeStr, err := os.ReadFile(path.Join(detailPath, "docker-compose.yml"))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("get [%s] docker-compose.yml error: %s", detailPath, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
detail.DockerCompose = string(dockerComposeStr)
|
||||||
|
paramStr, err := os.ReadFile(path.Join(detailPath, "config.json"))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("get [%s] form.json error: %s", detailPath, err.Error())
|
||||||
|
}
|
||||||
|
detail.Params = string(paramStr)
|
||||||
|
detailsMap[v] = detail
|
||||||
|
}
|
||||||
|
var newDetails []model.AppDetail
|
||||||
|
for _, v := range detailsMap {
|
||||||
|
newDetails = append(newDetails, v)
|
||||||
|
}
|
||||||
|
app.Details = newDetails
|
||||||
|
appsMap[localKey] = app
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
addAppArray []model.App
|
||||||
|
updateArray []model.App
|
||||||
|
appIds []uint
|
||||||
|
)
|
||||||
|
for _, v := range appsMap {
|
||||||
|
if v.ID == 0 {
|
||||||
|
addAppArray = append(addAppArray, v)
|
||||||
|
} else {
|
||||||
|
updateArray = append(updateArray, v)
|
||||||
|
appIds = append(appIds, v.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx, ctx := getTxAndContext()
|
||||||
|
if len(addAppArray) > 0 {
|
||||||
|
if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, update := range updateArray {
|
||||||
|
if err := appRepo.Save(ctx, &update); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := appTagRepo.DeleteByAppIds(ctx, appIds); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apps := append(addAppArray, updateArray...)
|
||||||
|
var (
|
||||||
|
addDetails []model.AppDetail
|
||||||
|
updateDetails []model.AppDetail
|
||||||
|
appTags []*model.AppTag
|
||||||
|
)
|
||||||
|
tags, _ := tagRepo.All()
|
||||||
|
tagMap := make(map[string]uint, len(tags))
|
||||||
|
for _, app := range tags {
|
||||||
|
tagMap[app.Key] = app.ID
|
||||||
|
}
|
||||||
|
for _, a := range apps {
|
||||||
|
for _, t := range a.TagsKey {
|
||||||
|
tagId, ok := tagMap[t]
|
||||||
|
if ok {
|
||||||
|
appTags = append(appTags, &model.AppTag{
|
||||||
|
AppId: a.ID,
|
||||||
|
TagId: tagId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, d := range a.Details {
|
||||||
|
d.AppId = a.ID
|
||||||
|
if d.ID == 0 {
|
||||||
|
addDetails = append(addDetails, d)
|
||||||
|
} else {
|
||||||
|
updateDetails = append(updateDetails, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(addDetails) > 0 {
|
||||||
|
if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, u := range updateDetails {
|
||||||
|
if err := appDetailRepo.Update(ctx, u); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(appTags) > 0 {
|
||||||
|
if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
global.LOG.Infof("sync local apps success")
|
||||||
|
}
|
||||||
|
func (a AppService) SyncAppListFromRemote() error {
|
||||||
updateRes, err := a.GetAppUpdate()
|
updateRes, err := a.GetAppUpdate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -323,11 +565,11 @@ func (a AppService) SyncAppList() error {
|
|||||||
Name: t.Name,
|
Name: t.Name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
oldApps, err := appRepo.GetBy()
|
oldApps, err := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
appsMap := getApps(oldApps, list.Items)
|
appsMap := getApps(oldApps, list.Items, false)
|
||||||
for _, l := range list.Items {
|
for _, l := range list.Items {
|
||||||
app := appsMap[l.Key]
|
app := appsMap[l.Key]
|
||||||
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
|
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
|
||||||
@ -383,8 +625,9 @@ func (a AppService) SyncAppList() error {
|
|||||||
var (
|
var (
|
||||||
addAppArray []model.App
|
addAppArray []model.App
|
||||||
updateArray []model.App
|
updateArray []model.App
|
||||||
|
tagMap = make(map[string]uint, len(tags))
|
||||||
)
|
)
|
||||||
tagMap := make(map[string]uint, len(tags))
|
|
||||||
for _, v := range appsMap {
|
for _, v := range appsMap {
|
||||||
if v.ID == 0 {
|
if v.ID == 0 {
|
||||||
addAppArray = append(addAppArray, v)
|
addAppArray = append(addAppArray, v)
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/env"
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"io/ioutil"
|
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -14,6 +11,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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/request"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
@ -33,7 +34,28 @@ import (
|
|||||||
type AppInstallService struct {
|
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)
|
||||||
|
LoadConnInfo(key string) (response.DatabaseConn, 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
|
var opts []repo.DBOption
|
||||||
|
|
||||||
if req.Name != "" {
|
if req.Name != "" {
|
||||||
@ -73,7 +95,7 @@ func (a AppInstallService) Page(req request.AppInstalledSearch) (int64, []respon
|
|||||||
return total, installDTOs, nil
|
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{
|
res := &response.AppInstalledCheck{
|
||||||
IsExist: false,
|
IsExist: false,
|
||||||
}
|
}
|
||||||
@ -103,7 +125,7 @@ func (a AppInstallService) CheckExist(key string) (*response.AppInstalledCheck,
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) LoadPort(key string) (int64, error) {
|
func (a *AppInstallService) LoadPort(key string) (int64, error) {
|
||||||
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return int64(0), nil
|
return int64(0), nil
|
||||||
@ -111,15 +133,19 @@ func (a AppInstallService) LoadPort(key string) (int64, error) {
|
|||||||
return app.Port, nil
|
return app.Port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) LoadPassword(key string) (string, error) {
|
func (a *AppInstallService) LoadConnInfo(key string) (response.DatabaseConn, error) {
|
||||||
|
var data response.DatabaseConn
|
||||||
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil
|
return data, nil
|
||||||
}
|
}
|
||||||
return app.Password, nil
|
data.Password = app.Password
|
||||||
|
data.ServiceName = app.ServiceName
|
||||||
|
data.Port = app.Port
|
||||||
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
||||||
var (
|
var (
|
||||||
installs []model.AppInstall
|
installs []model.AppInstall
|
||||||
err error
|
err error
|
||||||
@ -152,8 +178,8 @@ func (a AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]r
|
|||||||
return handleInstalled(installs, false)
|
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))
|
install, err := appInstallRepo.GetFirstByCtx(context.Background(), commonRepo.WithByID(req.InstallId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -180,49 +206,54 @@ func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
|
|||||||
}
|
}
|
||||||
return syncById(install.ID)
|
return syncById(install.ID)
|
||||||
case constant.Delete:
|
case constant.Delete:
|
||||||
tx, ctx := getTxAndContext()
|
if err := deleteAppInstall(install, req.DeleteBackup, req.ForceDelete, req.DeleteDB); err != nil && !req.ForceDelete {
|
||||||
if err := deleteAppInstall(ctx, install, req.DeleteBackup, req.ForceDelete, req.DeleteDB); err != nil && !req.ForceDelete {
|
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tx.Commit()
|
|
||||||
return nil
|
return nil
|
||||||
case constant.Sync:
|
case constant.Sync:
|
||||||
return syncById(install.ID)
|
return syncById(install.ID)
|
||||||
case constant.Upgrade:
|
case constant.Upgrade:
|
||||||
return updateInstall(install.ID, req.DetailId)
|
return upgradeInstall(install.ID, req.DetailId)
|
||||||
default:
|
default:
|
||||||
return errors.New("operate not support")
|
return errors.New("operate not support")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
|
func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
|
||||||
installed, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
|
installed, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
changePort := false
|
changePort := false
|
||||||
|
var (
|
||||||
|
oldPorts []int
|
||||||
|
newPorts []int
|
||||||
|
)
|
||||||
port, ok := req.Params["PANEL_APP_PORT_HTTP"]
|
port, ok := req.Params["PANEL_APP_PORT_HTTP"]
|
||||||
if ok {
|
if ok {
|
||||||
portN := int(math.Ceil(port.(float64)))
|
portN := int(math.Ceil(port.(float64)))
|
||||||
if portN != installed.HttpPort {
|
if portN != installed.HttpPort {
|
||||||
|
oldPorts = append(oldPorts, installed.HttpPort)
|
||||||
changePort = true
|
changePort = true
|
||||||
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
installed.HttpPort = httpPort
|
installed.HttpPort = httpPort
|
||||||
|
newPorts = append(newPorts, httpPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ports, ok := req.Params["PANEL_APP_PORT_HTTPS"]
|
ports, ok := req.Params["PANEL_APP_PORT_HTTPS"]
|
||||||
if ok {
|
if ok {
|
||||||
portN := int(math.Ceil(ports.(float64)))
|
portN := int(math.Ceil(ports.(float64)))
|
||||||
if portN != installed.HttpsPort {
|
if portN != installed.HttpsPort {
|
||||||
|
oldPorts = append(oldPorts, installed.HttpsPort)
|
||||||
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
installed.HttpsPort = httpsPort
|
installed.HttpsPort = httpsPort
|
||||||
|
newPorts = append(newPorts, httpsPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +271,7 @@ func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
|
|||||||
if err := env.Write(oldEnvMaps, envPath); err != nil {
|
if err := env.Write(oldEnvMaps, envPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_ = appInstallRepo.Save(&installed)
|
_ = appInstallRepo.Save(context.Background(), &installed)
|
||||||
|
|
||||||
if err := rebuildApp(installed); err != nil {
|
if err := rebuildApp(installed); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -267,16 +298,26 @@ func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
|
|||||||
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if changePort {
|
||||||
|
go func() {
|
||||||
|
_ = OperateFirewallPort(oldPorts, newPorts)
|
||||||
|
}()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) SyncAll() error {
|
func (a *AppInstallService) SyncAll(systemInit bool) error {
|
||||||
allList, err := appInstallRepo.ListBy()
|
allList, err := appInstallRepo.ListBy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, i := range allList {
|
for _, i := range allList {
|
||||||
if i.Status == constant.Installing {
|
if i.Status == constant.Installing {
|
||||||
|
if systemInit {
|
||||||
|
i.Status = constant.Error
|
||||||
|
i.Message = "System restart causes application exception"
|
||||||
|
_ = appInstallRepo.Save(context.Background(), &i)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := syncById(i.ID); err != nil {
|
if err := syncById(i.ID); err != nil {
|
||||||
@ -286,7 +327,7 @@ func (a AppInstallService) SyncAll() error {
|
|||||||
return nil
|
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))
|
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -310,7 +351,7 @@ func (a AppInstallService) GetServices(key string) ([]response.AppService, error
|
|||||||
return res, nil
|
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))
|
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||||
var versions []dto.AppVersion
|
var versions []dto.AppVersion
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -335,7 +376,7 @@ func (a AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion,
|
|||||||
return versions, nil
|
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)) {
|
if common.ScanPort(int(req.Port)) {
|
||||||
return buserr.WithDetail(constant.ErrPortInUsed, req.Port, nil)
|
return buserr.WithDetail(constant.ErrPortInUsed, req.Port, nil)
|
||||||
}
|
}
|
||||||
@ -360,10 +401,14 @@ func (a AppInstallService) ChangeAppPort(req request.PortUpdate) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := OperateFirewallPort([]int{int(appInstall.Port)}, []int{int(req.Port)}); err != nil {
|
||||||
|
global.LOG.Errorf("allow firewall failed, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error) {
|
func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error) {
|
||||||
var res []dto.AppResource
|
var res []dto.AppResource
|
||||||
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -373,14 +418,12 @@ func (a AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if app.Type == "website" {
|
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(appInstall.ID))
|
||||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(appInstall.ID))
|
for _, website := range websites {
|
||||||
for _, website := range websites {
|
res = append(res, dto.AppResource{
|
||||||
res = append(res, dto.AppResource{
|
Type: "website",
|
||||||
Type: "website",
|
Name: website.PrimaryDomain,
|
||||||
Name: website.PrimaryDomain,
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if app.Key == constant.AppOpenresty {
|
if app.Key == constant.AppOpenresty {
|
||||||
websites, _ := websiteRepo.GetBy()
|
websites, _ := websiteRepo.GetBy()
|
||||||
@ -404,7 +447,7 @@ func (a AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
|
func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
|
||||||
appInstall, err := getAppInstallByKey(key)
|
appInstall, err := getAppInstallByKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -426,7 +469,7 @@ func (a AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
|
|||||||
return string(contentByte), nil
|
return string(contentByte), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
|
func (a *AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
|
||||||
var (
|
var (
|
||||||
res []response.AppParam
|
res []response.AppParam
|
||||||
appForm dto.AppForm
|
appForm dto.AppForm
|
||||||
@ -459,14 +502,20 @@ func (a AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
|
|||||||
}
|
}
|
||||||
appParam.LabelZh = form.LabelZh
|
appParam.LabelZh = form.LabelZh
|
||||||
appParam.LabelEn = form.LabelEn
|
appParam.LabelEn = form.LabelEn
|
||||||
|
appParam.Value = v
|
||||||
if form.Type == "service" {
|
if form.Type == "service" {
|
||||||
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
||||||
appParam.Value = appInstall.Name
|
appParam.ShowValue = appInstall.Name
|
||||||
res = append(res, appParam)
|
} else if form.Type == "select" {
|
||||||
} else {
|
for _, fv := range form.Values {
|
||||||
appParam.Value = v
|
if fv.Value == v {
|
||||||
res = append(res, appParam)
|
appParam.ShowValue = fv.Label
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appParam.Values = form.Values
|
||||||
}
|
}
|
||||||
|
res = append(res, appParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
@ -534,15 +583,15 @@ func syncById(installId uint) error {
|
|||||||
if containerCount == 0 {
|
if containerCount == 0 {
|
||||||
appInstall.Status = constant.Error
|
appInstall.Status = constant.Error
|
||||||
appInstall.Message = "container is not found"
|
appInstall.Message = "container is not found"
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
if errCount == 0 && existedCount == 0 {
|
if errCount == 0 && existedCount == 0 {
|
||||||
appInstall.Status = constant.Running
|
appInstall.Status = constant.Running
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
if existedCount == normalCount {
|
if existedCount == normalCount {
|
||||||
appInstall.Status = constant.Stopped
|
appInstall.Status = constant.Stopped
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
if errCount == normalCount {
|
if errCount == normalCount {
|
||||||
appInstall.Status = constant.Error
|
appInstall.Status = constant.Error
|
||||||
@ -567,7 +616,7 @@ func syncById(installId uint) error {
|
|||||||
errMsg.Write([]byte("\n"))
|
errMsg.Write([]byte("\n"))
|
||||||
}
|
}
|
||||||
appInstall.Message = errMsg.String()
|
appInstall.Message = errMsg.String()
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value interface{}) error {
|
func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value interface{}) error {
|
||||||
@ -579,7 +628,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, appKey, appInstall.Name)
|
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, appKey, appInstall.Name)
|
||||||
lineBytes, err := ioutil.ReadFile(envPath)
|
lineBytes, err := os.ReadFile(envPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -622,7 +671,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
|
|||||||
}, commonRepo.WithByID(appInstall.ID))
|
}, commonRepo.WithByID(appInstall.ID))
|
||||||
}
|
}
|
||||||
if param == "user-password" {
|
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)
|
newVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", value)
|
||||||
_ = appInstallRepo.BatchUpdateBy(map[string]interface{}{
|
_ = appInstallRepo.BatchUpdateBy(map[string]interface{}{
|
||||||
"param": strings.ReplaceAll(appInstall.Param, oldVal, newVal),
|
"param": strings.ReplaceAll(appInstall.Param, oldVal, newVal),
|
||||||
|
@ -4,8 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/compose-spec/compose-go/types"
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -23,6 +27,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||||
|
composeV2 "github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -125,7 +130,23 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteAppInstall(ctx context.Context, install model.AppInstall, deleteBackup bool, forceDelete bool, deleteDB bool) error {
|
func handleAppInstallErr(ctx context.Context, install *model.AppInstall) error {
|
||||||
|
op := files.NewFileOp()
|
||||||
|
appDir := install.GetPath()
|
||||||
|
dir, _ := os.Stat(appDir)
|
||||||
|
if dir != nil {
|
||||||
|
_, _ = compose.Down(install.GetComposePath())
|
||||||
|
if err := op.DeleteDir(appDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := deleteLink(ctx, install, true, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete bool, deleteDB bool) error {
|
||||||
op := files.NewFileOp()
|
op := files.NewFileOp()
|
||||||
appDir := install.GetPath()
|
appDir := install.GetPath()
|
||||||
dir, _ := os.Stat(appDir)
|
dir, _ := os.Stat(appDir)
|
||||||
@ -134,36 +155,34 @@ func deleteAppInstall(ctx context.Context, install model.AppInstall, deleteBacku
|
|||||||
if err != nil && !forceDelete {
|
if err != nil && !forceDelete {
|
||||||
return handleErr(install, err, out)
|
return handleErr(install, err, out)
|
||||||
}
|
}
|
||||||
if err := op.DeleteDir(appDir); err != nil && !forceDelete {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
tx, ctx := helper.GetTxAndContext()
|
||||||
|
defer tx.Rollback()
|
||||||
if err := appInstallRepo.Delete(ctx, install); err != nil {
|
if err := appInstallRepo.Delete(ctx, install); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := deleteLink(ctx, &install, deleteDB, forceDelete); err != nil && !forceDelete {
|
if err := deleteLink(ctx, &install, deleteDB, forceDelete); err != nil && !forceDelete {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
|
||||||
|
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key))
|
||||||
|
if install.App.Key == constant.AppMysql {
|
||||||
|
_ = mysqlRepo.DeleteAll(ctx)
|
||||||
|
}
|
||||||
uploadDir := fmt.Sprintf("%s/1panel/uploads/app/%s/%s", global.CONF.System.BaseDir, install.App.Key, install.Name)
|
uploadDir := fmt.Sprintf("%s/1panel/uploads/app/%s/%s", global.CONF.System.BaseDir, install.App.Key, install.Name)
|
||||||
if _, err := os.Stat(uploadDir); err == nil {
|
if _, err := os.Stat(uploadDir); err == nil {
|
||||||
_ = os.RemoveAll(uploadDir)
|
_ = os.RemoveAll(uploadDir)
|
||||||
}
|
}
|
||||||
if deleteBackup {
|
if deleteBackup {
|
||||||
localDir, err := loadLocalDir()
|
localDir, _ := loadLocalDir()
|
||||||
if err != nil && !forceDelete {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, install.App.Key, install.Name)
|
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, install.App.Key, install.Name)
|
||||||
if _, err := os.Stat(backupDir); err == nil {
|
if _, err := os.Stat(backupDir); err == nil {
|
||||||
_ = os.RemoveAll(backupDir)
|
_ = os.RemoveAll(backupDir)
|
||||||
}
|
}
|
||||||
global.LOG.Infof("delete app %s-%s backups successful", install.App.Key, install.Name)
|
global.LOG.Infof("delete app %s-%s backups successful", install.App.Key, install.Name)
|
||||||
}
|
}
|
||||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
|
_ = op.DeleteDir(appDir)
|
||||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key))
|
tx.Commit()
|
||||||
if install.App.Key == constant.AppMysql {
|
|
||||||
_ = mysqlRepo.DeleteAll(ctx)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +209,7 @@ func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, f
|
|||||||
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateInstall(installId uint, detailId uint) error {
|
func upgradeInstall(installId uint, detailId uint) error {
|
||||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -205,7 +224,21 @@ func updateInstall(installId uint, detailId uint) error {
|
|||||||
if err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
|
if err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = compose.Down(install.GetComposePath()); err != nil {
|
|
||||||
|
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Key, "versions", detail.Version)
|
||||||
|
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rf %s/* %s", detailDir, install.GetPath()))
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
if stdout != nil {
|
||||||
|
return errors.New(string(stdout))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if out, err := compose.Down(install.GetComposePath()); err != nil {
|
||||||
|
if out != "" {
|
||||||
|
return errors.New(out)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
install.DockerCompose = detail.DockerCompose
|
install.DockerCompose = detail.DockerCompose
|
||||||
@ -216,32 +249,51 @@ func updateInstall(installId uint, detailId uint) error {
|
|||||||
if err := fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); err != nil {
|
if err := fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = compose.Up(install.GetComposePath()); err != nil {
|
if out, err := compose.Up(install.GetComposePath()); err != nil {
|
||||||
|
if out != "" {
|
||||||
|
return errors.New(out)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return appInstallRepo.Save(&install)
|
return appInstallRepo.Save(context.Background(), &install)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainerNames(install model.AppInstall) ([]string, error) {
|
func getContainerNames(install model.AppInstall) ([]string, error) {
|
||||||
composeMap := install.DockerCompose
|
envStr, err := coverEnvJsonToStr(install.Env)
|
||||||
envMap := make(map[string]interface{})
|
|
||||||
_ = json.Unmarshal([]byte(install.Env), &envMap)
|
|
||||||
newEnvMap := make(map[string]string, len(envMap))
|
|
||||||
handleMap(envMap, newEnvMap)
|
|
||||||
project, err := compose.GetComposeProject([]byte(composeMap), newEnvMap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
containerNames := []string{install.ContainerName}
|
project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(envStr), true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
containerMap := make(map[string]struct{})
|
||||||
|
containerMap[install.ContainerName] = struct{}{}
|
||||||
for _, service := range project.AllServices() {
|
for _, service := range project.AllServices() {
|
||||||
if service.ContainerName == "${CONTAINER_NAME}" || service.ContainerName == "" {
|
if service.ContainerName == "${CONTAINER_NAME}" || service.ContainerName == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
containerNames = append(containerNames, service.ContainerName)
|
containerMap[service.ContainerName] = struct{}{}
|
||||||
|
}
|
||||||
|
var containerNames []string
|
||||||
|
for k := range containerMap {
|
||||||
|
containerNames = append(containerNames, k)
|
||||||
}
|
}
|
||||||
return containerNames, nil
|
return containerNames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func coverEnvJsonToStr(envJson string) (string, error) {
|
||||||
|
envMap := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal([]byte(envJson), &envMap)
|
||||||
|
newEnvMap := make(map[string]string, len(envMap))
|
||||||
|
handleMap(envMap, newEnvMap)
|
||||||
|
envStr, err := gotenv.Marshal(newEnvMap)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return envStr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func checkLimit(app model.App) error {
|
func checkLimit(app model.App) error {
|
||||||
if app.Limit > 0 {
|
if app.Limit > 0 {
|
||||||
installs, err := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID))
|
installs, err := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID))
|
||||||
@ -256,11 +308,9 @@ func checkLimit(app model.App) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkRequiredAndLimit(app model.App) error {
|
func checkRequiredAndLimit(app model.App) error {
|
||||||
|
|
||||||
if err := checkLimit(app); err != nil {
|
if err := checkLimit(app); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if app.Required != "" {
|
if app.Required != "" {
|
||||||
var requiredArray []string
|
var requiredArray []string
|
||||||
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
|
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
|
||||||
@ -289,7 +339,6 @@ func checkRequiredAndLimit(app model.App) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,10 +355,17 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyAppData(key, version, installName string, params map[string]interface{}) (err error) {
|
func copyAppData(key, version, installName string, params map[string]interface{}, isLocal bool) (err error) {
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
resourceDir := path.Join(constant.AppResourceDir, key, "versions", version)
|
appResourceDir := constant.AppResourceDir
|
||||||
installAppDir := path.Join(constant.AppInstallDir, key)
|
installAppDir := path.Join(constant.AppInstallDir, key)
|
||||||
|
appKey := key
|
||||||
|
if isLocal {
|
||||||
|
appResourceDir = constant.LocalAppResourceDir
|
||||||
|
appKey = strings.TrimPrefix(key, "local")
|
||||||
|
installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
|
||||||
|
}
|
||||||
|
resourceDir := path.Join(appResourceDir, appKey, "versions", version)
|
||||||
|
|
||||||
if !fileOp.Stat(installAppDir) {
|
if !fileOp.Stat(installAppDir) {
|
||||||
if err = fileOp.CreateDir(installAppDir, 0755); err != nil {
|
if err = fileOp.CreateDir(installAppDir, 0755); err != nil {
|
||||||
@ -339,19 +395,64 @@ func copyAppData(key, version, installName string, params map[string]interface{}
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func upApp(composeFilePath string, appInstall model.AppInstall) {
|
// 处理文件夹权限等问题
|
||||||
out, err := compose.Up(composeFilePath)
|
func upAppPre(app model.App, appInstall *model.AppInstall) error {
|
||||||
if err != nil {
|
if app.Key == "nexus" {
|
||||||
if out != "" {
|
dataPath := path.Join(appInstall.GetPath(), "data")
|
||||||
appInstall.Message = out
|
if err := files.NewFileOp().Chown(dataPath, 200, 0); err != nil {
|
||||||
} else {
|
return err
|
||||||
appInstall.Message = err.Error()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getServiceFromInstall(appInstall *model.AppInstall) (service *composeV2.ComposeService, err error) {
|
||||||
|
var (
|
||||||
|
project *types.Project
|
||||||
|
envStr string
|
||||||
|
)
|
||||||
|
envStr, err = coverEnvJsonToStr(appInstall.Env)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
project, err = composeV2.GetComposeProject(appInstall.Name, appInstall.GetPath(), []byte(appInstall.DockerCompose), []byte(envStr), true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
service, err = composeV2.NewComposeService()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
service.SetProject(project)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func upApp(appInstall *model.AppInstall) {
|
||||||
|
upProject := func(appInstall *model.AppInstall) (err error) {
|
||||||
|
if err == nil {
|
||||||
|
var composeService *composeV2.ComposeService
|
||||||
|
composeService, err = getServiceFromInstall(appInstall)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = composeService.ComposeUp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := upProject(appInstall); err != nil {
|
||||||
appInstall.Status = constant.Error
|
appInstall.Status = constant.Error
|
||||||
_ = appInstallRepo.Save(&appInstall)
|
appInstall.Message = err.Error()
|
||||||
} else {
|
} else {
|
||||||
appInstall.Status = constant.Running
|
appInstall.Status = constant.Running
|
||||||
_ = appInstallRepo.Save(&appInstall)
|
}
|
||||||
|
exist, _ := appInstallRepo.GetFirst(commonRepo.WithByID(appInstall.ID))
|
||||||
|
if exist.ID > 0 {
|
||||||
|
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,20 +491,29 @@ func getAppDetails(details []model.AppDetail, versions []string) map[string]mode
|
|||||||
return appDetails
|
return appDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
|
func getApps(oldApps []model.App, items []dto.AppDefine, isLocal bool) map[string]model.App {
|
||||||
apps := make(map[string]model.App, len(oldApps))
|
apps := make(map[string]model.App, len(oldApps))
|
||||||
for _, old := range oldApps {
|
for _, old := range oldApps {
|
||||||
old.Status = constant.AppTakeDown
|
old.Status = constant.AppTakeDown
|
||||||
apps[old.Key] = old
|
apps[old.Key] = old
|
||||||
}
|
}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
app, ok := apps[item.Key]
|
key := item.Key
|
||||||
|
if isLocal {
|
||||||
|
key = "local" + key
|
||||||
|
}
|
||||||
|
app, ok := apps[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
app = model.App{}
|
app = model.App{}
|
||||||
}
|
}
|
||||||
|
if isLocal {
|
||||||
|
app.Resource = constant.AppResourceLocal
|
||||||
|
} else {
|
||||||
|
app.Resource = constant.AppResourceRemote
|
||||||
|
}
|
||||||
app.Name = item.Name
|
app.Name = item.Name
|
||||||
app.Limit = item.Limit
|
app.Limit = item.Limit
|
||||||
app.Key = item.Key
|
app.Key = key
|
||||||
app.ShortDescZh = item.ShortDescZh
|
app.ShortDescZh = item.ShortDescZh
|
||||||
app.ShortDescEn = item.ShortDescEn
|
app.ShortDescEn = item.ShortDescEn
|
||||||
app.Website = item.Website
|
app.Website = item.Website
|
||||||
@ -413,7 +523,7 @@ func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
|
|||||||
app.CrossVersionUpdate = item.CrossVersionUpdate
|
app.CrossVersionUpdate = item.CrossVersionUpdate
|
||||||
app.Required = item.GetRequired()
|
app.Required = item.GetRequired()
|
||||||
app.Status = constant.AppNormal
|
app.Status = constant.AppNormal
|
||||||
apps[item.Key] = app
|
apps[key] = app
|
||||||
}
|
}
|
||||||
return apps
|
return apps
|
||||||
}
|
}
|
||||||
@ -426,7 +536,7 @@ func handleErr(install model.AppInstall, err error, out string) error {
|
|||||||
reErr = errors.New(out)
|
reErr = errors.New(out)
|
||||||
install.Status = constant.Error
|
install.Status = constant.Error
|
||||||
}
|
}
|
||||||
_ = appInstallRepo.Save(&install)
|
_ = appInstallRepo.Save(context.Background(), &install)
|
||||||
return reErr
|
return reErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,7 +611,7 @@ func getAppInstallByKey(key string) (model.AppInstall, error) {
|
|||||||
return appInstall, nil
|
return appInstall, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateToolApp(installed model.AppInstall) {
|
func updateToolApp(installed *model.AppInstall) {
|
||||||
tooKey, ok := dto.AppToolMap[installed.App.Key]
|
tooKey, ok := dto.AppToolMap[installed.App.Key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@ -537,7 +647,7 @@ func updateToolApp(installed model.AppInstall) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
toolInstall.Env = string(contentByte)
|
toolInstall.Env = string(contentByte)
|
||||||
if err := appInstallRepo.Save(&toolInstall); err != nil {
|
if err := appInstallRepo.Save(context.Background(), &toolInstall); err != nil {
|
||||||
global.LOG.Errorf("update tool app [%s] error : %s", toolInstall.Name, err.Error())
|
global.LOG.Errorf("update tool app [%s] error : %s", toolInstall.Name, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ type IAuthService interface {
|
|||||||
SafeEntrance(c *gin.Context, code string) error
|
SafeEntrance(c *gin.Context, code string) error
|
||||||
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
||||||
LogOut(c *gin.Context) error
|
LogOut(c *gin.Context) error
|
||||||
|
MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAuthService() IAuthService {
|
func NewIAuthService() IAuthService {
|
||||||
@ -86,9 +87,9 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
|
|||||||
}
|
}
|
||||||
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
|
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
|
||||||
if err != nil {
|
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
|
return nil, constant.ErrAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +119,7 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
|
|||||||
j := jwt.NewJWT()
|
j := jwt.NewJWT()
|
||||||
claims := j.CreateClaims(jwt.BaseClaims{
|
claims := j.CreateClaims(jwt.BaseClaims{
|
||||||
Name: name,
|
Name: name,
|
||||||
}, lifeTime)
|
})
|
||||||
token, err := j.CreateToken(claims)
|
token, err := j.CreateToken(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||||
@ -26,7 +27,7 @@ type IBackupService interface {
|
|||||||
Create(backupDto dto.BackupOperate) error
|
Create(backupDto dto.BackupOperate) error
|
||||||
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
||||||
Update(ireq dto.BackupOperate) error
|
Update(ireq dto.BackupOperate) error
|
||||||
BatchDelete(ids []uint) error
|
Delete(id uint) error
|
||||||
BatchDeleteRecord(ids []uint) error
|
BatchDeleteRecord(ids []uint) error
|
||||||
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
|
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
|
||||||
|
|
||||||
@ -53,36 +54,13 @@ func NewIBackupService() IBackupService {
|
|||||||
func (u *BackupService) List() ([]dto.BackupInfo, error) {
|
func (u *BackupService) List() ([]dto.BackupInfo, error) {
|
||||||
ops, err := backupRepo.List(commonRepo.WithOrderBy("created_at desc"))
|
ops, err := backupRepo.List(commonRepo.WithOrderBy("created_at desc"))
|
||||||
var dtobas []dto.BackupInfo
|
var dtobas []dto.BackupInfo
|
||||||
ossExist, s3Exist, sftpExist, minioExist := false, false, false, false
|
dtobas = append(dtobas, u.loadByType("LOCAL", ops))
|
||||||
for _, group := range ops {
|
dtobas = append(dtobas, u.loadByType("OSS", ops))
|
||||||
switch group.Type {
|
dtobas = append(dtobas, u.loadByType("S3", ops))
|
||||||
case "OSS":
|
dtobas = append(dtobas, u.loadByType("SFTP", ops))
|
||||||
ossExist = true
|
dtobas = append(dtobas, u.loadByType("MINIO", ops))
|
||||||
case "S3":
|
dtobas = append(dtobas, u.loadByType("COS", ops))
|
||||||
s3Exist = true
|
dtobas = append(dtobas, u.loadByType("KODO", ops))
|
||||||
case "SFTP":
|
|
||||||
sftpExist = true
|
|
||||||
case "MINIO":
|
|
||||||
minioExist = true
|
|
||||||
}
|
|
||||||
var item dto.BackupInfo
|
|
||||||
if err := copier.Copy(&item, &group); err != nil {
|
|
||||||
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
|
||||||
}
|
|
||||||
dtobas = append(dtobas, item)
|
|
||||||
}
|
|
||||||
if !ossExist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "OSS"})
|
|
||||||
}
|
|
||||||
if !s3Exist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "S3"})
|
|
||||||
}
|
|
||||||
if !sftpExist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "SFTP"})
|
|
||||||
}
|
|
||||||
if !minioExist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "MINIO"})
|
|
||||||
}
|
|
||||||
return dtobas, err
|
return dtobas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +101,7 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
|
|||||||
case constant.Sftp:
|
case constant.Sftp:
|
||||||
varMap["username"] = backup.AccessKey
|
varMap["username"] = backup.AccessKey
|
||||||
varMap["password"] = backup.Credential
|
varMap["password"] = backup.Credential
|
||||||
case constant.OSS, constant.S3, constant.MinIo:
|
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||||
varMap["accessKey"] = backup.AccessKey
|
varMap["accessKey"] = backup.AccessKey
|
||||||
varMap["secretKey"] = backup.Credential
|
varMap["secretKey"] = backup.Credential
|
||||||
}
|
}
|
||||||
@ -171,7 +149,7 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
|
|||||||
case constant.Sftp:
|
case constant.Sftp:
|
||||||
varMap["username"] = backupDto.AccessKey
|
varMap["username"] = backupDto.AccessKey
|
||||||
varMap["password"] = backupDto.Credential
|
varMap["password"] = backupDto.Credential
|
||||||
case constant.OSS, constant.S3, constant.MinIo:
|
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||||
varMap["accessKey"] = backupDto.AccessKey
|
varMap["accessKey"] = backupDto.AccessKey
|
||||||
varMap["secretKey"] = backupDto.Credential
|
varMap["secretKey"] = backupDto.Credential
|
||||||
}
|
}
|
||||||
@ -182,8 +160,12 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
|
|||||||
return client.ListBuckets()
|
return client.ListBuckets()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) BatchDelete(ids []uint) error {
|
func (u *BackupService) Delete(id uint) error {
|
||||||
return backupRepo.Delete(commonRepo.WithIdsIn(ids))
|
cronjobs, _ := cronjobRepo.List(cronjobRepo.WithByBackupID(id))
|
||||||
|
if len(cronjobs) != 0 {
|
||||||
|
return buserr.New(constant.ErrBackupInUsed)
|
||||||
|
}
|
||||||
|
return backupRepo.Delete(commonRepo.WithByID(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) BatchDeleteRecord(ids []uint) error {
|
func (u *BackupService) BatchDeleteRecord(ids []uint) error {
|
||||||
@ -277,7 +259,7 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
|
|||||||
case constant.Sftp:
|
case constant.Sftp:
|
||||||
varMap["username"] = backup.AccessKey
|
varMap["username"] = backup.AccessKey
|
||||||
varMap["password"] = backup.Credential
|
varMap["password"] = backup.Credential
|
||||||
case constant.OSS, constant.S3, constant.MinIo:
|
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||||
varMap["accessKey"] = backup.AccessKey
|
varMap["accessKey"] = backup.AccessKey
|
||||||
varMap["secretKey"] = backup.Credential
|
varMap["secretKey"] = backup.Credential
|
||||||
}
|
}
|
||||||
@ -290,6 +272,19 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
|
|||||||
return backClient, nil
|
return backClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) loadByType(accountType string, accounts []model.BackupAccount) dto.BackupInfo {
|
||||||
|
for _, account := range accounts {
|
||||||
|
if account.Type == accountType {
|
||||||
|
var item dto.BackupInfo
|
||||||
|
if err := copier.Copy(&item, &account); err != nil {
|
||||||
|
global.LOG.Errorf("copy backup account to dto backup info failed, err: %v", err)
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dto.BackupInfo{Type: accountType}
|
||||||
|
}
|
||||||
|
|
||||||
func loadLocalDir() (string, error) {
|
func loadLocalDir() (string, error) {
|
||||||
backup, err := backupRepo.Get(commonRepo.WithByType("LOCAL"))
|
backup, err := backupRepo.Get(commonRepo.WithByType("LOCAL"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
@ -32,6 +33,7 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
timeNow := time.Now().Format("20060102150405")
|
timeNow := time.Now().Format("20060102150405")
|
||||||
|
|
||||||
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, req.Name, req.DetailName)
|
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, req.Name, req.DetailName)
|
||||||
|
|
||||||
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow)
|
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow)
|
||||||
@ -97,7 +99,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
appPath := fmt.Sprintf("%s/%s/%s", constant.AppInstallDir, install.App.Key, install.Name)
|
appPath := fmt.Sprintf("%s/%s", install.GetPath(), install.Name)
|
||||||
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
|
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -192,7 +194,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
|||||||
}
|
}
|
||||||
|
|
||||||
oldInstall.Status = constant.Running
|
oldInstall.Status = constant.Running
|
||||||
if err := appInstallRepo.Save(install); err != nil {
|
if err := appInstallRepo.Save(context.Background(), install); err != nil {
|
||||||
global.LOG.Errorf("save db app install failed, err: %v", err)
|
global.LOG.Errorf("save db app install failed, err: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -176,11 +175,11 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
|||||||
if appendonly == "yes" && redisInfo.Version == "6.0.16" {
|
if appendonly == "yes" && redisInfo.Version == "6.0.16" {
|
||||||
itemName = "appendonly.aof"
|
itemName = "appendonly.aof"
|
||||||
}
|
}
|
||||||
input, err := ioutil.ReadFile(recoverFile)
|
input, err := os.ReadFile(recoverFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = ioutil.WriteFile(composeDir+"/data/"+itemName, input, 0640); err != nil {
|
if err = os.WriteFile(composeDir+"/data/"+itemName, input, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -21,6 +22,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
@ -33,7 +35,7 @@ type IContainerService interface {
|
|||||||
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
ListVolume() ([]dto.Options, error)
|
ListVolume() ([]dto.Options, error)
|
||||||
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
CreateCompose(req dto.ComposeCreate) error
|
CreateCompose(req dto.ComposeCreate) (string, error)
|
||||||
ComposeOperation(req dto.ComposeOperation) error
|
ComposeOperation(req dto.ComposeOperation) error
|
||||||
ContainerCreate(req dto.ContainerCreate) error
|
ContainerCreate(req dto.ContainerCreate) error
|
||||||
ContainerOperation(req dto.ContainerOperation) error
|
ContainerOperation(req dto.ContainerOperation) error
|
||||||
@ -44,6 +46,8 @@ type IContainerService interface {
|
|||||||
CreateNetwork(req dto.NetworkCreat) error
|
CreateNetwork(req dto.NetworkCreat) error
|
||||||
DeleteVolume(req dto.BatchDelete) error
|
DeleteVolume(req dto.BatchDelete) error
|
||||||
CreateVolume(req dto.VolumeCreat) error
|
CreateVolume(req dto.VolumeCreat) error
|
||||||
|
TestCompose(req dto.ComposeCreate) (bool, error)
|
||||||
|
ComposeUpdate(req dto.ComposeUpdate) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIContainerService() IContainerService {
|
func NewIContainerService() IContainerService {
|
||||||
@ -155,10 +159,12 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
config := &container.Config{
|
config := &container.Config{
|
||||||
Image: req.Image,
|
Image: req.Image,
|
||||||
Cmd: req.Cmd,
|
Cmd: req.Cmd,
|
||||||
Env: req.Env,
|
Env: req.Env,
|
||||||
Labels: stringsToMap(req.Labels),
|
Labels: stringsToMap(req.Labels),
|
||||||
|
Tty: true,
|
||||||
|
OpenStdin: true,
|
||||||
}
|
}
|
||||||
hostConf := &container.HostConfig{
|
hostConf := &container.HostConfig{
|
||||||
AutoRemove: req.AutoRemove,
|
AutoRemove: req.AutoRemove,
|
||||||
@ -190,14 +196,21 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
|
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 !checkImageExist(client, req.Image) {
|
||||||
|
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 {
|
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
|
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)
|
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 {
|
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); 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 fmt.Errorf("create successful but start failed, err: %v", err)
|
return fmt.Errorf("create successful but start failed, err: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -215,9 +228,9 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
|
|||||||
case constant.ContainerOpStart:
|
case constant.ContainerOpStart:
|
||||||
err = client.ContainerStart(ctx, req.Name, types.ContainerStartOptions{})
|
err = client.ContainerStart(ctx, req.Name, types.ContainerStartOptions{})
|
||||||
case constant.ContainerOpStop:
|
case constant.ContainerOpStop:
|
||||||
err = client.ContainerStop(ctx, req.Name, nil)
|
err = client.ContainerStop(ctx, req.Name, container.StopOptions{})
|
||||||
case constant.ContainerOpRestart:
|
case constant.ContainerOpRestart:
|
||||||
err = client.ContainerRestart(ctx, req.Name, nil)
|
err = client.ContainerRestart(ctx, req.Name, container.StopOptions{})
|
||||||
case constant.ContainerOpKill:
|
case constant.ContainerOpKill:
|
||||||
err = client.ContainerKill(ctx, req.Name, "SIGKILL")
|
err = client.ContainerKill(ctx, req.Name, "SIGKILL")
|
||||||
case constant.ContainerOpPause:
|
case constant.ContainerOpPause:
|
||||||
@ -239,7 +252,7 @@ func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) {
|
|||||||
}
|
}
|
||||||
stdout, err := cmd.CombinedOutput()
|
stdout, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", errors.New(string(stdout))
|
||||||
}
|
}
|
||||||
return string(stdout), nil
|
return string(stdout), nil
|
||||||
}
|
}
|
||||||
@ -255,7 +268,7 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainterStats, erro
|
|||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -320,3 +333,33 @@ func calculateNetwork(network map[string]types.NetworkStats) (float64, float64)
|
|||||||
}
|
}
|
||||||
return rx, tx
|
return rx, tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkImageExist(client *client.Client, image string) bool {
|
||||||
|
images, err := client.ImageList(context.Background(), types.ImageListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, img := range images {
|
||||||
|
for _, tag := range img.RepoTags {
|
||||||
|
if tag == image || tag == image+":latest" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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(io.Discard, out)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -123,41 +125,49 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
|
|||||||
return int64(total), BackDatas, nil
|
return int64(total), BackDatas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
|
func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
|
||||||
if req.From == "template" {
|
if err := u.loadPath(&req); err != nil {
|
||||||
template, err := composeRepo.Get(commonRepo.WithByID(req.Template))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
req.From = "edit"
|
|
||||||
req.File = template.Content
|
|
||||||
}
|
}
|
||||||
if req.From == "edit" {
|
cmd := exec.Command("docker-compose", "-f", req.Path, "config")
|
||||||
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
|
stdout, err := cmd.CombinedOutput()
|
||||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
if err != nil {
|
||||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
return false, errors.New(string(stdout))
|
||||||
return err
|
}
|
||||||
}
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/docker-compose.yml", dir)
|
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error) {
|
||||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
if err := u.loadPath(&req); err != nil {
|
||||||
if err != nil {
|
return "", err
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
write := bufio.NewWriter(file)
|
|
||||||
_, _ = write.WriteString(string(req.File))
|
|
||||||
write.Flush()
|
|
||||||
req.Path = path
|
|
||||||
}
|
}
|
||||||
global.LOG.Infof("docker-compose.yml %s create successful, start to docker-compose up", req.Name)
|
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})
|
if req.From == "path" {
|
||||||
return nil
|
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 {
|
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
||||||
@ -199,3 +209,34 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
|||||||
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
)
|
)
|
||||||
@ -37,14 +36,14 @@ func (u *ContainerService) PageVolume(req dto.SearchWithPage) (int64, interface{
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
data []dto.Volume
|
data []dto.Volume
|
||||||
records []*types.Volume
|
records []*volume.Volume
|
||||||
)
|
)
|
||||||
sort.Slice(list.Volumes, func(i, j int) bool {
|
sort.Slice(list.Volumes, func(i, j int) bool {
|
||||||
return list.Volumes[i].CreatedAt > list.Volumes[j].CreatedAt
|
return list.Volumes[i].CreatedAt > list.Volumes[j].CreatedAt
|
||||||
})
|
})
|
||||||
total, start, end := len(list.Volumes), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
total, start, end := len(list.Volumes), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||||
if start > total {
|
if start > total {
|
||||||
records = make([]*types.Volume, 0)
|
records = make([]*volume.Volume, 0)
|
||||||
} else {
|
} else {
|
||||||
if end >= total {
|
if end >= total {
|
||||||
end = total
|
end = total
|
||||||
@ -119,7 +118,7 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreat) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
options := volume.VolumeCreateBody{
|
options := volume.CreateOptions{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Driver: req.Driver,
|
Driver: req.Driver,
|
||||||
DriverOpts: stringsToMap(req.Options),
|
DriverOpts: stringsToMap(req.Options),
|
||||||
|
@ -2,17 +2,15 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
@ -27,7 +25,10 @@ type ICronjobService interface {
|
|||||||
HandleOnce(id uint) error
|
HandleOnce(id uint) error
|
||||||
Update(id uint, req dto.CronjobUpdate) error
|
Update(id uint, req dto.CronjobUpdate) error
|
||||||
UpdateStatus(id uint, status string) error
|
UpdateStatus(id uint, status string) error
|
||||||
Delete(ids []uint) error
|
Delete(req dto.CronjobBatchDelete) error
|
||||||
|
Download(down dto.CronjobDownload) (string, error)
|
||||||
|
StartJob(cronjob *model.Cronjob) (int, error)
|
||||||
|
CleanRecord(req dto.CronjobClean) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICronjobService() ICronjobService {
|
func NewICronjobService() ICronjobService {
|
||||||
@ -79,6 +80,44 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
|
|||||||
return total, dtoCronjobs, err
|
return total, dtoCronjobs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
||||||
|
cronjob, err := cronjobRepo.Get(commonRepo.WithByID(req.CronjobID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.CleanData && cronjob.Type != "shell" && cronjob.Type != "curl" {
|
||||||
|
cronjob.RetainCopies = 0
|
||||||
|
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
localDir, err := loadLocalDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
client, err := NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
|
||||||
|
} else {
|
||||||
|
u.HandleRmExpired(backup.Type, "", &cronjob, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delRecords, err := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(req.CronjobID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, del := range delRecords {
|
||||||
|
_ = os.RemoveAll(del.Records)
|
||||||
|
}
|
||||||
|
if err := cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(req.CronjobID))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
||||||
record, _ := cronjobRepo.GetRecord(commonRepo.WithByID(down.RecordID))
|
record, _ := cronjobRepo.GetRecord(commonRepo.WithByID(down.RecordID))
|
||||||
if record.ID == 0 {
|
if record.ID == 0 {
|
||||||
@ -92,69 +131,23 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
|||||||
if cronjob.ID == 0 {
|
if cronjob.ID == 0 {
|
||||||
return "", constant.ErrRecordNotFound
|
return "", constant.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
|
if backup.Type == "LOCAL" || record.FromLocal {
|
||||||
global.LOG.Infof("start to download records %s from %s", cronjob.Type, backup.Type)
|
if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) {
|
||||||
varMap := make(map[string]interface{})
|
return "", constant.ErrRecordNotFound
|
||||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
}
|
||||||
|
return record.File, nil
|
||||||
|
}
|
||||||
|
client, err := NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
varMap["type"] = backup.Type
|
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, record.File)
|
||||||
if backup.Type != "LOCAL" {
|
_ = os.MkdirAll(path.Dir(tempPath), os.ModePerm)
|
||||||
varMap["bucket"] = backup.Bucket
|
isOK, err := client.Download(record.File, tempPath)
|
||||||
switch backup.Type {
|
if !isOK || err != nil {
|
||||||
case constant.Sftp:
|
return "", constant.ErrRecordNotFound
|
||||||
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 {
|
|
||||||
global.LOG.Errorf("mkdir %s failed, err: %v", tempPath, 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)
|
|
||||||
}
|
}
|
||||||
|
return tempPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) HandleOnce(id uint) error {
|
func (u *CronjobService) HandleOnce(id uint) error {
|
||||||
@ -201,21 +194,23 @@ func (u *CronjobService) StartJob(cronjob *model.Cronjob) (int, error) {
|
|||||||
return entryID, nil
|
return entryID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) Delete(ids []uint) error {
|
func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||||
if len(ids) == 1 {
|
for _, id := range req.IDs {
|
||||||
if err := u.HandleDelete(ids[0]); err != nil {
|
cronjob, _ := cronjobRepo.Get(commonRepo.WithByID(id))
|
||||||
|
if cronjob.ID == 0 {
|
||||||
|
return errors.New("find cronjob in db failed")
|
||||||
|
}
|
||||||
|
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||||
|
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||||
|
if err := u.CleanRecord(dto.CronjobClean{CronjobID: id, CleanData: req.CleanData}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cronjobRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return cronjobRepo.Delete(commonRepo.WithByID(ids[0]))
|
|
||||||
}
|
}
|
||||||
cronjobs, err := cronjobRepo.List(commonRepo.WithIdsIn(ids))
|
|
||||||
if err != nil {
|
return nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
for i := range cronjobs {
|
|
||||||
_ = u.HandleDelete(ids[i])
|
|
||||||
}
|
|
||||||
return cronjobRepo.Delete(commonRepo.WithIdsIn(ids))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||||
@ -238,6 +233,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
|||||||
upMap := make(map[string]interface{})
|
upMap := make(map[string]interface{})
|
||||||
upMap["entry_id"] = newEntryID
|
upMap["entry_id"] = newEntryID
|
||||||
upMap["name"] = req.Name
|
upMap["name"] = req.Name
|
||||||
|
upMap["spec"] = cronjob.Spec
|
||||||
upMap["script"] = req.Script
|
upMap["script"] = req.Script
|
||||||
upMap["spec_type"] = req.SpecType
|
upMap["spec_type"] = req.SpecType
|
||||||
upMap["week"] = req.Week
|
upMap["week"] = req.Week
|
||||||
|
@ -3,18 +3,18 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/robfig/cron/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||||
@ -22,19 +22,19 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
|||||||
message []byte
|
message []byte
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
record := cronjobRepo.StartRecords(cronjob.ID, "")
|
record := cronjobRepo.StartRecords(cronjob.ID, cronjob.KeepLocal, "")
|
||||||
record.FromLocal = cronjob.KeepLocal
|
|
||||||
go func() {
|
go func() {
|
||||||
switch cronjob.Type {
|
switch cronjob.Type {
|
||||||
case "shell":
|
case "shell":
|
||||||
if len(cronjob.Script) == 0 {
|
if len(cronjob.Script) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stdout, errExec := cmd.Exec(cronjob.Script)
|
stdout, errExec := cmd.ExecWithTimeOut(cronjob.Script, 5*time.Minute)
|
||||||
if errExec != nil {
|
if errExec != nil {
|
||||||
err = errExec
|
err = errExec
|
||||||
}
|
}
|
||||||
message = []byte(stdout)
|
message = []byte(stdout)
|
||||||
|
u.HandleRmExpired("LOCAL", "", cronjob, nil)
|
||||||
case "website":
|
case "website":
|
||||||
record.File, err = u.HandleBackup(cronjob, record.StartTime)
|
record.File, err = u.HandleBackup(cronjob, record.StartTime)
|
||||||
case "database":
|
case "database":
|
||||||
@ -48,11 +48,12 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
|||||||
if len(cronjob.URL) == 0 {
|
if len(cronjob.URL) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stdout, errCurl := cmd.Exec("curl " + cronjob.URL)
|
stdout, errCurl := cmd.ExecWithTimeOut("curl "+cronjob.URL, 5*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errCurl
|
err = errCurl
|
||||||
}
|
}
|
||||||
message = []byte(stdout)
|
message = []byte(stdout)
|
||||||
|
u.HandleRmExpired("LOCAL", "", cronjob, nil)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
||||||
@ -69,11 +70,6 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
|
func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
|
||||||
var (
|
|
||||||
backupDir string
|
|
||||||
fileName string
|
|
||||||
record model.BackupRecord
|
|
||||||
)
|
|
||||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -90,141 +86,60 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
fileName = fmt.Sprintf("db_%s_%s.sql.gz", cronjob.DBName, startTime.Format("20060102150405"))
|
paths, err := u.handleDatabase(*cronjob, app, backup, startTime)
|
||||||
backupDir = fmt.Sprintf("%s/database/mysql/%s/%s", localDir, app.Name, cronjob.DBName)
|
return strings.Join(paths, ","), err
|
||||||
if err = handleMysqlBackup(app, backupDir, cronjob.DBName, fileName); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
record.Type = "mysql"
|
|
||||||
record.Name = app.Name
|
|
||||||
record.DetailName = cronjob.DBName
|
|
||||||
case "website":
|
case "website":
|
||||||
fileName = fmt.Sprintf("website_%s_%s.tar.gz", cronjob.Website, startTime.Format("20060102150405"))
|
paths, err := u.handleWebsite(*cronjob, backup, startTime)
|
||||||
backupDir = fmt.Sprintf("%s/website/%s", localDir, cronjob.Website)
|
return strings.Join(paths, ","), err
|
||||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(cronjob.Website))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
record.Type = "website"
|
|
||||||
record.Name = website.PrimaryDomain
|
|
||||||
default:
|
default:
|
||||||
fileName = fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format("20060102150405"))
|
fileName := fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format("20060102150405"))
|
||||||
backupDir = fmt.Sprintf("%s/%s/%s", localDir, cronjob.Type, cronjob.Name)
|
backupDir := fmt.Sprintf("%s/%s/%s", localDir, cronjob.Type, cronjob.Name)
|
||||||
|
itemFileDir := fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name)
|
||||||
global.LOG.Infof("handle tar %s to %s", backupDir, fileName)
|
global.LOG.Infof("handle tar %s to %s", backupDir, fileName)
|
||||||
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil {
|
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
var client cloud_storage.CloudStorageClient
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
if !cronjob.KeepLocal {
|
||||||
if len(record.Name) != 0 {
|
defer func() {
|
||||||
record.FileName = fileName
|
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, fileName))
|
||||||
record.FileDir = backupDir
|
}()
|
||||||
record.Source = "LOCAL"
|
}
|
||||||
record.BackupType = backup.Type
|
client, err = NewIBackupService().NewClient(&backup)
|
||||||
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
if err != nil {
|
||||||
record.Source = backup.Type
|
return "", err
|
||||||
record.FileDir = itemFileDir
|
}
|
||||||
}
|
if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil {
|
||||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
return "", err
|
||||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fullPath := fmt.Sprintf("%s/%s", record.FileDir, fileName)
|
|
||||||
if backup.Type == "LOCAL" {
|
|
||||||
u.HandleRmExpired(backup.Type, backupDir, cronjob, nil)
|
|
||||||
return fullPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cronjob.KeepLocal {
|
|
||||||
defer func() {
|
|
||||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, fileName))
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
client, err := NewIBackupService().NewClient(&backup)
|
|
||||||
if err != nil {
|
|
||||||
return fullPath, err
|
|
||||||
}
|
|
||||||
if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil {
|
|
||||||
return fullPath, err
|
|
||||||
}
|
|
||||||
u.HandleRmExpired(backup.Type, itemFileDir, cronjob, client)
|
|
||||||
if cronjob.KeepLocal {
|
|
||||||
u.HandleRmExpired("LOCAL", backupDir, cronjob, client)
|
|
||||||
}
|
|
||||||
return fullPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *CronjobService) HandleDelete(id uint) error {
|
|
||||||
cronjob, _ := cronjobRepo.Get(commonRepo.WithByID(id))
|
|
||||||
if cronjob.ID == 0 {
|
|
||||||
return errors.New("find cronjob in db failed")
|
|
||||||
}
|
|
||||||
commonDir := fmt.Sprintf("%s/%s/", cronjob.Type, cronjob.Name)
|
|
||||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
|
||||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
|
||||||
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(id)))
|
|
||||||
|
|
||||||
dir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronjob.Type, cronjob.Name)
|
|
||||||
if _, err := os.Stat(dir); err == nil {
|
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
|
||||||
global.LOG.Errorf("rm file %s/task/%s failed, err: %v", constant.DataDir, commonDir, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *CronjobService) HandleRmExpired(backType, backupDir string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) {
|
|
||||||
global.LOG.Infof("start to handle remove expired, retain copies: %d", cronjob.RetainCopies)
|
|
||||||
if backType != "LOCAL" {
|
|
||||||
currentObjs, err := backClient.ListObjects(backupDir + "/")
|
|
||||||
if err != nil {
|
|
||||||
global.LOG.Errorf("list bucket object %s failed, err: %v", backupDir, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := 0; i < len(currentObjs)-int(cronjob.RetainCopies); i++ {
|
|
||||||
_, _ = backClient.Delete(currentObjs[i].(string))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
files, err := ioutil.ReadDir(backupDir)
|
|
||||||
if err != nil {
|
|
||||||
global.LOG.Errorf("read dir %s failed, err: %v", backupDir, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(files) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix := ""
|
|
||||||
switch cronjob.Type {
|
|
||||||
case "database":
|
|
||||||
prefix = "db_"
|
|
||||||
case "website":
|
|
||||||
prefix = "website_"
|
|
||||||
case "directory":
|
|
||||||
prefix = "directory_"
|
|
||||||
}
|
|
||||||
|
|
||||||
dbCopies := uint64(0)
|
|
||||||
for i := len(files) - 1; i >= 0; i-- {
|
|
||||||
if strings.HasPrefix(files[i].Name(), prefix) {
|
|
||||||
dbCopies++
|
|
||||||
if dbCopies > cronjob.RetainCopies {
|
|
||||||
_ = os.Remove(backupDir + "/" + files[i].Name())
|
|
||||||
_ = backupRepo.DeleteRecord(context.Background(), backupRepo.WithByFileName(files[i].Name()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, cronjob, client)
|
||||||
|
if backup.Type == "LOCAL" || cronjob.KeepLocal {
|
||||||
|
return fmt.Sprintf("%s/%s/%s/%s", localDir, cronjob.Type, cronjob.Name, fileName), nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s/%s/%s", cronjob.Type, cronjob.Name, fileName), nil
|
||||||
}
|
}
|
||||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)))
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) HandleRmExpired(backType, localDir string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) {
|
||||||
|
global.LOG.Infof("start to handle remove expired, retain copies: %d", cronjob.RetainCopies)
|
||||||
|
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), commonRepo.WithOrderBy("created_at desc"))
|
||||||
if len(records) > int(cronjob.RetainCopies) {
|
if len(records) > int(cronjob.RetainCopies) {
|
||||||
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
||||||
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(records[i].ID)))
|
files := strings.Split(records[i].File, ",")
|
||||||
|
for _, file := range files {
|
||||||
|
if backType != "LOCAL" {
|
||||||
|
_, _ = backClient.Delete(strings.ReplaceAll(file, localDir+"/", ""))
|
||||||
|
_ = os.Remove(file)
|
||||||
|
} else {
|
||||||
|
_ = os.Remove(file)
|
||||||
|
}
|
||||||
|
_ = backupRepo.DeleteRecord(context.TODO(), backupRepo.WithByFileName(path.Base(file)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = cronjobRepo.DeleteRecord(commonRepo.WithByID(uint(records[i].ID)))
|
||||||
|
_ = os.Remove(records[i].Records)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,7 +170,7 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar zcvf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
commands := fmt.Sprintf("tar zcvf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 5*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
@ -272,10 +187,144 @@ func handleUnTar(sourceFile, targetDir string) error {
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir)
|
commands := fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 5*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, app *repo.RootInfo, backup model.BackupAccount, startTime time.Time) ([]string, error) {
|
||||||
|
var paths []string
|
||||||
|
localDir, err := loadLocalDir()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var dblist []string
|
||||||
|
if cronjob.DBName == "all" {
|
||||||
|
mysqlService := NewIMysqlService()
|
||||||
|
dblist, err = mysqlService.ListDBName()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dblist = append(dblist, cronjob.DBName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var client cloud_storage.CloudStorageClient
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
client, err = NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dbName := range dblist {
|
||||||
|
var record model.BackupRecord
|
||||||
|
|
||||||
|
record.Type = "mysql"
|
||||||
|
record.Name = app.Name
|
||||||
|
record.Source = "LOCAL"
|
||||||
|
record.BackupType = backup.Type
|
||||||
|
|
||||||
|
backupDir := fmt.Sprintf("%s/database/mysql/%s/%s", localDir, app.Name, dbName)
|
||||||
|
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbName, startTime.Format("20060102150405"))
|
||||||
|
if err = handleMysqlBackup(app, backupDir, dbName, record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
record.DetailName = dbName
|
||||||
|
record.FileDir = backupDir
|
||||||
|
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||||
|
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||||
|
record.Source = backup.Type
|
||||||
|
record.FileDir = itemFileDir
|
||||||
|
}
|
||||||
|
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
|
||||||
|
|
||||||
|
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||||
|
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
if !cronjob.KeepLocal {
|
||||||
|
defer func() {
|
||||||
|
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
|
||||||
|
return paths, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
|
||||||
|
var paths []string
|
||||||
|
localDir, err := loadLocalDir()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var weblist []string
|
||||||
|
if cronjob.Website == "all" {
|
||||||
|
weblist, err = NewIWebsiteService().GetWebsiteOptions()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
weblist = append(weblist, cronjob.Website)
|
||||||
|
}
|
||||||
|
|
||||||
|
var client cloud_storage.CloudStorageClient
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
client, err = NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, websiteItem := range weblist {
|
||||||
|
var record model.BackupRecord
|
||||||
|
record.Type = "website"
|
||||||
|
record.Name = cronjob.Website
|
||||||
|
record.Source = "LOCAL"
|
||||||
|
record.BackupType = backup.Type
|
||||||
|
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(websiteItem))
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
backupDir := fmt.Sprintf("%s/website/%s", localDir, website.PrimaryDomain)
|
||||||
|
record.FileDir = backupDir
|
||||||
|
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||||
|
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||||
|
record.Source = backup.Type
|
||||||
|
record.FileDir = strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||||
|
}
|
||||||
|
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", website.PrimaryDomain, startTime.Format("20060102150405"))
|
||||||
|
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
|
||||||
|
if err := handleWebsiteBackup(&website, backupDir, record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
record.Name = website.PrimaryDomain
|
||||||
|
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||||
|
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
if !cronjob.KeepLocal {
|
||||||
|
defer func() {
|
||||||
|
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
|
||||||
|
return paths, nil
|
||||||
|
}
|
||||||
|
@ -2,9 +2,11 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"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/cpu"
|
||||||
"github.com/shirou/gopsutil/v3/disk"
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
"github.com/shirou/gopsutil/v3/host"
|
"github.com/shirou/gopsutil/v3/host"
|
||||||
@ -39,27 +41,6 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
|
|||||||
ss, _ := json.Marshal(hostInfo)
|
ss, _ := json.Marshal(hostInfo)
|
||||||
baseInfo.VirtualizationSystem = string(ss)
|
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()
|
appInstall, err := appInstallRepo.ListBy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -120,15 +101,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
|||||||
currentInfo.MemoryUsed = memoryInfo.Used
|
currentInfo.MemoryUsed = memoryInfo.Used
|
||||||
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
||||||
|
|
||||||
state, _ := disk.Usage("/")
|
currentInfo.DiskData = loadDiskInfo()
|
||||||
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
|
|
||||||
|
|
||||||
if ioOption == "all" {
|
if ioOption == "all" {
|
||||||
diskInfo, _ := disk.IOCounters()
|
diskInfo, _ := disk.IOCounters()
|
||||||
@ -136,20 +109,17 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
|||||||
currentInfo.IOReadBytes += state.ReadBytes
|
currentInfo.IOReadBytes += state.ReadBytes
|
||||||
currentInfo.IOWriteBytes += state.WriteBytes
|
currentInfo.IOWriteBytes += state.WriteBytes
|
||||||
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
|
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
|
||||||
currentInfo.IOTime += state.ReadTime / 1000 / 1000
|
currentInfo.IOReadTime += state.ReadTime
|
||||||
if state.WriteTime > state.ReadTime {
|
currentInfo.IOWriteTime += state.WriteTime
|
||||||
currentInfo.IOTime += state.WriteTime / 1000 / 1000
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
diskInfo, _ := disk.IOCounters(ioOption)
|
diskInfo, _ := disk.IOCounters(ioOption)
|
||||||
for _, state := range diskInfo {
|
for _, state := range diskInfo {
|
||||||
currentInfo.IOReadBytes += state.ReadBytes
|
currentInfo.IOReadBytes += state.ReadBytes
|
||||||
currentInfo.IOWriteBytes += state.WriteBytes
|
currentInfo.IOWriteBytes += state.WriteBytes
|
||||||
currentInfo.IOTime += state.ReadTime / 1000 / 1000
|
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
|
||||||
if state.WriteTime > state.ReadTime {
|
currentInfo.IOReadTime += state.ReadTime
|
||||||
currentInfo.IOTime += state.WriteTime / 1000 / 1000
|
currentInfo.IOWriteTime += state.WriteTime
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,3 +142,67 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
|||||||
currentInfo.ShotTime = time.Now()
|
currentInfo.ShotTime = time.Now()
|
||||||
return ¤tInfo
|
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, err := disk.Usage(mounts[i].Mount)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -94,25 +93,28 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", req.Name, req.Format, formatMap[req.Format])
|
createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", req.Name, req.Format, formatMap[req.Format])
|
||||||
if err := excuteSql(app.ContainerName, app.Password, createSql); err != nil {
|
if err := excSQL(app.ContainerName, app.Password, createSql); err != nil {
|
||||||
if strings.Contains(err.Error(), "ERROR 1007") {
|
if strings.Contains(err.Error(), "ERROR 1007") {
|
||||||
return nil, buserr.New(constant.ErrDatabaseIsExist)
|
return nil, buserr.New(constant.ErrDatabaseIsExist)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tmpPermission := req.Permission
|
tmpPermission := req.Permission
|
||||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
|
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
|
||||||
_ = excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
|
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
|
||||||
if strings.Contains(err.Error(), "ERROR 1396") {
|
if strings.Contains(err.Error(), "ERROR 1396") {
|
||||||
return nil, buserr.New(constant.ErrUserIsExist)
|
return nil, buserr.New(constant.ErrUserIsExist)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", req.Name, req.Username, tmpPermission)
|
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", req.Name, req.Username, tmpPermission)
|
||||||
|
if req.Name == "*" {
|
||||||
|
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, tmpPermission)
|
||||||
|
}
|
||||||
if app.Version == "5.7.39" {
|
if app.Version == "5.7.39" {
|
||||||
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
|
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
|
||||||
}
|
}
|
||||||
if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
|
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,10 +163,10 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
|
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
|
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
|
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
|
||||||
@ -292,7 +294,10 @@ 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 {
|
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
|
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 mysql.Name == "*" {
|
||||||
|
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, info.Value)
|
||||||
|
}
|
||||||
if app.Version == "5.7.39" {
|
if app.Version == "5.7.39" {
|
||||||
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
|
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
|
||||||
}
|
}
|
||||||
@ -339,7 +344,7 @@ func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error
|
|||||||
var files []string
|
var files []string
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
|
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
|
||||||
lineBytes, err := ioutil.ReadFile(path)
|
lineBytes, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -509,6 +514,21 @@ func excuteSql(containerName, password, command string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func excSQL(containerName, password, command string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.CommandContext(ctx, "docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
|
||||||
|
err := cmd.Run()
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
return buserr.WithDetail(constant.ErrExecTimeOut, containerName, nil)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
stdStr := strings.ReplaceAll(err.Error(), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||||
|
return errors.New(stdStr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string {
|
func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string {
|
||||||
isOn := false
|
isOn := false
|
||||||
hasGroup := false
|
hasGroup := false
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -215,7 +214,7 @@ type redisConfig struct {
|
|||||||
|
|
||||||
func confSet(redisName string, changeConf []redisConfig) error {
|
func confSet(redisName string, changeConf []redisConfig) error {
|
||||||
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", constant.AppInstallDir, redisName)
|
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", constant.AppInstallDir, redisName)
|
||||||
lineBytes, err := ioutil.ReadFile(path)
|
lineBytes, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -35,6 +34,7 @@ type daemonJsonItem struct {
|
|||||||
Mirrors []string `json:"registry-mirrors"`
|
Mirrors []string `json:"registry-mirrors"`
|
||||||
Registries []string `json:"insecure-registries"`
|
Registries []string `json:"insecure-registries"`
|
||||||
LiveRestore bool `json:"live-restore"`
|
LiveRestore bool `json:"live-restore"`
|
||||||
|
IPTables bool `json:"iptables"`
|
||||||
ExecOpts []string `json:"exec-opts"`
|
ExecOpts []string `json:"exec-opts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,55 +49,60 @@ func (u *DockerService) LoadDockerStatus() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
||||||
status := constant.StatusRunning
|
var data dto.DaemonJsonConf
|
||||||
|
data.IPTables = true
|
||||||
|
data.Status = constant.StatusRunning
|
||||||
stdout, err := cmd.Exec("systemctl is-active docker")
|
stdout, err := cmd.Exec("systemctl is-active docker")
|
||||||
if string(stdout) != "active\n" || err != nil {
|
if string(stdout) != "active\n" || err != nil {
|
||||||
status = constant.Stopped
|
data.Status = constant.Stopped
|
||||||
}
|
}
|
||||||
version := "-"
|
data.IsSwarm = false
|
||||||
|
stdout2, _ := cmd.Exec("docker info | grep Swarm")
|
||||||
|
if string(stdout2) == " Swarm: active\n" {
|
||||||
|
data.IsSwarm = true
|
||||||
|
}
|
||||||
|
data.Version = "-"
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
itemVersion, err := client.ServerVersion(ctx)
|
itemVersion, err := client.ServerVersion(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
version = itemVersion.Version
|
data.Version = itemVersion.Version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
var conf daemonJsonItem
|
var conf daemonJsonItem
|
||||||
deamonMap := make(map[string]interface{})
|
deamonMap := make(map[string]interface{})
|
||||||
if err := json.Unmarshal(file, &deamonMap); err != nil {
|
if err := json.Unmarshal(file, &deamonMap); err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
arr, err := json.Marshal(deamonMap)
|
arr, err := json.Marshal(deamonMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(arr, &conf); err != nil {
|
if err := json.Unmarshal(arr, &conf); err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
driver := "cgroupfs"
|
if _, ok := deamonMap["iptables"]; !ok {
|
||||||
|
conf.IPTables = true
|
||||||
|
}
|
||||||
|
data.CgroupDriver = "cgroupfs"
|
||||||
for _, opt := range conf.ExecOpts {
|
for _, opt := range conf.ExecOpts {
|
||||||
if strings.HasPrefix(opt, "native.cgroupdriver=") {
|
if strings.HasPrefix(opt, "native.cgroupdriver=") {
|
||||||
driver = strings.ReplaceAll(opt, "native.cgroupdriver=", "")
|
data.CgroupDriver = strings.ReplaceAll(opt, "native.cgroupdriver=", "")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data := dto.DaemonJsonConf{
|
data.Mirrors = conf.Mirrors
|
||||||
Status: status,
|
data.Registries = conf.Registries
|
||||||
Version: version,
|
data.IPTables = conf.IPTables
|
||||||
Mirrors: conf.Mirrors,
|
data.LiveRestore = conf.LiveRestore
|
||||||
Registries: conf.Registries,
|
|
||||||
LiveRestore: conf.LiveRestore,
|
|
||||||
CgroupDriver: driver,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &data
|
return &data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +114,7 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
_, _ = os.Create(constant.DaemonJsonPath)
|
_, _ = os.Create(constant.DaemonJsonPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -131,6 +136,11 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
} else {
|
} else {
|
||||||
deamonMap["live-restore"] = req.LiveRestore
|
deamonMap["live-restore"] = req.LiveRestore
|
||||||
}
|
}
|
||||||
|
if req.IPTables {
|
||||||
|
delete(deamonMap, "iptables")
|
||||||
|
} else {
|
||||||
|
deamonMap["iptables"] = false
|
||||||
|
}
|
||||||
if opts, ok := deamonMap["exec-opts"]; ok {
|
if opts, ok := deamonMap["exec-opts"]; ok {
|
||||||
if optsValue, isArray := opts.([]interface{}); isArray {
|
if optsValue, isArray := opts.([]interface{}); isArray {
|
||||||
for i := 0; i < len(optsValue); i++ {
|
for i := 0; i < len(optsValue); i++ {
|
||||||
@ -147,11 +157,15 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
deamonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
|
deamonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(deamonMap) == 0 {
|
||||||
|
_ = os.Remove(constant.DaemonJsonPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
newJson, err := json.MarshalIndent(deamonMap, "", "\t")
|
newJson, err := json.MarshalIndent(deamonMap, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +177,16 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
|
func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
|
||||||
|
if len(req.File) == 0 {
|
||||||
|
_ = os.Remove(constant.DaemonJsonPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
|
||||||
|
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _ = os.Create(constant.DaemonJsonPath)
|
||||||
|
}
|
||||||
file, err := os.OpenFile(constant.DaemonJsonPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
file, err := os.OpenFile(constant.DaemonJsonPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2,78 +2,38 @@ package service
|
|||||||
|
|
||||||
import "github.com/1Panel-dev/1Panel/backend/app/repo"
|
import "github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
|
|
||||||
type ServiceGroup struct {
|
|
||||||
AuthService
|
|
||||||
DashboardService
|
|
||||||
|
|
||||||
AppService
|
|
||||||
AppInstallService
|
|
||||||
|
|
||||||
ContainerService
|
|
||||||
ImageService
|
|
||||||
ImageRepoService
|
|
||||||
ComposeTemplateService
|
|
||||||
DockerService
|
|
||||||
|
|
||||||
MysqlService
|
|
||||||
RedisService
|
|
||||||
|
|
||||||
CronjobService
|
|
||||||
|
|
||||||
HostService
|
|
||||||
GroupService
|
|
||||||
CommandService
|
|
||||||
FileService
|
|
||||||
|
|
||||||
SettingService
|
|
||||||
BackupService
|
|
||||||
|
|
||||||
WebsiteGroupService
|
|
||||||
WebsiteService
|
|
||||||
WebsiteDnsAccountService
|
|
||||||
WebsiteSSLService
|
|
||||||
WebsiteAcmeAccountService
|
|
||||||
|
|
||||||
NginxService
|
|
||||||
|
|
||||||
LogService
|
|
||||||
SnapshotService
|
|
||||||
UpgradeService
|
|
||||||
}
|
|
||||||
|
|
||||||
var ServiceGroupApp = new(ServiceGroup)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
commonRepo = repo.NewCommonRepo()
|
||||||
|
|
||||||
appRepo = repo.RepoGroupApp.AppRepo
|
appRepo = repo.NewIAppRepo()
|
||||||
appTagRepo = repo.RepoGroupApp.AppTagRepo
|
appTagRepo = repo.NewIAppTagRepo()
|
||||||
appDetailRepo = repo.RepoGroupApp.AppDetailRepo
|
appDetailRepo = repo.NewIAppDetailRepo()
|
||||||
tagRepo = repo.RepoGroupApp.TagRepo
|
tagRepo = repo.NewITagRepo()
|
||||||
appInstallRepo = repo.RepoGroupApp.AppInstallRepo
|
appInstallRepo = repo.NewIAppInstallRepo()
|
||||||
appInstallResourceRepo = repo.RepoGroupApp.AppInstallResourceRpo
|
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
|
||||||
|
|
||||||
mysqlRepo = repo.RepoGroupApp.MysqlRepo
|
mysqlRepo = repo.NewIMysqlRepo()
|
||||||
|
|
||||||
imageRepoRepo = repo.RepoGroupApp.ImageRepoRepo
|
imageRepoRepo = repo.NewIImageRepoRepo()
|
||||||
composeRepo = repo.RepoGroupApp.ComposeTemplateRepo
|
composeRepo = repo.NewIComposeTemplateRepo()
|
||||||
|
|
||||||
cronjobRepo = repo.RepoGroupApp.CronjobRepo
|
cronjobRepo = repo.NewICronjobRepo()
|
||||||
|
|
||||||
hostRepo = repo.RepoGroupApp.HostRepo
|
hostRepo = repo.NewIHostRepo()
|
||||||
groupRepo = repo.RepoGroupApp.GroupRepo
|
groupRepo = repo.NewIGroupRepo()
|
||||||
commandRepo = repo.RepoGroupApp.CommandRepo
|
commandRepo = repo.NewICommandRepo()
|
||||||
|
|
||||||
settingRepo = repo.RepoGroupApp.SettingRepo
|
settingRepo = repo.NewISettingRepo()
|
||||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
backupRepo = repo.NewIBackupRepo()
|
||||||
|
|
||||||
websiteRepo = repo.NewIWebsiteRepo()
|
websiteRepo = repo.NewIWebsiteRepo()
|
||||||
websiteGroupRepo = repo.RepoGroupApp.WebsiteGroupRepo
|
websiteDomainRepo = repo.NewIWebsiteDomainRepo()
|
||||||
websiteDomainRepo = repo.RepoGroupApp.WebsiteDomainRepo
|
websiteDnsRepo = repo.NewIWebsiteDnsAccountRepo()
|
||||||
websiteDnsRepo = repo.RepoGroupApp.WebsiteDnsAccountRepo
|
|
||||||
websiteSSLRepo = repo.NewISSLRepo()
|
websiteSSLRepo = repo.NewISSLRepo()
|
||||||
websiteAcmeRepo = repo.NewIAcmeAccountRepo()
|
websiteAcmeRepo = repo.NewIAcmeAccountRepo()
|
||||||
|
|
||||||
logRepo = repo.RepoGroupApp.LogRepo
|
logRepo = repo.NewILogRepo()
|
||||||
snapshotRepo = repo.NewISnapshotRepo()
|
snapshotRepo = repo.NewISnapshotRepo()
|
||||||
|
|
||||||
|
runtimeRepo = repo.NewIRunTimeRepo()
|
||||||
)
|
)
|
||||||
|
@ -22,7 +22,30 @@ import (
|
|||||||
type FileService struct {
|
type FileService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) GetFileList(op request.FileOption) (response.FileInfo, error) {
|
type IFileService interface {
|
||||||
|
GetFileList(op request.FileOption) (response.FileInfo, error)
|
||||||
|
SearchUploadWithPage(req request.SearchUploadWithPage) (int64, interface{}, error)
|
||||||
|
GetFileTree(op request.FileOption) ([]response.FileTree, error)
|
||||||
|
Create(op request.FileCreate) error
|
||||||
|
Delete(op request.FileDelete) error
|
||||||
|
BatchDelete(op request.FileBatchDelete) error
|
||||||
|
ChangeMode(op request.FileCreate) error
|
||||||
|
Compress(c request.FileCompress) error
|
||||||
|
DeCompress(c request.FileDeCompress) error
|
||||||
|
GetContent(op request.FileOption) (response.FileInfo, error)
|
||||||
|
SaveContent(edit request.FileEdit) error
|
||||||
|
FileDownload(d request.FileDownload) (string, error)
|
||||||
|
DirSize(req request.DirSizeReq) (response.DirSizeRes, error)
|
||||||
|
ChangeName(req request.FileRename) error
|
||||||
|
Wget(w request.FileWget) (string, error)
|
||||||
|
MvFile(m request.FileMove) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIFileService() IFileService {
|
||||||
|
return &FileService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileService) GetFileList(op request.FileOption) (response.FileInfo, error) {
|
||||||
var fileInfo response.FileInfo
|
var fileInfo response.FileInfo
|
||||||
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
|
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
|
||||||
return fileInfo, nil
|
return fileInfo, nil
|
||||||
@ -35,7 +58,7 @@ func (f FileService) GetFileList(op request.FileOption) (response.FileInfo, erro
|
|||||||
return fileInfo, nil
|
return fileInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (int64, interface{}, error) {
|
func (f *FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (int64, interface{}, error) {
|
||||||
var (
|
var (
|
||||||
files []response.UploadInfo
|
files []response.UploadInfo
|
||||||
backData []response.UploadInfo
|
backData []response.UploadInfo
|
||||||
@ -65,7 +88,7 @@ func (f FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (int
|
|||||||
return int64(total), backData, nil
|
return int64(total), backData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) GetFileTree(op request.FileOption) ([]response.FileTree, error) {
|
func (f *FileService) GetFileTree(op request.FileOption) ([]response.FileTree, error) {
|
||||||
var treeArray []response.FileTree
|
var treeArray []response.FileTree
|
||||||
info, err := files.NewFileInfo(op.FileOption)
|
info, err := files.NewFileInfo(op.FileOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -88,7 +111,7 @@ func (f FileService) GetFileTree(op request.FileOption) ([]response.FileTree, er
|
|||||||
return append(treeArray, node), nil
|
return append(treeArray, node), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Create(op request.FileCreate) error {
|
func (f *FileService) Create(op request.FileCreate) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if fo.Stat(op.Path) {
|
if fo.Stat(op.Path) {
|
||||||
return buserr.New(constant.ErrFileIsExit)
|
return buserr.New(constant.ErrFileIsExit)
|
||||||
@ -107,7 +130,7 @@ func (f FileService) Create(op request.FileCreate) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Delete(op request.FileDelete) error {
|
func (f *FileService) Delete(op request.FileDelete) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if op.IsDir {
|
if op.IsDir {
|
||||||
return fo.DeleteDir(op.Path)
|
return fo.DeleteDir(op.Path)
|
||||||
@ -116,7 +139,7 @@ func (f FileService) Delete(op request.FileDelete) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) BatchDelete(op request.FileBatchDelete) error {
|
func (f *FileService) BatchDelete(op request.FileBatchDelete) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if op.IsDir {
|
if op.IsDir {
|
||||||
for _, file := range op.Paths {
|
for _, file := range op.Paths {
|
||||||
@ -134,12 +157,12 @@ func (f FileService) BatchDelete(op request.FileBatchDelete) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) ChangeMode(op request.FileCreate) error {
|
func (f *FileService) ChangeMode(op request.FileCreate) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Compress(c request.FileCompress) error {
|
func (f *FileService) Compress(c request.FileCompress) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
||||||
return buserr.New(constant.ErrFileIsExit)
|
return buserr.New(constant.ErrFileIsExit)
|
||||||
@ -147,12 +170,12 @@ func (f FileService) Compress(c request.FileCompress) error {
|
|||||||
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type))
|
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) DeCompress(c request.FileDeCompress) error {
|
func (f *FileService) DeCompress(c request.FileDeCompress) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type))
|
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) GetContent(op request.FileOption) (response.FileInfo, error) {
|
func (f *FileService) GetContent(op request.FileOption) (response.FileInfo, error) {
|
||||||
info, err := files.NewFileInfo(op.FileOption)
|
info, err := files.NewFileInfo(op.FileOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.FileInfo{}, err
|
return response.FileInfo{}, err
|
||||||
@ -160,7 +183,7 @@ func (f FileService) GetContent(op request.FileOption) (response.FileInfo, error
|
|||||||
return response.FileInfo{FileInfo: *info}, nil
|
return response.FileInfo{FileInfo: *info}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) SaveContent(edit request.FileEdit) error {
|
func (f *FileService) SaveContent(edit request.FileEdit) error {
|
||||||
info, err := files.NewFileInfo(files.FileOption{
|
info, err := files.NewFileInfo(files.FileOption{
|
||||||
Path: edit.Path,
|
Path: edit.Path,
|
||||||
Expand: false,
|
Expand: false,
|
||||||
@ -173,18 +196,18 @@ func (f FileService) SaveContent(edit request.FileEdit) error {
|
|||||||
return fo.WriteFile(edit.Path, strings.NewReader(edit.Content), info.FileMode)
|
return fo.WriteFile(edit.Path, strings.NewReader(edit.Content), info.FileMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) ChangeName(req request.FileRename) error {
|
func (f *FileService) ChangeName(req request.FileRename) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
return fo.Rename(req.OldName, req.NewName)
|
return fo.Rename(req.OldName, req.NewName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Wget(w request.FileWget) (string, error) {
|
func (f *FileService) Wget(w request.FileWget) (string, error) {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
key := "file-wget-" + common.GetUuid()
|
key := "file-wget-" + common.GetUuid()
|
||||||
return key, fo.DownloadFileWithProcess(w.Url, filepath.Join(w.Path, w.Name), key)
|
return key, fo.DownloadFileWithProcess(w.Url, filepath.Join(w.Path, w.Name), key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) MvFile(m request.FileMove) error {
|
func (f *FileService) MvFile(m request.FileMove) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if !fo.Stat(m.NewPath) {
|
if !fo.Stat(m.NewPath) {
|
||||||
return buserr.New(constant.ErrPathNotFound)
|
return buserr.New(constant.ErrPathNotFound)
|
||||||
@ -217,7 +240,7 @@ func (f FileService) MvFile(m request.FileMove) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) FileDownload(d request.FileDownload) (string, error) {
|
func (f *FileService) FileDownload(d request.FileDownload) (string, error) {
|
||||||
filePath := d.Paths[0]
|
filePath := d.Paths[0]
|
||||||
if d.Compress {
|
if d.Compress {
|
||||||
tempPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().UnixNano()))
|
tempPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().UnixNano()))
|
||||||
@ -233,7 +256,7 @@ func (f FileService) FileDownload(d request.FileDownload) (string, error) {
|
|||||||
return filePath, nil
|
return filePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) {
|
func (f *FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
size, err := fo.GetDirSize(req.Path)
|
size, err := fo.GetDirSize(req.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
448
backend/app/service/firewall.go
Normal file
448
backend/app/service/firewall.go
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/firewall"
|
||||||
|
fireClient "github.com/1Panel-dev/1Panel/backend/utils/firewall/client"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
)
|
||||||
|
|
||||||
|
const confPath = "/etc/sysctl.conf"
|
||||||
|
|
||||||
|
type FirewallService struct{}
|
||||||
|
|
||||||
|
type IFirewallService interface {
|
||||||
|
LoadBaseInfo() (dto.FirewallBaseInfo, error)
|
||||||
|
SearchWithPage(search dto.RuleSearch) (int64, interface{}, error)
|
||||||
|
OperateFirewall(operation string) error
|
||||||
|
OperatePortRule(req dto.PortRuleOperate, reload bool) error
|
||||||
|
OperateAddressRule(req dto.AddrRuleOperate, reload bool) error
|
||||||
|
UpdatePortRule(req dto.PortRuleUpdate) error
|
||||||
|
UpdateAddrRule(req dto.AddrRuleUpdate) error
|
||||||
|
BacthOperateRule(req dto.BatchRuleOperate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIFirewallService() IFirewallService {
|
||||||
|
return &FirewallService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) LoadBaseInfo() (dto.FirewallBaseInfo, error) {
|
||||||
|
var baseInfo dto.FirewallBaseInfo
|
||||||
|
baseInfo.PingStatus = u.pingStatus()
|
||||||
|
baseInfo.Status = "not running"
|
||||||
|
baseInfo.Version = "-"
|
||||||
|
baseInfo.Name = "-"
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "no such type" {
|
||||||
|
return baseInfo, nil
|
||||||
|
}
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
baseInfo.Name = client.Name()
|
||||||
|
baseInfo.Status, err = client.Status()
|
||||||
|
if err != nil {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
if baseInfo.Status == "not running" {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
baseInfo.Version, err = client.Version()
|
||||||
|
if err != nil {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
return baseInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}, error) {
|
||||||
|
var (
|
||||||
|
datas []fireClient.FireInfo
|
||||||
|
backDatas []fireClient.FireInfo
|
||||||
|
)
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if req.Type == "port" {
|
||||||
|
ports, err := client.ListPort()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if len(req.Info) != 0 {
|
||||||
|
for _, port := range ports {
|
||||||
|
if strings.Contains(port.Port, req.Info) {
|
||||||
|
datas = append(datas, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datas = ports
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addrs, err := client.ListAddress()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if len(req.Info) != 0 {
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if strings.Contains(addr.Address, req.Info) {
|
||||||
|
datas = append(datas, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datas = addrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total, start, end := len(datas), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||||
|
if start > total {
|
||||||
|
backDatas = make([]fireClient.FireInfo, 0)
|
||||||
|
} else {
|
||||||
|
if end >= total {
|
||||||
|
end = total
|
||||||
|
}
|
||||||
|
backDatas = datas[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Type == "port" {
|
||||||
|
apps := u.loadPortByApp()
|
||||||
|
for i := 0; i < len(backDatas); i++ {
|
||||||
|
port, _ := strconv.Atoi(backDatas[i].Port)
|
||||||
|
backDatas[i].IsUsed = common.ScanPort(port)
|
||||||
|
if backDatas[i].Protocol == "udp" {
|
||||||
|
backDatas[i].IsUsed = common.ScanUDPPort(port)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, app := range apps {
|
||||||
|
if app.HttpPort == backDatas[i].Port || app.HttpsPort == backDatas[i].Port {
|
||||||
|
backDatas[i].APPName = app.AppName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(total), backDatas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperateFirewall(operation string) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch operation {
|
||||||
|
case "start":
|
||||||
|
if err := client.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.addPortsBeforeStart(client); err != nil {
|
||||||
|
_ = client.Stop()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _ = cmd.Exec("systemctl restart docker")
|
||||||
|
return nil
|
||||||
|
case "stop":
|
||||||
|
if err := client.Stop(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _ = cmd.Exec("systemctl restart docker")
|
||||||
|
return nil
|
||||||
|
case "disablePing":
|
||||||
|
return u.updatePingStatus("0")
|
||||||
|
case "enablePing":
|
||||||
|
return u.updatePingStatus("1")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("not support such operation: %s", operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if client.Name() == "ufw" {
|
||||||
|
req.Port = strings.ReplaceAll(req.Port, "-", ":")
|
||||||
|
if req.Operation == "remove" && req.Protocol == "tcp/udp" {
|
||||||
|
req.Protocol = ""
|
||||||
|
return u.operatePort(client, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.Protocol == "tcp/udp" {
|
||||||
|
if client.Name() == "firewalld" && strings.Contains(req.Port, ",") {
|
||||||
|
ports := strings.Split(req.Port, ",")
|
||||||
|
for _, port := range ports {
|
||||||
|
if len(port) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
req.Port = port
|
||||||
|
req.Protocol = "tcp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Protocol = "udp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req.Protocol = "tcp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Protocol = "udp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strings.Contains(req.Port, ",") {
|
||||||
|
ports := strings.Split(req.Port, ",")
|
||||||
|
for _, port := range ports {
|
||||||
|
req.Port = port
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reload {
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload bool) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fireInfo fireClient.FireInfo
|
||||||
|
if err := copier.Copy(&fireInfo, &req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addressList := strings.Split(req.Address, ",")
|
||||||
|
for _, addr := range addressList {
|
||||||
|
if len(addr) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fireInfo.Address = addr
|
||||||
|
if err := client.RichRules(fireInfo, req.Operation); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reload {
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) UpdatePortRule(req dto.PortRuleUpdate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperatePortRule(req.OldRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperatePortRule(req.NewRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) UpdateAddrRule(req dto.AddrRuleUpdate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperateAddressRule(req.OldRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperateAddressRule(req.NewRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) BacthOperateRule(req dto.BatchRuleOperate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.Type == "port" {
|
||||||
|
for _, rule := range req.Rules {
|
||||||
|
if err := u.OperatePortRule(rule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
for _, rule := range req.Rules {
|
||||||
|
itemRule := dto.AddrRuleOperate{Operation: rule.Operation, Address: rule.Address, Strategy: rule.Strategy}
|
||||||
|
if err := u.OperateAddressRule(itemRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func OperateFirewallPort(oldPorts, newPorts []int) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, port := range newPorts {
|
||||||
|
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, port := range oldPorts {
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "remove"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) operatePort(client firewall.FirewallClient, req dto.PortRuleOperate) error {
|
||||||
|
var fireInfo fireClient.FireInfo
|
||||||
|
if err := copier.Copy(&fireInfo, &req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if client.Name() == "ufw" {
|
||||||
|
if len(fireInfo.Address) != 0 && fireInfo.Address != "Anywhere" {
|
||||||
|
return client.RichRules(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
return client.Port(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fireInfo.Address) != 0 || fireInfo.Strategy == "drop" {
|
||||||
|
return client.RichRules(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
return client.Port(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
type portOfApp struct {
|
||||||
|
AppName string
|
||||||
|
HttpPort string
|
||||||
|
HttpsPort string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) loadPortByApp() []portOfApp {
|
||||||
|
var datas []portOfApp
|
||||||
|
apps, err := appInstallRepo.ListBy()
|
||||||
|
if err != nil {
|
||||||
|
return datas
|
||||||
|
}
|
||||||
|
for i := 0; i < len(apps); i++ {
|
||||||
|
datas = append(datas, portOfApp{
|
||||||
|
AppName: apps[i].App.Key,
|
||||||
|
HttpPort: strconv.Itoa(apps[i].HttpPort),
|
||||||
|
HttpsPort: strconv.Itoa(apps[i].HttpsPort),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
systemPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
|
||||||
|
if err != nil {
|
||||||
|
return datas
|
||||||
|
}
|
||||||
|
datas = append(datas, portOfApp{AppName: "1panel", HttpPort: systemPort.Value})
|
||||||
|
|
||||||
|
return datas
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) pingStatus() string {
|
||||||
|
if _, err := os.Stat("/etc/sysctl.conf"); err != nil {
|
||||||
|
return constant.StatusNone
|
||||||
|
}
|
||||||
|
commond := "cat /etc/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= "
|
||||||
|
if cmd.HasNoPasswordSudo() {
|
||||||
|
commond = "sudo cat /etc/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= "
|
||||||
|
}
|
||||||
|
stdout, _ := cmd.Exec(commond)
|
||||||
|
if stdout == "net/ipv4/icmp_echo_ignore_all=1\n" {
|
||||||
|
return constant.StatusEnable
|
||||||
|
}
|
||||||
|
return constant.StatusDisable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) updatePingStatus(enabel string) error {
|
||||||
|
lineBytes, err := os.ReadFile(confPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
files := strings.Split(string(lineBytes), "\n")
|
||||||
|
var newFiles []string
|
||||||
|
hasLine := false
|
||||||
|
for _, line := range files {
|
||||||
|
if strings.Contains(line, "net/ipv4/icmp_echo_ignore_all") || strings.HasPrefix(line, "net/ipv4/icmp_echo_ignore_all") {
|
||||||
|
newFiles = append(newFiles, "net/ipv4/icmp_echo_ignore_all="+enabel)
|
||||||
|
hasLine = true
|
||||||
|
} else {
|
||||||
|
newFiles = append(newFiles, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasLine {
|
||||||
|
newFiles = append(newFiles, "net/ipv4/icmp_echo_ignore_all="+enabel)
|
||||||
|
}
|
||||||
|
file, err := os.OpenFile(confPath, os.O_WRONLY|os.O_TRUNC, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
_, err = file.WriteString(strings.Join(newFiles, "\n"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
commond := "sysctl -p"
|
||||||
|
if cmd.HasNoPasswordSudo() {
|
||||||
|
commond = "sudo sysctl -p"
|
||||||
|
}
|
||||||
|
stdout, err := cmd.Exec(commond)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("update ping status failed, err: %v", stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) error {
|
||||||
|
serverPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: serverPort.Value, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: "22", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: "80", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: "443", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
apps := u.loadPortByApp()
|
||||||
|
for _, app := range apps {
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: app.HttpPort, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Reload()
|
||||||
|
}
|
@ -22,7 +22,7 @@ func NewIGroupService() IGroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *GroupService) List(req dto.GroupSearch) ([]dto.GroupInfo, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, constant.ErrRecordNotFound
|
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 {
|
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 {
|
if group.ID != 0 {
|
||||||
return constant.ErrRecordExist
|
return constant.ErrRecordExist
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ func (u *GroupService) Delete(id uint) error {
|
|||||||
}
|
}
|
||||||
switch group.Type {
|
switch group.Type {
|
||||||
case "website":
|
case "website":
|
||||||
websites, _ := websiteRepo.GetBy(commonRepo.WithByGroupID(id))
|
websites, _ := websiteRepo.GetBy(websiteRepo.WithGroupID(id))
|
||||||
if len(websites) > 0 {
|
if len(websites) > 0 {
|
||||||
return buserr.New(constant.ErrGroupIsUsed)
|
return buserr.New(constant.ErrGroupIsUsed)
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ func (u *GroupService) Delete(id uint) error {
|
|||||||
|
|
||||||
func (u *GroupService) Update(req dto.GroupUpdate) error {
|
func (u *GroupService) Update(req dto.GroupUpdate) error {
|
||||||
if req.IsDefault {
|
if req.IsDefault {
|
||||||
if err := groupRepo.CancelDefault(); err != nil {
|
if err := groupRepo.CancelDefault(req.Type); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@ -15,6 +16,7 @@ type HostService struct{}
|
|||||||
|
|
||||||
type IHostService interface {
|
type IHostService interface {
|
||||||
TestLocalConn(id uint) bool
|
TestLocalConn(id uint) bool
|
||||||
|
TestByInfo(req dto.HostConnTest) bool
|
||||||
GetHostInfo(id uint) (*model.Host, error)
|
GetHostInfo(id uint) (*model.Host, error)
|
||||||
SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error)
|
SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error)
|
||||||
SearchWithPage(search dto.SearchHostWithPage) (int64, interface{}, error)
|
SearchWithPage(search dto.SearchHostWithPage) (int64, interface{}, error)
|
||||||
@ -27,6 +29,46 @@ func NewIHostService() IHostService {
|
|||||||
return &HostService{}
|
return &HostService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *HostService) TestByInfo(req dto.HostConnTest) bool {
|
||||||
|
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||||
|
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
req.Password = string(password)
|
||||||
|
}
|
||||||
|
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||||
|
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
req.PrivateKey = string(privateKey)
|
||||||
|
}
|
||||||
|
if len(req.Password) == 0 && len(req.PrivateKey) == 0 {
|
||||||
|
host, err := hostRepo.Get(hostRepo.WithByAddr(req.Addr))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
req.Password = host.Password
|
||||||
|
req.AuthMode = host.AuthMode
|
||||||
|
req.PrivateKey = host.PrivateKey
|
||||||
|
req.PassPhrase = host.PassPhrase
|
||||||
|
}
|
||||||
|
|
||||||
|
var connInfo ssh.ConnInfo
|
||||||
|
_ = copier.Copy(&connInfo, &req)
|
||||||
|
connInfo.PrivateKey = []byte(req.PrivateKey)
|
||||||
|
if len(req.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(req.PassPhrase)
|
||||||
|
}
|
||||||
|
client, err := connInfo.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (u *HostService) TestLocalConn(id uint) bool {
|
func (u *HostService) TestLocalConn(id uint) bool {
|
||||||
var (
|
var (
|
||||||
host model.Host
|
host model.Host
|
||||||
@ -47,6 +89,10 @@ func (u *HostService) TestLocalConn(id uint) bool {
|
|||||||
if err := copier.Copy(&connInfo, &host); err != nil {
|
if err := copier.Copy(&connInfo, &host); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
connInfo.PrivateKey = []byte(host.PrivateKey)
|
||||||
|
if len(host.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(host.PassPhrase)
|
||||||
|
}
|
||||||
client, err := connInfo.NewClient()
|
client, err := connInfo.NewClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
@ -77,6 +123,11 @@ func (u *HostService) SearchWithPage(search dto.SearchHostWithPage) (int64, inte
|
|||||||
}
|
}
|
||||||
group, _ := groupRepo.Get(commonRepo.WithByID(host.GroupID))
|
group, _ := groupRepo.Get(commonRepo.WithByID(host.GroupID))
|
||||||
item.GroupBelong = group.Name
|
item.GroupBelong = group.Name
|
||||||
|
if !item.RememberPassword {
|
||||||
|
item.Password = ""
|
||||||
|
item.PrivateKey = ""
|
||||||
|
item.PassPhrase = ""
|
||||||
|
}
|
||||||
dtoHosts = append(dtoHosts, item)
|
dtoHosts = append(dtoHosts, item)
|
||||||
}
|
}
|
||||||
return total, dtoHosts, err
|
return total, dtoHosts, err
|
||||||
@ -144,6 +195,8 @@ func (u *HostService) Create(req dto.HostOperate) (*dto.HostInfo, error) {
|
|||||||
upMap["auth_mode"] = req.AuthMode
|
upMap["auth_mode"] = req.AuthMode
|
||||||
upMap["password"] = req.Password
|
upMap["password"] = req.Password
|
||||||
upMap["private_key"] = req.PrivateKey
|
upMap["private_key"] = req.PrivateKey
|
||||||
|
upMap["pass_phrase"] = req.PassPhrase
|
||||||
|
upMap["remember_password"] = req.RememberPassword
|
||||||
upMap["description"] = req.Description
|
upMap["description"] = req.Description
|
||||||
if err := hostRepo.Update(sameHostID, upMap); err != nil {
|
if err := hostRepo.Update(sameHostID, upMap); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -34,6 +33,7 @@ type IImageService interface {
|
|||||||
ImageSave(req dto.ImageSave) error
|
ImageSave(req dto.ImageSave) error
|
||||||
ImagePush(req dto.ImagePush) (string, error)
|
ImagePush(req dto.ImagePush) (string, error)
|
||||||
ImageRemove(req dto.BatchDelete) error
|
ImageRemove(req dto.BatchDelete) error
|
||||||
|
ImageTag(req dto.ImageTag) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIImageService() IImageService {
|
func NewIImageService() IImageService {
|
||||||
@ -54,8 +54,8 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
|
|||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
if len(req.Info) != 0 {
|
if len(req.Info) != 0 {
|
||||||
lenth, count := len(list), 0
|
length, count := len(list), 0
|
||||||
for count < lenth {
|
for count < length {
|
||||||
hasTag := false
|
hasTag := false
|
||||||
for _, tag := range list[count].RepoTags {
|
for _, tag := range list[count].RepoTags {
|
||||||
if strings.Contains(tag, req.Info) {
|
if strings.Contains(tag, req.Info) {
|
||||||
@ -65,7 +65,7 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
|
|||||||
}
|
}
|
||||||
if !hasTag {
|
if !hasTag {
|
||||||
list = append(list[:count], list[(count+1):]...)
|
list = append(list[:count], list[(count+1):]...)
|
||||||
lenth--
|
length--
|
||||||
} else {
|
} else {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
@ -122,6 +122,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
fileName := "Dockerfile"
|
||||||
if req.From == "edit" {
|
if req.From == "edit" {
|
||||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
||||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||||
@ -141,7 +142,8 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
|||||||
write.Flush()
|
write.Flush()
|
||||||
req.Dockerfile = dir
|
req.Dockerfile = dir
|
||||||
} else {
|
} 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{})
|
tar, err := archive.TarWithOptions(req.Dockerfile+"/", &archive.TarOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,7 +151,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := types.ImageBuildOptions{
|
opts := types.ImageBuildOptions{
|
||||||
Dockerfile: "Dockerfile",
|
Dockerfile: fileName,
|
||||||
Tags: []string{req.Name},
|
Tags: []string{req.Name},
|
||||||
Remove: true,
|
Remove: true,
|
||||||
Labels: stringsToMap(req.Tags),
|
Labels: stringsToMap(req.Tags),
|
||||||
@ -171,7 +173,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
||||||
_, _ = file.WriteString(fmt.Sprintf("build image %s failed, err: %v", req.Name, err))
|
_, _ = file.WriteString(fmt.Sprintf("build image %s failed, err: %v", req.Name, err))
|
||||||
@ -179,14 +181,14 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
|||||||
return
|
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)
|
global.LOG.Errorf("build image %s failed", req.Name)
|
||||||
_, _ = file.Write(body)
|
_, _ = file.Write(body)
|
||||||
_, _ = file.WriteString("image build failed!")
|
_, _ = file.WriteString("image build failed!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
global.LOG.Infof("build image %s successful!", req.Name)
|
global.LOG.Infof("build image %s successful!", req.Name)
|
||||||
_, _ = io.Copy(file, res.Body)
|
_, _ = file.Write(body)
|
||||||
_, _ = file.WriteString("image build successful!")
|
_, _ = file.WriteString("image build successful!")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -272,7 +274,7 @@ func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content, err := ioutil.ReadAll(res.Body)
|
content, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -190,7 +189,7 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
deamonMap := make(map[string]interface{})
|
deamonMap := make(map[string]interface{})
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -226,7 +225,7 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"io"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
@ -18,6 +19,18 @@ import (
|
|||||||
type NginxService struct {
|
type NginxService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type INginxService interface {
|
||||||
|
GetNginxConfig() (response.FileInfo, error)
|
||||||
|
GetConfigByScope(req request.NginxScopeReq) ([]response.NginxParam, error)
|
||||||
|
UpdateConfigByScope(req request.NginxConfigUpdate) error
|
||||||
|
GetStatus() (response.NginxStatus, error)
|
||||||
|
UpdateConfigFile(req request.NginxConfigFileUpdate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewINginxService() INginxService {
|
||||||
|
return &NginxService{}
|
||||||
|
}
|
||||||
|
|
||||||
func (n NginxService) GetNginxConfig() (response.FileInfo, error) {
|
func (n NginxService) GetNginxConfig() (response.FileInfo, error) {
|
||||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -55,7 +68,7 @@ func (n NginxService) GetStatus() (response.NginxStatus, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return response.NginxStatus{}, err
|
return response.NginxStatus{}, err
|
||||||
}
|
}
|
||||||
content, err := ioutil.ReadAll(res.Body)
|
content, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.NginxStatus{}, err
|
return response.NginxStatus{}, err
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getNginxFull(website *model.Website) (dto.NginxFull, error) {
|
func getNginxFull(website *model.Website) (dto.NginxFull, error) {
|
||||||
@ -191,7 +192,7 @@ func opNginx(containerName, operate string) error {
|
|||||||
if operate == constant.NginxCheck {
|
if operate == constant.NginxCheck {
|
||||||
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
||||||
}
|
}
|
||||||
if out, err := cmd.Exec(nginxCmd); err != nil {
|
if out, err := cmd.ExecWithTimeOut(nginxCmd, 2*time.Second); err != nil {
|
||||||
return errors.New(out)
|
return errors.New(out)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
276
backend/app/service/runtime.go
Normal file
276
backend/app/service/runtime.go
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
|
"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"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RuntimeService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type IRuntimeService interface {
|
||||||
|
Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error)
|
||||||
|
Create(create request.RuntimeCreate) error
|
||||||
|
Delete(id uint) error
|
||||||
|
Update(req request.RuntimeUpdate) error
|
||||||
|
Get(id uint) (res *response.RuntimeRes, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRuntimeService() IRuntimeService {
|
||||||
|
return &RuntimeService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
|
||||||
|
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithName(create.Name))
|
||||||
|
if exist != nil {
|
||||||
|
return buserr.New(constant.ErrNameIsExist)
|
||||||
|
}
|
||||||
|
if create.Resource == constant.ResourceLocal {
|
||||||
|
runtime := &model.Runtime{
|
||||||
|
Name: create.Name,
|
||||||
|
Resource: create.Resource,
|
||||||
|
Type: create.Type,
|
||||||
|
Version: create.Version,
|
||||||
|
Status: constant.RuntimeNormal,
|
||||||
|
}
|
||||||
|
return runtimeRepo.Create(context.Background(), runtime)
|
||||||
|
}
|
||||||
|
exist, _ = runtimeRepo.GetFirst(runtimeRepo.WithImage(create.Image))
|
||||||
|
if exist != nil {
|
||||||
|
return buserr.New(constant.ErrImageExist)
|
||||||
|
}
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(create.AppDetailID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
buildDir := path.Join(constant.AppResourceDir, app.Key, "versions", appDetail.Version, "build")
|
||||||
|
if !fileOp.Stat(buildDir) {
|
||||||
|
return buserr.New(constant.ErrDirNotFound)
|
||||||
|
}
|
||||||
|
runtimeDir := path.Join(constant.RuntimeDir, create.Type)
|
||||||
|
tempDir := filepath.Join(runtimeDir, fmt.Sprintf("%d", time.Now().UnixNano()))
|
||||||
|
if err = fileOp.CopyDir(buildDir, tempDir); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oldDir := path.Join(tempDir, "build")
|
||||||
|
newNameDir := path.Join(runtimeDir, create.Name)
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
_ = fileOp.DeleteDir(newNameDir)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if oldDir != newNameDir {
|
||||||
|
if err = fileOp.Rename(oldDir, newNameDir); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = fileOp.DeleteDir(tempDir); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
composeContent, envContent, forms, err := handleParams(create.Image, create.Type, newNameDir, create.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
composeService, err := getComposeService(create.Name, newNameDir, composeContent, envContent, false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runtime := &model.Runtime{
|
||||||
|
Name: create.Name,
|
||||||
|
DockerCompose: string(composeContent),
|
||||||
|
Env: string(envContent),
|
||||||
|
AppDetailID: create.AppDetailID,
|
||||||
|
Type: create.Type,
|
||||||
|
Image: create.Image,
|
||||||
|
Resource: create.Resource,
|
||||||
|
Status: constant.RuntimeBuildIng,
|
||||||
|
Version: create.Version,
|
||||||
|
Params: string(forms),
|
||||||
|
}
|
||||||
|
if err = runtimeRepo.Create(context.Background(), runtime); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go buildRuntime(runtime, composeService, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) {
|
||||||
|
var (
|
||||||
|
opts []repo.DBOption
|
||||||
|
res []response.RuntimeRes
|
||||||
|
)
|
||||||
|
if req.Name != "" {
|
||||||
|
opts = append(opts, commonRepo.WithLikeName(req.Name))
|
||||||
|
}
|
||||||
|
if req.Status != "" {
|
||||||
|
opts = append(opts, runtimeRepo.WithStatus(req.Status))
|
||||||
|
}
|
||||||
|
total, runtimes, err := runtimeRepo.Page(req.Page, req.PageSize, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
for _, runtime := range runtimes {
|
||||||
|
res = append(res, response.RuntimeRes{
|
||||||
|
Runtime: runtime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return total, res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Delete(id uint) error {
|
||||||
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
website, _ := websiteRepo.GetFirst(websiteRepo.WithRuntimeID(id))
|
||||||
|
if website.ID > 0 {
|
||||||
|
return buserr.New(constant.ErrDelWithWebsite)
|
||||||
|
}
|
||||||
|
if runtime.Resource == constant.ResourceAppstore {
|
||||||
|
client, err := docker.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imageID, err := client.GetImageIDByName(runtime.Image)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if imageID != "" {
|
||||||
|
if err := client.DeleteImage(imageID); err != nil {
|
||||||
|
global.LOG.Errorf("delete image id [%s] error %v", imageID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
|
||||||
|
if err := files.NewFileOp().DeleteDir(runtimeDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runtimeRepo.DeleteBy(commonRepo.WithByID(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Get(id uint) (*response.RuntimeRes, error) {
|
||||||
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res := &response.RuntimeRes{}
|
||||||
|
res.Runtime = *runtime
|
||||||
|
if runtime.Resource == constant.ResourceLocal {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(runtime.AppDetailID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.AppID = appDetail.AppId
|
||||||
|
var (
|
||||||
|
appForm dto.AppForm
|
||||||
|
appParams []response.AppParam
|
||||||
|
)
|
||||||
|
if err := json.Unmarshal([]byte(runtime.Params), &appForm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
envs, err := gotenv.Unmarshal(runtime.Env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, form := range appForm.FormFields {
|
||||||
|
if v, ok := envs[form.EnvKey]; ok {
|
||||||
|
appParam := response.AppParam{
|
||||||
|
Edit: false,
|
||||||
|
Key: form.EnvKey,
|
||||||
|
Rule: form.Rule,
|
||||||
|
Type: form.Type,
|
||||||
|
Required: form.Required,
|
||||||
|
}
|
||||||
|
if form.Edit {
|
||||||
|
appParam.Edit = true
|
||||||
|
}
|
||||||
|
appParam.LabelZh = form.LabelZh
|
||||||
|
appParam.LabelEn = form.LabelEn
|
||||||
|
appParam.Multiple = form.Multiple
|
||||||
|
appParam.Value = v
|
||||||
|
if form.Type == "select" {
|
||||||
|
if form.Multiple {
|
||||||
|
if v == "" {
|
||||||
|
appParam.Value = []string{}
|
||||||
|
} else {
|
||||||
|
appParam.Value = strings.Split(v, ",")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, fv := range form.Values {
|
||||||
|
if fv.Value == v {
|
||||||
|
appParam.ShowValue = fv.Label
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appParam.Values = form.Values
|
||||||
|
}
|
||||||
|
appParams = append(appParams, appParam)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.AppParams = appParams
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||||
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
oldImage := runtime.Image
|
||||||
|
if runtime.Resource == constant.ResourceLocal {
|
||||||
|
runtime.Version = req.Version
|
||||||
|
return runtimeRepo.Save(runtime)
|
||||||
|
}
|
||||||
|
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
|
||||||
|
if exist != nil {
|
||||||
|
return buserr.New(constant.ErrImageExist)
|
||||||
|
}
|
||||||
|
runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
|
||||||
|
composeContent, envContent, _, err := handleParams(req.Image, runtime.Type, runtimeDir, req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
composeService, err := getComposeService(runtime.Name, runtimeDir, composeContent, envContent, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
runtime.Image = req.Image
|
||||||
|
runtime.Env = string(envContent)
|
||||||
|
runtime.DockerCompose = string(composeContent)
|
||||||
|
runtime.Status = constant.RuntimeBuildIng
|
||||||
|
_ = runtimeRepo.Save(runtime)
|
||||||
|
client, err := docker.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imageID, err := client.GetImageIDByName(oldImage)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go buildRuntime(runtime, composeService, imageID)
|
||||||
|
return nil
|
||||||
|
}
|
107
backend/app/service/runtime_utils.go
Normal file
107
backend/app/service/runtime_utils.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"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"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"github.com/docker/cli/cli/command"
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildRuntime(runtime *model.Runtime, service *docker.ComposeService, oldImageID string) {
|
||||||
|
err := service.ComposeBuild()
|
||||||
|
if err != nil {
|
||||||
|
runtime.Status = constant.RuntimeError
|
||||||
|
runtime.Message = buserr.New(constant.ErrImageBuildErr).Error() + ":" + err.Error()
|
||||||
|
} else {
|
||||||
|
runtime.Status = constant.RuntimeNormal
|
||||||
|
if oldImageID != "" {
|
||||||
|
client, err := docker.NewClient()
|
||||||
|
if err == nil {
|
||||||
|
newImageID, err := client.GetImageIDByName(runtime.Image)
|
||||||
|
if err == nil && newImageID != oldImageID {
|
||||||
|
global.LOG.Infof("delete imageID [%s] ", oldImageID)
|
||||||
|
if err := client.DeleteImage(oldImageID); err != nil {
|
||||||
|
global.LOG.Errorf("delete imageID [%s] error %v", oldImageID, err)
|
||||||
|
} else {
|
||||||
|
global.LOG.Infof("delete old image success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
global.LOG.Errorf("delete imageID [%s] error %v", oldImageID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = runtimeRepo.Save(runtime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleParams(image, runtimeType, runtimeDir string, params map[string]interface{}) (composeContent []byte, envContent []byte, forms []byte, err error) {
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
composeContent, err = fileOp.GetContent(path.Join(runtimeDir, "docker-compose.yml"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
env, err := gotenv.Read(path.Join(runtimeDir, ".env"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
forms, err = fileOp.GetContent(path.Join(runtimeDir, "config.json"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params["IMAGE_NAME"] = image
|
||||||
|
if runtimeType == constant.RuntimePHP {
|
||||||
|
if extends, ok := params["PHP_EXTENSIONS"]; ok {
|
||||||
|
if extendsArray, ok := extends.([]interface{}); ok {
|
||||||
|
strArray := make([]string, len(extendsArray))
|
||||||
|
for i, v := range extendsArray {
|
||||||
|
strArray[i] = fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
params["PHP_EXTENSIONS"] = strings.Join(strArray, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newMap := make(map[string]string)
|
||||||
|
handleMap(params, newMap)
|
||||||
|
for k, v := range newMap {
|
||||||
|
env[k] = v
|
||||||
|
}
|
||||||
|
envStr, err := gotenv.Marshal(env)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = gotenv.Write(env, path.Join(runtimeDir, ".env")); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
envContent = []byte(envStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getComposeService(name, runtimeDir string, composeFile, env []byte, skipNormalization bool) (*docker.ComposeService, error) {
|
||||||
|
project, err := docker.GetComposeProject(name, runtimeDir, composeFile, env, skipNormalization)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logPath := path.Join(runtimeDir, "build.log")
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
if fileOp.Stat(logPath) {
|
||||||
|
_ = fileOp.DeleteFile(logPath)
|
||||||
|
}
|
||||||
|
file, err := os.Create(logPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
composeService, err := docker.NewComposeService(command.WithOutputStream(file))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
composeService.SetProject(project)
|
||||||
|
return composeService, nil
|
||||||
|
}
|
@ -70,7 +70,14 @@ func (u *SettingService) UpdatePort(port uint) error {
|
|||||||
if common.ScanPort(int(port)) {
|
if common.ScanPort(int(port)) {
|
||||||
return buserr.WithDetail(constant.ErrPortInUsed, port, nil)
|
return buserr.WithDetail(constant.ErrPortInUsed, port, nil)
|
||||||
}
|
}
|
||||||
|
serverPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
portValue, _ := strconv.Atoi(serverPort.Value)
|
||||||
|
if err := OperateFirewallPort([]int{portValue}, []int{int(port)}); err != nil {
|
||||||
|
global.LOG.Errorf("set system firewall ports failed, err: %v", err)
|
||||||
|
}
|
||||||
if err := settingRepo.Update("ServerPort", strconv.Itoa(int(port))); err != nil {
|
if err := settingRepo.Update("ServerPort", strconv.Itoa(int(port))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -66,6 +65,9 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("incorrect snapshot name format of %s", snap)
|
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{
|
itemSnap := model.Snapshot{
|
||||||
Name: snap,
|
Name: snap,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
@ -481,7 +483,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
|||||||
|
|
||||||
func (u *SnapshotService) saveJson(snapJson SnapshotJson, path string) error {
|
func (u *SnapshotService) saveJson(snapJson SnapshotJson, path string) error {
|
||||||
remarkInfo, _ := json.MarshalIndent(snapJson, "", "\t")
|
remarkInfo, _ := json.MarshalIndent(snapJson, "", "\t")
|
||||||
if err := ioutil.WriteFile(fmt.Sprintf("%s/snapshot.json", path), remarkInfo, 0640); err != nil {
|
if err := os.WriteFile(fmt.Sprintf("%s/snapshot.json", path), remarkInfo, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -790,7 +792,7 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
|
|||||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
||||||
return fmt.Errorf("load docker daemon.json conf failed, err: %v", err)
|
return fmt.Errorf("load docker daemon.json conf failed, err: %v", err)
|
||||||
}
|
}
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -806,7 +808,7 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,7 +854,7 @@ func (u *SnapshotService) handleTar(sourceDir, targetDir, name, exclusionRules s
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
@ -869,7 +871,7 @@ func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar -zxf %s -C %s .", sourceDir, targetDir)
|
commands := fmt.Sprintf("tar -zxf %s -C %s .", sourceDir, targetDir)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user