1 Commits

Author SHA1 Message Date
zhengkunwang223
c618e6e03e feat: 修改伪静态配置存储目录 2023-04-18 22:37:38 +08:00
555 changed files with 19823 additions and 47423 deletions

View File

@@ -1,34 +0,0 @@
on:
pull_request:
branches:
- dev
push:
branches:
- dev
name: Build Test
jobs:
build-linux-binary:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18.14'
- name: Build Web
id: build_frontend
run: |
cd frontend && npm install && npm run build:pro
env:
NODE_OPTIONS: --max-old-space-size=8192
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.20.x'
- name: Build Server
uses: goreleaser/goreleaser-action@v4
with:
args: release --snapshot --clean

View File

@@ -1,66 +0,0 @@
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: Create Release And Upload assets
jobs:
create-release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18.14'
- name: Build Web
run: |
cd frontend && npm install && npm run build:pro
env:
NODE_OPTIONS: --max-old-space-size=8192
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.20.x'
- name: Build Release
uses: goreleaser/goreleaser-action@v4
with:
distribution: goreleaser
version: latest
args: release --skip-publish --clean
- name: Upload Assets
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
draft: true
body: |
# 一、安装和升级
## 1.1 一键安装
```sh
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
```
## 1.2 在线升级
登录 1Panel Web 控制台,在页面右下角点击 **【检查更新】** 进行在线升级。
>更多信息请查阅在线文档https://1panel.cn/docs/
# 二、更新日志
files: |
dist/*.tar.gz
dist/checksums.txt
- name: Setup OSSUTIL
uses: yizhoumo/setup-ossutil@v1
with:
endpoint: ${{ secrets.OSS_ENDPOINT }}
access-key-id: ${{ secrets.OSS_ACCESS_KEY_ID }}
access-key-secret: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
ossutil-version: '1.7.14'
- name: Upload Assets to OSS
run: ossutil cp -r dist/ oss://resource-fit2cloud-com/1panel/package/stable/${{ github.ref_name }}/release/ --include "*.tar.gz" --include "checksums.txt" --only-current-dir --force

12
.gitignore vendored
View File

@@ -23,15 +23,3 @@ cmd/server/web/assets
cmd/server/web/monacoeditorwork cmd/server/web/monacoeditorwork
cmd/server/web/index.html cmd/server/web/index.html
frontend/auto-imports.d.ts frontend/auto-imports.d.ts
frontend/components.d.ts
.history/
dist/
1pctl
1panel.service
install.sh
quick_start.sh
cmd/server/web/.DS_Store
cmd/server/.DS_Store
cmd/server/fileList.txt
.fileList.txt

View File

@@ -1,58 +0,0 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# - export NODE_OPTIONS="--max-old-space-size=8192"
# - make build_web
- chmod +x ./script.sh
- ./script.sh
- sed -i 's@ORIGINAL_VERSION=.*@ORIGINAL_VERSION=v{{ .Version }}@g' 1pctl
- go mod tidy
builds:
- main: ./cmd/server/main.go
binary: 1panel
flags:
- -trimpath
ldflags:
- -w -s
env:
- CGO_ENABLED=0
goos:
- linux
goarm:
- 7
goarch:
- amd64
- arm64
- arm
- ppc64le
- s390x
archives:
- format: tar.gz
name_template: "1panel-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{- if .Arm }}v{{ .Arm }}{{ end }}"
wrap_in_directory: true
files:
- 1pctl
- 1panel.service
- install.sh
- README.md
- LICENSE
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
release:
draft: true
mode: append
extra_files:
- glob: dist/*.tar.gz
- glob: dist/checksums.txt
name_template: "Release {{.Tag}}"
# The lines beneath this are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

View File

@@ -1,3 +0,0 @@
{
"ansible.python.interpreterPath": "/opt/homebrew/bin/python3"
}

View File

@@ -10,25 +10,20 @@ WEB_PATH=$(BASE_PAH)/frontend
SERVER_PATH=$(BASE_PAH)/backend 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
ASSERT_PATH= $(BASE_PAH)/cmd/server/web/assets
clean_assets:
rm -rf $(ASSERT_PATH)
upx_bin:
upx $(BUILD_PATH)/$(APP_NAME)
build_frontend: build_frontend:
cd $(WEB_PATH) && npm install && npm run build:pro cd $(WEB_PATH) && npm install && npm run build:dev
build_backend_on_linux: build_backend_on_linux:
cd $(SERVER_PATH) \ cd $(SERVER_PATH) \
&& GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -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_backend_on_darwin: build_backend_on_darwin:
cd $(SERVER_PATH) \ cd $(SERVER_PATH) \
&& GOOS=linux GOARCH=amd64 $(GOBUILD) -trimpath -ldflags '-s -w' -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_frontend build_backend_on_linux 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_on_local: clean_assets build_frontend build_backend_on_darwin upx_bin build_all: build_frontend build_backend_on_linux

View File

@@ -6,7 +6,6 @@
<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://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/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a> <a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=shield" alt="FOSSA Status"></a>
</p> </p>
------------------------------ ------------------------------
@@ -14,9 +13,9 @@
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括: 1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/)域名绑定、SSL 证书配置等一键搞定; - **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/)域名绑定、SSL 证书配置等一键搞定;
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理等; - **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括应用管理、主机监控、文件管理、数据库管理、容器管理等;
- **安全可靠**基于容器来管理和部署应用,最小漏洞暴露面,提供防火墙和日志审计等功能; - **安全可靠**:最小漏洞暴露面,提供防火墙和安全审计等功能;
- **一键备份**:支持一键备份和恢复,备份数据到各类云端存储,永不丢失。 - **一键备份**:支持一键备份和恢复,备份数据云端存储,永不丢失。
## UI 展示 ## UI 展示
@@ -42,9 +41,12 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
- [在线文档](https://1panel.cn/docs/) - [在线文档](https://1panel.cn/docs/)
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760) - [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
**加入微信交流群** ## 社区
如果您在使用过程中有任何疑问或对建议,欢迎提交 GitHub Issue 或加入到我们微信交流群进行交流沟通。
**微信交流群**
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/> <img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
@@ -59,10 +61,6 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date) [![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## FOSSA Status
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_large)
## License ## License
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved. Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.

View File

@@ -3,7 +3,6 @@
如果您发现安全问题,请直接联系我们: 如果您发现安全问题,请直接联系我们:
- wanghe@fit2cloud.com - wanghe@fit2cloud.com
- zhengkun@fit2cloud.com
- support@fit2cloud.com - support@fit2cloud.com
- 400-052-0755 - 400-052-0755
@@ -14,7 +13,6 @@
All security bugs should be reported to the contact as below: All security bugs should be reported to the contact as below:
- wanghe@fit2cloud.com - wanghe@fit2cloud.com
- zhengkun@fit2cloud.com
- support@fit2cloud.com - support@fit2cloud.com
- 400-052-0755 - 400-052-0755

View File

@@ -5,7 +5,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request" "github.com/1Panel-dev/1Panel/backend/app/dto/request"
"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/i18n"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -39,24 +38,14 @@ 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) {
go appService.SyncAppListFromLocal() appService.SyncAppListFromLocal()
res, err := appService.GetAppUpdate() global.LOG.Infof("sync app list start ...")
if err != nil { if err := appService.SyncAppListFromRemote(); err != nil {
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
} }
if !res.CanUpdate { global.LOG.Infof("sync app list success!")
helper.SuccessWithMsg(c, i18n.GetMsgByKey("AppStoreIsUpToDate"))
return
}
go func() {
global.LOG.Infof("sync app list start ...")
if err := appService.SyncAppListFromRemote(); err != nil {
global.LOG.Errorf("sync app list error [%s]", err.Error())
} else {
global.LOG.Infof("sync app list success!")
}
}()
helper.SuccessWithData(c, "") helper.SuccessWithData(c, "")
} }
@@ -130,22 +119,6 @@ func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
helper.SuccessWithData(c, appDetailDTO) helper.SuccessWithData(c, appDetailDTO)
} }
// @Tags App
// @Summary Get Ignore App
// @Description 获取忽略的应用版本
// @Accept json
// @Success 200 {object} response.IgnoredApp
// @Security ApiKeyAuth
// @Router /apps/ingored [get]
func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
res, err := appService.GetIgnoredApp()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags App // @Tags App
// @Summary Install app // @Summary Install app
// @Description 安装应用 // @Description 安装应用
@@ -154,7 +127,7 @@ func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
// @Success 200 {object} model.AppInstall // @Success 200 {object} model.AppInstall
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /apps/install [post] // @Router /apps/install [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[{"input_column":"name","input_value":"name","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"} // @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"name","input_value":"name","isList":false,"db":"app_installs","output_colume":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_colume":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"}
func (b *BaseApi) InstallApp(c *gin.Context) { func (b *BaseApi) InstallApp(c *gin.Context) {
var req request.AppInstallCreate var req request.AppInstallCreate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -118,7 +118,7 @@ func (b *BaseApi) LoadConnInfo(c *gin.Context) {
// @Description 删除前检查 // @Description 删除前检查
// @Accept json // @Accept json
// @Param appInstallId path integer true "App install id" // @Param appInstallId path integer true "App install id"
// @Success 200 {array} dto.AppResource // @Success 200 {anrry} dto.AppResource
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /apps/installed/delete/check/:appInstallId [get] // @Router /apps/installed/delete/check/:appInstallId [get]
func (b *BaseApi) DeleteCheck(c *gin.Context) { func (b *BaseApi) DeleteCheck(c *gin.Context) {
@@ -159,7 +159,7 @@ func (b *BaseApi) SyncInstalled(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /apps/installed/op [post] // @Router /apps/installed/op [post]
// @x-panel-log {"bodyKeys":["installId","operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"name","output_value":"appName"},{"input_column":"id","input_value":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"[operate] 应用 [appKey][appName]","formatEN":"[operate] App [appKey][appName]"} // @x-panel-log {"bodyKeys":["installId","operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"installId","isList":false,"db":"app_installs","output_colume":"app_id","output_value":"appId"},{"input_colume":"id","input_value":"installId","isList":false,"db":"app_installs","output_colume":"name","output_value":"appName"},{"input_colume":"id","input_value":"appId","isList":false,"db":"apps","output_colume":"key","output_value":"appKey"}],"formatZH":"[appKey] 应用 [appName] [operate]","formatEN":"[appKey] App [appName] [operate]"}
func (b *BaseApi) OperateInstalled(c *gin.Context) { func (b *BaseApi) OperateInstalled(c *gin.Context) {
var req request.AppInstalledOperate var req request.AppInstalledOperate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -178,7 +178,7 @@ func (b *BaseApi) OperateInstalled(c *gin.Context) {
// @Description 通过 key 获取应用 service // @Description 通过 key 获取应用 service
// @Accept json // @Accept json
// @Param key path string true "request" // @Param key path string true "request"
// @Success 200 {array} response.AppService // @Success 200 {anrry} response.AppService
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /apps/services/:key [get] // @Router /apps/services/:key [get]
func (b *BaseApi) GetServices(c *gin.Context) { func (b *BaseApi) GetServices(c *gin.Context) {
@@ -196,7 +196,7 @@ func (b *BaseApi) GetServices(c *gin.Context) {
// @Description 通过 install id 获取应用更新版本 // @Description 通过 install id 获取应用更新版本
// @Accept json // @Accept json
// @Param appInstallId path integer true "request" // @Param appInstallId path integer true "request"
// @Success 200 {array} dto.AppVersion // @Success 200 {anrry} dto.AppVersion
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /apps/installed/:appInstallId/versions [get] // @Router /apps/installed/:appInstallId/versions [get]
func (b *BaseApi) GetUpdateVersions(c *gin.Context) { func (b *BaseApi) GetUpdateVersions(c *gin.Context) {
@@ -305,25 +305,3 @@ func (b *BaseApi) UpdateInstalled(c *gin.Context) {
} }
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags App
// @Summary ignore App Update
// @Description 忽略应用升级版本
// @Accept json
// @Param request body request.AppInstalledIgnoreUpgrade true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/ignore [post]
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"忽略应用 [installId] 版本升级","formatEN":"Application param update [installId]"}
func (b *BaseApi) IgnoreUpgrade(c *gin.Context) {
var req request.AppInstalledIgnoreUpgrade
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := appInstallService.IgnoreUpgrade(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}

View File

@@ -1,6 +1,8 @@
package v1 package v1
import ( import (
"errors"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "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"
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
@@ -26,7 +28,7 @@ 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 req.AuthMethod != "jwt" && !req.IgnoreCaptcha { if req.AuthMethod != "jwt" {
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil { if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
@@ -100,15 +102,71 @@ func (b *BaseApi) Captcha(c *gin.Context) {
// @Summary Load safety status // @Summary Load safety status
// @Description 获取系统安全登录状态 // @Description 获取系统安全登录状态
// @Success 200 // @Success 200
// @Router /auth/issafety [get] // @Failure 402
func (b *BaseApi) CheckIsSafety(c *gin.Context) { // @Router /auth/status [get]
code := c.DefaultQuery("code", "") func (b *BaseApi) GetSafetyStatus(c *gin.Context) {
status, err := authService.CheckIsSafety(code) if err := authService.SafetyStatus(c); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) SafeEntrance(c *gin.Context) {
code, exist := c.Params.Get("code")
if !exist {
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
return
}
ok, err := authService.VerifyCode(code)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
return
}
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
return
}
if err := authService.SafeEntrance(c, code); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Auth
// @Summary Check is First login
// @Description 判断是否为首次登录
// @Success 200
// @Router /auth/status [get]
func (b *BaseApi) CheckIsFirstLogin(c *gin.Context) {
helper.SuccessWithData(c, authService.CheckIsFirst())
}
// @Tags Auth
// @Summary Init user
// @Description 初始化用户
// @Accept json
// @Param request body dto.InitUser true "request"
// @Success 200
// @Router /auth/init [post]
func (b *BaseApi) InitUserInfo(c *gin.Context) {
var req dto.InitUser
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 := authService.InitUser(c, req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
helper.SuccessWithData(c, status) helper.SuccessWithData(c, nil)
} }
// @Tags Auth // @Tags Auth
@@ -120,20 +178,6 @@ func (b *BaseApi) CheckIsDemo(c *gin.Context) {
helper.SuccessWithData(c, global.CONF.System.IsDemo) helper.SuccessWithData(c, global.CONF.System.IsDemo)
} }
// @Tags Auth
// @Summary Load System Language
// @Description 获取系统语言设置
// @Success 200
// @Router /auth/language [get]
func (b *BaseApi) GetLanguage(c *gin.Context) {
settingInfo, err := settingService.GetSettingInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, settingInfo.Language)
}
func saveLoginLogs(c *gin.Context, err error) { func saveLoginLogs(c *gin.Context, err error) {
var logs model.LoginLog var logs model.LoginLog
if err != nil { if err != nil {

View File

@@ -2,8 +2,6 @@ package v1
import ( import (
"encoding/base64" "encoding/base64"
"fmt"
"path"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "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"
@@ -60,7 +58,7 @@ func (b *BaseApi) CreateBackup(c *gin.Context) {
// @Description 获取 bucket 列表 // @Description 获取 bucket 列表
// @Accept json // @Accept json
// @Param request body dto.ForBuckets true "request" // @Param request body dto.ForBuckets true "request"
// @Success 200 {array} string // @Success 200 {anrry} string
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/backup/search [post] // @Router /settings/backup/search [post]
func (b *BaseApi) ListBuckets(c *gin.Context) { func (b *BaseApi) ListBuckets(c *gin.Context) {
@@ -98,22 +96,6 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
helper.SuccessWithData(c, buckets) helper.SuccessWithData(c, buckets)
} }
// @Tags Backup Account
// @Summary Load OneDrive info
// @Description 获取 OneDrive 信息
// @Accept json
// @Success 200 string clientID
// @Security ApiKeyAuth
// @Router /settings/backup/onedrive [get]
func (b *BaseApi) LoadOneDriveInfo(c *gin.Context) {
clientID, err := backupService.LoadOneDriveInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, clientID)
}
// @Tags Backup Account // @Tags Backup Account
// @Summary Delete backup account // @Summary Delete backup account
// @Description 删除备份账号 // @Description 删除备份账号
@@ -122,7 +104,7 @@ func (b *BaseApi) LoadOneDriveInfo(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":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":true,"db":"backup_accounts","output_column":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"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.OperateByID var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -204,7 +186,7 @@ func (b *BaseApi) DownloadRecord(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/backup/record/del [post] // @Router /settings/backup/record/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"backup_records","output_column":"file_name","output_value":"files"}],"formatZH":"删除备份记录 [files]","formatEN":"delete backup records [files]"} // @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"backup_records","output_colume":"file_name","output_value":"files"}],"formatZH":"删除备份记录 [files]","formatEN":"delete backup records [files]"}
func (b *BaseApi) DeleteBackupRecord(c *gin.Context) { func (b *BaseApi) DeleteBackupRecord(c *gin.Context) {
var req dto.BatchDeleteReq var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -269,7 +251,7 @@ func (b *BaseApi) UpdateBackup(c *gin.Context) {
// @Tags Backup Account // @Tags Backup Account
// @Summary List backup accounts // @Summary List backup accounts
// @Description 获取备份账号列表 // @Description 获取备份账号列表
// @Success 200 {array} dto.BackupInfo // @Success 200 {anrry} dto.BackupInfo
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/backup/search [get] // @Router /settings/backup/search [get]
func (b *BaseApi) ListBackup(c *gin.Context) { func (b *BaseApi) ListBackup(c *gin.Context) {
@@ -287,7 +269,7 @@ func (b *BaseApi) ListBackup(c *gin.Context) {
// @Description 获取备份账号内文件列表 // @Description 获取备份账号内文件列表
// @Accept json // @Accept json
// @Param request body dto.BackupSearchFile true "request" // @Param request body dto.BackupSearchFile true "request"
// @Success 200 {array} string // @Success 200 {anrry} string
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/backup/search/files [post] // @Router /settings/backup/search/files [post]
func (b *BaseApi) LoadFilesFromBackup(c *gin.Context) { func (b *BaseApi) LoadFilesFromBackup(c *gin.Context) {
@@ -374,14 +356,6 @@ func (b *BaseApi) Recover(c *gin.Context) {
return return
} }
if req.Source != "LOCAL" {
downloadPath, err := backupService.DownloadRecord(dto.DownloadRecord{Source: req.Source, FileDir: path.Dir(req.File), FileName: path.Base(req.File)})
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("download file failed, err: %v", err))
return
}
req.File = downloadPath
}
switch req.Type { switch req.Type {
case "mysql": case "mysql":
if err := backupService.MysqlRecover(req); err != nil { if err := backupService.MysqlRecover(req); err != nil {

View File

@@ -85,7 +85,7 @@ func (b *BaseApi) ListCommand(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/command/del [post] // @Router /hosts/command/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"commands","output_column":"name","output_value":"names"}],"formatZH":"删除快捷命令 [names]","formatEN":"delete quick command [names]"} // @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"commands","output_colume":"name","output_value":"names"}],"formatZH":"删除快捷命令 [names]","formatEN":"delete quick command [names]"}
func (b *BaseApi) DeleteCommand(c *gin.Context) { func (b *BaseApi) DeleteCommand(c *gin.Context) {
var req dto.BatchDeleteReq var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -66,7 +66,7 @@ func (b *BaseApi) SearchComposeTemplate(c *gin.Context) {
// @Summary List compose templates // @Summary List compose templates
// @Description 获取容器编排模版列表 // @Description 获取容器编排模版列表
// @Produce json // @Produce json
// @Success 200 {array} dto.ComposeTemplateInfo // @Success 200 {anrry} dto.ComposeTemplateInfo
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/template [get] // @Router /containers/template [get]
func (b *BaseApi) ListComposeTemplate(c *gin.Context) { func (b *BaseApi) ListComposeTemplate(c *gin.Context) {
@@ -87,7 +87,7 @@ func (b *BaseApi) ListComposeTemplate(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/template/del [post] // @Router /containers/template/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"compose_templates","output_column":"name","output_value":"names"}],"formatZH":"删除 compose 模版 [names]","formatEN":"delete compose template [names]"} // @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"compose_templates","output_colume":"name","output_value":"names"}],"formatZH":"删除 compose 模版 [names]","formatEN":"delete compose template [names]"}
func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) { func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) {
var req dto.BatchDeleteReq var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -114,7 +114,7 @@ func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/template/update [post] // @Router /containers/template/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"compose_templates","output_column":"name","output_value":"name"}],"formatZH":"更新 compose 模版 [name]","formatEN":"update compose template information [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"compose_templates","output_colume":"name","output_value":"name"}],"formatZH":"更新 compose 模版 [name]","formatEN":"update compose template information [name]"}
func (b *BaseApi) UpdateComposeTemplate(c *gin.Context) { func (b *BaseApi) UpdateComposeTemplate(c *gin.Context) {
var req dto.ComposeTemplateUpdate var req dto.ComposeTemplateUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -40,23 +40,6 @@ func (b *BaseApi) SearchContainer(c *gin.Context) {
}) })
} }
// @Tags Container
// @Summary List containers
// @Description 获取容器名称
// @Accept json
// @Produce json
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/list [post]
func (b *BaseApi) ListContainer(c *gin.Context) {
list, err := containerService.List()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Container Compose // @Tags Container Compose
// @Summary Page composes // @Summary Page composes
// @Description 获取编排列表分页 // @Description 获取编排列表分页
@@ -170,97 +153,17 @@ func (b *BaseApi) OperatorCompose(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Container
// @Summary Update container
// @Description 更新容器
// @Accept json
// @Param request body dto.ContainerOperate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/update [post]
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新容器 [name][image]","formatEN":"update container [name][image]"}
func (b *BaseApi) ContainerUpdate(c *gin.Context) {
var req dto.ContainerOperate
if err := c.ShouldBindJSON(&req); err != nil {
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 := containerService.ContainerUpdate(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Load container info
// @Description 获取容器表单信息
// @Accept json
// @Param request body dto.OperationWithName true "request"
// @Success 200 {object} dto.ContainerOperate
// @Security ApiKeyAuth
// @Router /containers/info [post]
func (b *BaseApi) ContainerInfo(c *gin.Context) {
var req dto.OperationWithName
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := containerService.ContainerInfo(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Summary Load container limis
// @Description 获取容器限制
// @Success 200 {object} dto.ResourceLimit
// @Security ApiKeyAuth
// @Router /containers/limit [get]
func (b *BaseApi) LoadResouceLimit(c *gin.Context) {
data, err := containerService.LoadResouceLimit()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Summary Load container stats
// @Description 获取容器列表资源占用
// @Success 200 {array} dto.ContainerListStats
// @Security ApiKeyAuth
// @Router /containers/list/stats [get]
func (b *BaseApi) ContainerListStats(c *gin.Context) {
datas, err := containerService.ContainerListStats()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, datas)
}
// @Tags Container // @Tags Container
// @Summary Create container // @Summary Create container
// @Description 创建容器 // @Description 创建容器
// @Accept json // @Accept json
// @Param request body dto.ContainerOperate true "request" // @Param request body dto.ContainerCreate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers [post] // @Router /containers [post]
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器 [name][image]","formatEN":"create container [name][image]"} // @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器 [name][image]","formatEN":"create container [name][image]"}
func (b *BaseApi) ContainerCreate(c *gin.Context) { func (b *BaseApi) ContainerCreate(c *gin.Context) {
var req dto.ContainerOperate var req dto.ContainerCreate
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
@@ -276,103 +179,6 @@ func (b *BaseApi) ContainerCreate(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Container
// @Summary Upgrade container
// @Description 更新容器镜像
// @Accept json
// @Param request body dto.ContainerUpgrade true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/upgrade [post]
// @x-panel-log {"bodyKeys":["name","image"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新容器镜像 [name][image]","formatEN":"upgrade container image [name][image]"}
func (b *BaseApi) ContainerUpgrade(c *gin.Context) {
var req dto.ContainerUpgrade
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 := containerService.ContainerUpgrade(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Clean container
// @Description 容器清理
// @Accept json
// @Param request body dto.ContainerPrune true "request"
// @Success 200 {object} dto.ContainerPruneReport
// @Security ApiKeyAuth
// @Router /containers/prune [post]
// @x-panel-log {"bodyKeys":["pruneType"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清理容器 [pruneType]","formatEN":"clean container [pruneType]"}
func (b *BaseApi) ContainerPrune(c *gin.Context) {
var req dto.ContainerPrune
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
}
report, err := containerService.Prune(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, report)
}
// @Tags Container
// @Summary Clean container log
// @Description 清理容器日志
// @Accept json
// @Param request body dto.OperationWithName true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/clean/log [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清理容器 [name] 日志","formatEN":"clean container [name] logs"}
func (b *BaseApi) CleanContainerLog(c *gin.Context) {
var req dto.OperationWithName
if err := c.ShouldBindJSON(&req); err != nil {
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 := containerService.ContainerLogClean(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Load container log
// @Description 获取容器操作日志
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/load/log [post]
func (b *BaseApi) LoadContainerLog(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content := containerService.LoadContainerLogs(req)
helper.SuccessWithData(c, content)
}
// @Tags Container // @Tags Container
// @Summary Operate Container // @Summary Operate Container
// @Description 容器操作 // @Description 容器操作
@@ -403,7 +209,7 @@ func (b *BaseApi) ContainerOperation(c *gin.Context) {
// @Summary Container stats // @Summary Container stats
// @Description 容器监控信息 // @Description 容器监控信息
// @Param id path integer true "容器id" // @Param id path integer true "容器id"
// @Success 200 {object} dto.ContainerStats // @Success 200 {object} dto.ContainterStats
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/stats/:id [get] // @Router /containers/stats/:id [get]
func (b *BaseApi) ContainerStats(c *gin.Context) { func (b *BaseApi) ContainerStats(c *gin.Context) {
@@ -451,29 +257,27 @@ func (b *BaseApi) Inspect(c *gin.Context) {
// @Tags Container // @Tags Container
// @Summary Container logs // @Summary Container logs
// @Description 容器日志 // @Description 容器日志
// @Param container query string false "容器名称" // @Accept json
// @Param since query string false "时间筛选" // @Param request body dto.ContainerLog true "request"
// @Param follow query string false "是否追踪" // @Success 200 {string} logs
// @Param tail query string false "显示行号"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/search/log [post] // @Router /containers/search/log [post]
func (b *BaseApi) ContainerLogs(c *gin.Context) { func (b *BaseApi) ContainerLogs(c *gin.Context) {
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil) var req dto.ContainerLog
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
}
logs, err := containerService.ContainerLogs(req)
if err != nil { if err != nil {
global.LOG.Errorf("gin context http handler failed, err: %v", err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer wsConn.Close()
container := c.Query("container")
since := c.Query("since")
follow := c.Query("follow") == "true"
tail := c.Query("tail")
if err := containerService.ContainerLogs(wsConn, container, since, tail, follow); err != nil {
_ = wsConn.WriteMessage(1, []byte(err.Error()))
return return
} }
helper.SuccessWithData(c, logs)
} }
// @Tags Container Network // @Tags Container Network
@@ -507,23 +311,6 @@ func (b *BaseApi) SearchNetwork(c *gin.Context) {
}) })
} }
// @Tags Container Network
// @Summary List networks
// @Description 获取容器网络列表
// @Accept json
// @Produce json
// @Success 200 {array} dto.Options
// @Security ApiKeyAuth
// @Router /containers/network [get]
func (b *BaseApi) ListNetwork(c *gin.Context) {
list, err := containerService.ListNetwork()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Container Network // @Tags Container Network
// @Summary Delete network // @Summary Delete network
// @Description 删除容器网络 // @Description 删除容器网络
@@ -555,13 +342,13 @@ func (b *BaseApi) DeleteNetwork(c *gin.Context) {
// @Summary Create network // @Summary Create network
// @Description 创建容器网络 // @Description 创建容器网络
// @Accept json // @Accept json
// @Param request body dto.NetworkCreate true "request" // @Param request body dto.NetworkCreat true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/network [post] // @Router /containers/network [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器网络 name","formatEN":"create container network [name]"} // @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器网络 name","formatEN":"create container network [name]"}
func (b *BaseApi) CreateNetwork(c *gin.Context) { func (b *BaseApi) CreateNetwork(c *gin.Context) {
var req dto.NetworkCreate var req dto.NetworkCreat
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
@@ -613,10 +400,11 @@ func (b *BaseApi) SearchVolume(c *gin.Context) {
// @Summary List volumes // @Summary List volumes
// @Description 获取容器存储卷列表 // @Description 获取容器存储卷列表
// @Accept json // @Accept json
// @Param request body dto.PageInfo true "request"
// @Produce json // @Produce json
// @Success 200 {array} dto.Options // @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/volume [get] // @Router /containers/volume/search [get]
func (b *BaseApi) ListVolume(c *gin.Context) { func (b *BaseApi) ListVolume(c *gin.Context) {
list, err := containerService.ListVolume() list, err := containerService.ListVolume()
if err != nil { if err != nil {
@@ -657,13 +445,13 @@ func (b *BaseApi) DeleteVolume(c *gin.Context) {
// @Summary Create volume // @Summary Create volume
// @Description 创建容器存储卷 // @Description 创建容器存储卷
// @Accept json // @Accept json
// @Param request body dto.VolumeCreate true "request" // @Param request body dto.VolumeCreat true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/volume [post] // @Router /containers/volume [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器存储卷 [name]","formatEN":"create container volume [name]"} // @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器存储卷 [name]","formatEN":"create container volume [name]"}
func (b *BaseApi) CreateVolume(c *gin.Context) { func (b *BaseApi) CreateVolume(c *gin.Context) {
var req dto.VolumeCreate var req dto.VolumeCreat
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

View File

@@ -7,7 +7,6 @@ import (
"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/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -78,9 +77,8 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
loc, _ := time.LoadLocation(common.LoadTimeZone()) req.StartTime = req.StartTime.Add(8 * time.Hour)
req.StartTime = req.StartTime.In(loc) req.EndTime = req.EndTime.Add(8 * time.Hour)
req.EndTime = req.EndTime.In(loc)
total, list, err := cronjobService.SearchRecords(req) total, list, err := cronjobService.SearchRecords(req)
if err != nil { if err != nil {
@@ -94,28 +92,6 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
}) })
} }
// @Tags Cronjob
// @Summary Load Cronjob record log
// @Description 获取计划任务记录日志
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjob/record/log [post]
func (b *BaseApi) LoadRecordLog(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content, err := cronjobService.LoadRecordLog(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Cronjob // @Tags Cronjob
// @Summary Clean job records // @Summary Clean job records
// @Description 清空计划任务记录 // @Description 清空计划任务记录
@@ -124,7 +100,7 @@ func (b *BaseApi) LoadRecordLog(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /cronjobs/records/clean [post] // @Router /cronjobs/records/clean [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"清空计划任务记录 [name]","formatEN":"clean cronjob [name] records"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"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) { func (b *BaseApi) CleanRecord(c *gin.Context) {
var req dto.CronjobClean var req dto.CronjobClean
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -148,7 +124,7 @@ func (b *BaseApi) CleanRecord(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /cronjobs/del [post] // @Router /cronjobs/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"cronjobs","output_column":"name","output_value":"names"}],"formatZH":"删除计划任务 [names]","formatEN":"delete cronjob [names]"} // @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"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.CronjobBatchDelete var req dto.CronjobBatchDelete
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -175,7 +151,7 @@ func (b *BaseApi) DeleteCronjob(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /cronjobs/update [post] // @Router /cronjobs/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"}
func (b *BaseApi) UpdateCronjob(c *gin.Context) { func (b *BaseApi) UpdateCronjob(c *gin.Context) {
var req dto.CronjobUpdate var req dto.CronjobUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -202,7 +178,7 @@ func (b *BaseApi) UpdateCronjob(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /cronjobs/status [post] // @Router /cronjobs/status [post]
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"修改计划任务 [name] 状态为 [status]","formatEN":"change the status of cronjob [name] to [status]."} // @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"修改计划任务 [name] 状态为 [status]","formatEN":"change the status of cronjob [name] to [status]."}
func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) { func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) {
var req dto.CronjobUpdateStatus var req dto.CronjobUpdateStatus
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -229,7 +205,7 @@ func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /cronjobs/download [post] // @Router /cronjobs/download [post]
// @x-panel-log {"bodyKeys":["recordID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"recordID","isList":false,"db":"job_records","output_column":"file","output_value":"file"}],"formatZH":"下载计划任务记录 [file]","formatEN":"download the cronjob record [file]"} // @x-panel-log {"bodyKeys":["recordID"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"recordID","isList":false,"db":"job_records","output_colume":"file","output_value":"file"}],"formatZH":"下载计划任务记录 [file]","formatEN":"download the cronjob record [file]"}
func (b *BaseApi) TargetDownload(c *gin.Context) { func (b *BaseApi) TargetDownload(c *gin.Context) {
var req dto.CronjobDownload var req dto.CronjobDownload
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -246,8 +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
} }
helper.SuccessWithData(c, filePath)
c.File(filePath)
} }
// @Tags Cronjob // @Tags Cronjob
@@ -258,7 +233,7 @@ func (b *BaseApi) TargetDownload(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /cronjobs/handle [post] // @Router /cronjobs/handle [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"手动执行计划任务 [name]","formatEN":"manually execute the cronjob [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"手动执行计划任务 [name]","formatEN":"manually execute the cronjob [name]"}
func (b *BaseApi) HandleOnce(c *gin.Context) { func (b *BaseApi) HandleOnce(c *gin.Context) {
var req dto.OperateByID var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -54,7 +54,7 @@ func (b *BaseApi) CreateMysql(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/description/update [post] // @Router /databases/description/update [post]
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"mysql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the mysql database [name] is modified => [description]"} // @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"mysql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the mysql database [name] is modified => [description]"}
func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) { func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) {
var req dto.UpdateDescription var req dto.UpdateDescription
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -80,7 +80,7 @@ func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/change/password [post] // @Router /databases/change/password [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 密码","formatEN":"Update database [name] password"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 密码","formatEN":"Update database [name] password"}
func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) { func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
var req dto.ChangeDBInfo var req dto.ChangeDBInfo
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -115,7 +115,7 @@ func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/change/access [post] // @Router /databases/change/access [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 访问权限","formatEN":"Update database [name] access"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 访问权限","formatEN":"Update database [name] access"}
func (b *BaseApi) ChangeMysqlAccess(c *gin.Context) { func (b *BaseApi) ChangeMysqlAccess(c *gin.Context) {
var req dto.ChangeDBInfo var req dto.ChangeDBInfo
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -188,12 +188,12 @@ func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) {
// @Summary Page mysql databases // @Summary Page mysql databases
// @Description 获取 mysql 数据库列表分页 // @Description 获取 mysql 数据库列表分页
// @Accept json // @Accept json
// @Param request body dto.MysqlDBSearch true "request" // @Param request body dto.SearchWithPage true "request"
// @Success 200 {object} dto.PageResult // @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/search [post] // @Router /databases/search [post]
func (b *BaseApi) SearchMysql(c *gin.Context) { func (b *BaseApi) SearchMysql(c *gin.Context) {
var req dto.MysqlDBSearch var req dto.SearchWithPage
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
@@ -216,11 +216,11 @@ func (b *BaseApi) SearchMysql(c *gin.Context) {
// @Description 获取 mysql 数据库列表 // @Description 获取 mysql 数据库列表
// @Accept json // @Accept json
// @Param request body dto.PageInfo true "request" // @Param request body dto.PageInfo true "request"
// @Success 200 {array} dto.MysqlOption // @Success 200 {anrry} string
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/options [get] // @Router /databases/options [get]
func (b *BaseApi) ListDBName(c *gin.Context) { func (b *BaseApi) ListDBName(c *gin.Context) {
list, err := mysqlService.ListDBOption() list, err := mysqlService.ListDBName()
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
@@ -229,31 +229,12 @@ func (b *BaseApi) ListDBName(c *gin.Context) {
helper.SuccessWithData(c, list) helper.SuccessWithData(c, list)
} }
// @Tags Database Mysql
// @Summary Load mysql database from remote
// @Description 从服务器获取
// @Security ApiKeyAuth
// @Router /databases/load/:from [get]
func (b *BaseApi) LoadDBFromRemote(c *gin.Context) {
from, err := helper.GetStrParamByKey(c, "from")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := mysqlService.LoadFromRemote(from); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Database Mysql // @Tags Database Mysql
// @Summary Check before delete mysql database // @Summary Check before delete mysql database
// @Description Mysql 数据库删除前检查 // @Description Mysql 数据库删除前检查
// @Accept json // @Accept json
// @Param request body dto.OperateByID true "request" // @Param request body dto.OperateByID true "request"
// @Success 200 {array} string // @Success 200 {anrry} string
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/del/check [post] // @Router /databases/del/check [post]
func (b *BaseApi) DeleteCheckMysql(c *gin.Context) { func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
@@ -283,7 +264,7 @@ func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /databases/del [post] // @Router /databases/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"删除 mysql 数据库 [name]","formatEN":"delete mysql database [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"删除 mysql 数据库 [name]","formatEN":"delete mysql database [name]"}
func (b *BaseApi) DeleteMysql(c *gin.Context) { func (b *BaseApi) DeleteMysql(c *gin.Context) {
var req dto.MysqlDBDelete var req dto.MysqlDBDelete
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -321,28 +302,6 @@ func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
helper.SuccessWithData(c, data) helper.SuccessWithData(c, data)
} }
// @Tags Database
// @Summary Load Database file
// @Description 获取数据库文件
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/load/file [post]
func (b *BaseApi) LoadDatabaseFile(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content, err := mysqlService.LoadDatabaseFile(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Database Mysql // @Tags Database Mysql
// @Summary Load mysql remote access // @Summary Load mysql remote access
// @Description 获取 mysql 远程访问权限 // @Description 获取 mysql 远程访问权限

View File

@@ -58,13 +58,13 @@ func (b *BaseApi) LoadDaemonJson(c *gin.Context) {
// @Summary Update docker daemon.json // @Summary Update docker daemon.json
// @Description 修改 docker 配置信息 // @Description 修改 docker 配置信息
// @Accept json // @Accept json
// @Param request body dto.SettingUpdate true "request" // @Param request body dto.DaemonJsonConf true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/daemonjson/update [post] // @Router /containers/daemonjson/update [post]
// @x-panel-log {"bodyKeys":["key", "value"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 配置 [key]=>[value]","formatEN":"Updated the docker daemon.json configuration [key]=>[value]"} // @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 配置","formatEN":"Updated the docker daemon.json configuration"}
func (b *BaseApi) UpdateDaemonJson(c *gin.Context) { func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
var req dto.SettingUpdate var req dto.DaemonJsonConf
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
@@ -78,30 +78,6 @@ func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Container Docker
// @Summary Update docker daemon.json log option
// @Description 修改 docker 日志配置
// @Accept json
// @Param request body dto.LogOption true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 日志配置","formatEN":"Updated the docker daemon.json log option"}
func (b *BaseApi) UpdateLogOption(c *gin.Context) {
var req dto.LogOption
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := dockerService.UpdateLogOption(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Container Docker // @Tags Container Docker
// @Summary Update docker daemon.json by upload file // @Summary Update docker daemon.json by upload file
// @Description 上传替换 docker 配置文件 // @Description 上传替换 docker 配置文件

View File

@@ -21,16 +21,14 @@ var (
imageService = service.NewIImageService() imageService = service.NewIImageService()
dockerService = service.NewIDockerService() dockerService = service.NewIDockerService()
mysqlService = service.NewIMysqlService() mysqlService = service.NewIMysqlService()
remoteDBService = service.NewIRemoteDBService() redisService = service.NewIRedisService()
redisService = service.NewIRedisService()
cronjobService = service.NewICronjobService() cronjobService = service.NewICronjobService()
hostService = service.NewIHostService() hostService = service.NewIHostService()
groupService = service.NewIGroupService() groupService = service.NewIGroupService()
fileService = service.NewIFileService() fileService = service.NewIFileService()
sshService = service.NewISSHService()
firewallService = service.NewIFirewallService() firewallService = service.NewIFirewallService()
settingService = service.NewISettingService() settingService = service.NewISettingService()
@@ -50,7 +48,4 @@ var (
upgradeService = service.NewIUpgradeService() upgradeService = service.NewIUpgradeService()
runtimeService = service.NewRuntimeService() runtimeService = service.NewRuntimeService()
processService = service.NewIProcessService()
hostToolService = service.NewIHostToolService()
) )

View File

@@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/url"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@@ -52,7 +51,7 @@ func (b *BaseApi) ListFiles(c *gin.Context) {
// @Description 分页获取上传文件 // @Description 分页获取上传文件
// @Accept json // @Accept json
// @Param request body request.SearchUploadWithPage true "request" // @Param request body request.SearchUploadWithPage true "request"
// @Success 200 {array} response.FileInfo // @Success 200 {anrry} response.FileInfo
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /files/upload/search [post] // @Router /files/upload/search [post]
func (b *BaseApi) SearchUploadWithPage(c *gin.Context) { func (b *BaseApi) SearchUploadWithPage(c *gin.Context) {
@@ -81,7 +80,7 @@ func (b *BaseApi) SearchUploadWithPage(c *gin.Context) {
// @Description 加载文件树 // @Description 加载文件树
// @Accept json // @Accept json
// @Param request body request.FileOption true "request" // @Param request body request.FileOption true "request"
// @Success 200 {array} response.FileTree // @Success 200 {anrry} response.FileTree
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /files/tree [post] // @Router /files/tree [post]
func (b *BaseApi) GetFileTree(c *gin.Context) { func (b *BaseApi) GetFileTree(c *gin.Context) {
@@ -187,29 +186,7 @@ func (b *BaseApi) ChangeFileMode(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
helper.SuccessWithOutData(c) helper.SuccessWithData(c, nil)
}
// @Tags File
// @Summary Change file owner
// @Description 修改文件用户/组
// @Accept json
// @Param request body request.FileRoleUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/owner [post]
// @x-panel-log {"bodyKeys":["path","user","group"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改用户/组 [paths] => [user]/[group]","formatEN":"Change owner [paths] => [user]/[group]"}
func (b *BaseApi) ChangeFileOwner(c *gin.Context) {
var req request.FileRoleUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := fileService.ChangeOwner(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
} }
// @Tags File // @Tags File
@@ -455,93 +432,39 @@ func (b *BaseApi) MoveFile(c *gin.Context) {
// @Router /files/download [post] // @Router /files/download [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"} // @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
func (b *BaseApi) Download(c *gin.Context) { func (b *BaseApi) Download(c *gin.Context) {
filePath := c.Query("path") var req request.FileDownload
file, err := os.Open(filePath)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
}
info, _ := file.Stat()
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
}
// @Tags File
// @Summary Chunk Download file
// @Description 分片下载下载文件
// @Accept json
// @Param request body request.FileDownload true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/chunkdownload [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
func (b *BaseApi) DownloadChunkFiles(c *gin.Context) {
var req request.FileChunkDownload
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
} }
fileOp := files.NewFileOp() filePath, err := fileService.FileDownload(req)
if !fileOp.Stat(req.Path) {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrPathNotFound, nil)
return
}
filePath := req.Path
fstFile, err := fileOp.OpenFile(filePath)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
info, err := fstFile.Stat() c.File(filePath)
if err != nil { }
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
// @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 return
} }
if info.IsDir() { if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileDownloadDir, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
c.File(req.Path)
c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", req.Name))
c.Writer.Header().Set("Content-Type", "application/octet-stream")
c.Writer.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Writer.Header().Set("Accept-Ranges", "bytes")
if c.Request.Header.Get("Range") != "" {
rangeHeader := c.Request.Header.Get("Range")
rangeArr := strings.Split(rangeHeader, "=")[1]
rangeParts := strings.Split(rangeArr, "-")
startPos, _ := strconv.ParseInt(rangeParts[0], 10, 64)
var endPos int64
if rangeParts[1] == "" {
endPos = info.Size() - 1
} else {
endPos, _ = strconv.ParseInt(rangeParts[1], 10, 64)
}
c.Writer.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", startPos, endPos, info.Size()))
c.Writer.WriteHeader(http.StatusPartialContent)
buffer := make([]byte, 1024*1024)
file, err := os.Open(filePath)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
_, _ = file.Seek(startPos, 0)
reader := io.LimitReader(file, endPos-startPos+1)
_, err = io.CopyBuffer(c.Writer, reader, buffer)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
} else {
c.File(filePath)
}
} }
// @Tags File // @Tags File
@@ -567,6 +490,34 @@ func (b *BaseApi) Size(c *gin.Context) {
helper.SuccessWithData(c, res) helper.SuccessWithData(c, res)
} }
// @Tags File
// @Summary Read file
// @Description 读取文件
// @Accept json
// @Param request body dto.FilePath true "request"
// @Success 200 {string} content
// @Security ApiKeyAuth
// @Router /files/loadfile [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"读取文件 [path]","formatEN":"Read file [path]"}
func (b *BaseApi) LoadFromFile(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
}
content, err := os.ReadFile(req.Path)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, string(content))
}
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.Stat(path.Dir(dstDir)); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(dstDir), os.ModePerm); err != nil { if err = os.MkdirAll(path.Dir(dstDir), os.ModePerm); err != nil {
@@ -603,7 +554,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /files/chunkupload [post] // @Router /files/chunkupload [post]
func (b *BaseApi) UploadChunkFiles(c *gin.Context) { func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
var err error
fileForm, err := c.FormFile("chunk") fileForm, err := c.FormFile("chunk")
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
@@ -614,16 +564,19 @@ 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
} }
chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex")) chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex"))
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
chunkCount, err := strconv.Atoi(c.PostForm("chunkCount")) chunkCount, err := strconv.Atoi(c.PostForm("chunkCount"))
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
fileOp := files.NewFileOp() fileOp := files.NewFileOp()
tmpDir := path.Join(global.CONF.System.TmpDir, "upload") tmpDir := path.Join(global.CONF.System.TmpDir, "upload")
if !fileOp.Stat(tmpDir) { if !fileOp.Stat(tmpDir) {
@@ -632,50 +585,37 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
return return
} }
} }
filename := c.PostForm("filename") filename := c.PostForm("filename")
fileDir := filepath.Join(tmpDir, filename) fileDir := filepath.Join(tmpDir, filename)
if chunkIndex == 0 {
if fileOp.Stat(fileDir) { _ = os.MkdirAll(fileDir, 0755)
_ = fileOp.DeleteDir(fileDir)
}
_ = os.MkdirAll(fileDir, 0755)
}
filePath := filepath.Join(fileDir, filename) filePath := filepath.Join(fileDir, filename)
defer func() { emptyFile, err := os.Create(filePath)
if err != nil {
_ = os.Remove(fileDir)
}
}()
var (
emptyFile *os.File
chunkData []byte
)
emptyFile, err = os.Create(filePath)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
defer emptyFile.Close() defer emptyFile.Close()
chunkData, err = io.ReadAll(uploadFile) chunkData, err := io.ReadAll(uploadFile)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, buserr.WithMap(constant.ErrFileUpload, map[string]interface{}{"name": filename, "detail": err.Error()}, 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 = os.WriteFile(chunkPath, chunkData, 0644) err = os.WriteFile(chunkPath, chunkData, 0644)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, buserr.WithMap(constant.ErrFileUpload, map[string]interface{}{"name": filename, "detail": err.Error()}, 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.ErrTypeInternalServer, buserr.WithMap(constant.ErrFileUpload, map[string]interface{}{"name": filename, "detail": err.Error()}, err)) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
return return
} }
helper.SuccessWithData(c, true) helper.SuccessWithData(c, true)
@@ -690,12 +630,19 @@ var wsUpgrade = websocket.Upgrader{
}, },
} }
var WsManager = websocket2.Manager{
Group: make(map[string]*websocket2.Client),
Register: make(chan *websocket2.Client, 128),
UnRegister: make(chan *websocket2.Client, 128),
ClientCount: 0,
}
func (b *BaseApi) Ws(c *gin.Context) { func (b *BaseApi) Ws(c *gin.Context) {
ws, err := wsUpgrade.Upgrade(c.Writer, c.Request, nil) ws, err := wsUpgrade.Upgrade(c.Writer, c.Request, nil)
if err != nil { if err != nil {
return return
} }
wsClient := websocket2.NewWsClient("fileClient", ws) wsClient := websocket2.NewWsClient("wsClient", ws)
go wsClient.Read() go wsClient.Read()
go wsClient.Write() go wsClient.Write()
} }

View File

@@ -138,7 +138,7 @@ func (b *BaseApi) OperateIPRule(c *gin.Context) {
// @Param request body dto.BatchRuleOperate true "request" // @Param request body dto.BatchRuleOperate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/firewall/batch [post] // @Router /hosts/firewall/ip [post]
func (b *BaseApi) BatchOperateRule(c *gin.Context) { func (b *BaseApi) BatchOperateRule(c *gin.Context) {
var req dto.BatchRuleOperate var req dto.BatchRuleOperate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -149,7 +149,7 @@ func (b *BaseApi) BatchOperateRule(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
if err := firewallService.BatchOperateRule(req); err != nil { if err := firewallService.BacthOperateRule(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
@@ -188,7 +188,7 @@ func (b *BaseApi) UpdatePortRule(c *gin.Context) {
// @Param request body dto.AddrRuleUpdate true "request" // @Param request body dto.AddrRuleUpdate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/firewall/update/addr [post] // @Router /hosts/firewall/update/ip [post]
func (b *BaseApi) UpdateAddrRule(c *gin.Context) { func (b *BaseApi) UpdateAddrRule(c *gin.Context) {
var req dto.AddrRuleUpdate var req dto.AddrRuleUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -42,7 +42,7 @@ func (b *BaseApi) CreateGroup(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /groups/del [post] // @Router /groups/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"name","output_value":"name"},{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"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
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -92,7 +92,7 @@ func (b *BaseApi) UpdateGroup(c *gin.Context) {
// @Description 查询系统组 // @Description 查询系统组
// @Accept json // @Accept json
// @Param request body dto.GroupSearch true "request" // @Param request body dto.GroupSearch true "request"
// @Success 200 {array} dto.GroupInfo // @Success 200 {anrry} dto.GroupInfo
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /groups/search [post] // @Router /groups/search [post]
func (b *BaseApi) ListGroup(c *gin.Context) { func (b *BaseApi) ListGroup(c *gin.Context) {

View File

@@ -1,11 +1,13 @@
package v1 package v1
import ( import (
"encoding/base64"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "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"
"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/encrypt" "github.com/1Panel-dev/1Panel/backend/utils/copier"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -28,6 +30,22 @@ func (b *BaseApi) CreateHost(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)
}
host, err := hostService.Create(req) host, err := hostService.Create(req)
if err != nil { if err != nil {
@@ -84,7 +102,7 @@ func (b *BaseApi) TestByID(c *gin.Context) {
// @Description 加载主机树 // @Description 加载主机树
// @Accept json // @Accept json
// @Param request body dto.SearchForTree true "request" // @Param request body dto.SearchForTree true "request"
// @Success 200 {array} dto.HostTree // @Success 200 {anrry} dto.HostTree
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/tree [post] // @Router /hosts/tree [post]
func (b *BaseApi) HostTree(c *gin.Context) { func (b *BaseApi) HostTree(c *gin.Context) {
@@ -108,7 +126,7 @@ func (b *BaseApi) HostTree(c *gin.Context) {
// @Description 获取主机列表分页 // @Description 获取主机列表分页
// @Accept json // @Accept json
// @Param request body dto.SearchHostWithPage true "request" // @Param request body dto.SearchHostWithPage true "request"
// @Success 200 {array} dto.HostTree // @Success 200 {anrry} dto.HostTree
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/search [post] // @Router /hosts/search [post]
func (b *BaseApi) SearchHost(c *gin.Context) { func (b *BaseApi) SearchHost(c *gin.Context) {
@@ -130,6 +148,33 @@ func (b *BaseApi) SearchHost(c *gin.Context) {
}) })
} }
// @Tags Host
// @Summary Load host info
// @Description 加载主机信息
// @Accept json
// @Param id path integer true "request"
// @Success 200 {object} dto.HostInfo
// @Security ApiKeyAuth
// @Router /hosts/:id [get]
func (b *BaseApi) GetHostInfo(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
host, err := hostService.GetHostInfo(id)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
var hostDto dto.HostInfo
if err := copier.Copy(&hostDto, host); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, hostDto)
}
// @Tags Host // @Tags Host
// @Summary Delete host // @Summary Delete host
// @Description 删除主机 // @Description 删除主机
@@ -138,7 +183,7 @@ func (b *BaseApi) SearchHost(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/del [post] // @Router /hosts/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"hosts","output_column":"addr","output_value":"addrs"}],"formatZH":"删除主机 [addrs]","formatEN":"delete host [addrs]"} // @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"hosts","output_colume":"addr","output_value":"addrs"}],"formatZH":"删除主机 [addrs]","formatEN":"delete host [addrs]"}
func (b *BaseApi) DeleteHost(c *gin.Context) { func (b *BaseApi) DeleteHost(c *gin.Context) {
var req dto.BatchDeleteReq var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -176,30 +221,21 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
var err error if req.AuthMode == "password" && len(req.Password) != 0 {
if len(req.Password) != 0 && req.AuthMode == "password" { password, err := base64.StdEncoding.DecodeString(req.Password)
req.Password, err = hostService.EncryptHost(req.Password)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
req.PrivateKey = "" req.Password = string(password)
req.PassPhrase = ""
} }
if len(req.PrivateKey) != 0 && req.AuthMode == "key" { if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
req.PrivateKey, err = hostService.EncryptHost(req.PrivateKey) privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
if len(req.PassPhrase) != 0 { req.PrivateKey = string(privateKey)
req.PassPhrase, err = encrypt.StringEncrypt(req.PassPhrase)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
}
req.Password = ""
} }
upMap := make(map[string]interface{}) upMap := make(map[string]interface{})
@@ -210,12 +246,10 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
upMap["user"] = req.User upMap["user"] = req.User
upMap["auth_mode"] = req.AuthMode upMap["auth_mode"] = req.AuthMode
upMap["remember_password"] = req.RememberPassword upMap["remember_password"] = req.RememberPassword
if req.AuthMode == "password" { if len(req.Password) != 0 {
upMap["password"] = req.Password upMap["password"] = req.Password
upMap["private_key"] = "" }
upMap["pass_phrase"] = "" if len(req.PrivateKey) != 0 {
} else {
upMap["password"] = ""
upMap["private_key"] = req.PrivateKey upMap["private_key"] = req.PrivateKey
upMap["pass_phrase"] = req.PassPhrase upMap["pass_phrase"] = req.PassPhrase
} }
@@ -235,7 +269,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /hosts/update/group [post] // @Router /hosts/update/group [post]
// @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"hosts","output_column":"addr","output_value":"addr"}],"formatZH":"切换主机[addr]分组 => [group]","formatEN":"change host [addr] group => [group]"} // @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"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
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -1,213 +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/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
)
// @Tags Host tool
// @Summary Get tool
// @Description 获取主机工具状态
// @Accept json
// @Param request body request.HostToolReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool [post]
func (b *BaseApi) GetToolStatus(c *gin.Context) {
var req request.HostToolReq
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
}
config, err := hostToolService.GetToolStatus(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, config)
}
// @Tags Host tool
// @Summary Create Host tool Config
// @Description 创建主机工具配置
// @Accept json
// @Param request body request.HostToolCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/create [post]
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"}
func (b *BaseApi) InitToolConfig(c *gin.Context) {
var req request.HostToolCreate
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 := hostToolService.CreateToolConfig(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Host tool
// @Summary Operate tool
// @Description 操作主机工具
// @Accept json
// @Param request body request.HostToolReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/operate [post]
// @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"}
func (b *BaseApi) OperateTool(c *gin.Context) {
var req request.HostToolReq
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
}
err := hostToolService.OperateTool(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Host tool
// @Summary Get tool config
// @Description 操作主机工具配置文件
// @Accept json
// @Param request body request.HostToolConfig true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/config [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"}
func (b *BaseApi) OperateToolConfig(c *gin.Context) {
var req request.HostToolConfig
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
}
config, err := hostToolService.OperateToolConfig(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, config)
}
// @Tags Host tool
// @Summary Get tool
// @Description 获取主机工具日志
// @Accept json
// @Param request body request.HostToolLogReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/log [post]
func (b *BaseApi) GetToolLog(c *gin.Context) {
var req request.HostToolLogReq
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
}
logContent, err := hostToolService.GetToolLog(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, logContent)
}
// @Tags Host tool
// @Summary Create Supervisor process
// @Description 操作守护进程
// @Accept json
// @Param request body request.SupervisorProcessConfig true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/supervisor/process [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"}
func (b *BaseApi) OperateProcess(c *gin.Context) {
var req request.SupervisorProcessConfig
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
}
err := hostToolService.OperateSupervisorProcess(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Host tool
// @Summary Get Supervisor process config
// @Description 获取 Supervisor 进程配置
// @Accept json
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/supervisor/process [get]
func (b *BaseApi) GetProcess(c *gin.Context) {
configs, err := hostToolService.GetSupervisorProcessConfig()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, configs)
}
// @Tags Host tool
// @Summary Get Supervisor process config
// @Description 操作 Supervisor 进程文件
// @Accept json
// @Param request body request.SupervisorProcessFileReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/tool/supervisor/process/file [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] Supervisor 进程文件 ","formatEN":"[operate] Supervisor Process Config file"}
func (b *BaseApi) GetProcessFile(c *gin.Context) {
var req request.SupervisorProcessFileReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content, err := hostToolService.OperateSupervisorProcessFile(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}

View File

@@ -44,7 +44,7 @@ func (b *BaseApi) SearchImage(c *gin.Context) {
// @Summary List images // @Summary List images
// @Description 获取镜像列表 // @Description 获取镜像列表
// @Produce json // @Produce json
// @Success 200 {array} dto.Options // @Success 200 {anrry} dto.Options
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/image [get] // @Router /containers/image [get]
func (b *BaseApi) ListImage(c *gin.Context) { func (b *BaseApi) ListImage(c *gin.Context) {
@@ -93,7 +93,7 @@ func (b *BaseApi) ImageBuild(c *gin.Context) {
// @Success 200 {string} log // @Success 200 {string} log
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/image/pull [post] // @Router /containers/image/pull [post]
// @x-panel-log {"bodyKeys":["repoID","imageName"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"镜像拉取 [reponame][imageName]","formatEN":"image pull [reponame][imageName]"} // @x-panel-log {"bodyKeys":["repoID","imageName"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"repoID","isList":false,"db":"image_repos","output_colume":"name","output_value":"reponame"}],"formatZH":"镜像拉取 [reponame][imageName]","formatEN":"image pull [reponame][imageName]"}
func (b *BaseApi) ImagePull(c *gin.Context) { func (b *BaseApi) ImagePull(c *gin.Context) {
var req dto.ImagePull var req dto.ImagePull
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -122,7 +122,7 @@ func (b *BaseApi) ImagePull(c *gin.Context) {
// @Success 200 {string} log // @Success 200 {string} log
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/image/push [post] // @Router /containers/image/push [post]
// @x-panel-log {"bodyKeys":["repoID","tagName","name"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"[tagName] 推送到 [reponame][name]","formatEN":"push [tagName] to [reponame][name]"} // @x-panel-log {"bodyKeys":["repoID","tagName","name"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"repoID","isList":false,"db":"image_repos","output_colume":"name","output_value":"reponame"}],"formatZH":"[tagName] 推送到 [reponame][name]","formatEN":"push [tagName] to [reponame][name]"}
func (b *BaseApi) ImagePush(c *gin.Context) { func (b *BaseApi) ImagePush(c *gin.Context) {
var req dto.ImagePush var req dto.ImagePush
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -207,7 +207,7 @@ func (b *BaseApi) ImageSave(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/image/tag [post] // @Router /containers/image/tag [post]
// @x-panel-log {"bodyKeys":["repoID","targetName"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"tag 镜像 [reponame][targetName]","formatEN":"tag image [reponame][targetName]"} // @x-panel-log {"bodyKeys":["repoID","targetName"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"repoID","isList":false,"db":"image_repos","output_colume":"name","output_value":"reponame"}],"formatZH":"tag 镜像 [reponame][targetName]","formatEN":"tag image [reponame][targetName]"}
func (b *BaseApi) ImageTag(c *gin.Context) { func (b *BaseApi) ImageTag(c *gin.Context) {
var req dto.ImageTag var req dto.ImageTag
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -44,7 +44,7 @@ func (b *BaseApi) SearchRepo(c *gin.Context) {
// @Summary List image repos // @Summary List image repos
// @Description 获取镜像仓库列表 // @Description 获取镜像仓库列表
// @Produce json // @Produce json
// @Success 200 {array} dto.ImageRepoOption // @Success 200 {anrry} dto.ImageRepoOption
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/repo [get] // @Router /containers/repo [get]
func (b *BaseApi) ListRepo(c *gin.Context) { func (b *BaseApi) ListRepo(c *gin.Context) {
@@ -119,7 +119,7 @@ func (b *BaseApi) CreateRepo(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/repo/del [post] // @Router /containers/repo/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"image_repos","output_column":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"} // @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"image_repos","output_colume":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
func (b *BaseApi) DeleteRepo(c *gin.Context) { func (b *BaseApi) DeleteRepo(c *gin.Context) {
var req dto.ImageRepoDelete var req dto.ImageRepoDelete
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -147,7 +147,7 @@ func (b *BaseApi) DeleteRepo(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /containers/repo/update [post] // @Router /containers/repo/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_column":"name","output_value":"name"}],"formatZH":"更新镜像仓库 [name]","formatEN":"update image repo information [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_colume":"name","output_value":"name"}],"formatZH":"更新镜像仓库 [name]","formatEN":"update image repo information [name]"}
func (b *BaseApi) UpdateRepo(c *gin.Context) { func (b *BaseApi) UpdateRepo(c *gin.Context) {
var req dto.ImageRepoUpdate var req dto.ImageRepoUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -89,19 +89,3 @@ func (b *BaseApi) CleanLogs(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Logs
// @Summary Load system logs
// @Description 获取系统日志
// @Success 200
// @Security ApiKeyAuth
// @Router /logs/system [get]
func (b *BaseApi) GetSystemLogs(c *gin.Context) {
data, err := logService.LoadSystemLog()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}

View File

@@ -9,7 +9,6 @@ import (
"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/common"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/net" "github.com/shirou/gopsutil/v3/net"
@@ -25,9 +24,8 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
loc, _ := time.LoadLocation(common.LoadTimeZone()) req.StartTime = req.StartTime.Add(8 * time.Hour)
req.StartTime = req.StartTime.In(loc) req.EndTime = req.EndTime.Add(8 * time.Hour)
req.EndTime = req.EndTime.In(loc)
var backdatas []dto.MonitorData var backdatas []dto.MonitorData
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" { if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {

View File

@@ -27,7 +27,7 @@ func (b *BaseApi) GetNginx(c *gin.Context) {
// @Description 获取部分 OpenResty 配置信息 // @Description 获取部分 OpenResty 配置信息
// @Accept json // @Accept json
// @Param request body request.NginxScopeReq true "request" // @Param request body request.NginxScopeReq true "request"
// @Success 200 {array} response.NginxParam // @Success 200 {anrry} response.NginxParam
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /openResty/scope [post] // @Router /openResty/scope [post]
func (b *BaseApi) GetNginxConfigByScope(c *gin.Context) { func (b *BaseApi) GetNginxConfigByScope(c *gin.Context) {
@@ -53,7 +53,7 @@ func (b *BaseApi) GetNginxConfigByScope(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /openResty/update [post] // @Router /openResty/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新 nginx 配置 [domain]","formatEN":"Update nginx conf [domain]"} // @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新 nginx 配置 [domain]","formatEN":"Update nginx conf [domain]"}
func (b *BaseApi) UpdateNginxConfigByScope(c *gin.Context) { func (b *BaseApi) UpdateNginxConfigByScope(c *gin.Context) {
var req request.NginxConfigUpdate var req request.NginxConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -1,40 +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"
websocket2 "github.com/1Panel-dev/1Panel/backend/utils/websocket"
"github.com/gin-gonic/gin"
)
func (b *BaseApi) ProcessWs(c *gin.Context) {
ws, err := wsUpgrade.Upgrade(c.Writer, c.Request, nil)
if err != nil {
return
}
wsClient := websocket2.NewWsClient("processClient", ws)
go wsClient.Read()
go wsClient.Write()
}
// @Tags Process
// @Summary Stop Process
// @Description 停止进程
// @Param request body request.ProcessReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /process/stop [post]
// @x-panel-log {"bodyKeys":["PID"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"结束进程 [PID]","formatEN":"结束进程 [PID]"}
func (b *BaseApi) StopProcess(c *gin.Context) {
var req request.ProcessReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := processService.StopProcess(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
helper.SuccessWithOutData(c)
}

View File

@@ -1,158 +0,0 @@
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 Database
// @Summary Create remote database
// @Description 创建远程数据库
// @Accept json
// @Param request body dto.RemoteDBCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/remote [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建远程数据库 [name][type]","formatEN":"create remote database [name][type]"}
func (b *BaseApi) CreateRemoteDB(c *gin.Context) {
var req dto.RemoteDBCreate
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 := remoteDBService.Create(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Database
// @Summary Page remote databases
// @Description 获取远程数据库列表分页
// @Accept json
// @Param request body dto.RemoteDBSearch true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /databases/remote/search [post]
func (b *BaseApi) SearchRemoteDB(c *gin.Context) {
var req dto.RemoteDBSearch
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
total, list, err := remoteDBService.SearchWithPage(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
}
// @Tags Database
// @Summary List remote databases
// @Description 获取远程数据库列表
// @Success 200 {array} dto.RemoteDBOption
// @Security ApiKeyAuth
// @Router /databases/remote/list/:type [get]
func (b *BaseApi) ListRemoteDB(c *gin.Context) {
dbType, err := helper.GetStrParamByKey(c, "type")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
list, err := remoteDBService.List(dbType)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Database
// @Summary Get remote databases
// @Description 获取远程数据库
// @Success 200 {object} dto.RemoteDBInfo
// @Security ApiKeyAuth
// @Router /databases/remote/:name [get]
func (b *BaseApi) GetRemoteDB(c *gin.Context) {
name, err := helper.GetStrParamByKey(c, "name")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := remoteDBService.Get(name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Database
// @Summary Delete remote database
// @Description 删除远程数据库
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/remote/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"databases","output_column":"name","output_value":"names"}],"formatZH":"删除远程数据库 [names]","formatEN":"delete remote database [names]"}
func (b *BaseApi) DeleteRemoteDB(c *gin.Context) {
var req dto.OperateByID
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 := remoteDBService.Delete(req.ID); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Database
// @Summary Update remote database
// @Description 更新远程数据库
// @Accept json
// @Param request body dto.RemoteDBUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/remote/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新远程数据库 [name]","formatEN":"update remote database [name]"}
func (b *BaseApi) UpdateRemoteDB(c *gin.Context) {
var req dto.RemoteDBUpdate
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 := remoteDBService.Update(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@@ -2,16 +2,14 @@ package v1
import ( import (
"errors" "errors"
"fmt" "time"
"os"
"path"
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "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"
"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/mfa" "github.com/1Panel-dev/1Panel/backend/utils/mfa"
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -94,64 +92,6 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags System Setting
// @Summary Update system ssl
// @Description 修改系统 ssl 登录
// @Accept json
// @Param request body dto.SSLUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/ssl/update [post]
// @x-panel-log {"bodyKeys":["ssl"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
func (b *BaseApi) UpdateSSL(c *gin.Context) {
var req dto.SSLUpdate
if err := c.ShouldBindJSON(&req); err != nil {
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 := settingService.UpdateSSL(c, req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Load system cert info
// @Description 获取证书信息
// @Success 200 {object} dto.SettingInfo
// @Security ApiKeyAuth
// @Router /settings/ssl/info [get]
func (b *BaseApi) LoadFromCert(c *gin.Context) {
info, err := settingService.LoadFromCert()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, info)
}
// @Tags System Setting
// @Summary Download system cert
// @Description 下载证书
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/ssl/download [post]
func (b *BaseApi) DownloadSSL(c *gin.Context) {
pathItem := path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt")
if _, err := os.Stat(pathItem); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
c.File(pathItem)
}
// @Tags System Setting // @Tags System Setting
// @Summary Update system port // @Summary Update system port
// @Description 更新系统端口 // @Description 更新系统端口
@@ -206,41 +146,27 @@ func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags System Setting
// @Summary Load time zone options
// @Description 加载系统可用时区
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/time/option [get]
func (b *BaseApi) LoadTimeZone(c *gin.Context) {
zones, err := settingService.LoadTimeZone()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, zones)
}
// @Tags System Setting // @Tags System Setting
// @Summary Sync system time // @Summary Sync system time
// @Description 系统时间同步 // @Description 系统时间同步
// @Accept json
// @Param request body dto.SyncTime true "request"
// @Success 200 {string} ntime // @Success 200 {string} ntime
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/time/sync [post] // @Router /settings/time/sync [post]
// @x-panel-log {"bodyKeys":["ntpSite"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步[ntpSite]","formatEN":"sync system time [ntpSite]"} // @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步","formatEN":"sync system time"}
func (b *BaseApi) SyncTime(c *gin.Context) { func (b *BaseApi) SyncTime(c *gin.Context) {
var req dto.SyncTime ntime, err := ntp.Getremotetime()
if err := c.ShouldBindJSON(&req); err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.SuccessWithData(c, time.Now().Format("2006-01-02 15:04:05 MST -0700"))
return return
} }
if err := settingService.SyncTime(req); err != nil {
ts := ntime.Format("2006-01-02 15:04:05")
if err := ntp.UpdateSystemDate(ts); 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, ntime.Format("2006-01-02 15:04:05 MST -0700"))
} }
// @Tags System Setting // @Tags System Setting
@@ -280,23 +206,11 @@ func (b *BaseApi) CleanMonitor(c *gin.Context) {
// @Tags System Setting // @Tags System Setting
// @Summary Load mfa info // @Summary Load mfa info
// @Description 获取 mfa 信息 // @Description 获取 mfa 信息
// @Param interval path string true "request"
// @Success 200 {object} mfa.Otp // @Success 200 {object} mfa.Otp
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/mfa/:interval [get] // @Router /settings/mfa [get]
func (b *BaseApi) GetMFA(c *gin.Context) { func (b *BaseApi) GetMFA(c *gin.Context) {
intervalStr, ok := c.Params.Get("interval") otp, err := mfa.GetOtp("admin")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error interval in path"))
return
}
interval, err := strconv.Atoi(intervalStr)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("type conversion failed, err: %v", err))
return
}
otp, err := mfa.GetOtp("admin", interval)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
@@ -320,17 +234,12 @@ func (b *BaseApi) MFABind(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
success := mfa.ValidCode(req.Code, req.Interval, req.Secret) success := mfa.ValidCode(req.Code, req.Secret)
if !success { if !success {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("code is not valid")) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("code is not valid"))
return return
} }
if err := settingService.Update("MFAInterval", req.Interval); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := settingService.Update("MFAStatus", "enable"); err != nil { if err := settingService.Update("MFAStatus", "enable"); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return

View File

@@ -68,7 +68,7 @@ func (b *BaseApi) ImportSnapshot(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/snapshot/description/update [post] // @Router /settings/snapshot/description/update [post]
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"快照 [name] 描述信息修改 [description]","formatEN":"The description of the snapshot [name] is modified => [description]"} // @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"快照 [name] 描述信息修改 [description]","formatEN":"The description of the snapshot [name] is modified => [description]"}
func (b *BaseApi) UpdateSnapDescription(c *gin.Context) { func (b *BaseApi) UpdateSnapDescription(c *gin.Context) {
var req dto.UpdateDescription var req dto.UpdateDescription
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -119,7 +119,7 @@ func (b *BaseApi) SearchSnapshot(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/snapshot/recover [post] // @Router /settings/snapshot/recover [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 恢复","formatEN":"Recover from system backup [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 恢复","formatEN":"Recover from system backup [name]"}
func (b *BaseApi) RecoverSnapshot(c *gin.Context) { func (b *BaseApi) RecoverSnapshot(c *gin.Context) {
var req dto.SnapshotRecover var req dto.SnapshotRecover
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -146,7 +146,7 @@ func (b *BaseApi) RecoverSnapshot(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/snapshot/rollback [post] // @Router /settings/snapshot/rollback [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 回滚","formatEN":"Rollback from system backup [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 回滚","formatEN":"Rollback from system backup [name]"}
func (b *BaseApi) RollbackSnapshot(c *gin.Context) { func (b *BaseApi) RollbackSnapshot(c *gin.Context) {
var req dto.SnapshotRecover var req dto.SnapshotRecover
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -173,7 +173,7 @@ func (b *BaseApi) RollbackSnapshot(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /settings/snapshot/del [post] // @Router /settings/snapshot/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"删除系统快照 [name]","formatEN":"Delete system backup [name]"} // @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"删除系统快照 [name]","formatEN":"Delete system backup [name]"}
func (b *BaseApi) DeleteSnapshot(c *gin.Context) { func (b *BaseApi) DeleteSnapshot(c *gin.Context) {
var req dto.BatchDeleteReq var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -1,200 +0,0 @@
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 SSH
// @Summary Load host ssh setting info
// @Description 加载 SSH 配置信息
// @Success 200 {object} dto.SSHInfo
// @Security ApiKeyAuth
// @Router /host/ssh/search [post]
func (b *BaseApi) GetSSHInfo(c *gin.Context) {
info, err := sshService.GetSSHInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, info)
}
// @Tags SSH
// @Summary Operate ssh
// @Description 修改 SSH 服务状态
// @Accept json
// @Param request body dto.Operate true "request"
// @Security ApiKeyAuth
// @Router /host/ssh/operate [post]
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"}
func (b *BaseApi) OperateSSH(c *gin.Context) {
var req dto.Operate
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 := sshService.OperateSSH(req.Operation); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Update host ssh setting
// @Description 更新 SSH 配置
// @Accept json
// @Param request body dto.SettingUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/update [post]
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"}
func (b *BaseApi) UpdateSSH(c *gin.Context) {
var req dto.SettingUpdate
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 := sshService.Update(req.Key, req.Value); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Update host ssh setting by file
// @Description 上传文件更新 SSH 配置
// @Accept json
// @Param request body dto.SSHConf true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
var req dto.SSHConf
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 := sshService.UpdateByFile(req.File); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Generate host ssh secret
// @Description 生成 ssh 密钥
// @Accept json
// @Param request body dto.GenerateSSH true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/generate [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
func (b *BaseApi) GenerateSSH(c *gin.Context) {
var req dto.GenerateSSH
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 := sshService.GenerateSSH(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Load host ssh secret
// @Description 获取 ssh 密钥
// @Accept json
// @Param request body dto.GenerateLoad true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/secret [post]
func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
var req dto.GenerateLoad
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := sshService.LoadSSHSecret(req.EncryptionMode)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags SSH
// @Summary Load host ssh logs
// @Description 获取 ssh 登录日志
// @Accept json
// @Param request body dto.SearchSSHLog true "request"
// @Success 200 {object} dto.SSHLog
// @Security ApiKeyAuth
// @Router /host/ssh/logs [post]
func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
var req dto.SearchSSHLog
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := sshService.LoadLog(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags SSH
// @Summary Load host ssh conf
// @Description 获取 ssh 配置文件
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/conf [get]
func (b *BaseApi) LoadSSHConf(c *gin.Context) {
data, err := sshService.LoadSSHConf()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}

View File

@@ -6,9 +6,10 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"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/cmd" "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/copier" "github.com/1Panel-dev/1Panel/backend/utils/copier"
@@ -20,27 +21,24 @@ import (
) )
func (b *BaseApi) WsSsh(c *gin.Context) { func (b *BaseApi) WsSsh(c *gin.Context) {
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
global.LOG.Errorf("gin context http handler failed, err: %v", err)
return
}
defer wsConn.Close()
id, err := strconv.Atoi(c.Query("id")) id, err := strconv.Atoi(c.Query("id"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param id in request")) { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80")) cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param cols in request")) { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40")) rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
host, err := hostService.GetHostInfo(uint(id)) host, err := hostService.GetHostInfo(uint(id))
if wshandleError(wsConn, errors.WithMessage(err, "load host info by id failed")) { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
var connInfo ssh.ConnInfo var connInfo ssh.ConnInfo
@@ -50,12 +48,24 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
connInfo.PassPhrase = []byte(host.PassPhrase) connInfo.PassPhrase = []byte(host.PassPhrase)
} }
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
global.LOG.Errorf("gin context http handler failed, err: %v", err)
return
}
defer wsConn.Close()
client, err := connInfo.NewClient() client, err := connInfo.NewClient()
if wshandleError(wsConn, errors.WithMessage(err, "failed to set up the connection. Please check the host information")) { if wshandleError(wsConn, errors.WithMessage(err, "failed to set up the connection. Please check the host information")) {
return return
} }
defer client.Close() defer client.Close()
ssConn, err := connInfo.NewSshConn(cols, rows)
if wshandleError(wsConn, err) {
return
}
defer ssConn.Close()
sws, err := terminal.NewLogicSshWsSession(cols, rows, true, connInfo.Client, wsConn) sws, err := terminal.NewLogicSshWsSession(cols, rows, true, connInfo.Client, wsConn)
if wshandleError(wsConn, err) { if wshandleError(wsConn, err) {
return return
@@ -74,36 +84,37 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
} }
func (b *BaseApi) RedisWsSsh(c *gin.Context) { func (b *BaseApi) RedisWsSsh(c *gin.Context) {
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
redisConf, err := redisService.LoadConf()
if err != nil {
global.LOG.Errorf("load redis container failed, err: %v", err)
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil) wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil { if err != nil {
global.LOG.Errorf("gin context http handler failed, err: %v", err) global.LOG.Errorf("gin context http handler failed, err: %v", err)
return return
} }
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param cols in request")) {
return
}
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
return
}
redisConf, err := redisService.LoadConf()
if wshandleError(wsConn, errors.WithMessage(err, "load redis container failed")) {
return
}
defer wsConn.Close() defer wsConn.Close()
commands := "redis-cli" commands := fmt.Sprintf("docker exec -it %s redis-cli", redisConf.ContainerName)
if len(redisConf.Requirepass) != 0 { if len(redisConf.Requirepass) != 0 {
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass) commands = fmt.Sprintf("docker exec -it %s redis-cli -a %s --no-auth-warning", redisConf.ContainerName, redisConf.Requirepass)
} }
pidMap := loadMapFromDockerTop(redisConf.ContainerName) slave, err := terminal.NewCommand(commands)
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
if wshandleError(wsConn, err) { if wshandleError(wsConn, err) {
return return
} }
defer killBash(redisConf.ContainerName, commands, pidMap)
defer slave.Close() defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave) tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
@@ -124,6 +135,24 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
} }
func (b *BaseApi) ContainerWsSsh(c *gin.Context) { func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
containerID := c.Query("containerid")
command := c.Query("command")
user := c.Query("user")
if len(command) == 0 || len(containerID) == 0 {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error param of command or containerID"))
return
}
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil) wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil { if err != nil {
global.LOG.Errorf("gin context http handler failed, err: %v", err) global.LOG.Errorf("gin context http handler failed, err: %v", err)
@@ -131,33 +160,11 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
} }
defer wsConn.Close() defer wsConn.Close()
containerID := c.Query("containerid") cmds := fmt.Sprintf("docker exec %s %s", containerID, command)
command := c.Query("command")
user := c.Query("user")
if len(command) == 0 || len(containerID) == 0 {
if wshandleError(wsConn, errors.New("error param of command or containerID")) {
return
}
}
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param cols in request")) {
return
}
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
return
}
cmds := []string{"exec", containerID, command}
if len(user) != 0 { if len(user) != 0 {
cmds = []string{"exec", "-u", user, containerID, command} cmds = fmt.Sprintf("docker exec -u %s %s %s", user, containerID, command)
} }
if cmd.CheckIllegal(user, containerID, command) { stdout, err := cmd.Exec(cmds)
if wshandleError(wsConn, errors.New(" The command contains illegal characters.")) {
return
}
}
stdout, err := cmd.ExecWithCheck("docker", cmds...)
if wshandleError(wsConn, errors.WithMessage(err, stdout)) { if wshandleError(wsConn, errors.WithMessage(err, stdout)) {
return return
} }
@@ -166,12 +173,10 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
if len(user) != 0 { if len(user) != 0 {
commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command) commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command)
} }
pidMap := loadMapFromDockerTop(containerID)
slave, err := terminal.NewCommand(commands) slave, err := terminal.NewCommand(commands)
if wshandleError(wsConn, err) { if wshandleError(wsConn, err) {
return return
} }
defer killBash(containerID, command, pidMap)
defer slave.Close() defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave) tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
@@ -211,42 +216,6 @@ func wshandleError(ws *websocket.Conn, err error) bool {
return false return false
} }
func loadMapFromDockerTop(containerID string) map[string]string {
pidMap := make(map[string]string)
sudo := cmd.SudoHandleCmd()
stdout, err := cmd.Execf("%s docker top %s -eo pid,command ", sudo, containerID)
if err != nil {
return pidMap
}
lines := strings.Split(stdout, "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) != 2 {
continue
}
pidMap[parts[0]] = parts[1]
}
return pidMap
}
func killBash(containerID, comm string, pidMap map[string]string) {
sudo := cmd.SudoHandleCmd()
newPidMap := loadMapFromDockerTop(containerID)
for pid, command := range newPidMap {
isOld := false
for pid2 := range pidMap {
if pid == pid2 {
isOld = true
break
}
}
if !isOld && command == comm {
_, _ = cmd.Execf("%s kill -9 %s", sudo, pid)
}
}
}
var upGrader = websocket.Upgrader{ var upGrader = websocket.Upgrader{
ReadBufferSize: 1024, ReadBufferSize: 1024,
WriteBufferSize: 1024 * 1024 * 10, WriteBufferSize: 1024 * 1024 * 10,

View File

@@ -36,7 +36,7 @@ func (b *BaseApi) PageWebsite(c *gin.Context) {
// @Tags Website // @Tags Website
// @Summary List websites // @Summary List websites
// @Description 获取网站列表 // @Description 获取网站列表
// @Success 200 {array} response.WebsiteDTO // @Success 200 {anrry} response.WebsiteDTO
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/list [get] // @Router /websites/list [get]
func (b *BaseApi) GetWebsites(c *gin.Context) { func (b *BaseApi) GetWebsites(c *gin.Context) {
@@ -51,7 +51,7 @@ func (b *BaseApi) GetWebsites(c *gin.Context) {
// @Tags Website // @Tags Website
// @Summary List website names // @Summary List website names
// @Description 获取网站列表 // @Description 获取网站列表
// @Success 200 {array} string // @Success 200 {anrry} string
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/options [get] // @Router /websites/options [get]
func (b *BaseApi) GetWebsiteOptions(c *gin.Context) { func (b *BaseApi) GetWebsiteOptions(c *gin.Context) {
@@ -95,7 +95,7 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/operate [post] // @Router /websites/operate [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[operate] 网站 [domain]","formatEN":"[operate] website [domain]"} // @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[operate] 网站 [domain]","formatEN":"[operate] website [domain]"}
func (b *BaseApi) OpWebsite(c *gin.Context) { func (b *BaseApi) OpWebsite(c *gin.Context) {
var req request.WebsiteOp var req request.WebsiteOp
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -118,7 +118,7 @@ func (b *BaseApi) OpWebsite(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/del [post] // @Router /websites/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain]","formatEN":"Delete website [domain]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain]","formatEN":"Delete website [domain]"}
func (b *BaseApi) DeleteWebsite(c *gin.Context) { func (b *BaseApi) DeleteWebsite(c *gin.Context) {
var req request.WebsiteDelete var req request.WebsiteDelete
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -207,7 +207,7 @@ func (b *BaseApi) GetWebsiteNginx(c *gin.Context) {
// @Description 通过网站 id 查询域名 // @Description 通过网站 id 查询域名
// @Accept json // @Accept json
// @Param websiteId path integer true "request" // @Param websiteId path integer true "request"
// @Success 200 {array} model.WebsiteDomain // @Success 200 {anrry} model.WebsiteDomain
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/domains/:websiteId [get] // @Router /websites/domains/:websiteId [get]
func (b *BaseApi) GetWebDomains(c *gin.Context) { func (b *BaseApi) GetWebDomains(c *gin.Context) {
@@ -232,7 +232,7 @@ func (b *BaseApi) GetWebDomains(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/domains/del [post] // @Router /websites/domains/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_domains","output_column":"domain","output_value":"domain"}],"formatZH":"删除域名 [domain]","formatEN":"Delete domain [domain]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_domains","output_colume":"domain","output_value":"domain"}],"formatZH":"删除域名 [domain]","formatEN":"Delete domain [domain]"}
func (b *BaseApi) DeleteWebDomain(c *gin.Context) { func (b *BaseApi) DeleteWebDomain(c *gin.Context) {
var req request.WebsiteDomainDelete var req request.WebsiteDomainDelete
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -300,7 +300,7 @@ func (b *BaseApi) GetNginxConfig(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/config/update [post] // @Router /websites/config/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"nginx 配置修改 [domain]","formatEN":"Nginx conf update [domain]"} // @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"nginx 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
func (b *BaseApi) UpdateNginxConfig(c *gin.Context) { func (b *BaseApi) UpdateNginxConfig(c *gin.Context) {
var req request.NginxConfigUpdate var req request.NginxConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -344,7 +344,7 @@ func (b *BaseApi) GetHTTPSConfig(c *gin.Context) {
// @Success 200 {object} response.WebsiteHTTPS // @Success 200 {object} response.WebsiteHTTPS
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/:id/https [post] // @Router /websites/:id/https [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"} // @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"}
func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) { func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) {
var req request.WebsiteHTTPSOp var req request.WebsiteHTTPSOp
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -367,7 +367,7 @@ func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) {
// @Description 网站创建前检查 // @Description 网站创建前检查
// @Accept json // @Accept json
// @Param request body request.WebsiteInstallCheckReq true "request" // @Param request body request.WebsiteInstallCheckReq true "request"
// @Success 200 {array} response.WebsitePreInstallCheck // @Success 200 {anrry} request.WebsitePreInstallCheck
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/check [post] // @Router /websites/check [post]
func (b *BaseApi) CreateWebsiteCheck(c *gin.Context) { func (b *BaseApi) CreateWebsiteCheck(c *gin.Context) {
@@ -414,7 +414,7 @@ func (b *BaseApi) GetWebsiteWafConfig(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/waf/update [post] // @Router /websites/waf/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"} // @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"}
func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) { func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafUpdate var req request.WebsiteWafUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -428,28 +428,6 @@ func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Website WAF
// @Summary Update website waf file
// @Description 更新 网站 waf 配置文件
// @Accept json
// @Param request body request.WebsiteWafUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/file/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置文件修改 [domain]","formatEN":"WAF conf file update [domain]"}
func (b *BaseApi) UpdateWebsiteWafFile(c *gin.Context) {
var req request.WebsiteWafFileUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.UpdateWafFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website Nginx // @Tags Website Nginx
// @Summary Update website nginx conf // @Summary Update website nginx conf
// @Description 更新 网站 nginx 配置 // @Description 更新 网站 nginx 配置
@@ -458,7 +436,7 @@ func (b *BaseApi) UpdateWebsiteWafFile(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/nginx/update [post] // @Router /websites/nginx/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] Nginx 配置修改","formatEN":"[domain] Nginx conf update"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[domain] Nginx 配置修改","formatEN":"[domain] Nginx conf update"}
func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) { func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) {
var req request.WebsiteNginxUpdate var req request.WebsiteNginxUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -480,7 +458,7 @@ func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) {
// @Success 200 {object} response.WebsiteLog // @Success 200 {object} response.WebsiteLog
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/log [post] // @Router /websites/log [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain][operate] 日志","formatEN":"[domain][operate] logs"} // @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[domain][operate] 日志","formatEN":"[domain][operate] logs"}
func (b *BaseApi) OpWebsiteLog(c *gin.Context) { func (b *BaseApi) OpWebsiteLog(c *gin.Context) {
var req request.WebsiteLogReq var req request.WebsiteLogReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -503,7 +481,7 @@ func (b *BaseApi) OpWebsiteLog(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/default/server [post] // @Router /websites/default/server [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改默认 server => [domain]","formatEN":"Change default server => [domain]"} // @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"修改默认 server => [domain]","formatEN":"Change default server => [domain]"}
func (b *BaseApi) ChangeDefaultServer(c *gin.Context) { func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
var req request.WebsiteDefaultUpdate var req request.WebsiteDefaultUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -547,7 +525,7 @@ func (b *BaseApi) GetWebsitePHPConfig(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/php/config [post] // @Router /websites/php/config [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] PHP 配置修改","formatEN":"[domain] PHP conf update"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"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) { func (b *BaseApi) UpdateWebsitePHPConfig(c *gin.Context) {
var req request.WebsitePHPConfigUpdate var req request.WebsitePHPConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -563,13 +541,13 @@ func (b *BaseApi) UpdateWebsitePHPConfig(c *gin.Context) {
// @Tags Website PHP // @Tags Website PHP
// @Summary Update php conf // @Summary Update php conf
// @Description 更新 php 配置文件 // @Description 更新 php 配置
// @Accept json // @Accept json
// @Param request body request.WebsitePHPFileUpdate true "request" // @Param request body request.WebsitePHPFileUpdate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/php/update [post] // @Router /websites/php/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 配置修改 [domain]","formatEN":"Nginx conf update [domain]"} // @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"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) { func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
var req request.WebsitePHPFileUpdate var req request.WebsitePHPFileUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -583,28 +561,6 @@ func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
// @Tags Website PHP
// @Summary Update php version
// @Description 变更 php 版本
// @Accept json
// @Param request body request.WebsitePHPVersionReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/php/version [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 版本变更 [domain]","formatEN":"php version update [domain]"}
func (b *BaseApi) ChangePHPVersion(c *gin.Context) {
var req request.WebsitePHPVersionReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.ChangePHPVersion(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Website // @Tags Website
// @Summary Get rewrite conf // @Summary Get rewrite conf
// @Description 获取伪静态配置 // @Description 获取伪静态配置
@@ -635,7 +591,7 @@ func (b *BaseApi) GetRewriteConfig(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/rewrite/update [post] // @Router /websites/rewrite/update [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"伪静态配置修改 [domain]","formatEN":"Nginx conf rewrite update [domain]"} // @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"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) { func (b *BaseApi) UpdateRewriteConfig(c *gin.Context) {
var req request.NginxRewriteUpdate var req request.NginxRewriteUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -657,7 +613,7 @@ func (b *BaseApi) UpdateRewriteConfig(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/dir/update [post] // @Router /websites/dir/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录","formatEN":"Update domain [domain] dir"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"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) { func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
var req request.WebsiteUpdateDir var req request.WebsiteUpdateDir
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -679,7 +635,7 @@ func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/dir/permission [post] // @Router /websites/dir/permission [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录权限","formatEN":"Update domain [domain] dir permission"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"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) { func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
var req request.WebsiteUpdateDirPermission var req request.WebsiteUpdateDirPermission
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -692,223 +648,3 @@ func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
} }
helper.SuccessWithOutData(c) helper.SuccessWithOutData(c)
} }
// @Tags Website
// @Summary Get proxy conf
// @Description 获取反向代理配置
// @Accept json
// @Param request body request.WebsiteProxyReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxies [post]
func (b *BaseApi) GetProxyConfig(c *gin.Context) {
var req request.WebsiteProxyReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
res, err := websiteService.GetProxies(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Update proxy conf
// @Description 修改反向代理配置
// @Accept json
// @Param request body request.WebsiteProxyConfig true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxies/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 反向代理配置 ","formatEN":"Update domain [domain] proxy config"}
func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
var req request.WebsiteProxyConfig
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
err := websiteService.OperateProxy(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Update proxy file
// @Description 更新反向代理文件
// @Accept json
// @Param request body request.NginxProxyUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxy/file [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新反向代理文件 [domain]","formatEN":"Nginx conf proxy file update [domain]"}
func (b *BaseApi) UpdateProxyConfigFile(c *gin.Context) {
var req request.NginxProxyUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.UpdateProxyFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Get AuthBasic conf
// @Description 获取密码访问配置
// @Accept json
// @Param request body request.NginxAuthReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/auths [post]
func (b *BaseApi) GetAuthConfig(c *gin.Context) {
var req request.NginxAuthReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
res, err := websiteService.GetAuthBasics(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Get AuthBasic conf
// @Description 更新密码访问配置
// @Accept json
// @Param request body request.NginxAuthUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/auths/update [post]
func (b *BaseApi) UpdateAuthConfig(c *gin.Context) {
var req request.NginxAuthUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.UpdateAuthBasic(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Get AntiLeech conf
// @Description 获取防盗链配置
// @Accept json
// @Param request body request.NginxCommonReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/leech [post]
func (b *BaseApi) GetAntiLeech(c *gin.Context) {
var req request.NginxCommonReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
res, err := websiteService.GetAntiLeech(req.WebsiteID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Update AntiLeech
// @Description 更新防盗链配置
// @Accept json
// @Param request body request.NginxAntiLeechUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/leech/update [post]
func (b *BaseApi) UpdateAntiLeech(c *gin.Context) {
var req request.NginxAntiLeechUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.UpdateAntiLeech(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Update redirect conf
// @Description 修改重定向配置
// @Accept json
// @Param request body request.NginxRedirectReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/redirect/update [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 重定向理配置 ","formatEN":"Update domain [domain] redirect config"}
func (b *BaseApi) UpdateRedirectConfig(c *gin.Context) {
var req request.NginxRedirectReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
err := websiteService.OperateRedirect(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Get redirect conf
// @Description 获取重定向配置
// @Accept json
// @Param request body request.WebsiteProxyReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/redirect [post]
func (b *BaseApi) GetRedirectConfig(c *gin.Context) {
var req request.WebsiteRedirectReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
res, err := websiteService.GetRedirect(req.WebsiteID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Update redirect file
// @Description 更新重定向文件
// @Accept json
// @Param request body request.NginxRedirectUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/redirect/file [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新重定向文件 [domain]","formatEN":"Nginx conf redirect file update [domain]"}
func (b *BaseApi) UpdateRedirectConfigFile(c *gin.Context) {
var req request.NginxRedirectUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.UpdateRedirectFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}

View File

@@ -64,7 +64,7 @@ func (b *BaseApi) CreateWebsiteAcmeAccount(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/acme/del [post] // @Router /websites/acme/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_acme_accounts","output_column":"email","output_value":"email"}],"formatZH":"删除网站 acme [email]","formatEN":"Delete website acme [email]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_acme_accounts","output_colume":"email","output_value":"email"}],"formatZH":"删除网站 acme [email]","formatEN":"Delete website acme [email]"}
func (b *BaseApi) DeleteWebsiteAcmeAccount(c *gin.Context) { func (b *BaseApi) DeleteWebsiteAcmeAccount(c *gin.Context) {
var req request.WebsiteResourceReq var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -85,7 +85,7 @@ func (b *BaseApi) UpdateWebsiteDnsAccount(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/dns/del [post] // @Router /websites/dns/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_dns_accounts","output_column":"name","output_value":"name"}],"formatZH":"删除网站 dns [name]","formatEN":"Delete website dns [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_dns_accounts","output_colume":"name","output_value":"name"}],"formatZH":"删除网站 dns [name]","formatEN":"Delete website dns [name]"}
func (b *BaseApi) DeleteWebsiteDnsAccount(c *gin.Context) { func (b *BaseApi) DeleteWebsiteDnsAccount(c *gin.Context) {
var req request.WebsiteResourceReq var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -35,7 +35,7 @@ func (b *BaseApi) PageWebsiteSSL(c *gin.Context) {
Items: accounts, Items: accounts,
}) })
} else { } else {
list, err := websiteSSLService.Search(req) list, err := websiteSSLService.Search()
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
@@ -75,7 +75,7 @@ func (b *BaseApi) CreateWebsiteSSL(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/ssl/renew [post] // @Router /websites/ssl/renew [post]
// @x-panel-log {"bodyKeys":["SSLId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"SSLId","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"重置 ssl [domain]","formatEN":"Renew ssl [domain]"} // @x-panel-log {"bodyKeys":["SSLId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"SSLId","isList":false,"db":"website_ssls","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"重置 ssl [domain]","formatEN":"Renew ssl [domain]"}
func (b *BaseApi) RenewWebsiteSSL(c *gin.Context) { func (b *BaseApi) RenewWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLRenew var req request.WebsiteSSLRenew
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -94,7 +94,7 @@ func (b *BaseApi) RenewWebsiteSSL(c *gin.Context) {
// @Description 解析网站 ssl // @Description 解析网站 ssl
// @Accept json // @Accept json
// @Param request body request.WebsiteDNSReq true "request" // @Param request body request.WebsiteDNSReq true "request"
// @Success 200 {array} response.WebsiteDNSRes // @Success 200 {anrry} response.WebsiteDNSRes
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/ssl/resolve [post] // @Router /websites/ssl/resolve [post]
func (b *BaseApi) GetDNSResolve(c *gin.Context) { func (b *BaseApi) GetDNSResolve(c *gin.Context) {
@@ -119,7 +119,7 @@ func (b *BaseApi) GetDNSResolve(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/ssl/del [post] // @Router /websites/ssl/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_ssls","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"}
func (b *BaseApi) DeleteWebsiteSSL(c *gin.Context) { func (b *BaseApi) DeleteWebsiteSSL(c *gin.Context) {
var req request.WebsiteResourceReq var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@@ -185,7 +185,7 @@ func (b *BaseApi) GetWebsiteSSLById(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /websites/ssl/update [post] // @Router /websites/ssl/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新证书设置 [domain]","formatEN":"Update ssl config [domain]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"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) { func (b *BaseApi) UpdateWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLUpdate var req request.WebsiteSSLUpdate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@@ -1,7 +1,7 @@
package dto package dto
import ( import (
"github.com/1Panel-dev/1Panel/backend/app/model" "encoding/json"
) )
type AppDatabase struct { type AppDatabase struct {
@@ -15,10 +15,6 @@ type AuthParam struct {
RootPassword string `json:"PANEL_DB_ROOT_PASSWORD"` RootPassword string `json:"PANEL_DB_ROOT_PASSWORD"`
} }
type RedisAuthParam struct {
RootPassword string `json:"PANEL_REDIS_ROOT_PASSWORD"`
}
type ContainerExec struct { type ContainerExec struct {
ContainerName string `json:"containerName"` ContainerName string `json:"containerName"`
DbParam AppDatabase `json:"dbParam"` DbParam AppDatabase `json:"dbParam"`
@@ -36,47 +32,19 @@ type AppVersion struct {
} }
type AppList struct { type AppList struct {
Valid bool `json:"valid"` Version string `json:"version"`
Violations []string `json:"violations"` Tags []Tag `json:"tags"`
LastModified int `json:"lastModified"` Items []AppDefine `json:"items"`
Apps []AppDefine `json:"apps"`
Extra ExtraProperties `json:"additionalProperties"`
} }
type AppDefine struct { type AppDefine struct {
Icon string `json:"icon"` Key string `json:"key"`
Name string `json:"name"`
ReadMe string `json:"readMe"`
LastModified int `json:"lastModified"`
AppProperty AppProperty `json:"additionalProperties"`
Versions []AppConfigVersion `json:"versions"`
}
type LocalAppAppDefine struct {
AppProperty model.App `json:"additionalProperties" yaml:"additionalProperties"`
}
type LocalAppParam struct {
AppParams LocalAppInstallDefine `json:"additionalProperties" yaml:"additionalProperties"`
}
type LocalAppInstallDefine struct {
FormFields interface{} `json:"formFields" yaml:"formFields"`
}
type ExtraProperties struct {
Tags []Tag `json:"tags"`
}
type AppProperty struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"`
Tags []string `json:"tags"` Tags []string `json:"tags"`
Versions []string `json:"versions"`
ShortDescZh string `json:"shortDescZh"` ShortDescZh string `json:"shortDescZh"`
ShortDescEn string `json:"shortDescEn"` ShortDescEn string `json:"shortDescEn"`
Key string `json:"key"` Type string `json:"type"`
Required []string `json:"Required"` Required []string `json:"Required"`
CrossVersionUpdate bool `json:"crossVersionUpdate"` CrossVersionUpdate bool `json:"crossVersionUpdate"`
Limit int `json:"limit"` Limit int `json:"limit"`
@@ -86,12 +54,9 @@ type AppProperty struct {
Document string `json:"document"` Document string `json:"document"`
} }
type AppConfigVersion struct { func (define AppDefine) GetRequired() string {
Name string `json:"name"` by, _ := json.Marshal(define.Required)
LastModified int `json:"lastModified"` return string(by)
DownloadUrl string `json:"downloadUrl"`
DownloadCallBackUrl string `json:"downloadCallBackUrl"`
AppForm interface{} `json:"additionalProperties"`
} }
type Tag struct { type Tag struct {
@@ -114,7 +79,6 @@ type AppFormFields struct {
Edit bool `json:"edit"` Edit bool `json:"edit"`
Rule string `json:"rule"` Rule string `json:"rule"`
Multiple bool `json:"multiple"` Multiple bool `json:"multiple"`
Child interface{} `json:"child"`
Values []AppFormValue `json:"values"` Values []AppFormValue `json:"values"`
} }

View File

@@ -12,19 +12,16 @@ type UserLoginInfo struct {
} }
type MfaCredential struct { type MfaCredential struct {
Secret string `json:"secret"` Secret string `json:"secret"`
Code string `json:"code"` Code string `json:"code"`
Interval string `json:"interval"`
} }
type Login struct { type Login struct {
Name string `json:"name"` Name string `json:"name"`
Password string `json:"password"` Password string `json:"password"`
IgnoreCaptcha bool `json:"ignoreCaptcha"` Captcha string `json:"captcha"`
Captcha string `json:"captcha"` CaptchaID string `json:"captchaID"`
CaptchaID string `json:"captchaID"` AuthMethod string `json:"authMethod"`
AuthMethod string `json:"authMethod"`
Language string `json:"language"`
} }
type MFALogin struct { type MFALogin struct {
@@ -33,3 +30,8 @@ type MFALogin struct {
Code string `json:"code"` Code string `json:"code"`
AuthMethod string `json:"authMethod"` AuthMethod string `json:"authMethod"`
} }
type InitUser struct {
Name string `json:"name" validate:"required"`
Password string `json:"password" validate:"required"`
}

View File

@@ -8,17 +8,15 @@ type BackupOperate struct {
Bucket string `json:"bucket"` Bucket string `json:"bucket"`
AccessKey string `json:"accessKey"` AccessKey string `json:"accessKey"`
Credential string `json:"credential"` Credential string `json:"credential"`
BackupPath string `json:"backupPath"`
Vars string `json:"vars" validate:"required"` Vars string `json:"vars" validate:"required"`
} }
type BackupInfo struct { type BackupInfo struct {
ID uint `json:"id"` ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
Type string `json:"type"` Type string `json:"type"`
Bucket string `json:"bucket"` Bucket string `json:"bucket"`
BackupPath string `json:"backupPath"` Vars string `json:"vars"`
Vars string `json:"vars"`
} }
type BackupSearch struct { type BackupSearch struct {
@@ -38,7 +36,6 @@ type CommonBackup struct {
DetailName string `json:"detailName"` DetailName string `json:"detailName"`
} }
type CommonRecover struct { type CommonRecover struct {
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive"`
Type string `json:"type" validate:"required,oneof=app mysql redis website"` Type string `json:"type" validate:"required,oneof=app mysql redis website"`
Name string `json:"name"` Name string `json:"name"`
DetailName string `json:"detailName"` DetailName string `json:"detailName"`
@@ -62,7 +59,7 @@ type BackupRecords struct {
} }
type DownloadRecord struct { type DownloadRecord struct {
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive"` 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"`
} }

View File

@@ -2,9 +2,7 @@ package dto
type SearchWithPage struct { type SearchWithPage struct {
PageInfo PageInfo
Info string `json:"info"` Info string `json:"info"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
} }
type PageInfo struct { type PageInfo struct {
@@ -14,7 +12,7 @@ type PageInfo struct {
type UpdateDescription struct { type UpdateDescription struct {
ID uint `json:"id" validate:"required"` ID uint `json:"id" validate:"required"`
Description string `json:"description" validate:"max=256"` Description string `json:"description"`
} }
type OperationWithName struct { type OperationWithName struct {
@@ -25,10 +23,6 @@ type OperateByID struct {
ID uint `json:"id" validate:"required"` ID uint `json:"id" validate:"required"`
} }
type Operate struct {
Operation string `json:"operation" validate:"required"`
}
type BatchDeleteReq struct { type BatchDeleteReq struct {
Ids []uint `json:"ids" validate:"required"` Ids []uint `json:"ids" validate:"required"`
} }

View File

@@ -5,8 +5,6 @@ import "time"
type PageContainer struct { type PageContainer struct {
PageInfo PageInfo
Name string `json:"name"` Name string `json:"name"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
Filters string `json:"filters"` Filters string `json:"filters"`
} }
@@ -24,29 +22,18 @@ type ContainerInfo struct {
State string `json:"state"` State string `json:"state"`
RunTime string `json:"runTime"` RunTime string `json:"runTime"`
Ports []string `json:"ports"`
IsFromApp bool `json:"isFromApp"` IsFromApp bool `json:"isFromApp"`
IsFromCompose bool `json:"isFromCompose"` IsFromCompose bool `json:"isFromCompose"`
} }
type ResourceLimit struct { type ContainerCreate struct {
CPU int `json:"cpu"`
Memory int `json:"memory"`
}
type ContainerOperate struct {
ContainerID string `json:"containerID"`
ForcePull bool `json:"forcePull"`
Name string `json:"name"` Name string `json:"name"`
Image string `json:"image"` Image string `json:"image"`
Network string `json:"network"`
PublishAllPorts bool `json:"publishAllPorts"` PublishAllPorts bool `json:"publishAllPorts"`
ExposedPorts []PortHelper `json:"exposedPorts"` ExposedPorts []PortHelper `json:"exposedPorts"`
Cmd []string `json:"cmd"` Cmd []string `json:"cmd"`
CPUShares int64 `json:"cpuShares"` NanoCPUs int64 `json:"nanoCPUs"`
NanoCPUs float64 `json:"nanoCPUs"` Memory int64 `json:"memory"`
Memory float64 `json:"memory"`
AutoRemove bool `json:"autoRemove"` AutoRemove bool `json:"autoRemove"`
Volumes []VolumeHelper `json:"volumes"` Volumes []VolumeHelper `json:"volumes"`
Labels []string `json:"labels"` Labels []string `json:"labels"`
@@ -54,19 +41,7 @@ type ContainerOperate struct {
RestartPolicy string `json:"restartPolicy"` RestartPolicy string `json:"restartPolicy"`
} }
type ContainerUpgrade struct { type ContainterStats struct {
Name string `json:"name" validate:"required"`
Image string `json:"image" validate:"required"`
ForcePull bool `json:"forcePull"`
}
type ContainerListStats struct {
ContainerID string `json:"containerID"`
CPUPercent float64 `json:"cpuPercent"`
MemoryPercent float64 `json:"memoryPercent"`
}
type ContainerStats struct {
CPUPercent float64 `json:"cpuPercent"` CPUPercent float64 `json:"cpuPercent"`
Memory float64 `json:"memory"` Memory float64 `json:"memory"`
Cache float64 `json:"cache"` Cache float64 `json:"cache"`
@@ -84,10 +59,13 @@ type VolumeHelper struct {
Mode string `json:"mode"` Mode string `json:"mode"`
} }
type PortHelper struct { type PortHelper struct {
HostIP string `json:"hostIP"` ContainerPort int `json:"containerPort"`
HostPort string `json:"hostPort"` HostPort int `json:"hostPort"`
ContainerPort string `json:"containerPort"` }
Protocol string `json:"protocol"`
type ContainerLog struct {
ContainerID string `json:"containerID" validate:"required"`
Mode string `json:"mode" validate:"required"`
} }
type ContainerOperation struct { type ContainerOperation struct {
@@ -96,16 +74,6 @@ type ContainerOperation struct {
NewName string `json:"newName"` NewName string `json:"newName"`
} }
type ContainerPrune struct {
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network"`
WithTagAll bool `json:"withTagAll"`
}
type ContainerPruneReport struct {
DeletedNumber int `json:"deletedNumber"`
SpaceReclaimed int `json:"spaceReclaimed"`
}
type Network struct { type Network struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@@ -117,7 +85,7 @@ type Network struct {
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
Attachable bool `json:"attachable"` Attachable bool `json:"attachable"`
} }
type NetworkCreate struct { type NetworkCreat struct {
Name string `json:"name"` Name string `json:"name"`
Driver string `json:"driver"` Driver string `json:"driver"`
Options []string `json:"options"` Options []string `json:"options"`
@@ -134,7 +102,7 @@ type Volume struct {
Mountpoint string `json:"mountpoint"` Mountpoint string `json:"mountpoint"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
} }
type VolumeCreate struct { type VolumeCreat struct {
Name string `json:"name"` Name string `json:"name"`
Driver string `json:"driver"` Driver string `json:"driver"`
Options []string `json:"options"` Options []string `json:"options"`
@@ -172,7 +140,6 @@ type ComposeOperation struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Path string `json:"path" validate:"required"` Path string `json:"path" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=start stop down"` Operation string `json:"operation" validate:"required,oneof=start stop down"`
WithFile bool `json:"withFile"`
} }
type ComposeUpdate struct { type ComposeUpdate struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`

View File

@@ -6,14 +6,12 @@ type CronjobCreate struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Type string `json:"type" validate:"required"` Type string `json:"type" validate:"required"`
SpecType string `json:"specType" validate:"required"` SpecType string `json:"specType" validate:"required"`
Week int `json:"week" validate:"number,max=6,min=0"` Week int `json:"week" validate:"number,max=7,min=1"`
Day int `json:"day" validate:"number"` Day int `json:"day" validate:"number"`
Hour int `json:"hour" validate:"number"` Hour int `json:"hour" validate:"number"`
Minute int `json:"minute" validate:"number"` Minute int `json:"minute" validate:"number"`
Second int `json:"second" validate:"number"`
Script string `json:"script"` Script string `json:"script"`
ContainerName string `json:"containerName"`
Website string `json:"website"` Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"` ExclusionRules string `json:"exclusionRules"`
DBName string `json:"dbName"` DBName string `json:"dbName"`
@@ -28,14 +26,12 @@ type CronjobUpdate struct {
ID uint `json:"id" validate:"required"` ID uint `json:"id" validate:"required"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
SpecType string `json:"specType" validate:"required"` SpecType string `json:"specType" validate:"required"`
Week int `json:"week" validate:"number,max=6,min=0"` Week int `json:"week" validate:"number,max=7,min=1"`
Day int `json:"day" validate:"number"` Day int `json:"day" validate:"number"`
Hour int `json:"hour" validate:"number"` Hour int `json:"hour" validate:"number"`
Minute int `json:"minute" validate:"number"` Minute int `json:"minute" validate:"number"`
Second int `json:"second" validate:"number"`
Script string `json:"script"` Script string `json:"script"`
ContainerName string `json:"containerName"`
Website string `json:"website"` Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"` ExclusionRules string `json:"exclusionRules"`
DBName string `json:"dbName"` DBName string `json:"dbName"`
@@ -75,10 +71,8 @@ type CronjobInfo struct {
Day int `json:"day"` Day int `json:"day"`
Hour int `json:"hour"` Hour int `json:"hour"`
Minute int `json:"minute"` Minute int `json:"minute"`
Second int `json:"second"`
Script string `json:"script"` Script string `json:"script"`
ContainerName string `json:"containerName"`
Website string `json:"website"` Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"` ExclusionRules string `json:"exclusionRules"`
DBName string `json:"dbName"` DBName string `json:"dbName"`
@@ -89,7 +83,7 @@ type CronjobInfo struct {
TargetDirID int `json:"targetDirID"` TargetDirID int `json:"targetDirID"`
RetainCopies int `json:"retainCopies"` RetainCopies int `json:"retainCopies"`
LastRecordTime string `json:"lastRecordTime"` LastRecrodTime string `json:"lastRecrodTime"`
Status string `json:"status"` Status string `json:"status"`
} }

View File

@@ -2,20 +2,10 @@ package dto
import "time" import "time"
type MysqlDBSearch struct {
PageInfo
Info string `json:"info"`
From string `json:"from"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type MysqlDBInfo struct { type MysqlDBInfo struct {
ID uint `json:"id"` ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
Name string `json:"name"` Name string `json:"name"`
From string `json:"from"`
MysqlName string `json:"mysqlName"`
Format string `json:"format"` Format string `json:"format"`
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
@@ -24,15 +14,8 @@ type MysqlDBInfo struct {
Description string `json:"description"` Description string `json:"description"`
} }
type MysqlOption struct {
ID uint `json:"id"`
Name string `json:"name"`
From string `json:"from"`
}
type MysqlDBCreate struct { type MysqlDBCreate struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
From string `json:"from" validate:"required"`
Format string `json:"format" validate:"required,oneof=utf8mb4 utf8 gbk big5"` Format string `json:"format" validate:"required,oneof=utf8mb4 utf8 gbk big5"`
Username string `json:"username" validate:"required"` Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"` Password string `json:"password" validate:"required"`
@@ -117,7 +100,6 @@ type MysqlConfUpdateByFile struct {
type ChangeDBInfo struct { type ChangeDBInfo struct {
ID uint `json:"id"` ID uint `json:"id"`
From string `json:"from"`
Value string `json:"value" validate:"required"` Value string `json:"value" validate:"required"`
} }

View File

@@ -13,16 +13,10 @@ type DaemonJsonConf struct {
LiveRestore bool `json:"liveRestore"` LiveRestore bool `json:"liveRestore"`
IPTables bool `json:"iptables"` IPTables bool `json:"iptables"`
CgroupDriver string `json:"cgroupDriver"` CgroupDriver string `json:"cgroupDriver"`
LogMaxSize string `json:"logMaxSize"`
LogMaxFile string `json:"logMaxFile"`
}
type LogOption struct {
LogMaxSize string `json:"logMaxSize"`
LogMaxFile string `json:"logMaxFile"`
} }
type DockerOperation struct { type DockerOperation struct {
Operation string `json:"operation" validate:"required,oneof=start restart stop"` StopSocket bool `json:"stopSocket"`
StopService bool `json:"stopService"`
Operation string `json:"operation" validate:"required,oneof=start restart stop"`
} }

View File

@@ -10,35 +10,35 @@ type ImageInfo struct {
} }
type ImageLoad struct { type ImageLoad struct {
Path string `json:"path" validate:"required"` Path string `josn:"path" validate:"required"`
} }
type ImageBuild struct { type ImageBuild struct {
From string `json:"from" validate:"required"` From string `josn:"from" validate:"required"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Dockerfile string `json:"dockerfile" validate:"required"` Dockerfile string `josn:"dockerfile" validate:"required"`
Tags []string `json:"tags"` Tags []string `josn:"tags"`
} }
type ImagePull struct { type ImagePull struct {
RepoID uint `json:"repoID"` RepoID uint `josn:"repoID"`
ImageName string `json:"imageName" validate:"required"` ImageName string `josn:"imageName" validate:"required"`
} }
type ImageTag struct { type ImageTag struct {
RepoID uint `json:"repoID"` RepoID uint `josn:"repoID"`
SourceID string `json:"sourceID" validate:"required"` SourceID string `json:"sourceID" validate:"required"`
TargetName string `json:"targetName" validate:"required"` TargetName string `josn:"targetName" validate:"required"`
} }
type ImagePush struct { type ImagePush struct {
RepoID uint `json:"repoID" validate:"required"` RepoID uint `josn:"repoID" validate:"required"`
TagName string `json:"tagName" validate:"required"` TagName string `json:"tagName" validate:"required"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
} }
type ImageSave struct { type ImageSave struct {
TagName string `json:"tagName" validate:"required"` TagName string `json:"tagName" validate:"required"`
Path string `json:"path" validate:"required"` Path string `josn:"path" validate:"required"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
} }

View File

@@ -6,8 +6,8 @@ type ImageRepoCreate struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
DownloadUrl string `json:"downloadUrl"` DownloadUrl string `json:"downloadUrl"`
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
Username string `json:"username" validate:"max=256"` Username string `json:"username"`
Password string `json:"password" validate:"max=256"` Password string `json:"password"`
Auth bool `json:"auth"` Auth bool `json:"auth"`
} }
@@ -15,8 +15,8 @@ type ImageRepoUpdate struct {
ID uint `json:"id"` ID uint `json:"id"`
DownloadUrl string `json:"downloadUrl"` DownloadUrl string `json:"downloadUrl"`
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
Username string `json:"username" validate:"max=256"` Username string `json:"username"`
Password string `json:"password" validate:"max=256"` Password string `json:"password"`
Auth bool `json:"auth"` Auth bool `json:"auth"`
} }

View File

@@ -28,20 +28,13 @@ type NginxParam struct {
Params []string Params []string
} }
type NginxAuth struct {
Username string `json:"username"`
Remark string `json:"remark"`
}
type NginxKey string type NginxKey string
const ( const (
Index NginxKey = "index" Index NginxKey = "index"
LimitConn NginxKey = "limit-conn" LimitConn NginxKey = "limit-conn"
SSL NginxKey = "ssl" SSL NginxKey = "ssl"
CACHE NginxKey = "cache" HttpPer NginxKey = "http-per"
HttpPer NginxKey = "http-per"
ProxyCache NginxKey = "proxy-cache"
) )
var ScopeKeyMap = map[NginxKey][]string{ var ScopeKeyMap = map[NginxKey][]string{
@@ -53,7 +46,5 @@ var ScopeKeyMap = map[NginxKey][]string{
var StaticFileKeyMap = map[NginxKey]struct { var StaticFileKeyMap = map[NginxKey]struct {
}{ }{
SSL: {}, SSL: {},
CACHE: {},
ProxyCache: {},
} }

View File

@@ -1,52 +0,0 @@
package dto
import "time"
type RemoteDBSearch struct {
PageInfo
Info string `json:"info"`
Type string `json:"type"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type RemoteDBInfo struct {
ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"`
Name string `json:"name" validate:"max=256"`
From string `json:"from"`
Version string `json:"version"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
Description string `json:"description"`
}
type RemoteDBOption struct {
ID uint `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
}
type RemoteDBCreate struct {
Name string `json:"name" validate:"required,max=256"`
Type string `json:"type" validate:"required,oneof=mysql"`
From string `json:"from" validate:"required,oneof=local remote"`
Version string `json:"version" validate:"required"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Description string `json:"description"`
}
type RemoteDBUpdate struct {
ID uint `json:"id"`
Version string `json:"version" validate:"required"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Description string `json:"description"`
}

View File

@@ -18,18 +18,6 @@ type AppInstallCreate struct {
Params map[string]interface{} `json:"params"` Params map[string]interface{} `json:"params"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Services map[string]string `json:"services"` Services map[string]string `json:"services"`
AppContainerConfig
}
type AppContainerConfig struct {
Advanced bool `json:"advanced"`
CpuQuota float64 `json:"cpuQuota"`
MemoryLimit float64 `json:"memoryLimit"`
MemoryUnit string `json:"memoryUnit"`
ContainerName string `json:"containerName"`
AllowPort bool `json:"allowPort"`
EditCompose bool `json:"editCompose"`
DockerCompose string `json:"dockerCompose"`
} }
type AppInstalledSearch struct { type AppInstalledSearch struct {
@@ -58,18 +46,11 @@ type AppInstalledOperate struct {
ForceDelete bool `json:"forceDelete"` ForceDelete bool `json:"forceDelete"`
DeleteBackup bool `json:"deleteBackup"` DeleteBackup bool `json:"deleteBackup"`
DeleteDB bool `json:"deleteDB"` DeleteDB bool `json:"deleteDB"`
Backup bool `json:"backup"`
} }
type AppInstalledUpdate struct { type AppInstalledUpdate struct {
InstallId uint `json:"installId" validate:"required"` InstallId uint `json:"installId" validate:"required"`
Params map[string]interface{} `json:"params" validate:"required"` Params map[string]interface{} `json:"params" validate:"required"`
AppContainerConfig
}
type AppInstalledIgnoreUpgrade struct {
DetailID uint `json:"detailID" validate:"required"`
Operate string `json:"operate" validate:"required,oneof=cancel ignore"`
} }
type PortUpdate struct { type PortUpdate struct {

View File

@@ -22,7 +22,6 @@ type FileCreate struct {
IsLink bool `json:"isLink"` IsLink bool `json:"isLink"`
IsSymlink bool `json:"isSymlink"` IsSymlink bool `json:"isSymlink"`
LinkPath string `json:"linkPath"` LinkPath string `json:"linkPath"`
Sub bool `json:"sub"`
} }
type FileDelete struct { type FileDelete struct {
@@ -82,11 +81,6 @@ type FileDownload struct {
Compress bool `json:"compress" validate:"required"` Compress bool `json:"compress" validate:"required"`
} }
type FileChunkDownload struct {
Path string `json:"path" validate:"required"`
Name string `json:"name" validate:"required"`
}
type DirSizeReq struct { type DirSizeReq struct {
Path string `json:"path" validate:"required"` Path string `json:"path" validate:"required"`
} }
@@ -94,10 +88,3 @@ type DirSizeReq struct {
type FileProcessReq struct { type FileProcessReq struct {
Key string `json:"key"` Key string `json:"key"`
} }
type FileRoleUpdate struct {
Path string `json:"path" validate:"required"`
User string `json:"user" validate:"required"`
Group string `json:"group" validate:"required"`
Sub bool `json:"sub" validate:"required"`
}

View File

@@ -1,41 +0,0 @@
package request
type HostToolReq struct {
Type string `json:"type" validate:"required,oneof=supervisord"`
Operate string `json:"operate" validate:"oneof=status restart start stop"`
}
type HostToolCreate struct {
Type string `json:"type" validate:"required"`
SupervisorConfig
}
type SupervisorConfig struct {
ConfigPath string `json:"configPath"`
ServiceName string `json:"serviceName"`
}
type HostToolLogReq struct {
Type string `json:"type" validate:"required,oneof=supervisord"`
}
type HostToolConfig struct {
Type string `json:"type" validate:"required,oneof=supervisord"`
Operate string `json:"operate" validate:"oneof=get set"`
Content string `json:"content"`
}
type SupervisorProcessConfig struct {
Name string `json:"name"`
Operate string `json:"operate"`
Command string `json:"command"`
User string `json:"user"`
Dir string `json:"dir"`
Numprocs string `json:"numprocs"`
}
type SupervisorProcessFileReq struct {
Name string `json:"name" validate:"required"`
Operate string `json:"operate" validate:"required,oneof=get clear update" `
Content string `json:"content"`
File string `json:"file" validate:"required,oneof=out.log err.log config"`
}

View File

@@ -3,8 +3,9 @@ package request
import "github.com/1Panel-dev/1Panel/backend/app/dto" import "github.com/1Panel-dev/1Panel/backend/app/dto"
type NginxConfigFileUpdate struct { type NginxConfigFileUpdate struct {
Content string `json:"content" validate:"required"` Content string `json:"content" validate:"required"`
Backup bool `json:"backup" validate:"required"` FilePath string `json:"filePath" validate:"required"`
Backup bool `json:"backup" validate:"required"`
} }
type NginxScopeReq struct { type NginxScopeReq struct {
@@ -29,59 +30,3 @@ type NginxRewriteUpdate struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Content string `json:"content" validate:"required"` Content string `json:"content" validate:"required"`
} }
type NginxProxyUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Content string `json:"content" validate:"required"`
Name string `json:"name" validate:"required"`
}
type NginxAuthUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Operate string `json:"operate" validate:"required"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Remark string `json:"remark"`
}
type NginxAuthReq struct {
WebsiteID uint `json:"websiteID" validate:"required"`
}
type NginxCommonReq struct {
WebsiteID uint `json:"websiteID" validate:"required"`
}
type NginxAntiLeechUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Extends string `json:"extends" validate:"required"`
Return string `json:"return" validate:"required"`
Enable bool `json:"enable" validate:"required"`
ServerNames []string `json:"serverNames"`
Cache bool `json:"cache"`
CacheTime int `json:"cacheTime"`
CacheUint string `json:"cacheUint"`
NoneRef bool `json:"noneRef"`
LogEnable bool `json:"logEnable"`
Blocked bool `json:"blocked"`
}
type NginxRedirectReq struct {
Name string `json:"name" validate:"required"`
WebsiteID uint `json:"websiteID" validate:"required"`
Domains []string `json:"domains"`
KeepPath bool `json:"keepPath" validate:"required"`
Enable bool `json:"enable" validate:"required"`
Type string `json:"type" validate:"required"`
Redirect string `json:"redirect" validate:"required"`
Path string `json:"path"`
Target string `json:"target" validate:"required"`
Operate string `json:"operate" validate:"required"`
RedirectRoot bool `json:"redirectRoot"`
}
type NginxRedirectUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Content string `json:"content" validate:"required"`
Name string `json:"name" validate:"required"`
}

View File

@@ -1,5 +0,0 @@
package request
type ProcessReq struct {
PID int32 `json:"PID" validate:"required"`
}

View File

@@ -7,8 +7,6 @@ import (
type WebsiteSearch struct { type WebsiteSearch struct {
dto.PageInfo dto.PageInfo
Name string `json:"name"` Name string `json:"name"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
WebsiteGroupID uint `json:"websiteGroupId"` WebsiteGroupID uint `json:"websiteGroupId"`
} }
@@ -20,7 +18,6 @@ type WebsiteCreate struct {
OtherDomains string `json:"otherDomains"` OtherDomains string `json:"otherDomains"`
Proxy string `json:"proxy"` Proxy string `json:"proxy"`
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"` WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
IPV6 bool `json:"IPV6"`
AppType string `json:"appType" validate:"oneof=new installed"` AppType string `json:"appType" validate:"oneof=new installed"`
AppInstall NewAppInstall `json:"appInstall"` AppInstall NewAppInstall `json:"appInstall"`
@@ -40,8 +37,6 @@ type NewAppInstall struct {
Name string `json:"name"` Name string `json:"name"`
AppDetailId uint `json:"appDetailID"` AppDetailId uint `json:"appDetailID"`
Params map[string]interface{} `json:"params"` Params map[string]interface{} `json:"params"`
AppContainerConfig
} }
type WebsiteInstallCheckReq struct { type WebsiteInstallCheckReq struct {
@@ -54,7 +49,6 @@ type WebsiteUpdate struct {
Remark string `json:"remark"` Remark string `json:"remark"`
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"` WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
ExpireDate string `json:"expireDate"` ExpireDate string `json:"expireDate"`
IPV6 bool `json:"IPV6"`
} }
type WebsiteDelete struct { type WebsiteDelete struct {
@@ -75,12 +69,6 @@ type WebsiteWafReq struct {
Rule string `json:"rule" validate:"required"` Rule string `json:"rule" validate:"required"`
} }
type WebsiteRedirectUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Enable bool `json:"enable" validate:"required"`
}
type WebsiteWafUpdate struct { type WebsiteWafUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"` WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"` Key string `json:"key" validate:"required"`
@@ -121,18 +109,15 @@ type WebsiteDomainDelete struct {
} }
type WebsiteHTTPSOp struct { type WebsiteHTTPSOp struct {
WebsiteID uint `json:"websiteId" validate:"required"` WebsiteID uint `json:"websiteId" validate:"required"`
Enable bool `json:"enable" validate:"required"` Enable bool `json:"enable" validate:"required"`
WebsiteSSLID uint `json:"websiteSSLId"` WebsiteSSLID uint `json:"websiteSSLId"`
Type string `json:"type" validate:"oneof=existed auto manual"` Type string `json:"type" validate:"oneof=existed auto manual"`
PrivateKey string `json:"privateKey"` PrivateKey string `json:"privateKey"`
Certificate string `json:"certificate"` Certificate string `json:"certificate"`
PrivateKeyPath string `json:"privateKeyPath"` HttpConfig string `json:"HttpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
CertificatePath string `json:"certificatePath"` SSLProtocol []string `json:"SSLProtocol"`
ImportType string `json:"importType"` Algorithm string `json:"algorithm"`
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
} }
type WebsiteNginxUpdate struct { type WebsiteNginxUpdate struct {
@@ -151,11 +136,8 @@ type WebsiteDefaultUpdate struct {
} }
type WebsitePHPConfigUpdate struct { type WebsitePHPConfigUpdate struct {
ID uint `json:"id" validate:"required"` ID uint `json:"id" validate:"required"`
Params map[string]string `json:"params"` Params map[string]string `json:"params" validate:"required"`
Scope string `json:"scope" validate:"required"`
DisableFunctions []string `json:"disableFunctions"`
UploadMaxSize string `json:"uploadMaxSize"`
} }
type WebsitePHPFileUpdate struct { type WebsitePHPFileUpdate struct {
@@ -164,12 +146,6 @@ type WebsitePHPFileUpdate struct {
Content string `json:"content" validate:"required"` Content string `json:"content" validate:"required"`
} }
type WebsitePHPVersionReq struct {
WebsiteID uint `json:"websiteID" validate:"required"`
RuntimeID uint `json:"runtimeID" validate:"required"`
RetainConfig bool `json:"retainConfig" validate:"required"`
}
type WebsiteUpdateDir struct { type WebsiteUpdateDir struct {
ID uint `json:"id" validate:"required"` ID uint `json:"id" validate:"required"`
SiteDir string `json:"siteDir" validate:"required"` SiteDir string `json:"siteDir" validate:"required"`
@@ -180,34 +156,3 @@ type WebsiteUpdateDirPermission struct {
User string `json:"user" validate:"required"` User string `json:"user" validate:"required"`
Group string `json:"group" validate:"required"` Group string `json:"group" validate:"required"`
} }
type WebsiteProxyConfig struct {
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
Enable bool `json:"enable" validate:"required"`
Cache bool `json:"cache" validate:"required"`
CacheTime int `json:"cacheTime" validate:"required"`
CacheUnit string `json:"cacheUnit" validate:"required"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier" validate:"required"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
}
type WebsiteProxyReq struct {
ID uint `json:"id" validate:"required"`
}
type WebsiteRedirectReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
}
type WebsiteWafFileUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Content string `json:"content" validate:"required"`
Type string `json:"type" validate:"required,oneof=cc ip_white ip_block url_white url_block cookie_block args_check post_check ua_check file_ext_block"`
}

View File

@@ -4,7 +4,6 @@ import "github.com/1Panel-dev/1Panel/backend/app/dto"
type WebsiteSSLSearch struct { type WebsiteSSLSearch struct {
dto.PageInfo dto.PageInfo
AcmeAccountID string `json:"acmeAccountID"`
} }
type WebsiteSSLCreate struct { type WebsiteSSLCreate struct {

View File

@@ -1,7 +1,6 @@
package response package response
import ( import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"time" "time"
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
@@ -13,15 +12,15 @@ type AppRes struct {
} }
type AppUpdateRes struct { type AppUpdateRes struct {
CanUpdate bool `json:"canUpdate"` Version string `json:"version"`
AppStoreLastModified int `json:"appStoreLastModified"` CanUpdate bool `json:"canUpdate"`
DownloadPath string `json:"downloadPath"`
} }
type AppDTO struct { type AppDTO struct {
model.App model.App
Installed bool `json:"installed"` Versions []string `json:"versions"`
Versions []string `json:"versions"` Tags []model.Tag `json:"tags"`
Tags []model.Tag `json:"tags"`
} }
type TagDTO struct { type TagDTO struct {
@@ -48,13 +47,6 @@ type AppDetailDTO struct {
Image string `json:"image"` Image string `json:"image"`
} }
type IgnoredApp struct {
Icon string `json:"icon"`
Name string `json:"name"`
Version string `json:"version"`
DetailID uint `json:"detailID"`
}
type AppInstalledDTO struct { type AppInstalledDTO struct {
model.AppInstall model.AppInstall
Total int `json:"total"` Total int `json:"total"`
@@ -62,7 +54,6 @@ type AppInstalledDTO struct {
AppName string `json:"appName"` AppName string `json:"appName"`
Icon string `json:"icon"` Icon string `json:"icon"`
CanUpdate bool `json:"canUpdate"` CanUpdate bool `json:"canUpdate"`
Path string `json:"path"`
} }
type DatabaseConn struct { type DatabaseConn struct {
@@ -90,8 +81,3 @@ type AppParam struct {
Required bool `json:"required"` Required bool `json:"required"`
Multiple bool `json:"multiple"` Multiple bool `json:"multiple"`
} }
type AppConfig struct {
Params []AppParam `json:"params"`
request.AppContainerConfig
}

View File

@@ -1,41 +0,0 @@
package response
type HostToolRes struct {
Type string `json:"type"`
Config interface{} `json:"config"`
}
type Supervisor struct {
ConfigPath string `json:"configPath"`
IncludeDir string `json:"includeDir"`
LogPath string `json:"logPath"`
IsExist bool `json:"isExist"`
Init bool `json:"init"`
Msg string `json:"msg"`
Version string `json:"version"`
Status string `json:"status"`
CtlExist bool `json:"ctlExist"`
ServiceName string `json:"serviceName"`
}
type HostToolConfig struct {
Content string `json:"content"`
}
type SupervisorProcessConfig struct {
Name string `json:"name"`
Command string `json:"command"`
User string `json:"user"`
Dir string `json:"dir"`
Numprocs string `json:"numprocs"`
Msg string `json:"msg"`
Status []ProcessStatus `json:"status"`
}
type ProcessStatus struct {
Name string `json:"name"`
Status string `json:"status"`
PID string `json:"PID"`
Uptime string `json:"uptime"`
Msg string `json:"msg"`
}

View File

@@ -1,7 +1,5 @@
package response package response
import "github.com/1Panel-dev/1Panel/backend/app/dto"
type NginxStatus struct { type NginxStatus struct {
Active string `json:"active"` Active string `json:"active"`
Accepts string `json:"accepts"` Accepts string `json:"accepts"`
@@ -16,40 +14,3 @@ type NginxParam struct {
Name string `json:"name"` Name string `json:"name"`
Params []string `json:"params"` Params []string `json:"params"`
} }
type NginxAuthRes struct {
Enable bool `json:"enable"`
Items []dto.NginxAuth `json:"items"`
}
type NginxAntiLeechRes struct {
Enable bool `json:"enable"`
Extends string `json:"extends"`
Return string `json:"return"`
ServerNames []string `json:"serverNames"`
Cache bool `json:"cache"`
CacheTime int `json:"cacheTime"`
CacheUint string `json:"cacheUint"`
NoneRef bool `json:"noneRef"`
LogEnable bool `json:"logEnable"`
Blocked bool `json:"blocked"`
}
type NginxRedirectConfig struct {
WebsiteID uint `json:"websiteID"`
Name string `json:"name"`
Domains []string `json:"domains"`
KeepPath bool `json:"keepPath"`
Enable bool `json:"enable"`
Type string `json:"type"`
Redirect string `json:"redirect"`
Path string `json:"path"`
Target string `json:"target"`
FilePath string `json:"filePath"`
Content string `json:"content"`
RedirectRoot bool `json:"redirectRoot"`
}
type NginxFile struct {
Content string `json:"content"`
}

View File

@@ -26,8 +26,9 @@ type WebsiteNginxConfig struct {
} }
type WebsiteWafConfig struct { type WebsiteWafConfig struct {
Enable bool `json:"enable"` Enable bool `json:"enable"`
Content string `json:"content"` FilePath string `json:"filePath"`
Content string `json:"content"`
} }
type WebsiteHTTPS struct { type WebsiteHTTPS struct {
@@ -44,9 +45,7 @@ type WebsiteLog struct {
} }
type PHPConfig struct { type PHPConfig struct {
Params map[string]string `json:"params"` Params map[string]string `json:"params"`
DisableFunctions []string `json:"disableFunctions"`
UploadMaxSize string `json:"uploadMaxSize"`
} }
type NginxRewriteRes struct { type NginxRewriteRes struct {

View File

@@ -5,13 +5,10 @@ import "time"
type SettingInfo struct { type SettingInfo struct {
UserName string `json:"userName"` UserName string `json:"userName"`
Email string `json:"email"` Email string `json:"email"`
SystemIP string `json:"systemIP"`
SystemVersion string `json:"systemVersion"` SystemVersion string `json:"systemVersion"`
SessionTimeout string `json:"sessionTimeout"` SessionTimeout string `json:"sessionTimeout"`
LocalTime string `json:"localTime"` LocalTime string `json:"localTime"`
TimeZone string `json:"timeZone"`
NtpSite string `json:"ntpSite"`
Port string `json:"port"` Port string `json:"port"`
PanelName string `json:"panelName"` PanelName string `json:"panelName"`
@@ -19,20 +16,14 @@ type SettingInfo struct {
Language string `json:"language"` Language string `json:"language"`
ServerPort string `json:"serverPort"` ServerPort string `json:"serverPort"`
SSL string `json:"ssl"`
SSLType string `json:"sslType"`
BindDomain string `json:"bindDomain"`
AllowIPs string `json:"allowIPs"`
SecurityEntrance string `json:"securityEntrance"` SecurityEntrance string `json:"securityEntrance"`
ExpirationDays string `json:"expirationDays"` ExpirationDays string `json:"expirationDays"`
ExpirationTime string `json:"expirationTime"` ExpirationTime string `json:"expirationTime"`
ComplexityVerification string `json:"complexityVerification"` ComplexityVerification string `json:"complexityVerification"`
MFAStatus string `json:"mfaStatus"` MFAStatus string `json:"mfaStatus"`
MFASecret string `json:"mfaSecret"` MFASecret string `json:"mfaSecret"`
MFAInterval string `json:"mfaInterval"`
MonitorStatus string `json:"monitorStatus"` MonitorStatus string `json:"monitorStatus"`
MonitorInterval string `json:"monitorInterval"`
MonitorStoreDays string `json:"monitorStoreDays"` MonitorStoreDays string `json:"monitorStoreDays"`
MessageType string `json:"messageType"` MessageType string `json:"messageType"`
@@ -40,8 +31,7 @@ type SettingInfo struct {
WeChatVars string `json:"weChatVars"` WeChatVars string `json:"weChatVars"`
DingVars string `json:"dingVars"` DingVars string `json:"dingVars"`
AppStoreVersion string `json:"appStoreVersion"` AppStoreVersion string `json:"appStoreVersion"`
AppStoreLastModified string `json:"appStoreLastModified"`
} }
type SettingUpdate struct { type SettingUpdate struct {
@@ -49,23 +39,6 @@ type SettingUpdate struct {
Value string `json:"value"` Value string `json:"value"`
} }
type SSLUpdate struct {
SSLType string `json:"sslType"`
Domain string `json:"domain"`
SSL string `json:"ssl" validate:"required,oneof=enable disable"`
Cert string `json:"cert"`
Key string `json:"key"`
SSLID uint `json:"sslID"`
}
type SSLInfo struct {
Domain string `json:"domain"`
Timeout string `json:"timeout"`
RootPath string `json:"rootPath"`
Cert string `json:"cert"`
Key string `json:"key"`
SSLID uint `json:"sslID"`
}
type PasswordUpdate struct { type PasswordUpdate struct {
OldPassword string `json:"oldPassword" validate:"required"` OldPassword string `json:"oldPassword" validate:"required"`
NewPassword string `json:"newPassword" validate:"required"` NewPassword string `json:"newPassword" validate:"required"`
@@ -76,8 +49,8 @@ type PortUpdate struct {
} }
type SnapshotCreate struct { type SnapshotCreate struct {
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO COS KODO OneDrive"` From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO COS KODO"`
Description string `json:"description" validate:"max=256"` Description string `json:"description"`
} }
type SnapshotRecover struct { type SnapshotRecover struct {
IsNew bool `json:"isNew"` IsNew bool `json:"isNew"`
@@ -87,12 +60,12 @@ type SnapshotRecover struct {
type SnapshotImport struct { type SnapshotImport struct {
From string `json:"from"` From string `json:"from"`
Names []string `json:"names"` Names []string `json:"names"`
Description string `json:"description" validate:"max=256"` Description string `json:"description"`
} }
type SnapshotInfo struct { type SnapshotInfo struct {
ID uint `json:"id"` ID uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description" validate:"max=256"` Description string `json:"description"`
From string `json:"from"` From string `json:"from"`
Status string `json:"status"` Status string `json:"status"`
Message string `json:"message"` Message string `json:"message"`
@@ -114,10 +87,6 @@ type UpgradeInfo struct {
ReleaseNote string `json:"releaseNote"` ReleaseNote string `json:"releaseNote"`
} }
type SyncTime struct {
NtpSite string `json:"ntpSite"`
}
type Upgrade struct { type Upgrade struct {
Version string `json:"version"` Version string `json:"version"`
} }

View File

@@ -1,49 +0,0 @@
package dto
import "time"
type SSHInfo struct {
Status string `json:"status"`
Message string `json:"message"`
Port string `json:"port"`
ListenAddress string `json:"listenAddress"`
PasswordAuthentication string `json:"passwordAuthentication"`
PubkeyAuthentication string `json:"pubkeyAuthentication"`
PermitRootLogin string `json:"permitRootLogin"`
UseDNS string `json:"useDNS"`
}
type GenerateSSH struct {
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
Password string `json:"password"`
}
type GenerateLoad struct {
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
}
type SSHConf struct {
File string `json:"file"`
}
type SearchSSHLog struct {
PageInfo
Info string `json:"info"`
Status string `json:"Status" validate:"required,oneof=Success Failed All"`
}
type SSHLog struct {
Logs []SSHHistory `json:"logs"`
TotalCount int `json:"totalCount"`
SuccessfulCount int `json:"successfulCount"`
FailedCount int `json:"failedCount"`
}
type SSHHistory struct {
Date time.Time `json:"date"`
DateStr string `json:"dateStr"`
Area string `json:"area"`
User string `json:"user"`
AuthMode string `json:"authMode"`
Address string `json:"address"`
Port string `json:"port"`
Status string `json:"status"`
Message string `json:"message"`
}

View File

@@ -2,25 +2,22 @@ package model
type App struct { type App struct {
BaseModel BaseModel
Name string `json:"name" gorm:"type:varchar(64);not null"` Name string `json:"name" gorm:"type:varchar(64);not null"`
Key string `json:"key" gorm:"type:varchar(64);not null;"` Key string `json:"key" gorm:"type:varchar(64);not null;uniqueIndex"`
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh" gorm:"type:longtext;"` ShortDescZh string `json:"shortDescZh" gorm:"type:longtext;"`
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn" gorm:"type:longtext;"` ShortDescEn string `json:"shortDescEn" gorm:"type:longtext;"`
Icon string `json:"icon" gorm:"type:longtext;"` Icon string `json:"icon" gorm:"type:longtext;"`
Type string `json:"type" gorm:"type:varchar(64);not null"` Type string `json:"type" gorm:"type:varchar(64);not null"`
Status string `json:"status" gorm:"type:varchar(64);not null"` Status string `json:"status" gorm:"type:varchar(64);not null"`
Required string `json:"required" gorm:"type:varchar(64);"` Required string `json:"required" gorm:"type:varchar(64);not null"`
CrossVersionUpdate bool `json:"crossVersionUpdate"` CrossVersionUpdate bool `json:"crossVersionUpdate"`
Limit int `json:"limit" gorm:"type:Integer;not null"` Limit int `json:"limit" gorm:"type:Integer;not null"`
Website string `json:"website" gorm:"type:varchar(64);not null"` Website string `json:"website" gorm:"type:varchar(64);not null"`
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"` Resource string `json:"resource" gorm:"type:varchar;not null;default:remote"`
ReadMe string `json:"readMe" gorm:"type:varchar;"` Details []AppDetail `json:"-" gorm:"-:migration"`
LastModified int `json:"lastModified" gorm:"type:Integer;"` TagsKey []string `json:"-" gorm:"-"`
AppTags []AppTag `json:"-" gorm:"-:migration"`
Details []AppDetail `json:"-" gorm:"-:migration"`
TagsKey []string `json:"tags" yaml:"tags" gorm:"-"`
AppTags []AppTag `json:"-" gorm:"-:migration"`
} }

View File

@@ -2,15 +2,11 @@ package model
type AppDetail struct { type AppDetail struct {
BaseModel BaseModel
AppId uint `json:"appId" gorm:"type:integer;not null"` AppId uint `json:"appId" gorm:"type:integer;not null"`
Version string `json:"version" gorm:"type:varchar(64);not null"` Version string `json:"version" gorm:"type:varchar(64);not null"`
Params string `json:"-" gorm:"type:longtext;"` Params string `json:"-" gorm:"type:longtext;"`
DockerCompose string `json:"dockerCompose" gorm:"type:longtext;"` DockerCompose string `json:"-" gorm:"type:longtext;not null"`
Status string `json:"status" gorm:"type:varchar(64);not null"` Readme string `json:"readme" gorm:"type:longtext;"`
LastVersion string `json:"lastVersion" gorm:"type:varchar(64);"` Status string `json:"status" gorm:"type:varchar(64);not null"`
LastModified int `json:"lastModified" gorm:"type:integer;"` LastVersion string `json:"lastVersion" gorm:"type:varchar(64);"`
DownloadUrl string `json:"downloadUrl" gorm:"type:varchar;"`
DownloadCallBackUrl string `json:"downloadCallBackUrl" gorm:"type:longtext;"`
Update bool `json:"update"`
IgnoreUpgrade bool `json:"ignoreUpgrade"`
} }

View File

@@ -6,7 +6,6 @@ type BackupAccount struct {
Bucket string `gorm:"type:varchar(256)" json:"bucket"` Bucket string `gorm:"type:varchar(256)" json:"bucket"`
AccessKey string `gorm:"type:varchar(256)" json:"accessKey"` AccessKey string `gorm:"type:varchar(256)" json:"accessKey"`
Credential string `gorm:"type:varchar(256)" json:"credential"` Credential string `gorm:"type:varchar(256)" json:"credential"`
BackupPath string `gorm:"type:varchar(256)" json:"backupPath"`
Vars string `gorm:"type:longText" json:"vars"` Vars string `gorm:"type:longText" json:"vars"`
} }

View File

@@ -13,9 +13,7 @@ type Cronjob struct {
Day uint64 `gorm:"type:decimal" json:"day"` Day uint64 `gorm:"type:decimal" json:"day"`
Hour uint64 `gorm:"type:decimal" json:"hour"` Hour uint64 `gorm:"type:decimal" json:"hour"`
Minute uint64 `gorm:"type:decimal" json:"minute"` Minute uint64 `gorm:"type:decimal" json:"minute"`
Second uint64 `gorm:"type:decimal" json:"second"`
ContainerName string `gorm:"type:varchar(64)" json:"containerName"`
Script string `gorm:"longtext" json:"script"` Script string `gorm:"longtext" json:"script"`
Website string `gorm:"type:varchar(64)" json:"website"` Website string `gorm:"type:varchar(64)" json:"website"`
DBName string `gorm:"type:varchar(64)" json:"dbName"` DBName string `gorm:"type:varchar(64)" json:"dbName"`

View File

@@ -3,7 +3,6 @@ package model
type DatabaseMysql struct { type DatabaseMysql struct {
BaseModel BaseModel
Name string `json:"name" gorm:"type:varchar(256);not null"` Name string `json:"name" gorm:"type:varchar(256);not null"`
From string `json:"from" gorm:"type:varchar(256);not null;default:local"`
MysqlName string `json:"mysqlName" gorm:"type:varchar(64);not null"` MysqlName string `json:"mysqlName" gorm:"type:varchar(64);not null"`
Format string `json:"format" gorm:"type:varchar(64);not null"` Format string `json:"format" gorm:"type:varchar(64);not null"`
Username string `json:"username" gorm:"type:varchar(256);not null"` Username string `json:"username" gorm:"type:varchar(256);not null"`

View File

@@ -1,14 +0,0 @@
package model
type RemoteDB struct {
BaseModel
Name string `json:"name" gorm:"type:varchar(64);not null"`
Type string `json:"type" gorm:"type:varchar(64);not null"`
Version string `json:"version" gorm:"type:varchar(64);not null"`
From string `json:"from" gorm:"type:varchar(64);not null"`
Address string `json:"address" gorm:"type:varchar(64);not null"`
Port uint `json:"port" gorm:"type:decimal;not null"`
Username string `json:"username" gorm:"type:varchar(64)"`
Password string `json:"password" gorm:"type:varchar(64)"`
Description string `json:"description" gorm:"type:varchar(256);"`
}

View File

@@ -19,7 +19,6 @@ type Website struct {
ErrorLog bool `json:"errorLog"` ErrorLog bool `json:"errorLog"`
AccessLog bool `json:"accessLog"` AccessLog bool `json:"accessLog"`
DefaultServer bool `json:"defaultServer"` DefaultServer bool `json:"defaultServer"`
IPV6 bool `json:"IPV6"`
Rewrite string `gorm:"type:varchar" json:"rewrite"` Rewrite string `gorm:"type:varchar" json:"rewrite"`
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"` WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`

View File

@@ -24,7 +24,6 @@ type IAppRepo interface {
GetByKey(ctx context.Context, key string) (model.App, error) GetByKey(ctx context.Context, key string) (model.App, error)
Create(ctx context.Context, app *model.App) error Create(ctx context.Context, app *model.App) error
Save(ctx context.Context, app *model.App) error Save(ctx context.Context, app *model.App) error
BatchDelete(ctx context.Context, apps []model.App) error
} }
func NewIAppRepo() IAppRepo { func NewIAppRepo() IAppRepo {
@@ -107,7 +106,3 @@ func (a AppRepo) Create(ctx context.Context, app *model.App) error {
func (a AppRepo) Save(ctx context.Context, app *model.App) error { func (a AppRepo) Save(ctx context.Context, app *model.App) error {
return getTx(ctx).Omit(clause.Associations).Save(app).Error return getTx(ctx).Omit(clause.Associations).Save(app).Error
} }
func (a AppRepo) BatchDelete(ctx context.Context, apps []model.App) error {
return getTx(ctx).Omit(clause.Associations).Delete(&apps).Error
}

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause"
) )
type AppDetailRepo struct { type AppDetailRepo struct {
@@ -13,14 +12,12 @@ type AppDetailRepo struct {
type IAppDetailRepo interface { type IAppDetailRepo interface {
WithVersion(version string) DBOption WithVersion(version string) DBOption
WithAppId(id uint) DBOption WithAppId(id uint) DBOption
WithIgnored() DBOption
GetFirst(opts ...DBOption) (model.AppDetail, error) GetFirst(opts ...DBOption) (model.AppDetail, error)
Update(ctx context.Context, detail model.AppDetail) error Update(ctx context.Context, detail model.AppDetail) error
BatchCreate(ctx context.Context, details []model.AppDetail) error BatchCreate(ctx context.Context, details []model.AppDetail) error
DeleteByAppIds(ctx context.Context, appIds []uint) error DeleteByAppIds(ctx context.Context, appIds []uint) error
GetBy(opts ...DBOption) ([]model.AppDetail, error) GetBy(opts ...DBOption) ([]model.AppDetail, error)
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
BatchDelete(ctx context.Context, appDetails []model.AppDetail) error
} }
func NewIAppDetailRepo() IAppDetailRepo { func NewIAppDetailRepo() IAppDetailRepo {
@@ -32,19 +29,12 @@ func (a AppDetailRepo) WithVersion(version string) DBOption {
return g.Where("version = ?", version) return g.Where("version = ?", version)
} }
} }
func (a AppDetailRepo) WithAppId(id uint) DBOption { func (a AppDetailRepo) WithAppId(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("app_id = ?", id) return g.Where("app_id = ?", id)
} }
} }
func (a AppDetailRepo) WithIgnored() DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("ignore_upgrade = 1")
}
}
func (a AppDetailRepo) GetFirst(opts ...DBOption) (model.AppDetail, error) { func (a AppDetailRepo) GetFirst(opts ...DBOption) (model.AppDetail, error) {
var detail model.AppDetail var detail model.AppDetail
err := getDb(opts...).Model(&model.AppDetail{}).Find(&detail).Error err := getDb(opts...).Model(&model.AppDetail{}).Find(&detail).Error
@@ -76,7 +66,3 @@ func (a AppDetailRepo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOpti
} }
return db.Updates(&maps).Error return db.Updates(&maps).Error
} }
func (a AppDetailRepo) BatchDelete(ctx context.Context, appDetails []model.AppDetail) error {
return getTx(ctx).Omit(clause.Associations).Delete(&appDetails).Error
}

View File

@@ -19,10 +19,8 @@ type IAppInstallRepo interface {
WithAppIdsIn(appIds []uint) DBOption WithAppIdsIn(appIds []uint) DBOption
WithStatus(status string) DBOption WithStatus(status string) DBOption
WithServiceName(serviceName string) DBOption WithServiceName(serviceName string) DBOption
WithContainerName(containerName string) DBOption
WithPort(port int) DBOption WithPort(port int) DBOption
WithIdNotInWebsite() DBOption WithIdNotInWebsite() DBOption
WithIDNotIs(id uint) DBOption
ListBy(opts ...DBOption) ([]model.AppInstall, error) ListBy(opts ...DBOption) ([]model.AppInstall, error)
GetFirst(opts ...DBOption) (model.AppInstall, error) GetFirst(opts ...DBOption) (model.AppInstall, error)
Create(ctx context.Context, install *model.AppInstall) error Create(ctx context.Context, install *model.AppInstall) error
@@ -57,12 +55,6 @@ func (a *AppInstallRepo) WithAppId(appId uint) DBOption {
} }
} }
func (a *AppInstallRepo) WithIDNotIs(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("id != ?", id)
}
}
func (a *AppInstallRepo) WithAppIdsIn(appIds []uint) DBOption { func (a *AppInstallRepo) WithAppIdsIn(appIds []uint) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("app_id in (?)", appIds) return g.Where("app_id in (?)", appIds)
@@ -81,12 +73,6 @@ func (a *AppInstallRepo) WithServiceName(serviceName string) DBOption {
} }
} }
func (a *AppInstallRepo) WithContainerName(containerName string) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("container_name = ?", containerName)
}
}
func (a *AppInstallRepo) WithPort(port int) DBOption { func (a *AppInstallRepo) WithPort(port int) DBOption {
return func(db *gorm.DB) *gorm.DB { return func(db *gorm.DB) *gorm.DB {
return db.Where("https_port = ? or http_port = ?", port, port) return db.Where("https_port = ? or http_port = ?", port, port)
@@ -126,7 +112,7 @@ func (a *AppInstallRepo) Create(ctx context.Context, install *model.AppInstall)
} }
func (a *AppInstallRepo) Save(ctx context.Context, install *model.AppInstall) error { func (a *AppInstallRepo) Save(ctx context.Context, install *model.AppInstall) error {
return getTx(ctx).Save(&install).Error return getTx(ctx).Omit(clause.Associations).Save(&install).Error
} }
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error { func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
@@ -192,19 +178,10 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
if err := json.Unmarshal([]byte(appInstall.Env), &envMap); err != nil { if err := json.Unmarshal([]byte(appInstall.Env), &envMap); err != nil {
return nil, err return nil, err
} }
switch app.Key { password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
case "mysql": if ok {
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string) info.Password = password
if ok {
info.Password = password
}
case "redis":
password, ok := envMap["PANEL_REDIS_ROOT_PASSWORD"].(string)
if ok {
info.Password = password
}
} }
userPassword, ok := envMap["PANEL_DB_USER_PASSWORD"].(string) userPassword, ok := envMap["PANEL_DB_USER_PASSWORD"].(string)
if ok { if ok {
info.UserPassword = userPassword info.UserPassword = userPassword

View File

@@ -19,7 +19,6 @@ type IAppInstallResourceRpo interface {
GetFirst(opts ...DBOption) (model.AppInstallResource, error) GetFirst(opts ...DBOption) (model.AppInstallResource, error)
Create(ctx context.Context, resource *model.AppInstallResource) error Create(ctx context.Context, resource *model.AppInstallResource) error
DeleteBy(ctx context.Context, opts ...DBOption) error DeleteBy(ctx context.Context, opts ...DBOption) error
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
} }
func NewIAppInstallResourceRpo() IAppInstallResourceRpo { func NewIAppInstallResourceRpo() IAppInstallResourceRpo {
@@ -72,11 +71,3 @@ func (a AppInstallResourceRpo) Create(ctx context.Context, resource *model.AppIn
func (a AppInstallResourceRpo) DeleteBy(ctx context.Context, opts ...DBOption) error { func (a AppInstallResourceRpo) DeleteBy(ctx context.Context, opts ...DBOption) error {
return getTx(ctx, opts...).Delete(&model.AppInstallResource{}).Error return getTx(ctx, opts...).Delete(&model.AppInstallResource{}).Error
} }
func (a *AppInstallResourceRpo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error {
db := getDb(opts...).Model(&model.AppInstallResource{})
if len(opts) == 0 {
db = db.Where("1=1")
}
return db.Updates(&maps).Error
}

View File

@@ -2,7 +2,6 @@ package repo
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
@@ -17,7 +16,6 @@ type ICommonRepo interface {
WithByName(name string) DBOption WithByName(name string) DBOption
WithByType(tp string) DBOption WithByType(tp string) DBOption
WithOrderBy(orderStr string) DBOption WithOrderBy(orderStr string) DBOption
WithOrderRuleBy(orderBy, order string) DBOption
WithByGroupID(groupID uint) DBOption WithByGroupID(groupID uint) DBOption
WithLikeName(name string) DBOption WithLikeName(name string) DBOption
WithIdsIn(ids []uint) DBOption WithIdsIn(ids []uint) DBOption
@@ -95,21 +93,6 @@ func (c *CommonRepo) WithOrderBy(orderStr string) DBOption {
} }
} }
func (c *CommonRepo) WithOrderRuleBy(orderBy, order string) DBOption {
switch order {
case constant.OrderDesc:
order = "desc"
case constant.OrderAsc:
order = "asc"
default:
orderBy = "created_at"
order = "desc"
}
return func(g *gorm.DB) *gorm.DB {
return g.Order(fmt.Sprintf("%s %s", orderBy, order))
}
}
func (c *CommonRepo) WithIdsIn(ids []uint) DBOption { func (c *CommonRepo) WithIdsIn(ids []uint) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("id in (?)", ids) return g.Where("id in (?)", ids)

View File

@@ -15,7 +15,6 @@ type IComposeTemplateRepo interface {
Update(id uint, vars map[string]interface{}) error Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error Delete(opts ...DBOption) error
GetRecord(opts ...DBOption) (model.Compose, error)
CreateRecord(compose *model.Compose) error CreateRecord(compose *model.Compose) error
DeleteRecord(opts ...DBOption) error DeleteRecord(opts ...DBOption) error
ListRecord() ([]model.Compose, error) ListRecord() ([]model.Compose, error)
@@ -73,16 +72,6 @@ func (u *ComposeTemplateRepo) Delete(opts ...DBOption) error {
return db.Delete(&model.ComposeTemplate{}).Error return db.Delete(&model.ComposeTemplate{}).Error
} }
func (u *ComposeTemplateRepo) GetRecord(opts ...DBOption) (model.Compose, error) {
var compose model.Compose
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&compose).Error
return compose, err
}
func (u *ComposeTemplateRepo) ListRecord() ([]model.Compose, error) { func (u *ComposeTemplateRepo) ListRecord() ([]model.Compose, error) {
var composes []model.Compose var composes []model.Compose
if err := global.DB.Find(&composes).Error; err != nil { if err := global.DB.Find(&composes).Error; err != nil {

View File

@@ -83,7 +83,7 @@ func (u *CronjobRepo) Page(page, size int, opts ...DBOption) (int64, []model.Cro
} }
count := int64(0) count := int64(0)
db = db.Count(&count) db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&cronjobs).Error err := db.Order("created_at desc").Limit(size).Offset(size * (page - 1)).Find(&cronjobs).Error
return count, cronjobs, err return count, cronjobs, err
} }

View File

@@ -13,14 +13,13 @@ type MysqlRepo struct{}
type IMysqlRepo interface { type IMysqlRepo interface {
Get(opts ...DBOption) (model.DatabaseMysql, error) Get(opts ...DBOption) (model.DatabaseMysql, error)
WithByMysqlName(mysqlName string) DBOption WithByMysqlName(mysqlName string) DBOption
WithByFrom(from string) DBOption
List(opts ...DBOption) ([]model.DatabaseMysql, error) List(opts ...DBOption) ([]model.DatabaseMysql, error)
Page(limit, offset int, opts ...DBOption) (int64, []model.DatabaseMysql, error) Page(limit, offset int, opts ...DBOption) (int64, []model.DatabaseMysql, error)
Create(ctx context.Context, mysql *model.DatabaseMysql) error Create(ctx context.Context, mysql *model.DatabaseMysql) error
Delete(ctx context.Context, opts ...DBOption) error Delete(ctx context.Context, opts ...DBOption) error
Update(id uint, vars map[string]interface{}) error Update(id uint, vars map[string]interface{}) error
UpdateDatabaseInfo(id uint, vars map[string]interface{}) error UpdateDatabaseInfo(id uint, vars map[string]interface{}) error
DeleteLocal(ctx context.Context) error DeleteAll(ctx context.Context) error
} }
func NewIMysqlRepo() IMysqlRepo { func NewIMysqlRepo() IMysqlRepo {
@@ -67,8 +66,8 @@ func (u *MysqlRepo) Delete(ctx context.Context, opts ...DBOption) error {
return getTx(ctx, opts...).Delete(&model.DatabaseMysql{}).Error return getTx(ctx, opts...).Delete(&model.DatabaseMysql{}).Error
} }
func (u *MysqlRepo) DeleteLocal(ctx context.Context) error { func (u *MysqlRepo) DeleteAll(ctx context.Context) error {
return getTx(ctx).Where("`from` = ?", "local").Delete(&model.DatabaseMysql{}).Error return getTx(ctx).Where("1 = 1").Delete(&model.DatabaseMysql{}).Error
} }
func (u *MysqlRepo) Update(id uint, vars map[string]interface{}) error { func (u *MysqlRepo) Update(id uint, vars map[string]interface{}) error {
@@ -87,12 +86,3 @@ func (u *MysqlRepo) WithByMysqlName(mysqlName string) DBOption {
return g.Where("mysql_name = ?", mysqlName) return g.Where("mysql_name = ?", mysqlName)
} }
} }
func (u *MysqlRepo) WithByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(from) != 0 {
return g.Where("`from` = ?", from)
}
return g
}
}

View File

@@ -1,84 +0,0 @@
package repo
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
)
type RemoteDBRepo struct{}
type IRemoteDBRepo interface {
GetList(opts ...DBOption) ([]model.RemoteDB, error)
Page(limit, offset int, opts ...DBOption) (int64, []model.RemoteDB, error)
Create(database *model.RemoteDB) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
Get(opts ...DBOption) (model.RemoteDB, error)
WithByFrom(from string) DBOption
WithoutByFrom(from string) DBOption
}
func NewIRemoteDBRepo() IRemoteDBRepo {
return &RemoteDBRepo{}
}
func (u *RemoteDBRepo) Get(opts ...DBOption) (model.RemoteDB, error) {
var database model.RemoteDB
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&database).Error
return database, err
}
func (u *RemoteDBRepo) Page(page, size int, opts ...DBOption) (int64, []model.RemoteDB, error) {
var users []model.RemoteDB
db := global.DB.Model(&model.RemoteDB{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
return count, users, err
}
func (u *RemoteDBRepo) GetList(opts ...DBOption) ([]model.RemoteDB, error) {
var databases []model.RemoteDB
db := global.DB.Model(&model.RemoteDB{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&databases).Error
return databases, err
}
func (c *RemoteDBRepo) WithByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`from` == ?", from)
}
}
func (c *RemoteDBRepo) WithoutByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`from` != ?", from)
}
}
func (u *RemoteDBRepo) Create(database *model.RemoteDB) error {
return global.DB.Create(database).Error
}
func (u *RemoteDBRepo) Update(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.RemoteDB{}).Where("id = ?", id).Updates(vars).Error
}
func (u *RemoteDBRepo) Delete(opts ...DBOption) error {
db := global.DB
for _, opt := range opts {
db = opt(db)
}
return db.Delete(&model.RemoteDB{}).Error
}

View File

@@ -14,7 +14,6 @@ type IRuntimeRepo interface {
WithImage(image string) DBOption WithImage(image string) DBOption
WithNotId(id uint) DBOption WithNotId(id uint) DBOption
WithStatus(status string) DBOption WithStatus(status string) DBOption
WithDetailId(id uint) DBOption
Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error) Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error)
Create(ctx context.Context, runtime *model.Runtime) error Create(ctx context.Context, runtime *model.Runtime) error
Save(runtime *model.Runtime) error Save(runtime *model.Runtime) error
@@ -44,12 +43,6 @@ func (r *RuntimeRepo) WithImage(image string) DBOption {
} }
} }
func (r *RuntimeRepo) WithDetailId(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("app_detail_id = ?", id)
}
}
func (r *RuntimeRepo) WithNotId(id uint) DBOption { func (r *RuntimeRepo) WithNotId(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)

View File

@@ -1,8 +1,6 @@
package repo package repo
import ( import (
"time"
"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"
"gorm.io/gorm" "gorm.io/gorm"
@@ -16,13 +14,6 @@ type ISettingRepo interface {
Create(key, value string) error Create(key, value string) error
Update(key, value string) error Update(key, value string) error
WithByKey(key string) DBOption WithByKey(key string) DBOption
CreateMonitorBase(model model.MonitorBase) error
BatchCreateMonitorIO(ioList []model.MonitorIO) error
BatchCreateMonitorNet(ioList []model.MonitorNetwork) error
DelMonitorBase(timeForDelete time.Time) error
DelMonitorIO(timeForDelete time.Time) error
DelMonitorNet(timeForDelete time.Time) error
} }
func NewISettingRepo() ISettingRepo { func NewISettingRepo() ISettingRepo {
@@ -66,22 +57,3 @@ func (c *SettingRepo) WithByKey(key string) DBOption {
func (u *SettingRepo) Update(key, value string) error { func (u *SettingRepo) Update(key, value string) error {
return global.DB.Model(&model.Setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error return global.DB.Model(&model.Setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error
} }
func (u *SettingRepo) CreateMonitorBase(model model.MonitorBase) error {
return global.DB.Create(&model).Error
}
func (u *SettingRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) BatchCreateMonitorNet(ioList []model.MonitorNetwork) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) DelMonitorBase(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
}
func (u *SettingRepo) DelMonitorIO(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
}
func (u *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/1Panel-dev/1Panel/backend/i18n"
"math" "math"
"os" "os"
"path" "path"
@@ -12,9 +11,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"gopkg.in/yaml.v3"
"github.com/1Panel-dev/1Panel/backend/utils/env" "github.com/1Panel-dev/1Panel/backend/utils/env"
"github.com/1Panel-dev/1Panel/backend/utils/nginx" "github.com/1Panel-dev/1Panel/backend/utils/nginx"
"github.com/joho/godotenv" "github.com/joho/godotenv"
@@ -46,11 +42,10 @@ type IAppInstallService interface {
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
Operate(req request.AppInstalledOperate) error Operate(req request.AppInstalledOperate) error
Update(req request.AppInstalledUpdate) error Update(req request.AppInstalledUpdate) error
IgnoreUpgrade(req request.AppInstalledIgnoreUpgrade) error
SyncAll(systemInit bool) error SyncAll(systemInit bool) error
GetServices(key string) ([]response.AppService, error) GetServices(key string) ([]response.AppService, error)
GetUpdateVersions(installId uint) ([]dto.AppVersion, error) GetUpdateVersions(installId uint) ([]dto.AppVersion, error)
GetParams(id uint) (*response.AppConfig, error) GetParams(id uint) ([]response.AppParam, error)
ChangeAppPort(req request.PortUpdate) error ChangeAppPort(req request.PortUpdate) error
GetDefaultConfigByKey(key string) (string, error) GetDefaultConfigByKey(key string) (string, error)
DeleteCheck(installId uint) ([]dto.AppResource, error) DeleteCheck(installId uint) ([]dto.AppResource, error)
@@ -61,12 +56,7 @@ func NewIAppInstalledService() IAppInstallService {
} }
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) { func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
var ( var opts []repo.DBOption
opts []repo.DBOption
total int64
installs []model.AppInstall
err error
)
if req.Name != "" { if req.Name != "" {
opts = append(opts, commonRepo.WithLikeName(req.Name)) opts = append(opts, commonRepo.WithLikeName(req.Name))
@@ -92,25 +82,15 @@ func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []respo
opts = append(opts, appInstallRepo.WithAppIdsIn(appIds)) opts = append(opts, appInstallRepo.WithAppIdsIn(appIds))
} }
if req.Update { total, installs, err := appInstallRepo.Page(req.Page, req.PageSize, opts...)
installs, err = appInstallRepo.ListBy(opts...) if err != nil {
if err != nil { return 0, nil, err
return 0, nil, err
}
} else {
total, installs, err = appInstallRepo.Page(req.Page, req.PageSize, opts...)
if err != nil {
return 0, nil, err
}
} }
installDTOs, err := handleInstalled(installs, req.Update) installDTOs, err := handleInstalled(installs, req.Update)
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err
} }
if req.Update {
total = int64(len(installDTOs))
}
return total, installDTOs, nil return total, installDTOs, nil
} }
@@ -203,9 +183,6 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
if err != nil { if err != nil {
return err return err
} }
if !req.ForceDelete && !files.NewFileOp().Stat(install.GetPath()) {
return buserr.New(constant.ErrInstallDirNotFound)
}
dockerComposePath := install.GetComposePath() dockerComposePath := install.GetComposePath()
switch req.Operate { switch req.Operate {
case constant.Rebuild: case constant.Rebuild:
@@ -236,7 +213,7 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
case constant.Sync: case constant.Sync:
return syncById(install.ID) return syncById(install.ID)
case constant.Upgrade: case constant.Upgrade:
return upgradeInstall(install.ID, req.DetailId, req.Backup) return upgradeInstall(install.ID, req.DetailId)
default: default:
return errors.New("operate not support") return errors.New("operate not support")
} }
@@ -248,68 +225,35 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
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)
}
backupDockerCompose := installed.DockerCompose
if req.Advanced {
composeMap := make(map[string]interface{})
if req.EditCompose {
if err = yaml.Unmarshal([]byte(req.DockerCompose), &composeMap); err != nil {
return err
}
} else {
if err = yaml.Unmarshal([]byte(installed.DockerCompose), &composeMap); err != nil {
return err
}
}
if err = addDockerComposeCommonParam(composeMap, installed.ServiceName, req.AppContainerConfig, req.Params); err != nil {
return err
}
composeByte, err := yaml.Marshal(composeMap)
if err != nil {
return err
}
installed.DockerCompose = string(composeByte)
if req.ContainerName == "" {
req.Params[constant.ContainerName] = installed.ContainerName
} else {
req.Params[constant.ContainerName] = req.ContainerName
if installed.ContainerName != req.ContainerName {
exist, _ := appInstallRepo.GetFirst(appInstallRepo.WithContainerName(req.ContainerName), appInstallRepo.WithIDNotIs(installed.ID))
if exist.ID > 0 {
return buserr.New(constant.ErrContainerName)
}
containerExist, err := checkContainerNameIsExist(req.ContainerName, installed.GetPath())
if err != nil {
return err
}
if containerExist {
return buserr.New(constant.ErrContainerName)
}
installed.ContainerName = req.ContainerName
}
} }
} }
@@ -318,7 +262,6 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
if err != nil { if err != nil {
return err return err
} }
backupEnvMaps := oldEnvMaps
handleMap(req.Params, oldEnvMaps) handleMap(req.Params, oldEnvMaps)
paramByte, err := json.Marshal(oldEnvMaps) paramByte, err := json.Marshal(oldEnvMaps)
if err != nil { if err != nil {
@@ -328,74 +271,57 @@ 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
} }
fileOp := files.NewFileOp()
_ = fileOp.WriteFile(installed.GetComposePath(), strings.NewReader(installed.DockerCompose), 0755)
if err := rebuildApp(installed); err != nil {
_ = env.Write(backupEnvMaps, envPath)
_ = fileOp.WriteFile(installed.GetComposePath(), strings.NewReader(backupDockerCompose), 0755)
return err
}
installed.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &installed) _ = appInstallRepo.Save(context.Background(), &installed)
if err := rebuildApp(installed); err != nil {
return err
}
website, _ := websiteRepo.GetFirst(websiteRepo.WithAppInstallId(installed.ID)) website, _ := websiteRepo.GetFirst(websiteRepo.WithAppInstallId(installed.ID))
if changePort && website.ID != 0 && website.Status == constant.Running { if changePort && website.ID != 0 && website.Status == constant.Running {
go func() { nginxInstall, err := getNginxFull(&website)
nginxInstall, err := getNginxFull(&website) if err != nil {
if err != nil { return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error()) }
return config := nginxInstall.SiteConfig.Config
} servers := config.FindServers()
config := nginxInstall.SiteConfig.Config if len(servers) == 0 {
servers := config.FindServers() return buserr.WithErr(constant.ErrUpdateBuWebsite, errors.New("nginx config is not valid"))
if len(servers) == 0 { }
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, errors.New("nginx config is not valid")).Error()) server := servers[0]
return proxy := fmt.Sprintf("http://127.0.0.1:%d", installed.HttpPort)
} server.UpdateRootProxy([]string{proxy})
server := servers[0]
proxy := fmt.Sprintf("http://127.0.0.1:%d", installed.HttpPort)
server.UpdateRootProxy([]string{proxy})
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil { if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error()) return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
return }
} if err := nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName); err != nil {
if err := nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName); err != nil { return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error()) }
return }
} if changePort {
go func() {
_ = OperateFirewallPort(oldPorts, newPorts)
}() }()
} }
return nil return nil
} }
func (a *AppInstallService) IgnoreUpgrade(req request.AppInstalledIgnoreUpgrade) error {
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(req.DetailID))
if err != nil {
return err
}
appDetail.IgnoreUpgrade = req.Operate == "ignore"
return appDetailRepo.Update(context.Background(), appDetail)
}
func (a *AppInstallService) SyncAll(systemInit bool) 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 || i.Status == constant.Upgrading { if i.Status == constant.Installing {
if systemInit { if systemInit {
i.Status = constant.Error i.Status = constant.Error
i.Message = "1Panel restart causes the task to terminate" i.Message = "System restart causes application exception"
_ = appInstallRepo.Save(context.Background(), &i) _ = appInstallRepo.Save(context.Background(), &i)
} }
continue continue
} }
if !systemInit { if err := syncById(i.ID); err != nil {
if err := syncById(i.ID); err != nil { global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
}
} }
} }
return nil return nil
@@ -440,12 +366,6 @@ func (a *AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion,
return versions, err return versions, err
} }
for _, detail := range details { for _, detail := range details {
if detail.IgnoreUpgrade {
continue
}
if common.IsCrossVersion(install.Version, detail.Version) && !app.CrossVersionUpdate {
continue
}
if common.CompareVersion(detail.Version, install.Version) { if common.CompareVersion(detail.Version, install.Version) {
versions = append(versions, dto.AppVersion{ versions = append(versions, dto.AppVersion{
Version: detail.Version, Version: detail.Version,
@@ -481,6 +401,10 @@ 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
} }
@@ -528,16 +452,7 @@ func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
filePath := path.Join(constant.AppResourceDir, appInstall.App.Key, "versions", appInstall.Version, "conf")
fileOp := files.NewFileOp()
filePath := path.Join(constant.AppResourceDir, "remote", appInstall.App.Key, appInstall.Version, "conf")
if !fileOp.Stat(filePath) {
filePath = path.Join(constant.AppResourceDir, appInstall.App.Key, "versions", appInstall.Version, "conf")
}
if !fileOp.Stat(filePath) {
return "", buserr.New(constant.ErrPathNotFound)
}
if key == constant.AppMysql { if key == constant.AppMysql {
filePath = path.Join(filePath, "my.cnf") filePath = path.Join(filePath, "my.cnf")
} }
@@ -554,12 +469,11 @@ func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
return string(contentByte), nil return string(contentByte), nil
} }
func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) { func (a *AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
var ( var (
params []response.AppParam res []response.AppParam
appForm dto.AppForm appForm dto.AppForm
envs = make(map[string]interface{}) envs = make(map[string]interface{})
res response.AppConfig
) )
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(id)) install, err := appInstallRepo.GetFirst(commonRepo.WithByID(id))
if err != nil { if err != nil {
@@ -569,10 +483,10 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = json.Unmarshal([]byte(detail.Params), &appForm); err != nil { if err := json.Unmarshal([]byte(detail.Params), &appForm); err != nil {
return nil, err return nil, err
} }
if err = json.Unmarshal([]byte(install.Env), &envs); err != nil { if err := json.Unmarshal([]byte(install.Env), &envs); err != nil {
return nil, err return nil, err
} }
for _, form := range appForm.FormFields { for _, form := range appForm.FormFields {
@@ -601,29 +515,10 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
} }
appParam.Values = form.Values appParam.Values = form.Values
} }
params = append(params, appParam) res = append(res, appParam)
} else {
params = append(params, response.AppParam{
Edit: form.Edit,
Key: form.EnvKey,
Rule: form.Rule,
Type: form.Type,
LabelZh: form.LabelZh,
LabelEn: form.LabelEn,
Value: form.Default,
Values: form.Values,
})
} }
} }
return res, nil
config := getAppCommonConfig(envs)
config.DockerCompose = install.DockerCompose
res.Params = params
if config.ContainerName == "" {
config.ContainerName = install.ContainerName
}
res.AppContainerConfig = config
return &res, nil
} }
func syncById(installId uint) error { func syncById(installId uint) error {
@@ -634,10 +529,12 @@ func syncById(installId uint) error {
if appInstall.Status == constant.Installing { if appInstall.Status == constant.Installing {
return nil return nil
} }
containerNames, err := getContainerNames(appInstall) containerNames, err := getContainerNames(appInstall)
if err != nil { if err != nil {
return err return err
} }
cli, err := docker.NewClient() cli, err := docker.NewClient()
if err != nil { if err != nil {
return err return err
@@ -663,16 +560,16 @@ func syncById(installId uint) error {
errorContainers = append(errorContainers, n.Names[0]) errorContainers = append(errorContainers, n.Names[0])
} }
} }
for _, name := range containerNames { for _, old := range containerNames {
exist := false exist := false
for _, container := range containers { for _, new := range containers {
if common.ExistWithStrArray(name, container.Names) { if common.ExistWithStrArray(old, new.Names) {
exist = true exist = true
break break
} }
} }
if !exist { if !exist {
notFoundContainers = append(notFoundContainers, name) notFoundContainers = append(notFoundContainers, old)
} }
} }
@@ -685,10 +582,10 @@ func syncById(installId uint) error {
if containerCount == 0 { if containerCount == 0 {
appInstall.Status = constant.Error appInstall.Status = constant.Error
appInstall.Message = i18n.GetMsgWithMap("ErrContainerNotFound", map[string]interface{}{"name": strings.Join(containerNames, ",")}) appInstall.Message = "container is not found"
return appInstallRepo.Save(context.Background(), &appInstall) return appInstallRepo.Save(context.Background(), &appInstall)
} }
if errCount == 0 && existedCount == 0 && notFoundCount == 0 { if errCount == 0 && existedCount == 0 {
appInstall.Status = constant.Running appInstall.Status = constant.Running
return appInstallRepo.Save(context.Background(), &appInstall) return appInstallRepo.Save(context.Background(), &appInstall)
} }
@@ -703,14 +600,22 @@ func syncById(installId uint) error {
appInstall.Status = constant.UnHealthy appInstall.Status = constant.UnHealthy
} }
var errMsg string var errMsg strings.Builder
if errCount > 0 { if errCount > 0 {
errMsg += i18n.GetMsgWithMap("ErrContainerMsg", map[string]interface{}{"name": strings.Join(errorContainers, ",")}) errMsg.Write([]byte(string(rune(errCount)) + " error containers:"))
for _, e := range errorContainers {
errMsg.Write([]byte(e))
}
errMsg.Write([]byte("\n"))
} }
if notFoundCount > 0 { if notFoundCount > 0 {
errMsg += i18n.GetMsgWithMap("ErrContainerNotFound", map[string]interface{}{"name": strings.Join(notFoundContainers, ",")}) errMsg.Write([]byte(string(rune(notFoundCount)) + " not found containers:"))
for _, e := range notFoundContainers {
errMsg.Write([]byte(e))
}
errMsg.Write([]byte("\n"))
} }
appInstall.Message = errMsg appInstall.Message = errMsg.String()
return appInstallRepo.Save(context.Background(), &appInstall) return appInstallRepo.Save(context.Background(), &appInstall)
} }
@@ -731,11 +636,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
envKey := "" envKey := ""
switch param { switch param {
case "password": case "password":
if appKey == "mysql" { envKey = "PANEL_DB_ROOT_PASSWORD="
envKey = "PANEL_DB_ROOT_PASSWORD="
} else {
envKey = "PANEL_REDIS_ROOT_PASSWORD="
}
case "port": case "port":
envKey = "PANEL_APP_PORT_HTTP=" envKey = "PANEL_APP_PORT_HTTP="
case "user-password": case "user-password":
@@ -764,10 +665,6 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
if param == "password" { if param == "password" {
oldVal = fmt.Sprintf("\"PANEL_DB_ROOT_PASSWORD\":\"%v\"", appInstall.Password) oldVal = fmt.Sprintf("\"PANEL_DB_ROOT_PASSWORD\":\"%v\"", appInstall.Password)
newVal = fmt.Sprintf("\"PANEL_DB_ROOT_PASSWORD\":\"%v\"", value) newVal = fmt.Sprintf("\"PANEL_DB_ROOT_PASSWORD\":\"%v\"", value)
if appKey == "redis" {
oldVal = fmt.Sprintf("\"PANEL_REDIS_ROOT_PASSWORD\":\"%v\"", appInstall.Password)
newVal = fmt.Sprintf("\"PANEL_REDIS_ROOT_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),
"env": strings.ReplaceAll(appInstall.Env, oldVal, newVal), "env": strings.ReplaceAll(appInstall.Env, oldVal, newVal),

View File

@@ -2,25 +2,19 @@ package service
import ( import (
"context" "context"
"encoding/base64"
"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"
"net/http"
"os" "os"
"os/exec" "os/exec"
"path" "path"
"reflect" "reflect"
"regexp"
"strconv" "strconv"
"strings" "strings"
"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/i18n"
"github.com/subosito/gotenv"
"gopkg.in/yaml.v3"
"github.com/1Panel-dev/1Panel/backend/app/repo" "github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/utils/env" "github.com/1Panel-dev/1Panel/backend/utils/env"
@@ -35,7 +29,6 @@ import (
"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" 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"
dockerTypes "github.com/docker/docker/api/types"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@@ -49,19 +42,7 @@ var (
func checkPort(key string, params map[string]interface{}) (int, error) { func checkPort(key string, params map[string]interface{}) (int, error) {
port, ok := params[key] port, ok := params[key]
if ok { if ok {
portN := 0 portN := int(math.Ceil(port.(float64)))
var err error
switch p := port.(type) {
case string:
portN, err = strconv.Atoi(p)
if err != nil {
return portN, nil
}
case float64:
portN = int(math.Ceil(p))
case int:
portN = p
}
oldInstalled, _ := appInstallRepo.ListBy(appInstallRepo.WithPort(portN)) oldInstalled, _ := appInstallRepo.ListBy(appInstallRepo.WithPort(portN))
if len(oldInstalled) > 0 { if len(oldInstalled) > 0 {
@@ -83,33 +64,20 @@ func checkPort(key string, params map[string]interface{}) (int, error) {
func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall, params map[string]interface{}) error { func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall, params map[string]interface{}) error {
var dbConfig dto.AppDatabase var dbConfig dto.AppDatabase
if app.Type == "runtime" { if app.Type == "runtime" {
switch app.Key { var authParam dto.AuthParam
case "mysql", "mariadb", "postgresql": paramByte, err := json.Marshal(params)
if password, ok := params["PANEL_DB_ROOT_PASSWORD"]; ok { if err != nil {
if password != "" { return err
authParam := dto.AuthParam{ }
RootPassword: password.(string), if err := json.Unmarshal(paramByte, &authParam); err != nil {
} return err
authByte, err := json.Marshal(authParam) }
if err != nil { if authParam.RootPassword != "" {
return err authByte, err := json.Marshal(authParam)
} if err != nil {
appInstall.Param = string(authByte) return err
}
}
case "redis":
if password, ok := params["PANEL_REDIS_ROOT_PASSWORD"]; ok {
if password != "" {
authParam := dto.RedisAuthParam{
RootPassword: password.(string),
}
authByte, err := json.Marshal(authParam)
if err != nil {
return err
}
appInstall.Param = string(authByte)
}
} }
appInstall.Param = string(authByte)
} }
} }
if app.Type == "website" || app.Type == "tool" { if app.Type == "website" || app.Type == "tool" {
@@ -117,7 +85,7 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
if err != nil { if err != nil {
return err return err
} }
if err = json.Unmarshal(paramByte, &dbConfig); err != nil { if err := json.Unmarshal(paramByte, &dbConfig); err != nil {
return err return err
} }
} }
@@ -130,7 +98,7 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
var resourceId uint var resourceId uint
if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" { if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" {
iMysqlRepo := repo.NewIMysqlRepo() iMysqlRepo := repo.NewIMysqlRepo()
oldMysqlDb, _ := iMysqlRepo.Get(commonRepo.WithByName(dbConfig.DbName), iMysqlRepo.WithByFrom(constant.ResourceLocal)) oldMysqlDb, _ := iMysqlRepo.Get(commonRepo.WithByName(dbConfig.DbName))
resourceId = oldMysqlDb.ID resourceId = oldMysqlDb.ID
if oldMysqlDb.ID > 0 { if oldMysqlDb.ID > 0 {
if oldMysqlDb.Username != dbConfig.DbUser || oldMysqlDb.Password != dbConfig.Password { if oldMysqlDb.Username != dbConfig.DbUser || oldMysqlDb.Password != dbConfig.Password {
@@ -143,7 +111,6 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
createMysql.Format = "utf8mb4" createMysql.Format = "utf8mb4"
createMysql.Permission = "%" createMysql.Permission = "%"
createMysql.Password = dbConfig.Password createMysql.Password = dbConfig.Password
createMysql.From = "local"
mysqldb, err := NewIMysqlService().Create(ctx, createMysql) mysqldb, err := NewIMysqlService().Create(ctx, createMysql)
if err != nil { if err != nil {
return err return err
@@ -200,15 +167,15 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name)) _ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key)) _ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key))
if install.App.Key == constant.AppMysql { if install.App.Key == constant.AppMysql {
_ = mysqlRepo.DeleteLocal(ctx) _ = mysqlRepo.DeleteAll(ctx)
} }
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/app/%s/%s", 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, _ := loadLocalDir() localDir, _ := loadLocalDir()
backupDir := path.Join(localDir, fmt.Sprintf("app/%s/%s", 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)
} }
@@ -242,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 upgradeInstall(installId uint, detailId uint, backup bool) 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
@@ -254,121 +221,40 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
if install.Version == detail.Version { if install.Version == detail.Version {
return errors.New("two version is same") return errors.New("two version is same")
} }
install.Status = constant.Upgrading if err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
return err
}
go func() { detailDir := path.Join(constant.ResourceDir, "apps", install.App.Key, "versions", detail.Version)
if backup { cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rf %s/* %s", detailDir, install.GetPath()))
if err = NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil { stdout, err := cmd.CombinedOutput()
global.LOG.Errorf(i18n.GetMsgWithMap("ErrAppBackup", map[string]interface{}{"name": install.Name, "err": err.Error()})) if err != nil {
}
}
var upErr error
defer func() {
if upErr != nil {
install.Status = constant.UpgradeErr
install.Message = upErr.Error()
_ = appInstallRepo.Save(context.Background(), &install)
}
}()
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version)
if install.App.Resource == constant.AppResourceRemote {
if upErr = downloadApp(install.App, detail, &install); upErr != nil {
return
}
go func() {
_, _ = http.Get(detail.DownloadCallBackUrl)
}()
}
if install.App.Resource == constant.AppResourceLocal {
detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version)
}
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
stdout, _ := cmd.CombinedOutput()
if stdout != nil { if stdout != nil {
global.LOG.Errorf("upgrade app [%s] [%s] cp file log : %s ", install.App.Key, install.Name, string(stdout)) return errors.New(string(stdout))
} }
return err
}
composeMap := make(map[string]interface{}) if out, err := compose.Down(install.GetComposePath()); err != nil {
if upErr = yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); upErr != nil { if out != "" {
return return errors.New(out)
}
value, ok := composeMap["services"]
if !ok {
upErr = buserr.New(constant.ErrFileParse)
return
}
servicesMap := value.(map[string]interface{})
index := 0
oldServiceName := ""
for k := range servicesMap {
oldServiceName = k
index++
if index > 0 {
break
}
}
servicesMap[install.ServiceName] = servicesMap[oldServiceName]
if install.ServiceName != oldServiceName {
delete(servicesMap, oldServiceName)
} }
return err
}
install.DockerCompose = detail.DockerCompose
install.Version = detail.Version
install.AppDetailId = detailId
envs := make(map[string]interface{}) fileOp := files.NewFileOp()
if upErr = json.Unmarshal([]byte(install.Env), &envs); upErr != nil { if err := fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); err != nil {
return return err
}
if out, err := compose.Up(install.GetComposePath()); err != nil {
if out != "" {
return errors.New(out)
} }
config := getAppCommonConfig(envs) return err
if config.ContainerName == "" { }
config.ContainerName = install.ContainerName
envs[constant.ContainerName] = install.ContainerName
}
config.Advanced = true
if upErr = addDockerComposeCommonParam(composeMap, install.ServiceName, config, envs); upErr != nil {
return
}
paramByte, upErr := json.Marshal(envs)
if upErr != nil {
return
}
install.Env = string(paramByte)
composeByte, upErr := yaml.Marshal(composeMap)
if upErr != nil {
return
}
install.DockerCompose = string(composeByte)
install.Version = detail.Version
install.AppDetailId = detailId
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
return
}
fileOp := files.NewFileOp()
envParams := make(map[string]string, len(envs))
handleMap(envs, envParams)
if err = env.Write(envParams, install.GetEnvPath()); err != nil {
return
}
if upErr = fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); upErr != nil {
return
}
if out, err := compose.Up(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
upErr = err
return
}
install.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &install)
}()
return appInstallRepo.Save(context.Background(), &install) return appInstallRepo.Save(context.Background(), &install)
} }
@@ -382,6 +268,7 @@ func getContainerNames(install model.AppInstall) ([]string, error) {
return nil, err return nil, err
} }
containerMap := make(map[string]struct{}) 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
@@ -392,9 +279,6 @@ func getContainerNames(install model.AppInstall) ([]string, error) {
for k := range containerMap { for k := range containerMap {
containerNames = append(containerNames, k) containerNames = append(containerNames, k)
} }
if len(containerNames) == 0 {
containerNames = append(containerNames, install.ContainerName)
}
return containerNames, nil return containerNames, nil
} }
@@ -427,6 +311,34 @@ 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 != "" {
var requiredArray []string
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
return err
}
for _, key := range requiredArray {
if key == "" {
continue
}
requireApp, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return err
}
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(requireApp.ID))
if err != nil {
return err
}
var detailIds []uint
for _, d := range details {
detailIds = append(detailIds, d.ID)
}
_, err = appInstallRepo.GetFirst(appInstallRepo.WithDetailIdsIn(detailIds))
if err != nil {
return buserr.WithDetail(constant.ErrAppRequired, requireApp.Name, nil)
}
}
}
return nil return nil
} }
@@ -443,74 +355,24 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
} }
} }
func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall) (err error) { func copyAppData(key, version, installName string, params map[string]interface{}, isLocal bool) (err error) {
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
appDownloadDir := path.Join(appResourceDir, app.Key)
appVersionDir := path.Join(appDownloadDir, appDetail.Version)
fileOp := files.NewFileOp() fileOp := files.NewFileOp()
if !appDetail.Update && fileOp.Stat(appVersionDir) { appResourceDir := constant.AppResourceDir
return installAppDir := path.Join(constant.AppInstallDir, key)
} appKey := key
if !fileOp.Stat(appDownloadDir) { if isLocal {
_ = fileOp.CreateDir(appDownloadDir, 0755)
}
if !fileOp.Stat(appVersionDir) {
_ = fileOp.CreateDir(appVersionDir, 0755)
}
global.LOG.Infof("download app[%s] from %s", app.Name, appDetail.DownloadUrl)
filePath := path.Join(appVersionDir, appDetail.Version+".tar.gz")
defer func() {
if err != nil {
if appInstall != nil {
appInstall.Status = constant.DownloadErr
appInstall.Message = err.Error()
}
}
}()
if err = fileOp.DownloadFile(appDetail.DownloadUrl, filePath); err != nil {
global.LOG.Errorf("download app[%s] error %v", app.Name, err)
return
}
if err = fileOp.Decompress(filePath, appVersionDir, files.TarGz); err != nil {
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
return
}
_ = fileOp.DeleteFile(filePath)
appDetail.Update = false
_ = appDetailRepo.Update(context.Background(), appDetail)
return
}
func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall, req request.AppInstallCreate) (err error) {
fileOp := files.NewFileOp()
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
if app.Resource == constant.AppResourceRemote {
err = downloadApp(app, appDetail, appInstall)
if err != nil {
return
}
go func() {
_, _ = http.Get(appDetail.DownloadCallBackUrl)
}()
}
appKey := app.Key
installAppDir := path.Join(constant.AppInstallDir, app.Key)
if app.Resource == constant.AppResourceLocal {
appResourceDir = constant.LocalAppResourceDir appResourceDir = constant.LocalAppResourceDir
appKey = strings.TrimPrefix(app.Key, "local") appKey = strings.TrimPrefix(key, "local")
installAppDir = path.Join(constant.LocalAppInstallDir, appKey) installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
} }
resourceDir := path.Join(appResourceDir, appKey, appDetail.Version) 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 {
return return
} }
} }
appDir := path.Join(installAppDir, req.Name) appDir := path.Join(installAppDir, installName)
if fileOp.Stat(appDir) { if fileOp.Stat(appDir) {
if err = fileOp.DeleteDir(appDir); err != nil { if err = fileOp.DeleteDir(appDir); err != nil {
return return
@@ -519,90 +381,62 @@ func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppIns
if err = fileOp.Copy(resourceDir, installAppDir); err != nil { if err = fileOp.Copy(resourceDir, installAppDir); err != nil {
return return
} }
versionDir := path.Join(installAppDir, appDetail.Version) versionDir := path.Join(installAppDir, version)
if err = fileOp.Rename(versionDir, appDir); err != nil { if err = fileOp.Rename(versionDir, appDir); err != nil {
return return
} }
envPath := path.Join(appDir, ".env") envPath := path.Join(appDir, ".env")
envParams := make(map[string]string, len(req.Params)) envParams := make(map[string]string, len(params))
handleMap(req.Params, envParams) handleMap(params, envParams)
if err = env.Write(envParams, envPath); err != nil { if err = env.Write(envParams, envPath); err != nil {
return return
} }
if err := fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(appInstall.DockerCompose), 0755); err != nil {
return err
}
return return
} }
// 处理文件夹权限等问题 // 处理文件夹权限等问题
func upAppPre(app model.App, appInstall *model.AppInstall) error { func upAppPre(app model.App, appInstall *model.AppInstall) error {
dataPath := path.Join(appInstall.GetPath(), "data") if app.Key == "nexus" {
fileOp := files.NewFileOp() dataPath := path.Join(appInstall.GetPath(), "data")
switch app.Key { if err := files.NewFileOp().Chown(dataPath, 200, 0); err != nil {
case "nexus": return err
return fileOp.ChownR(dataPath, "200", "0", true) }
case "sftpgo":
return fileOp.ChownR(dataPath, "1000", "1000", true)
case "pgadmin4":
return fileOp.ChownR(dataPath, "5050", "5050", true)
} }
return nil return nil
} }
func checkContainerNameIsExist(containerName, appDir string) (bool, error) { func getServiceFromInstall(appInstall *model.AppInstall) (service *composeV2.ComposeService, err error) {
client, err := composeV2.NewDockerClient() var (
project *types.Project
envStr string
)
envStr, err = coverEnvJsonToStr(appInstall.Env)
if err != nil { if err != nil {
return false, err return
} }
var options dockerTypes.ContainerListOptions project, err = composeV2.GetComposeProject(appInstall.Name, appInstall.GetPath(), []byte(appInstall.DockerCompose), []byte(envStr), true)
list, err := client.ContainerList(context.Background(), options)
if err != nil { if err != nil {
return false, err return
} }
for _, container := range list { service, err = composeV2.NewComposeService()
if containerName == container.Names[0][1:] { if err != nil {
if workDir, ok := container.Labels[composeWorkdirLabel]; ok { return
if workDir != appDir {
return true, nil
}
} else {
return true, nil
}
}
} }
return false, nil service.SetProject(project)
return
} }
func upApp(appInstall *model.AppInstall) { func upApp(appInstall *model.AppInstall) {
upProject := func(appInstall *model.AppInstall) (err error) { upProject := func(appInstall *model.AppInstall) (err error) {
if err == nil { if err == nil {
var ( var composeService *composeV2.ComposeService
out string composeService, err = getServiceFromInstall(appInstall)
errMsg string if err != nil {
) return err
if appInstall.App.Type != "php" { }
out, err = compose.Pull(appInstall.GetComposePath()) err = composeService.ComposeUp()
if err != nil {
if out != "" {
if strings.Contains(out, "no such host") {
errMsg = i18n.GetMsgByKey("ErrNoSuchHost") + ":"
}
if strings.Contains(out, "timeout") {
errMsg = i18n.GetMsgByKey("ErrImagePullTimeOut") + ":"
}
appInstall.Message = errMsg + out
}
return err
}
}
out, err = compose.Up(appInstall.GetComposePath())
if err != nil { if err != nil {
if out != "" {
appInstall.Message = errMsg + out
}
return err return err
} }
return return
@@ -612,6 +446,7 @@ func upApp(appInstall *model.AppInstall) {
} }
if err := upProject(appInstall); err != nil { if err := upProject(appInstall); err != nil {
appInstall.Status = constant.Error appInstall.Status = constant.Error
appInstall.Message = err.Error()
} else { } else {
appInstall.Status = constant.Running appInstall.Status = constant.Running
} }
@@ -634,21 +469,21 @@ func rebuildApp(appInstall model.AppInstall) error {
return syncById(appInstall.ID) return syncById(appInstall.ID)
} }
func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) map[string]model.AppDetail { func getAppDetails(details []model.AppDetail, versions []string) map[string]model.AppDetail {
appDetails := make(map[string]model.AppDetail, len(details)) appDetails := make(map[string]model.AppDetail, len(details))
for _, old := range details { for _, old := range details {
old.Status = constant.AppTakeDown old.Status = constant.AppTakeDown
appDetails[old.Version] = old appDetails[old.Version] = old
} }
for _, v := range versions { for _, v := range versions {
version := v.Name detail, ok := appDetails[v]
detail, ok := appDetails[version]
if ok { if ok {
detail.Status = constant.AppNormal detail.Status = constant.AppNormal
appDetails[version] = detail appDetails[v] = detail
} else { } else {
appDetails[version] = model.AppDetail{ appDetails[v] = model.AppDetail{
Version: version, Version: v,
Status: constant.AppNormal, Status: constant.AppNormal,
} }
} }
@@ -656,110 +491,43 @@ func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) m
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 {
config := item.AppProperty key := item.Key
key := config.Key if isLocal {
key = "local" + key
}
app, ok := apps[key] app, ok := apps[key]
if !ok { if !ok {
app = model.App{} app = model.App{}
} }
app.Resource = constant.AppResourceRemote if isLocal {
app.Resource = constant.AppResourceLocal
} else {
app.Resource = constant.AppResourceRemote
}
app.Name = item.Name app.Name = item.Name
app.Limit = config.Limit app.Limit = item.Limit
app.Key = key app.Key = key
app.ShortDescZh = config.ShortDescZh app.ShortDescZh = item.ShortDescZh
app.ShortDescEn = config.ShortDescEn app.ShortDescEn = item.ShortDescEn
app.Website = config.Website app.Website = item.Website
app.Document = config.Document app.Document = item.Document
app.Github = config.Github app.Github = item.Github
app.Type = config.Type app.Type = item.Type
app.CrossVersionUpdate = config.CrossVersionUpdate app.CrossVersionUpdate = item.CrossVersionUpdate
app.Required = item.GetRequired()
app.Status = constant.AppNormal app.Status = constant.AppNormal
app.LastModified = item.LastModified
app.ReadMe = item.ReadMe
apps[key] = app apps[key] = app
} }
return apps return apps
} }
func handleLocalAppDetail(versionDir string, appDetail *model.AppDetail) error {
fileOp := files.NewFileOp()
dockerComposePath := path.Join(versionDir, "docker-compose.yml")
if !fileOp.Stat(dockerComposePath) {
return errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "docker-compose.yml"}))
}
dockerComposeByte, _ := fileOp.GetContent(dockerComposePath)
if dockerComposeByte == nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "docker-compose.yml"}))
}
appDetail.DockerCompose = string(dockerComposeByte)
paramPath := path.Join(versionDir, "data.yml")
if !fileOp.Stat(paramPath) {
return errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "data.yml"}))
}
paramByte, _ := fileOp.GetContent(paramPath)
if paramByte == nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml"}))
}
appParamConfig := dto.LocalAppParam{}
if err := yaml.Unmarshal(paramByte, &appParamConfig); err != nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml"}))
}
dataJson, err := json.Marshal(appParamConfig.AppParams)
if err != nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
}
appDetail.Params = string(dataJson)
return nil
}
func handleLocalApp(appDir string) (app *model.App, err error) {
fileOp := files.NewFileOp()
configYamlPath := path.Join(appDir, "data.yml")
if !fileOp.Stat(configYamlPath) {
err = errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "data.yml"}))
return
}
iconPath := path.Join(appDir, "logo.png")
if !fileOp.Stat(iconPath) {
err = errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "logo.png"}))
return
}
configYamlByte, err := fileOp.GetContent(configYamlPath)
if err != nil {
err = errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
return
}
localAppDefine := dto.LocalAppAppDefine{}
if err = yaml.Unmarshal(configYamlByte, &localAppDefine); err != nil {
err = errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
return
}
app = &localAppDefine.AppProperty
app.Resource = constant.AppResourceLocal
app.Status = constant.AppNormal
app.Recommend = 9999
app.TagsKey = append(app.TagsKey, "Local")
app.Key = "local" + app.Key
readMePath := path.Join(appDir, "README.md")
readMeByte, err := fileOp.GetContent(readMePath)
if err == nil {
app.ReadMe = string(readMeByte)
}
iconByte, _ := fileOp.GetContent(iconPath)
if iconByte != nil {
iconStr := base64.StdEncoding.EncodeToString(iconByte)
app.Icon = iconStr
}
return
}
func handleErr(install model.AppInstall, err error, out string) error { func handleErr(install model.AppInstall, err error, out string) error {
reErr := err reErr := err
install.Message = err.Error() install.Message = err.Error()
@@ -772,15 +540,34 @@ func handleErr(install model.AppInstall, err error, out string) error {
return reErr return reErr
} }
func getAppFromRepo(downloadPath, version string) error {
downloadUrl := downloadPath
appDir := constant.AppResourceDir
global.LOG.Infof("download file from %s", downloadUrl)
fileOp := files.NewFileOp()
if _, err := fileOp.CopyAndBackup(appDir); err != nil {
return err
}
packagePath := path.Join(constant.ResourceDir, path.Base(downloadUrl))
if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
return err
}
if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.TarGz); err != nil {
return err
}
_ = NewISettingService().Update("AppStoreVersion", version)
defer func() {
_ = fileOp.DeleteFile(packagePath)
}()
return nil
}
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) { func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
var res []response.AppInstalledDTO var res []response.AppInstalledDTO
for _, installed := range appInstallList { for _, installed := range appInstallList {
if updated && (installed.App.Type == "php" || installed.Status == constant.Installing || (installed.App.Key == constant.AppMysql && installed.Version == "5.6.51")) {
continue
}
installDTO := response.AppInstalledDTO{ installDTO := response.AppInstalledDTO{
AppInstall: installed, AppInstall: installed,
Path: installed.GetPath(),
} }
app, err := appRepo.GetFirst(commonRepo.WithByID(installed.AppId)) app, err := appRepo.GetFirst(commonRepo.WithByID(installed.AppId))
if err != nil { if err != nil {
@@ -792,18 +579,9 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]respons
} }
var versions []string var versions []string
for _, detail := range details { for _, detail := range details {
if detail.IgnoreUpgrade {
continue
}
if common.IsCrossVersion(installed.Version, detail.Version) && !app.CrossVersionUpdate {
continue
}
versions = append(versions, detail.Version) versions = append(versions, detail.Version)
} }
versions = common.GetSortedVersions(versions) versions = common.GetSortedVersions(versions)
if len(versions) == 0 {
continue
}
lastVersion := versions[0] lastVersion := versions[0]
if common.IsCrossVersion(installed.Version, lastVersion) { if common.IsCrossVersion(installed.Version, lastVersion) {
installDTO.CanUpdate = app.CrossVersionUpdate installDTO.CanUpdate = app.CrossVersionUpdate
@@ -882,108 +660,3 @@ func updateToolApp(installed *model.AppInstall) {
return return
} }
} }
func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName string, req request.AppContainerConfig, params map[string]interface{}) error {
services, serviceValid := composeMap["services"].(map[string]interface{})
if !serviceValid {
return buserr.New(constant.ErrFileParse)
}
service, serviceExist := services[serviceName]
if !serviceExist {
return buserr.New(constant.ErrFileParse)
}
serviceValue := service.(map[string]interface{})
deploy := map[string]interface{}{
"resources": map[string]interface{}{
"limits": map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
},
},
}
serviceValue["deploy"] = deploy
ports, ok := serviceValue["ports"].([]interface{})
if ok {
for i, port := range ports {
portStr, portOK := port.(string)
if !portOK {
continue
}
portArray := strings.Split(portStr, ":")
if len(portArray) == 2 {
portArray = append([]string{"${HOST_IP}"}, portArray...)
}
ports[i] = strings.Join(portArray, ":")
}
serviceValue["ports"] = ports
}
params[constant.CPUS] = "0"
params[constant.MemoryLimit] = "0"
if req.Advanced {
if req.CpuQuota > 0 {
params[constant.CPUS] = req.CpuQuota
}
if req.MemoryLimit > 0 {
params[constant.MemoryLimit] = strconv.FormatFloat(req.MemoryLimit, 'f', -1, 32) + req.MemoryUnit
}
}
_, portExist := serviceValue["ports"].([]interface{})
if portExist {
allowHost := "127.0.0.1"
if req.Advanced && req.AllowPort {
allowHost = "0.0.0.0"
}
params[constant.HostIP] = allowHost
}
services[serviceName] = serviceValue
return nil
}
func getAppCommonConfig(envs map[string]interface{}) request.AppContainerConfig {
config := request.AppContainerConfig{}
if hostIp, ok := envs[constant.HostIP]; ok {
config.AllowPort = hostIp.(string) == "0.0.0.0"
} else {
config.AllowPort = true
}
if cpuCore, ok := envs[constant.CPUS]; ok {
numStr, ok := cpuCore.(string)
if ok {
num, err := strconv.ParseFloat(numStr, 64)
if err == nil {
config.CpuQuota = num
}
} else {
num64, flOk := cpuCore.(float64)
if flOk {
config.CpuQuota = num64
}
}
} else {
config.CpuQuota = 0
}
if memLimit, ok := envs[constant.MemoryLimit]; ok {
re := regexp.MustCompile(`(\d+)([A-Za-z]+)`)
matches := re.FindStringSubmatch(memLimit.(string))
if len(matches) == 3 {
num, err := strconv.ParseFloat(matches[1], 64)
if err == nil {
unit := matches[2]
config.MemoryLimit = num
config.MemoryUnit = unit
}
}
} else {
config.MemoryLimit = 0
config.MemoryUnit = "M"
}
if containerName, ok := envs[constant.ContainerName]; ok {
config.ContainerName = containerName.(string)
}
return config
}

View File

@@ -1,7 +1,9 @@
package service package service
import ( import (
"fmt"
"strconv" "strconv"
"time"
"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"
@@ -17,8 +19,11 @@ import (
type AuthService struct{} type AuthService struct{}
type IAuthService interface { type IAuthService interface {
CheckIsSafety(code string) (string, error) SafetyStatus(c *gin.Context) error
CheckIsFirst() bool
InitUser(c *gin.Context, req dto.InitUser) error
VerifyCode(code string) (bool, error) VerifyCode(code string) (bool, 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) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error)
@@ -28,16 +33,32 @@ func NewIAuthService() IAuthService {
return &AuthService{} return &AuthService{}
} }
func (u *AuthService) SafeEntrance(c *gin.Context, code string) error {
codeWithMD5 := encrypt.Md5(code)
cookieValue, _ := encrypt.StringEncrypt(codeWithMD5)
c.SetCookie(codeWithMD5, cookieValue, 604800, "", "", false, false)
expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
if err != nil {
return err
}
timeout, _ := strconv.Atoi(expiredSetting.Value)
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
return err
}
return nil
}
func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) { func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) {
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName")) nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
if err != nil { if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error()) return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
} }
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password")) passwrodSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil { if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error()) return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
} }
pass, err := encrypt.StringDecrypt(passwordSetting.Value) pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil { if err != nil {
return nil, constant.ErrAuth return nil, constant.ErrAuth
} }
@@ -48,12 +69,10 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = settingRepo.Update("Language", info.Language); err != nil {
return nil, err
}
if mfa.Value == "enable" { if mfa.Value == "enable" {
return &dto.UserLoginInfo{Name: nameSetting.Value, MfaStatus: mfa.Value}, nil return &dto.UserLoginInfo{Name: nameSetting.Value, MfaStatus: mfa.Value}, nil
} }
return u.generateSession(c, info.Name, info.AuthMethod) return u.generateSession(c, info.Name, info.AuthMethod)
} }
@@ -62,11 +81,11 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
if err != nil { if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error()) return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
} }
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password")) passwrodSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil { if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error()) return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
} }
pass, err := encrypt.StringDecrypt(passwordSetting.Value) pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -78,11 +97,7 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
if err != nil { if err != nil {
return nil, err return nil, err
} }
mfaInterval, err := settingRepo.Get(settingRepo.WithByKey("MFAInterval")) success := mfa.ValidCode(info.Code, mfaSecret.Value)
if err != nil {
return nil, err
}
success := mfa.ValidCode(info.Code, mfaInterval.Value, mfaSecret.Value)
if !success { if !success {
return nil, constant.ErrAuth return nil, constant.ErrAuth
} }
@@ -115,7 +130,7 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
sessionUser, err := global.SESSION.Get(sID) sessionUser, err := global.SESSION.Get(sID)
if err != nil { if err != nil {
sID = uuid.New().String() sID = uuid.New().String()
c.SetCookie(constant.SessionName, sID, 0, "", "", false, false) c.SetCookie(constant.SessionName, sID, 604800, "", "", false, false)
err := global.SESSION.Set(sID, sessionUser, lifeTime) err := global.SESSION.Set(sID, sessionUser, lifeTime)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -149,16 +164,57 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
return setting.Value == code, nil return setting.Value == code, nil
} }
func (u *AuthService) CheckIsSafety(code string) (string, error) { func (u *AuthService) SafetyStatus(c *gin.Context) error {
status, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance")) setting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil { if err != nil {
return "", err return err
} }
if len(status.Value) == 0 { codeWithEcrypt, err := c.Cookie(encrypt.Md5(setting.Value))
return "disable", nil if err != nil {
return err
} }
if status.Value == code { code, err := encrypt.StringDecrypt(codeWithEcrypt)
return "pass", nil if err != nil {
return err
} }
return "unpass", nil if code != encrypt.Md5(setting.Value) {
return errors.New("code not match")
}
return nil
}
func (u *AuthService) CheckIsFirst() bool {
user, _ := settingRepo.Get(settingRepo.WithByKey("UserName"))
pass, _ := settingRepo.Get(settingRepo.WithByKey("Password"))
return len(user.Value) == 0 || len(pass.Value) == 0
}
func (u *AuthService) InitUser(c *gin.Context, req dto.InitUser) error {
user, _ := settingRepo.Get(settingRepo.WithByKey("UserName"))
pass, _ := settingRepo.Get(settingRepo.WithByKey("Password"))
if len(user.Value) == 0 || len(pass.Value) == 0 {
newPass, err := encrypt.StringEncrypt(req.Password)
if err != nil {
return err
}
if err := settingRepo.Update("UserName", req.Name); err != nil {
return err
}
if err := settingRepo.Update("Password", newPass); err != nil {
return err
}
expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
if err != nil {
return err
}
timeout, _ := strconv.Atoi(expiredSetting.Value)
if timeout != 0 {
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
return err
}
}
return nil
}
return fmt.Errorf("can't init user because user %s is in system", user.Value)
} }

View File

@@ -2,14 +2,9 @@ package service
import ( import (
"context" "context"
"encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"net/http"
"net/url"
"os" "os"
"path"
"strings" "strings"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -18,7 +13,7 @@ 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/cloud_storage" "github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files" "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@@ -28,7 +23,6 @@ type BackupService struct{}
type IBackupService interface { type IBackupService interface {
List() ([]dto.BackupInfo, error) List() ([]dto.BackupInfo, error)
SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error) SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error)
LoadOneDriveInfo() (string, error)
DownloadRecord(info dto.DownloadRecord) (string, error) DownloadRecord(info dto.DownloadRecord) (string, error)
Create(backupDto dto.BackupOperate) error Create(backupDto dto.BackupOperate) error
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
@@ -37,7 +31,7 @@ type IBackupService interface {
BatchDeleteRecord(ids []uint) error BatchDeleteRecord(ids []uint) error
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
ListFiles(req dto.BackupSearchFile) ([]string, error) ListFiles(req dto.BackupSearchFile) ([]interface{}, error)
MysqlBackup(db dto.CommonBackup) error MysqlBackup(db dto.CommonBackup) error
MysqlRecover(db dto.CommonRecover) error MysqlRecover(db dto.CommonRecover) error
@@ -67,7 +61,6 @@ func (u *BackupService) List() ([]dto.BackupInfo, error) {
dtobas = append(dtobas, u.loadByType("MINIO", ops)) dtobas = append(dtobas, u.loadByType("MINIO", ops))
dtobas = append(dtobas, u.loadByType("COS", ops)) dtobas = append(dtobas, u.loadByType("COS", ops))
dtobas = append(dtobas, u.loadByType("KODO", ops)) dtobas = append(dtobas, u.loadByType("KODO", ops))
dtobas = append(dtobas, u.loadByType("OneDrive", ops))
return dtobas, err return dtobas, err
} }
@@ -90,18 +83,6 @@ func (u *BackupService) SearchRecordsWithPage(search dto.RecordSearch) (int64, [
return total, dtobas, err return total, dtobas, err
} }
func (u *BackupService) LoadOneDriveInfo() (string, error) {
OneDriveID, err := settingRepo.Get(settingRepo.WithByKey("OneDriveID"))
if err != nil {
return "", err
}
idItem, err := base64.StdEncoding.DecodeString(OneDriveID.Value)
if err != nil {
return "", err
}
return string(idItem), err
}
func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error) { func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error) {
if info.Source == "LOCAL" { if info.Source == "LOCAL" {
return info.FileDir + "/" + info.FileName, nil return info.FileDir + "/" + info.FileName, nil
@@ -114,6 +95,7 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil { if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
return "", err return "", err
} }
varMap["type"] = backup.Type
varMap["bucket"] = backup.Bucket varMap["bucket"] = backup.Bucket
switch backup.Type { switch backup.Type {
case constant.Sftp: case constant.Sftp:
@@ -122,27 +104,20 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo: 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
case constant.OneDrive:
varMap["accessToken"] = backup.Credential
} }
backClient, err := cloud_storage.NewCloudStorageClient(backup.Type, varMap) backClient, err := cloud_storage.NewCloudStorageClient(varMap)
if err != nil { if err != nil {
return "", fmt.Errorf("new cloud storage client failed, err: %v", err) return "", fmt.Errorf("new cloud storage client failed, err: %v", err)
} }
targetPath := fmt.Sprintf("%s/download/%s/%s", constant.DataDir, info.FileDir, info.FileName) tempPath := fmt.Sprintf("%sdownload%s", constant.DataDir, info.FileDir)
if _, err := os.Stat(path.Dir(targetPath)); err != nil && os.IsNotExist(err) { if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(targetPath), os.ModePerm); err != nil { if err = os.MkdirAll(tempPath, os.ModePerm); err != nil {
global.LOG.Errorf("mkdir %s failed, err: %v", path.Dir(targetPath), err) global.LOG.Errorf("mkdir %s failed, err: %v", tempPath, err)
} }
} }
srcPath := fmt.Sprintf("%s/%s", info.FileDir, info.FileName) targetPath := tempPath + info.FileName
if len(backup.BackupPath) != 0 { if _, err = os.Stat(targetPath); err != nil && os.IsNotExist(err) {
itemPath := strings.TrimPrefix(backup.BackupPath, "/") isOK, err := backClient.Download(info.FileName, targetPath)
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
srcPath = itemPath + srcPath
}
if exist, _ := backClient.Exist(srcPath); exist {
isOK, err := backClient.Download(srcPath, targetPath)
if !isOK { if !isOK {
return "", fmt.Errorf("cloud storage download failed, err: %v", err) return "", fmt.Errorf("cloud storage download failed, err: %v", err)
} }
@@ -158,12 +133,6 @@ func (u *BackupService) Create(backupDto dto.BackupOperate) error {
if err := copier.Copy(&backup, &backupDto); err != nil { if err := copier.Copy(&backup, &backupDto); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error()) return errors.WithMessage(constant.ErrStructTransform, err.Error())
} }
if backupDto.Type == constant.OneDrive {
if err := u.loadAccessToken(&backup); err != nil {
return err
}
}
if err := backupRepo.Create(&backup); err != nil { if err := backupRepo.Create(&backup); err != nil {
return err return err
} }
@@ -175,6 +144,7 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
if err := json.Unmarshal([]byte(backupDto.Vars), &varMap); err != nil { if err := json.Unmarshal([]byte(backupDto.Vars), &varMap); err != nil {
return nil, err return nil, err
} }
varMap["type"] = backupDto.Type
switch backupDto.Type { switch backupDto.Type {
case constant.Sftp: case constant.Sftp:
varMap["username"] = backupDto.AccessKey varMap["username"] = backupDto.AccessKey
@@ -183,7 +153,7 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
varMap["accessKey"] = backupDto.AccessKey varMap["accessKey"] = backupDto.AccessKey
varMap["secretKey"] = backupDto.Credential varMap["secretKey"] = backupDto.Credential
} }
client, err := cloud_storage.NewCloudStorageClient(backupDto.Type, varMap) client, err := cloud_storage.NewCloudStorageClient(varMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -209,7 +179,7 @@ func (u *BackupService) BatchDeleteRecord(ids []uint) error {
global.LOG.Errorf("remove file %s failed, err: %v", record.FileDir+record.FileName, err) global.LOG.Errorf("remove file %s failed, err: %v", record.FileDir+record.FileName, err)
} }
} else { } else {
backupAccount, err := backupRepo.Get(commonRepo.WithByType(record.Source)) backupAccount, err := backupRepo.Get(commonRepo.WithByName(record.Source))
if err != nil { if err != nil {
return err return err
} }
@@ -243,17 +213,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
upMap := make(map[string]interface{}) upMap := make(map[string]interface{})
upMap["bucket"] = req.Bucket upMap["bucket"] = req.Bucket
upMap["credential"] = req.Credential upMap["credential"] = req.Credential
upMap["backup_path"] = req.BackupPath
upMap["vars"] = req.Vars upMap["vars"] = req.Vars
backup.Vars = req.Vars
if req.Type == constant.OneDrive {
if err := u.loadAccessToken(&backup); err != nil {
return err
}
upMap["credential"] = backup.Credential
upMap["vars"] = backup.Vars
}
if err := backupRepo.Update(req.ID, upMap); err != nil { if err := backupRepo.Update(req.ID, upMap); err != nil {
return err return err
} }
@@ -263,7 +223,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
if strings.HasSuffix(dirStr, "/") { if strings.HasSuffix(dirStr, "/") {
dirStr = dirStr[:strings.LastIndex(dirStr, "/")] dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
} }
if err := copyDir(oldDir, dirStr); err != nil { if err := updateBackupDir(dirStr, oldDir); err != nil {
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars})) _ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
return err return err
} }
@@ -273,7 +233,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
return nil return nil
} }
func (u *BackupService) ListFiles(req dto.BackupSearchFile) ([]string, error) { func (u *BackupService) ListFiles(req dto.BackupSearchFile) ([]interface{}, error) {
backup, err := backupRepo.Get(backupRepo.WithByType(req.Type)) backup, err := backupRepo.Get(backupRepo.WithByType(req.Type))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -282,21 +242,7 @@ func (u *BackupService) ListFiles(req dto.BackupSearchFile) ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
prefix := "system_snapshot" return client.ListObjects("system_snapshot/")
if len(backup.BackupPath) != 0 {
prefix = path.Join(strings.TrimPrefix(backup.BackupPath, "/"), prefix)
}
files, err := client.ListObjects(prefix)
if err != nil {
return nil, err
}
var datas []string
for _, file := range files {
if len(file) != 0 {
datas = append(datas, path.Base(file))
}
}
return datas, nil
} }
func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) { func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) {
@@ -304,6 +250,7 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil { if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
return nil, err return nil, err
} }
varMap["type"] = backup.Type
if backup.Type == "LOCAL" { if backup.Type == "LOCAL" {
return nil, errors.New("not support") return nil, errors.New("not support")
} }
@@ -315,11 +262,9 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo: 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
case constant.OneDrive:
varMap["accessToken"] = backup.Credential
} }
backClient, err := cloud_storage.NewCloudStorageClient(backup.Type, varMap) backClient, err := cloud_storage.NewCloudStorageClient(varMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -340,53 +285,6 @@ func (u *BackupService) loadByType(accountType string, accounts []model.BackupAc
return dto.BackupInfo{Type: accountType} return dto.BackupInfo{Type: accountType}
} }
func (u *BackupService) loadAccessToken(backup *model.BackupAccount) error {
varMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
return fmt.Errorf("unmarshal backup vars failed, err: %v", err)
}
data := url.Values{}
data.Set("client_id", global.CONF.System.OneDriveID)
data.Set("client_secret", global.CONF.System.OneDriveSc)
data.Set("grant_type", "authorization_code")
data.Set("code", varMap["code"].(string))
data.Set("redirect_uri", constant.OneDriveRedirectURI)
client := &http.Client{}
req, err := http.NewRequest("POST", "https://login.microsoftonline.com/common/oauth2/v2.0/token", strings.NewReader(data.Encode()))
if err != nil {
return fmt.Errorf("new http post client for access token failed, err: %v", err)
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("request for access token failed, err: %v", err)
}
delete(varMap, "code")
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read data from response body failed, err: %v", err)
}
defer resp.Body.Close()
token := map[string]interface{}{}
if err := json.Unmarshal(respBody, &token); err != nil {
return fmt.Errorf("unmarshal data from response body failed, err: %v", err)
}
accessToken, ok := token["refresh_token"].(string)
if !ok {
return errors.New("no such access token in response")
}
itemVars, err := json.Marshal(varMap)
if err != nil {
return fmt.Errorf("json marshal var map failed, err: %v", err)
}
backup.Credential = accessToken
backup.Vars = string(itemVars)
return nil
}
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 {
@@ -411,33 +309,18 @@ func loadLocalDir() (string, error) {
return "", fmt.Errorf("error type dir: %T", varMap["dir"]) return "", fmt.Errorf("error type dir: %T", varMap["dir"])
} }
func copyDir(src, dst string) error { func updateBackupDir(dir, oldDir string) error {
srcInfo, err := os.Stat(src) if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err != nil { if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return err return err
}
if err = os.MkdirAll(dst, srcInfo.Mode()); err != nil {
return err
}
files, err := os.ReadDir(src)
if err != nil {
return err
}
fileOP := fileUtils.NewFileOp()
for _, file := range files {
srcPath := fmt.Sprintf("%s/%s", src, file.Name())
dstPath := fmt.Sprintf("%s/%s", dst, file.Name())
if file.IsDir() {
if err = copyDir(srcPath, dstPath); err != nil {
global.LOG.Errorf("copy dir %s to %s failed, err: %v", srcPath, dstPath, err)
}
} else {
if err := fileOP.CopyFile(srcPath, dst); err != nil {
global.LOG.Errorf("copy file %s to %s failed, err: %v", srcPath, dstPath, err)
}
} }
} }
if strings.HasSuffix(oldDir, "/") {
oldDir = oldDir[:strings.LastIndex(oldDir, "/")]
}
stdout, err := cmd.Execf("cp -r %s/* %s", oldDir, dir)
if err != nil {
return errors.New(string(stdout))
}
return nil return nil
} }

View File

@@ -34,7 +34,7 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) error {
} }
timeNow := time.Now().Format("20060102150405") timeNow := time.Now().Format("20060102150405")
backupDir := path.Join(localDir, fmt.Sprintf("app/%s/%s", 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)
if err := handleAppBackup(&install, backupDir, fileName); err != nil { if err := handleAppBackup(&install, backupDir, fileName); err != nil {
@@ -99,21 +99,23 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
return err return err
} }
appPath := install.GetPath() 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
} }
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID)) resource, _ := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(install.ID))
for _, resource := range resources { if resource.ID != 0 && resource.ResourceId != 0 {
if resource.Key == "mysql" { mysqlInfo, err := appInstallRepo.LoadBaseInfo(constant.AppMysql, "")
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId)) if err != nil {
if err != nil { return err
return err }
} db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
if err := handleMysqlBackup(db.MysqlName, db.Name, tmpDir, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil { if err != nil {
return err return err
} }
if err := handleMysqlBackup(mysqlInfo, tmpDir, db.Name, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil {
return err
} }
} }
@@ -146,12 +148,12 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
if err := json.Unmarshal(appjson, &oldInstall); err != nil { if err := json.Unmarshal(appjson, &oldInstall); err != nil {
return fmt.Errorf("unmarshal app.json failed, err: %v", err) return fmt.Errorf("unmarshal app.json failed, err: %v", err)
} }
if oldInstall.App.Key != install.App.Key || oldInstall.Name != install.Name { if oldInstall.App.Key != install.App.Key || oldInstall.Name != install.Name || oldInstall.Version != install.Version || oldInstall.ID != install.ID {
return errors.New("the current backup file does not match the application") return errors.New("the current backup file does not match the application")
} }
if !isRollback { if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format("20060102150405"))) rollbackFile := fmt.Sprintf("%s/original/app/%s_%s.tar.gz", global.CONF.System.BaseDir, install.Name, time.Now().Format("20060102150405"))
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil { if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
return fmt.Errorf("backup app %s for rollback before recover failed, err: %v", install.Name, err) return fmt.Errorf("backup app %s for rollback before recover failed, err: %v", install.Name, err)
} }
@@ -170,104 +172,32 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
}() }()
} }
newEnvFile := "" resource, _ := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(install.ID))
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID)) if resource.ID != 0 && install.App.Key != "mysql" {
for _, resource := range resources { mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, "")
if resource.Key == "mysql" {
mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, "")
if err != nil {
return err
}
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
if err != nil {
return err
}
newDB, envMap, err := reCreateDB(db.ID, oldInstall.Env)
if err != nil {
return err
}
oldHost := fmt.Sprintf("\"PANEL_DB_HOST\":\"%v\"", envMap["PANEL_DB_HOST"].(string))
newHost := fmt.Sprintf("\"PANEL_DB_HOST\":\"%v\"", mysqlInfo.ServiceName)
oldInstall.Env = strings.ReplaceAll(oldInstall.Env, oldHost, newHost)
envMap["PANEL_DB_HOST"] = mysqlInfo.ServiceName
newEnvFile, err = coverEnvJsonToStr(oldInstall.Env)
if err != nil {
return err
}
_ = appInstallResourceRepo.BatchUpdateBy(map[string]interface{}{"resource_id": newDB.ID}, commonRepo.WithByID(resource.ID))
if err := handleMysqlRecover(dto.CommonRecover{
Name: newDB.MysqlName,
DetailName: newDB.Name,
File: fmt.Sprintf("%s/%s.sql.gz", tmpPath, install.Name),
}, true); err != nil {
global.LOG.Errorf("handle recover from sql.gz failed, err: %v", err)
return err
}
}
}
appDir := install.GetPath()
backPath := fmt.Sprintf("%s_bak", appDir)
_ = fileOp.Rename(appDir, backPath)
_ = fileOp.CreateDir(appDir, 0755)
if err := handleUnTar(tmpPath+"/app.tar.gz", fmt.Sprintf("%s/%s", constant.AppInstallDir, install.App.Key)); err != nil {
global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
_ = fileOp.DeleteDir(appDir)
_ = fileOp.Rename(backPath, appDir)
return err
}
_ = fileOp.DeleteDir(backPath)
if len(newEnvFile) != 0 {
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, install.App.Key, install.Name)
file, err := os.OpenFile(envPath, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil { if err != nil {
return err return err
} }
defer file.Close() db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
_, _ = file.WriteString(newEnvFile) if err != nil {
return err
}
if err := handleMysqlRecover(mysqlInfo, tmpPath, db.Name, fmt.Sprintf("%s.sql.gz", install.Name), true); err != nil {
global.LOG.Errorf("handle recover from sql.gz failed, err: %v", err)
return err
}
} }
oldInstall.ID = install.ID if err := handleUnTar(tmpPath+"/app.tar.gz", fmt.Sprintf("%s/%s", constant.AppInstallDir, install.App.Key)); err != nil {
oldInstall.Status = constant.StatusRunning global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
oldInstall.AppId = install.AppId return err
oldInstall.AppDetailId = install.AppDetailId }
oldInstall.App.ID = install.AppId
if err := appInstallRepo.Save(context.Background(), &oldInstall); err != nil { oldInstall.Status = constant.Running
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
} }
isOk = true isOk = true
return nil return nil
} }
func reCreateDB(dbID uint, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
mysqlService := NewIMysqlService()
ctx := context.Background()
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, DeleteBackup: true, ForceDelete: true})
envMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(oldEnv), &envMap); err != nil {
return nil, envMap, err
}
oldName, _ := envMap["PANEL_DB_NAME"].(string)
oldUser, _ := envMap["PANEL_DB_USER"].(string)
oldPassword, _ := envMap["PANEL_DB_USER_PASSWORD"].(string)
createDB, err := mysqlService.Create(context.Background(), dto.MysqlDBCreate{
Name: oldName,
From: "local",
Format: "utf8mb4",
Username: oldUser,
Password: oldPassword,
Permission: "%",
})
if err != nil {
return nil, envMap, err
}
return createDB, envMap, nil
}

View File

@@ -1,8 +1,10 @@
package service package service
import ( import (
"compress/gzip"
"fmt" "fmt"
"os" "os"
"os/exec"
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -10,9 +12,9 @@ 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/app/repo"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/files" "github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@@ -21,22 +23,24 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
if err != nil { if err != nil {
return err return err
} }
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
timeNow := time.Now().Format("20060102150405") if err != nil {
targetDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", req.Name, req.DetailName))
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow)
if err := handleMysqlBackup(req.Name, req.DetailName, targetDir, fileName); err != nil {
return err return err
} }
timeNow := time.Now().Format("20060102150405")
backupDir := fmt.Sprintf("%s/database/mysql/%s/%s", localDir, req.Name, req.DetailName)
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow)
if err := handleMysqlBackup(app, backupDir, req.DetailName, fileName); err != nil {
return err
}
record := &model.BackupRecord{ record := &model.BackupRecord{
Type: "mysql", Type: "mysql",
Name: req.Name, Name: app.Name,
DetailName: req.DetailName, DetailName: req.DetailName,
Source: "LOCAL", Source: "LOCAL",
BackupType: "LOCAL", BackupType: "LOCAL",
FileDir: targetDir, FileDir: backupDir,
FileName: fileName, FileName: fileName,
} }
if err := backupRepo.CreateRecord(record); err != nil { if err := backupRepo.CreateRecord(record); err != nil {
@@ -46,13 +50,26 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
} }
func (u *BackupService) MysqlRecover(req dto.CommonRecover) error { func (u *BackupService) MysqlRecover(req dto.CommonRecover) error {
if err := handleMysqlRecover(req, false); err != nil { app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
fileOp := files.NewFileOp()
if !fileOp.Stat(req.File) {
return errors.New(fmt.Sprintf("%s file is not exist", req.File))
}
global.LOG.Infof("recover database %s-%s from backup file %s", req.Name, req.DetailName, req.File)
if err := handleMysqlRecover(app, path.Dir(req.File), req.DetailName, path.Base(req.File), false); err != nil {
return err return err
} }
return nil return nil
} }
func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error { func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
file := req.File file := req.File
fileName := path.Base(req.File) fileName := path.Base(req.File)
if strings.HasSuffix(fileName, ".tar.gz") { if strings.HasSuffix(fileName, ".tar.gz") {
@@ -89,92 +106,77 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
}() }()
} }
req.File = path.Dir(file) + "/" + fileName if err := handleMysqlRecover(app, path.Dir(file), req.DetailName, fileName, false); err != nil {
if err := handleMysqlRecover(req, false); err != nil {
return err return err
} }
global.LOG.Info("recover from uploads successful!") global.LOG.Info("recover from uploads successful!")
return nil return nil
} }
func handleMysqlBackup(name, dbName, targetDir, fileName string) error { func handleMysqlBackup(app *repo.RootInfo, backupDir, dbName, fileName string) error {
dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByMysqlName(name)) fileOp := files.NewFileOp()
if err != nil { if !fileOp.Stat(backupDir) {
return err if err := os.MkdirAll(backupDir, os.ModePerm); err != nil {
} return fmt.Errorf("mkdir %s failed, err: %v", backupDir, err)
cli, _, err := LoadMysqlClientByFrom(dbInfo.From) }
if err != nil {
return err
} }
outfile, _ := os.OpenFile(backupDir+"/"+fileName, os.O_RDWR|os.O_CREATE, 0755)
global.LOG.Infof("start to mysqldump | gzip > %s.gzip", backupDir+"/"+fileName)
cmd := exec.Command("docker", "exec", app.ContainerName, "mysqldump", "-uroot", "-p"+app.Password, dbName)
gzipCmd := exec.Command("gzip", "-cf")
gzipCmd.Stdin, _ = cmd.StdoutPipe()
gzipCmd.Stdout = outfile
_ = gzipCmd.Start()
_ = cmd.Run()
_ = gzipCmd.Wait()
backupInfo := client.BackupInfo{
Name: dbName,
Format: dbInfo.Format,
TargetDir: targetDir,
FileName: fileName,
Timeout: 300,
}
if err := cli.Backup(backupInfo); err != nil {
return err
}
return nil return nil
} }
func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error { func handleMysqlRecover(mysqlInfo *repo.RootInfo, recoverDir, dbName, fileName string, isRollback bool) error {
isOk := false isOk := false
fileOp := files.NewFileOp()
if !fileOp.Stat(req.File) {
return errors.New(fmt.Sprintf("%s file is not exist", req.File))
}
dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(req.DetailName), mysqlRepo.WithByMysqlName(req.Name))
if err != nil {
return err
}
cli, _, err := LoadMysqlClientByFrom(dbInfo.From)
if err != nil {
return err
}
if !isRollback { if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/mysql/%s_%s.sql.gz", req.DetailName, time.Now().Format("20060102150405"))) rollbackFile := fmt.Sprintf("%s/original/database/%s_%s.sql.gz", global.CONF.System.BaseDir, mysqlInfo.Name, time.Now().Format("20060102150405"))
if err := cli.Backup(client.BackupInfo{ if err := handleMysqlBackup(mysqlInfo, path.Dir(rollbackFile), dbName, path.Base(rollbackFile)); err != nil {
Name: req.DetailName, return fmt.Errorf("backup mysql db %s for rollback before recover failed, err: %v", mysqlInfo.Name, err)
Format: dbInfo.Format,
TargetDir: path.Dir(rollbackFile),
FileName: path.Base(rollbackFile),
Timeout: 300,
}); err != nil {
return fmt.Errorf("backup mysql db %s for rollback before recover failed, err: %v", req.DetailName, err)
} }
defer func() { defer func() {
if !isOk { if !isOk {
global.LOG.Info("recover failed, start to rollback now") global.LOG.Info("recover failed, start to rollback now")
if err := cli.Recover(client.RecoverInfo{ if err := handleMysqlRecover(mysqlInfo, path.Dir(rollbackFile), dbName, path.Base(rollbackFile), true); err != nil {
Name: req.DetailName, global.LOG.Errorf("rollback mysql db %s from %s failed, err: %v", dbName, rollbackFile, err)
Format: dbInfo.Format, return
SourceFile: rollbackFile,
Timeout: 300,
}); err != nil {
global.LOG.Errorf("rollback mysql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
} }
global.LOG.Infof("rollback mysql db %s from %s successful", req.DetailName, rollbackFile) global.LOG.Infof("rollback mysql db %s from %s successful", dbName, rollbackFile)
_ = os.RemoveAll(rollbackFile) _ = os.RemoveAll(rollbackFile)
} else { } else {
_ = os.RemoveAll(rollbackFile) _ = os.RemoveAll(rollbackFile)
} }
}() }()
} }
if err := cli.Recover(client.RecoverInfo{ file := recoverDir + "/" + fileName
Name: req.DetailName, fi, _ := os.Open(file)
Format: dbInfo.Format, defer fi.Close()
SourceFile: req.File, cmd := exec.Command("docker", "exec", "-i", mysqlInfo.ContainerName, "mysql", "-uroot", "-p"+mysqlInfo.Password, dbName)
if strings.HasSuffix(fileName, ".gz") {
Timeout: 300, gzipFile, err := os.Open(file)
}); err != nil { if err != nil {
return err return err
}
defer gzipFile.Close()
gzipReader, err := gzip.NewReader(gzipFile)
if err != nil {
return err
}
defer gzipReader.Close()
cmd.Stdin = gzipReader
} else {
cmd.Stdin = fi
}
stdout, err := cmd.CombinedOutput()
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
return errors.New(stdStr)
} }
isOk = true isOk = true
return nil return nil

View File

@@ -37,13 +37,13 @@ func (u *BackupService) RedisBackup() error {
timeNow := time.Now().Format("20060102150405") timeNow := time.Now().Format("20060102150405")
fileName := fmt.Sprintf("%s.rdb", timeNow) fileName := fmt.Sprintf("%s.rdb", timeNow)
if appendonly == "yes" { if appendonly == "yes" {
if strings.HasPrefix(redisInfo.Version, "6.") { if redisInfo.Version == "6.0.16" {
fileName = fmt.Sprintf("%s.aof", timeNow) fileName = fmt.Sprintf("%s.aof", timeNow)
} else { } else {
fileName = fmt.Sprintf("%s.tar.gz", timeNow) fileName = fmt.Sprintf("%s.tar.gz", timeNow)
} }
} }
backupDir := path.Join(localDir, fmt.Sprintf("database/redis/%s", redisInfo.Name)) backupDir := fmt.Sprintf("%s/database/redis/%s", localDir, redisInfo.Name)
if err := handleRedisBackup(redisInfo, backupDir, fileName); err != nil { if err := handleRedisBackup(redisInfo, backupDir, fileName); err != nil {
return err return err
} }
@@ -120,10 +120,10 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
} }
if appendonly == "yes" { if appendonly == "yes" {
if strings.HasPrefix(redisInfo.Version, "6.") && !strings.HasSuffix(recoverFile, ".aof") { if redisInfo.Version == "6.0.16" && !strings.HasSuffix(recoverFile, ".aof") {
return buserr.New(constant.ErrTypeOfRedis) return buserr.New(constant.ErrTypeOfRedis)
} }
if strings.HasPrefix(redisInfo.Version, "7.") && !strings.HasSuffix(recoverFile, ".tar.gz") { if redisInfo.Version == "7.0.5" && !strings.HasSuffix(recoverFile, ".tar.gz") {
return buserr.New(constant.ErrTypeOfRedis) return buserr.New(constant.ErrTypeOfRedis)
} }
} else { } else {
@@ -137,13 +137,13 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
if !isRollback { if !isRollback {
suffix := "rdb" suffix := "rdb"
if appendonly == "yes" { if appendonly == "yes" {
if strings.HasPrefix(redisInfo.Version, "6.") { if redisInfo.Version == "6.0.16" {
suffix = "aof" suffix = "aof"
} else { } else {
suffix = "tar.gz" suffix = "tar.gz"
} }
} }
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format("20060102150405"), suffix)) rollbackFile := fmt.Sprintf("%s/original/database/redis/%s_%s.%s", global.CONF.System.BaseDir, redisInfo.Name, time.Now().Format("20060102150405"), suffix)
if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil { if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
return fmt.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err) return fmt.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err)
} }
@@ -165,14 +165,14 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
if _, err := compose.Down(composeDir + "/docker-compose.yml"); err != nil { if _, err := compose.Down(composeDir + "/docker-compose.yml"); err != nil {
return err return err
} }
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "7.") { if appendonly == "yes" && redisInfo.Version == "7.0.5" {
redisDataDir := fmt.Sprintf("%s/%s/%s/data", constant.AppInstallDir, "redis", redisInfo.Name) redisDataDir := fmt.Sprintf("%s/%s/%s/data", constant.AppInstallDir, "redis", redisInfo.Name)
if err := handleUnTar(recoverFile, redisDataDir); err != nil { if err := handleUnTar(recoverFile, redisDataDir); err != nil {
return err return err
} }
} else { } else {
itemName := "dump.rdb" itemName := "dump.rdb"
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "6.") { if appendonly == "yes" && redisInfo.Version == "6.0.16" {
itemName = "appendonly.aof" itemName = "appendonly.aof"
} }
input, err := os.ReadFile(recoverFile) input, err := os.ReadFile(recoverFile)

View File

@@ -11,7 +11,6 @@ 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/cmd" "github.com/1Panel-dev/1Panel/backend/utils/cmd"
@@ -31,7 +30,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
} }
timeNow := time.Now().Format("20060102150405") timeNow := time.Now().Format("20060102150405")
backupDir := path.Join(localDir, fmt.Sprintf("website/%s", req.Name)) backupDir := fmt.Sprintf("%s/website/%s", localDir, req.Name)
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow) fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow)
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil { if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil {
return err return err
@@ -81,11 +80,11 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
temPathWithName := tmpPath + "/" + website.Alias temPathWithName := tmpPath + "/" + website.Alias
if !fileOp.Stat(tmpPath+"/website.json") || !fileOp.Stat(temPathWithName+".conf") || !fileOp.Stat(temPathWithName+".web.tar.gz") { if !fileOp.Stat(tmpPath+"/website.json") || !fileOp.Stat(temPathWithName+".conf") || !fileOp.Stat(temPathWithName+".web.tar.gz") {
return buserr.WithDetail(constant.ErrBackupExist, ".conf or .web.tar.gz", nil) return errors.New("the wrong recovery package does not have .conf or .web.tar.gz files")
} }
if website.Type == constant.Deployment { if website.Type == constant.Deployment {
if !fileOp.Stat(temPathWithName + ".app.tar.gz") { if !fileOp.Stat(temPathWithName + ".app.tar.gz") {
return buserr.WithDetail(constant.ErrBackupExist, ".app.tar.gz", nil) return errors.New("the wrong recovery package does not have .app.tar.gz files")
} }
} }
var oldWebsite model.Website var oldWebsite model.Website
@@ -96,14 +95,13 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
if err := json.Unmarshal(websiteJson, &oldWebsite); err != nil { if err := json.Unmarshal(websiteJson, &oldWebsite); err != nil {
return fmt.Errorf("unmarshal app.json failed, err: %v", err) return fmt.Errorf("unmarshal app.json failed, err: %v", err)
} }
if oldWebsite.Alias != website.Alias || oldWebsite.Type != website.Type || oldWebsite.ID != website.ID {
if err := checkValidOfWebsite(&oldWebsite, website); err != nil { return errors.New("the current backup file does not match the application")
return err
} }
isOk := false isOk := false
if !isRollback { if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405"))) rollbackFile := fmt.Sprintf("%s/original/website/%s_%s.tar.gz", global.CONF.System.BaseDir, website.Alias, time.Now().Format("20060102150405"))
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil { if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err) return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
} }
@@ -157,7 +155,6 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
return errors.New(string(stdout)) return errors.New(string(stdout))
} }
oldWebsite.ID = website.ID
if err := websiteRepo.SaveWithoutCtx(&oldWebsite); err != nil { if err := websiteRepo.SaveWithoutCtx(&oldWebsite); err != nil {
global.LOG.Errorf("handle save website data failed, err: %v", err) global.LOG.Errorf("handle save website data failed, err: %v", err)
return err return err
@@ -215,26 +212,3 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
return nil return nil
} }
func checkValidOfWebsite(oldWebsite, website *model.Website) error {
if oldWebsite.Alias != website.Alias || oldWebsite.Type != website.Type {
return buserr.WithDetail(constant.ErrBackupMatch, fmt.Sprintf("oldName: %s, oldType: %v", oldWebsite.Alias, oldWebsite.Type), nil)
}
if oldWebsite.AppInstallID != 0 {
_, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil {
return buserr.WithDetail(constant.ErrBackupMatch, "app", nil)
}
}
if oldWebsite.RuntimeID != 0 {
if _, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID)); err != nil {
return buserr.WithDetail(constant.ErrBackupMatch, "runtime", nil)
}
}
if oldWebsite.WebsiteSSLID != 0 {
if _, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID)); err != nil {
return buserr.WithDetail(constant.ErrBackupMatch, "ssl", nil)
}
}
return nil
}

View File

@@ -3,23 +3,19 @@ package service
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"os"
"os/exec" "os/exec"
"path"
"path/filepath"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"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/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/common"
"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"
@@ -28,44 +24,30 @@ import (
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/gorilla/websocket"
v1 "github.com/opencontainers/image-spec/specs-go/v1" v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/mem"
) )
type ContainerService struct{} type ContainerService struct{}
type IContainerService interface { type IContainerService interface {
Page(req dto.PageContainer) (int64, interface{}, error) Page(req dto.PageContainer) (int64, interface{}, error)
List() ([]string, error)
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error) PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
ListNetwork() ([]dto.Options, error)
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) (string, error) CreateCompose(req dto.ComposeCreate) (string, error)
ComposeOperation(req dto.ComposeOperation) error ComposeOperation(req dto.ComposeOperation) error
ContainerCreate(req dto.ContainerOperate) error ContainerCreate(req dto.ContainerCreate) error
ContainerUpdate(req dto.ContainerOperate) error
ContainerUpgrade(req dto.ContainerUpgrade) error
ContainerInfo(req dto.OperationWithName) (*dto.ContainerOperate, error)
ContainerListStats() ([]dto.ContainerListStats, error)
LoadResouceLimit() (*dto.ResourceLimit, error)
ContainerLogClean(req dto.OperationWithName) error
ContainerOperation(req dto.ContainerOperation) error ContainerOperation(req dto.ContainerOperation) error
ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error ContainerLogs(param dto.ContainerLog) (string, error)
ContainerStats(id string) (*dto.ContainerStats, error) ContainerStats(id string) (*dto.ContainterStats, error)
Inspect(req dto.InspectReq) (string, error) Inspect(req dto.InspectReq) (string, error)
DeleteNetwork(req dto.BatchDelete) error DeleteNetwork(req dto.BatchDelete) error
CreateNetwork(req dto.NetworkCreate) error CreateNetwork(req dto.NetworkCreat) error
DeleteVolume(req dto.BatchDelete) error DeleteVolume(req dto.BatchDelete) error
CreateVolume(req dto.VolumeCreate) error CreateVolume(req dto.VolumeCreat) error
TestCompose(req dto.ComposeCreate) (bool, error) TestCompose(req dto.ComposeCreate) (bool, error)
ComposeUpdate(req dto.ComposeUpdate) error ComposeUpdate(req dto.ComposeUpdate) error
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
LoadContainerLogs(req dto.OperationWithNameAndType) string
} }
func NewIContainerService() IContainerService { func NewIContainerService() IContainerService {
@@ -74,8 +56,9 @@ func NewIContainerService() IContainerService {
func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, error) { func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, error) {
var ( var (
records []types.Container records []types.Container
list []types.Container list []types.Container
backDatas []dto.ContainerInfo
) )
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
@@ -91,40 +74,19 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
return 0, nil, err return 0, nil, err
} }
if len(req.Name) != 0 { if len(req.Name) != 0 {
length, count := len(list), 0 lenth, count := len(list), 0
for count < length { for count < lenth {
if !strings.Contains(list[count].Names[0][1:], req.Name) { if !strings.Contains(list[count].Names[0][1:], req.Name) {
list = append(list[:count], list[(count+1):]...) list = append(list[:count], list[(count+1):]...)
length-- lenth--
} else { } else {
count++ count++
} }
} }
} }
switch req.OrderBy { sort.Slice(list, func(i, j int) bool {
case "name": return list[i].Created > list[j].Created
sort.Slice(list, func(i, j int) bool { })
if req.Order == constant.OrderAsc {
return list[i].Names[0][1:] < list[j].Names[0][1:]
}
return list[i].Names[0][1:] > list[j].Names[0][1:]
})
case "state":
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].State < list[j].State
}
return list[i].State > list[j].State
})
default:
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].Created < list[j].Created
}
return list[i].Created > list[j].Created
})
}
total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total { if start > total {
records = make([]types.Container, 0) records = make([]types.Container, 0)
@@ -135,87 +97,31 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
records = list[start:end] records = list[start:end]
} }
backDatas := make([]dto.ContainerInfo, len(records)) for _, container := range records {
for i := 0; i < len(records); i++ {
item := records[i]
IsFromCompose := false IsFromCompose := false
if _, ok := item.Labels[composeProjectLabel]; ok { if _, ok := container.Labels[composeProjectLabel]; ok {
IsFromCompose = true IsFromCompose = true
} }
IsFromApp := false IsFromApp := false
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" { if created, ok := container.Labels[composeCreatedBy]; ok && created == "Apps" {
IsFromApp = true IsFromApp = true
} }
backDatas = append(backDatas, dto.ContainerInfo{
var ports []string ContainerID: container.ID,
for _, port := range item.Ports { CreateTime: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
itemPortStr := fmt.Sprintf("%v/%s", port.PrivatePort, port.Type) Name: container.Names[0][1:],
if port.PublicPort != 0 { ImageId: strings.Split(container.ImageID, ":")[1],
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type) ImageName: container.Image,
} State: container.State,
ports = append(ports, itemPortStr) RunTime: container.Status,
}
backDatas[i] = dto.ContainerInfo{
ContainerID: item.ID,
CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"),
Name: item.Names[0][1:],
ImageId: strings.Split(item.ImageID, ":")[1],
ImageName: item.Image,
State: item.State,
RunTime: item.Status,
Ports: ports,
IsFromApp: IsFromApp, IsFromApp: IsFromApp,
IsFromCompose: IsFromCompose, IsFromCompose: IsFromCompose,
} })
} }
return int64(total), backDatas, nil return int64(total), backDatas, nil
} }
func (u *ContainerService) List() ([]string, error) {
client, err := docker.NewDockerClient()
if err != nil {
return nil, err
}
containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil {
return nil, err
}
var datas []string
for _, container := range containers {
for _, name := range container.Names {
if len(name) != 0 {
datas = append(datas, strings.TrimPrefix(name, "/"))
}
}
}
return datas, nil
}
func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error) {
client, err := docker.NewDockerClient()
if err != nil {
return nil, err
}
list, err := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil {
return nil, err
}
var datas []dto.ContainerListStats
var wg sync.WaitGroup
wg.Add(len(list))
for i := 0; i < len(list); i++ {
go func(item types.Container) {
cpu, mem := loadCpuAndMem(client, item.ID)
datas = append(datas, dto.ContainerListStats{CPUPercent: cpu, MemoryPercent: mem, ContainerID: item.ID})
wg.Done()
}(list[i])
}
wg.Wait()
return datas, nil
}
func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) { func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
@@ -240,97 +146,64 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
return string(bytes), nil return string(bytes), nil
} }
func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error) { func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
report := dto.ContainerPruneReport{} if len(req.ExposedPorts) != 0 {
client, err := docker.NewDockerClient() for _, port := range req.ExposedPorts {
if err != nil { if common.ScanPort(port.HostPort) {
return report, err return buserr.WithDetail(constant.ErrPortInUsed, port.HostPort, nil)
} }
pruneFilters := filters.NewArgs()
if req.WithTagAll {
pruneFilters.Add("dangling", "false")
if req.PruneType != "image" {
pruneFilters.Add("until", "24h")
} }
} }
switch req.PruneType {
case "container":
rep, err := client.ContainersPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.ContainersDeleted)
report.SpaceReclaimed = int(rep.SpaceReclaimed)
case "image":
rep, err := client.ImagesPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.ImagesDeleted)
report.SpaceReclaimed = int(rep.SpaceReclaimed)
case "network":
rep, err := client.NetworksPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.NetworksDeleted)
case "volume":
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.VolumesDeleted)
report.SpaceReclaimed = int(rep.SpaceReclaimed)
}
return report, nil
}
func (u *ContainerService) LoadResouceLimit() (*dto.ResourceLimit, error) {
cpuCounts, err := cpu.Counts(true)
if err != nil {
return nil, fmt.Errorf("load cpu limit failed, err: %v", err)
}
memoryInfo, err := mem.VirtualMemory()
if err != nil {
return nil, fmt.Errorf("load memory limit failed, err: %v", err)
}
data := dto.ResourceLimit{
CPU: cpuCounts,
Memory: int(memoryInfo.Total),
}
return &data, nil
}
func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
return err return err
} }
ctx := context.Background() config := &container.Config{
newContainer, _ := client.ContainerInspect(ctx, req.Name) Image: req.Image,
if newContainer.ContainerJSONBase != nil { Cmd: req.Cmd,
return buserr.New(constant.ErrContainerName) Env: req.Env,
Labels: stringsToMap(req.Labels),
Tty: true,
OpenStdin: true,
} }
hostConf := &container.HostConfig{
var config container.Config AutoRemove: req.AutoRemove,
var hostConf container.HostConfig PublishAllPorts: req.PublishAllPorts,
var networkConf network.NetworkingConfig RestartPolicy: container.RestartPolicy{Name: req.RestartPolicy},
if err := loadConfigInfo(req, &config, &hostConf, &networkConf); err != nil { }
return err if req.RestartPolicy == "on-failure" {
hostConf.RestartPolicy.MaximumRetryCount = 5
}
if req.NanoCPUs != 0 {
hostConf.NanoCPUs = req.NanoCPUs * 1000000000
}
if req.Memory != 0 {
hostConf.Memory = req.Memory
}
if len(req.ExposedPorts) != 0 {
hostConf.PortBindings = make(nat.PortMap)
for _, port := range req.ExposedPorts {
bindItem := nat.PortBinding{HostPort: strconv.Itoa(port.HostPort)}
hostConf.PortBindings[nat.Port(fmt.Sprintf("%d/tcp", port.ContainerPort))] = []nat.PortBinding{bindItem}
}
}
if len(req.Volumes) != 0 {
config.Volumes = make(map[string]struct{})
for _, volume := range req.Volumes {
config.Volumes[volume.ContainerDir] = struct{}{}
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
}
} }
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)
if !checkImageExist(client, req.Image) || req.ForcePull { ctx := context.Background()
if !checkImageExist(client, req.Image) {
if err := pullImages(ctx, client, req.Image); err != nil { if err := pullImages(ctx, client, req.Image); err != nil {
if !req.ForcePull { return err
return err
}
global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err)
} }
} }
container, err := client.ContainerCreate(ctx, &config, &hostConf, &networkConf, &v1.Platform{}, req.Name) container, err := client.ContainerCreate(ctx, config, hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name)
if err != nil { if err != nil {
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true}) _ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
return err return err
@@ -343,156 +216,6 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
return nil return nil
} }
func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.ContainerOperate, error) {
client, err := docker.NewDockerClient()
if err != nil {
return nil, err
}
ctx := context.Background()
oldContainer, err := client.ContainerInspect(ctx, req.Name)
if err != nil {
return nil, err
}
var data dto.ContainerOperate
data.ContainerID = oldContainer.ID
data.Name = strings.ReplaceAll(oldContainer.Name, "/", "")
data.Image = oldContainer.Config.Image
if oldContainer.NetworkSettings != nil {
for network := range oldContainer.NetworkSettings.Networks {
data.Network = network
break
}
}
data.Cmd = oldContainer.Config.Cmd
data.Env = oldContainer.Config.Env
data.CPUShares = oldContainer.HostConfig.CPUShares
for key, val := range oldContainer.Config.Labels {
data.Labels = append(data.Labels, fmt.Sprintf("%s=%s", key, val))
}
for key, val := range oldContainer.HostConfig.PortBindings {
var itemPort dto.PortHelper
if !strings.Contains(string(key), "/") {
continue
}
itemPort.ContainerPort = strings.Split(string(key), "/")[0]
itemPort.Protocol = strings.Split(string(key), "/")[1]
for _, binds := range val {
itemPort.HostIP = binds.HostIP
itemPort.HostPort = binds.HostPort
data.ExposedPorts = append(data.ExposedPorts, itemPort)
}
}
data.AutoRemove = oldContainer.HostConfig.AutoRemove
data.PublishAllPorts = oldContainer.HostConfig.PublishAllPorts
data.RestartPolicy = oldContainer.HostConfig.RestartPolicy.Name
if oldContainer.HostConfig.NanoCPUs != 0 {
data.NanoCPUs = float64(oldContainer.HostConfig.NanoCPUs) / 1000000000
}
if oldContainer.HostConfig.Memory != 0 {
data.Memory = float64(oldContainer.HostConfig.Memory) / 1024 / 1024
}
data.Volumes = loadVolumeBinds(oldContainer.HostConfig.Binds)
return &data, nil
}
func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
client, err := docker.NewDockerClient()
if err != nil {
return err
}
ctx := context.Background()
newContainer, _ := client.ContainerInspect(ctx, req.Name)
if newContainer.ContainerJSONBase != nil && newContainer.ID != req.ContainerID {
return buserr.New(constant.ErrContainerName)
}
oldContainer, err := client.ContainerInspect(ctx, req.ContainerID)
if err != nil {
return err
}
if !checkImageExist(client, req.Image) || req.ForcePull {
if err := pullImages(ctx, client, req.Image); err != nil {
if !req.ForcePull {
return err
}
global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err)
}
}
if err := client.ContainerRemove(ctx, req.ContainerID, types.ContainerRemoveOptions{Force: true}); err != nil {
return err
}
config := oldContainer.Config
hostConf := oldContainer.HostConfig
var networkConf network.NetworkingConfig
if err := loadConfigInfo(req, config, hostConf, &networkConf); err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return err
}
global.LOG.Infof("new container info %s has been update, now start to recreate", req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, &networkConf, &v1.Platform{}, req.Name)
if err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return fmt.Errorf("update contianer failed, err: %v", err)
}
global.LOG.Infof("update container %s successful! now check if the container is started.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
return fmt.Errorf("update successful but start failed, err: %v", err)
}
return nil
}
func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
client, err := docker.NewDockerClient()
if err != nil {
return err
}
ctx := context.Background()
oldContainer, err := client.ContainerInspect(ctx, req.Name)
if err != nil {
return err
}
if !checkImageExist(client, req.Image) || req.ForcePull {
if err := pullImages(ctx, client, req.Image); err != nil {
if !req.ForcePull {
return err
}
global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err)
}
}
config := oldContainer.Config
config.Image = req.Image
hostConf := oldContainer.HostConfig
var networkConf network.NetworkingConfig
if oldContainer.NetworkSettings != nil {
for networkKey := range oldContainer.NetworkSettings.Networks {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{networkKey: {}}
break
}
}
if err := client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{Force: true}); err != nil {
return err
}
global.LOG.Infof("new container info %s has been update, now start to recreate", req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, &networkConf, &v1.Platform{}, req.Name)
if err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return fmt.Errorf("upgrade contianer failed, err: %v", err)
}
global.LOG.Infof("upgrade container %s successful! now check if the container is started.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
return fmt.Errorf("upgrade successful but start failed, err: %v", err)
}
return nil
}
func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error { func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error {
var err error var err error
ctx := context.Background() ctx := context.Background()
@@ -515,10 +238,6 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
case constant.ContainerOpUnpause: case constant.ContainerOpUnpause:
err = client.ContainerUnpause(ctx, req.Name) err = client.ContainerUnpause(ctx, req.Name)
case constant.ContainerOpRename: case constant.ContainerOpRename:
newContainer, _ := client.ContainerInspect(ctx, req.NewName)
if newContainer.ContainerJSONBase != nil {
return buserr.New(constant.ErrContainerName)
}
err = client.ContainerRename(ctx, req.Name, req.NewName) err = client.ContainerRename(ctx, req.Name, req.NewName)
case constant.ContainerOpRemove: case constant.ContainerOpRemove:
err = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true}) err = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
@@ -526,75 +245,19 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
return err return err
} }
func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error { func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) {
client, err := docker.NewDockerClient() cmd := exec.Command("docker", "logs", req.ContainerID)
if req.Mode != "all" {
cmd = exec.Command("docker", "logs", req.ContainerID, "--since", req.Mode)
}
stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return err return "", errors.New(string(stdout))
} }
container, err := client.ContainerInspect(context.Background(), req.Name) return string(stdout), nil
if err != nil {
return err
}
file, err := os.OpenFile(container.LogPath, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return err
}
defer file.Close()
if err = file.Truncate(0); err != nil {
return err
}
_, _ = file.Seek(0, 0)
files, _ := filepath.Glob(fmt.Sprintf("%s.*", container.LogPath))
for _, file := range files {
_ = os.Remove(file)
}
return nil
} }
func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error { func (u *ContainerService) ContainerStats(id string) (*dto.ContainterStats, error) {
if cmd.CheckIllegal(container, since, tail) {
return buserr.New(constant.ErrCmdIllegal)
}
command := fmt.Sprintf("docker logs %s", container)
if tail != "0" {
command += " -n " + tail
}
if since != "all" {
command += " --since " + since
}
if follow {
command += " -f"
}
command += " 2>&1"
cmd := exec.Command("bash", "-c", command)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
if err := cmd.Start(); err != nil {
return err
}
buffer := make([]byte, 1024)
for {
n, err := stdout.Read(buffer)
if err != nil {
if err == io.EOF {
break
}
global.LOG.Errorf("read bytes from container log failed, err: %v", err)
continue
}
if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil {
global.LOG.Errorf("send message with container log to ws failed, err: %v", err)
break
}
}
return nil
}
func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error) {
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -607,16 +270,16 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
body, err := io.ReadAll(res.Body) body, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
res.Body.Close()
return nil, err return nil, err
} }
res.Body.Close()
var stats *types.StatsJSON var stats *types.StatsJSON
if err := json.Unmarshal(body, &stats); err != nil { if err := json.Unmarshal(body, &stats); err != nil {
return nil, err return nil, err
} }
var data dto.ContainerStats var data dto.ContainterStats
data.CPUPercent = calculateCPUPercentUnix(stats) previousCPU := stats.PreCPUStats.CPUUsage.TotalUsage
previousSystem := stats.PreCPUStats.SystemUsage
data.CPUPercent = calculateCPUPercentUnix(previousCPU, previousSystem, stats)
data.IORead, data.IOWrite = calculateBlockIO(stats.BlkioStats) data.IORead, data.IOWrite = calculateBlockIO(stats.BlkioStats)
data.Memory = float64(stats.MemoryStats.Usage) / 1024 / 1024 data.Memory = float64(stats.MemoryStats.Usage) / 1024 / 1024
if cache, ok := stats.MemoryStats.Stats["cache"]; ok { if cache, ok := stats.MemoryStats.Stats["cache"]; ok {
@@ -628,81 +291,28 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
return &data, nil return &data, nil
} }
func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) string {
filePath := ""
switch req.Type {
case "image-pull", "image-push", "image-build":
filePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
case "compose-detail", "compose-create":
client, err := docker.NewDockerClient()
if err != nil {
return ""
}
options := types.ContainerListOptions{All: true}
options.Filters = filters.NewArgs()
options.Filters.Add("label", fmt.Sprintf("%s=%s", composeProjectLabel, req.Name))
containers, err := client.ContainerList(context.Background(), options)
if err != nil {
return ""
}
for _, container := range containers {
config := container.Labels[composeConfigLabel]
workdir := container.Labels[composeWorkdirLabel]
if len(config) != 0 && len(workdir) != 0 && strings.Contains(config, workdir) {
filePath = config
break
} else {
filePath = workdir
break
}
}
if req.Type == "compose-create" {
filePath = path.Join(path.Dir(filePath), "compose.log")
}
}
if _, err := os.Stat(filePath); err != nil {
return ""
}
content, err := os.ReadFile(filePath)
if err != nil {
return ""
}
return string(content)
}
func stringsToMap(list []string) map[string]string { func stringsToMap(list []string) map[string]string {
var lableMap = make(map[string]string) var lableMap = make(map[string]string)
for _, label := range list { for _, label := range list {
if strings.Contains(label, "=") { sps := strings.Split(label, "=")
sps := strings.SplitN(label, "=", 2) if len(sps) > 1 {
lableMap[sps[0]] = sps[1] lableMap[sps[0]] = sps[1]
} }
} }
return lableMap return lableMap
} }
func calculateCPUPercentUnix(previousCPU, previousSystem uint64, v *types.StatsJSON) float64 {
func calculateCPUPercentUnix(stats *types.StatsJSON) float64 { var (
cpuPercent := 0.0 cpuPercent = 0.0
cpuDelta := float64(stats.CPUStats.CPUUsage.TotalUsage) - float64(stats.PreCPUStats.CPUUsage.TotalUsage) cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(previousCPU)
systemDelta := float64(stats.CPUStats.SystemUsage) - float64(stats.PreCPUStats.SystemUsage) systemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem)
)
if systemDelta > 0.0 && cpuDelta > 0.0 { if systemDelta > 0.0 && cpuDelta > 0.0 {
cpuPercent = (cpuDelta / systemDelta) * 100.0 cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
if len(stats.CPUStats.CPUUsage.PercpuUsage) != 0 {
cpuPercent = cpuPercent * float64(len(stats.CPUStats.CPUUsage.PercpuUsage))
}
} }
return cpuPercent return cpuPercent
} }
func calculateMemPercentUnix(memStats types.MemoryStats) float64 {
memPercent := 0.0
memUsage := float64(memStats.Usage - memStats.Stats["cache"])
memLimit := float64(memStats.Limit)
if memUsage > 0.0 && memLimit > 0.0 {
memPercent = (memUsage / memLimit) * 100.0
}
return memPercent
}
func calculateBlockIO(blkio types.BlkioStats) (blkRead float64, blkWrite float64) { func calculateBlockIO(blkio types.BlkioStats) (blkRead float64, blkWrite float64) {
for _, bioEntry := range blkio.IoServiceBytesRecursive { for _, bioEntry := range blkio.IoServiceBytesRecursive {
switch strings.ToLower(bioEntry.Op) { switch strings.ToLower(bioEntry.Op) {
@@ -753,171 +363,3 @@ func pullImages(ctx context.Context, client *client.Client, image string) error
} }
return nil return nil
} }
func loadCpuAndMem(client *client.Client, container string) (float64, float64) {
res, err := client.ContainerStats(context.Background(), container, false)
if err != nil {
return 0, 0
}
body, err := io.ReadAll(res.Body)
if err != nil {
res.Body.Close()
return 0, 0
}
res.Body.Close()
var stats *types.StatsJSON
if err := json.Unmarshal(body, &stats); err != nil {
return 0, 0
}
CPUPercent := calculateCPUPercentUnix(stats)
MemPercent := calculateMemPercentUnix(stats.MemoryStats)
return CPUPercent, MemPercent
}
func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {
portMap := make(nat.PortMap)
if len(ports) == 0 {
return portMap, nil
}
for _, port := range ports {
if strings.Contains(port.ContainerPort, "-") {
if !strings.Contains(port.HostPort, "-") {
return portMap, buserr.New(constant.ErrPortRules)
}
hostStart, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[0])
hostEnd, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[1])
containerStart, _ := strconv.Atoi(strings.Split(port.ContainerPort, "-")[0])
containerEnd, _ := strconv.Atoi(strings.Split(port.ContainerPort, "-")[1])
if (hostEnd-hostStart) <= 0 || (containerEnd-containerStart) <= 0 {
return portMap, buserr.New(constant.ErrPortRules)
}
if (containerEnd - containerStart) != (hostEnd - hostStart) {
return portMap, buserr.New(constant.ErrPortRules)
}
for i := 0; i <= hostEnd-hostStart; i++ {
bindItem := nat.PortBinding{HostPort: strconv.Itoa(hostStart + i), HostIP: port.HostIP}
portMap[nat.Port(fmt.Sprintf("%d/%s", containerStart+i, port.Protocol))] = []nat.PortBinding{bindItem}
}
for i := hostStart; i <= hostEnd; i++ {
if common.ScanPort(i) {
return portMap, buserr.WithDetail(constant.ErrPortInUsed, i, nil)
}
}
} else {
portItem := 0
if strings.Contains(port.HostPort, "-") {
portItem, _ = strconv.Atoi(strings.Split(port.HostPort, "-")[0])
} else {
portItem, _ = strconv.Atoi(port.HostPort)
}
if common.ScanPort(portItem) {
return portMap, buserr.WithDetail(constant.ErrPortInUsed, portItem, nil)
}
bindItem := nat.PortBinding{HostPort: strconv.Itoa(portItem), HostIP: port.HostIP}
portMap[nat.Port(fmt.Sprintf("%s/%s", port.ContainerPort, port.Protocol))] = []nat.PortBinding{bindItem}
}
}
return portMap, nil
}
func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf *container.HostConfig, networkConf *network.NetworkingConfig) error {
portMap, err := checkPortStats(req.ExposedPorts)
if err != nil {
return err
}
exposeds := make(nat.PortSet)
for port := range portMap {
exposeds[port] = struct{}{}
}
config.Image = req.Image
config.Cmd = req.Cmd
config.Env = req.Env
config.Labels = stringsToMap(req.Labels)
config.ExposedPorts = exposeds
if len(req.Network) != 0 {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
} else {
networkConf = &network.NetworkingConfig{}
}
hostConf.AutoRemove = req.AutoRemove
hostConf.CPUShares = req.CPUShares
hostConf.PublishAllPorts = req.PublishAllPorts
hostConf.RestartPolicy = container.RestartPolicy{Name: req.RestartPolicy}
if req.RestartPolicy == "on-failure" {
hostConf.RestartPolicy.MaximumRetryCount = 5
}
hostConf.NanoCPUs = int64(req.NanoCPUs * 1000000000)
hostConf.Memory = int64(req.Memory * 1024 * 1024)
hostConf.PortBindings = portMap
hostConf.Binds = []string{}
config.Volumes = make(map[string]struct{})
for _, volume := range req.Volumes {
config.Volumes[volume.ContainerDir] = struct{}{}
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
}
return nil
}
func reCreateAfterUpdate(name string, client *client.Client, config *container.Config, hostConf *container.HostConfig, networkConf *types.NetworkSettings) {
ctx := context.Background()
var oldNetworkConf network.NetworkingConfig
if networkConf != nil {
for networkKey := range networkConf.Networks {
oldNetworkConf.EndpointsConfig = map[string]*network.EndpointSettings{networkKey: {}}
break
}
}
oldContainer, err := client.ContainerCreate(ctx, config, hostConf, &oldNetworkConf, &v1.Platform{}, name)
if err != nil {
global.LOG.Errorf("recreate after container update failed, err: %v", err)
return
}
if err := client.ContainerStart(ctx, oldContainer.ID, types.ContainerStartOptions{}); err != nil {
global.LOG.Errorf("restart after container update failed, err: %v", err)
}
}
func loadVolumeBinds(binds []string) []dto.VolumeHelper {
var datas []dto.VolumeHelper
for _, bind := range binds {
parts := strings.Split(bind, ":")
var volumeItem dto.VolumeHelper
if len(parts) > 3 {
continue
}
volumeItem.SourceDir = parts[0]
if len(parts) == 1 {
volumeItem.ContainerDir = parts[0]
volumeItem.Mode = "rw"
}
if len(parts) == 2 {
switch parts[1] {
case "r", "ro":
volumeItem.ContainerDir = parts[0]
volumeItem.Mode = "ro"
case "rw":
volumeItem.ContainerDir = parts[0]
volumeItem.Mode = "rw"
default:
volumeItem.ContainerDir = parts[1]
volumeItem.Mode = "rw"
}
}
if len(parts) == 3 {
volumeItem.ContainerDir = parts[1]
if parts[2] == "r" {
volumeItem.Mode = "ro"
} else {
volumeItem.Mode = parts[2]
}
}
datas = append(datas, volumeItem)
}
return datas
}

View File

@@ -4,7 +4,6 @@ import (
"bufio" "bufio"
"errors" "errors"
"fmt" "fmt"
"io"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@@ -14,10 +13,8 @@ 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/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/compose" "github.com/1Panel-dev/1Panel/backend/utils/compose"
"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"
@@ -94,7 +91,7 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
} }
} }
for _, item := range composeCreatedByLocal { for _, item := range composeCreatedByLocal {
if err := composeRepo.DeleteRecord(commonRepo.WithByID(item.ID)); err != nil { if err := composeRepo.DeleteRecord(commonRepo.WithByName(item.Name)); err != nil {
global.LOG.Error(err) global.LOG.Error(err)
} }
} }
@@ -103,11 +100,11 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
records = append(records, value) records = append(records, value)
} }
if len(req.Info) != 0 { if len(req.Info) != 0 {
length, count := len(records), 0 lenth, count := len(records), 0
for count < length { for count < lenth {
if !strings.Contains(records[count].Name, req.Info) { if !strings.Contains(records[count].Name, req.Info) {
records = append(records[:count], records[(count+1):]...) records = append(records[:count], records[(count+1):]...)
length-- lenth--
} else { } else {
count++ count++
} }
@@ -129,13 +126,6 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
} }
func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) { func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
if cmd.CheckIllegal(req.Path) {
return false, buserr.New(constant.ErrCmdIllegal)
}
composeItem, _ := composeRepo.GetRecord(commonRepo.WithByName(req.Name))
if composeItem.ID != 0 {
return false, constant.ErrRecordExist
}
if err := u.loadPath(&req); err != nil { if err := u.loadPath(&req); err != nil {
return false, err return false, err
} }
@@ -148,16 +138,13 @@ func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
} }
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error) { func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error) {
if cmd.CheckIllegal(req.Name, req.Path) {
return "", buserr.New(constant.ErrCmdIllegal)
}
if err := u.loadPath(&req); err != nil { if err := u.loadPath(&req); err != nil {
return "", err return "", err
} }
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 req.From == "path" { if req.From == "path" {
req.Name = path.Base(path.Dir(req.Path)) req.Name = path.Base(strings.ReplaceAll(req.Path, "/"+path.Base(req.Path), ""))
} }
logName := path.Dir(req.Path) + "/compose.log" logName := path.Dir(req.Path) + "/compose.log"
file, err := os.OpenFile(logName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) file, err := os.OpenFile(logName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
@@ -167,10 +154,9 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
go func() { go func() {
defer file.Close() defer file.Close()
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d") cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
multiWriter := io.MultiWriter(os.Stdout, file) stdout, err := cmd.CombinedOutput()
cmd.Stdout = multiWriter _, _ = file.Write(stdout)
cmd.Stderr = multiWriter if err != nil {
if err := cmd.Run(); err != nil {
global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err) global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err)
_, _ = compose.Down(req.Path) _, _ = compose.Down(req.Path)
_, _ = file.WriteString("docker-compose up failed!") _, _ = file.WriteString("docker-compose up failed!")
@@ -181,13 +167,10 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
_, _ = file.WriteString("docker-compose up successful!") _, _ = file.WriteString("docker-compose up successful!")
}() }()
return req.Name, nil return logName, nil
} }
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error { func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
if cmd.CheckIllegal(req.Path, req.Operation) {
return buserr.New(constant.ErrCmdIllegal)
}
if _, err := os.Stat(req.Path); err != nil { if _, err := os.Stat(req.Path); err != nil {
return fmt.Errorf("load file with path %s failed, %v", req.Path, err) return fmt.Errorf("load file with path %s failed, %v", req.Path, err)
} }
@@ -197,18 +180,13 @@ func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name) global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name)
if req.Operation == "down" { if req.Operation == "down" {
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name)) _ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
if req.WithFile { _ = os.RemoveAll(strings.ReplaceAll(req.Path, "/docker-compose.yml", ""))
_ = os.RemoveAll(path.Dir(req.Path))
}
} }
return nil return nil
} }
func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error { func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
if cmd.CheckIllegal(req.Name, req.Path) {
return buserr.New(constant.ErrCmdIllegal)
}
if _, err := os.Stat(req.Path); err != nil { if _, err := os.Stat(req.Path); err != nil {
return fmt.Errorf("load file with path %s failed, %v", req.Path, err) return fmt.Errorf("load file with path %s failed, %v", req.Path, err)
} }
@@ -233,7 +211,15 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
} }
func (u *ContainerService) loadPath(req *dto.ComposeCreate) error { func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
if req.From == "template" || req.From == "edit" { 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) dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) { if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil { if err = os.MkdirAll(dir, os.ModePerm); err != nil {

View File

@@ -24,11 +24,11 @@ func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface
return 0, nil, err return 0, nil, err
} }
if len(req.Info) != 0 { if len(req.Info) != 0 {
length, count := len(list), 0 lenth, count := len(list), 0
for count < length { for count < lenth {
if !strings.Contains(list[count].Name, req.Info) { if !strings.Contains(list[count].Name, req.Info) {
list = append(list[:count], list[(count+1):]...) list = append(list[:count], list[(count+1):]...)
length-- lenth--
} else { } else {
count++ count++
} }
@@ -75,26 +75,6 @@ func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface
return int64(total), data, nil return int64(total), data, nil
} }
func (u *ContainerService) ListNetwork() ([]dto.Options, error) {
client, err := docker.NewDockerClient()
if err != nil {
return nil, err
}
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
if err != nil {
return nil, err
}
var datas []dto.Options
for _, item := range list {
datas = append(datas, dto.Options{Option: item.Name})
}
sort.Slice(datas, func(i, j int) bool {
return datas[i].Option < datas[j].Option
})
return datas, nil
}
func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error { func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
@@ -110,7 +90,7 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
} }
return nil return nil
} }
func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error { func (u *ContainerService) CreateNetwork(req dto.NetworkCreat) error {
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
return err return err

View File

@@ -24,11 +24,11 @@ func (u *ContainerService) PageVolume(req dto.SearchWithPage) (int64, interface{
return 0, nil, err return 0, nil, err
} }
if len(req.Info) != 0 { if len(req.Info) != 0 {
length, count := len(list.Volumes), 0 lenth, count := len(list.Volumes), 0
for count < length { for count < lenth {
if !strings.Contains(list.Volumes[count].Name, req.Info) { if !strings.Contains(list.Volumes[count].Name, req.Info) {
list.Volumes = append(list.Volumes[:count], list.Volumes[(count+1):]...) list.Volumes = append(list.Volumes[:count], list.Volumes[(count+1):]...)
length-- lenth--
} else { } else {
count++ count++
} }
@@ -80,16 +80,13 @@ func (u *ContainerService) ListVolume() ([]dto.Options, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var datas []dto.Options var data []dto.Options
for _, item := range list.Volumes { for _, item := range list.Volumes {
datas = append(datas, dto.Options{ data = append(data, dto.Options{
Option: item.Name, Option: item.Name,
}) })
} }
sort.Slice(datas, func(i, j int) bool { return data, nil
return datas[i].Option < datas[j].Option
})
return datas, nil
} }
func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error { func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
@@ -106,7 +103,7 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
} }
return nil return nil
} }
func (u *ContainerService) CreateVolume(req dto.VolumeCreate) error { func (u *ContainerService) CreateVolume(req dto.VolumeCreat) error {
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
return err return err

View File

@@ -9,7 +9,6 @@ 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/jinzhu/copier" "github.com/jinzhu/copier"
@@ -30,8 +29,6 @@ type ICronjobService interface {
Download(down dto.CronjobDownload) (string, error) Download(down dto.CronjobDownload) (string, error)
StartJob(cronjob *model.Cronjob) (int, error) StartJob(cronjob *model.Cronjob) (int, error)
CleanRecord(req dto.CronjobClean) error CleanRecord(req dto.CronjobClean) error
LoadRecordLog(req dto.OperateByID) (string, error)
} }
func NewICronjobService() ICronjobService { func NewICronjobService() ICronjobService {
@@ -39,7 +36,7 @@ func NewICronjobService() ICronjobService {
} }
func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) { func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order)) total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info))
var dtoCronjobs []dto.CronjobInfo var dtoCronjobs []dto.CronjobInfo
for _, cronjob := range cronjobs { for _, cronjob := range cronjobs {
var item dto.CronjobInfo var item dto.CronjobInfo
@@ -56,9 +53,9 @@ func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, inter
} }
record, _ := cronjobRepo.RecordFirst(cronjob.ID) record, _ := cronjobRepo.RecordFirst(cronjob.ID)
if record.ID != 0 { if record.ID != 0 {
item.LastRecordTime = record.StartTime.Format("2006-01-02 15:04:05") item.LastRecrodTime = record.StartTime.Format("2006-01-02 15:04:05")
} else { } else {
item.LastRecordTime = "-" item.LastRecrodTime = "-"
} }
dtoCronjobs = append(dtoCronjobs, item) dtoCronjobs = append(dtoCronjobs, item)
} }
@@ -83,27 +80,12 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
return total, dtoCronjobs, err return total, dtoCronjobs, err
} }
func (u *CronjobService) LoadRecordLog(req dto.OperateByID) (string, error) {
record, err := cronjobRepo.GetRecord(commonRepo.WithByID(req.ID))
if err != nil {
return "", err
}
if _, err := os.Stat(record.Records); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(record.Records)
if err != nil {
return "", err
}
return string(content), nil
}
func (u *CronjobService) CleanRecord(req dto.CronjobClean) error { func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
cronjob, err := cronjobRepo.Get(commonRepo.WithByID(req.CronjobID)) cronjob, err := cronjobRepo.Get(commonRepo.WithByID(req.CronjobID))
if err != nil { if err != nil {
return err return err
} }
if req.CleanData && (cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory") { if req.CleanData && cronjob.Type != "shell" && cronjob.Type != "curl" {
cronjob.RetainCopies = 0 cronjob.RetainCopies = 0
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID))) backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
if err != nil { if err != nil {
@@ -118,9 +100,9 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
if err != nil { if err != nil {
return err return err
} }
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client) u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
} else { } else {
u.HandleRmExpired(backup.Type, backup.BackupPath, "", &cronjob, nil) u.HandleRmExpired(backup.Type, "", &cronjob, nil)
} }
} }
delRecords, err := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(req.CronjobID))) delRecords, err := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(req.CronjobID)))
@@ -141,27 +123,29 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
if record.ID == 0 { if record.ID == 0 {
return "", constant.ErrRecordNotFound return "", constant.ErrRecordNotFound
} }
cronjob, _ := cronjobRepo.Get(commonRepo.WithByID(record.CronjobID))
if cronjob.ID == 0 {
return "", constant.ErrRecordNotFound
}
backup, _ := backupRepo.Get(commonRepo.WithByID(down.BackupAccountID)) backup, _ := backupRepo.Get(commonRepo.WithByID(down.BackupAccountID))
if backup.ID == 0 { if cronjob.ID == 0 {
return "", constant.ErrRecordNotFound return "", constant.ErrRecordNotFound
} }
if backup.Type == "LOCAL" || record.FromLocal { if backup.Type == "LOCAL" || record.FromLocal {
if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) { if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) {
return "", err return "", constant.ErrRecordNotFound
} }
return record.File, nil return record.File, nil
} }
client, err := NewIBackupService().NewClient(&backup)
if err != nil {
return "", err
}
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, record.File) tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, record.File)
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) { _ = os.MkdirAll(path.Dir(tempPath), os.ModePerm)
client, err := NewIBackupService().NewClient(&backup) isOK, err := client.Download(record.File, tempPath)
if err != nil { if !isOK || err != nil {
return "", err return "", constant.ErrRecordNotFound
}
_ = os.MkdirAll(path.Dir(tempPath), os.ModePerm)
isOK, err := client.Download(record.File, tempPath)
if !isOK || err != nil {
return "", err
}
} }
return tempPath, nil return tempPath, nil
} }
@@ -206,6 +190,7 @@ func (u *CronjobService) StartJob(cronjob *model.Cronjob) (int, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
global.LOG.Debug(global.Cron.Entries())
return entryID, nil return entryID, nil
} }
@@ -237,30 +222,24 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
if err != nil { if err != nil {
return constant.ErrRecordNotFound return constant.ErrRecordNotFound
} }
upMap := make(map[string]interface{})
cronjob.EntryID = cronModel.EntryID cronjob.EntryID = cronModel.EntryID
cronjob.Type = cronModel.Type cronjob.Type = cronModel.Type
cronjob.Spec = loadSpec(cronjob) cronjob.Spec = loadSpec(cronjob)
if cronModel.Status == constant.StatusEnable { newEntryID, err := u.StartJob(&cronjob)
newEntryID, err := u.StartJob(&cronjob) if err != nil {
if err != nil { return err
return err
}
upMap["entry_id"] = newEntryID
} else {
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
} }
upMap := make(map[string]interface{})
upMap["entry_id"] = newEntryID
upMap["name"] = req.Name upMap["name"] = req.Name
upMap["spec"] = cronjob.Spec upMap["spec"] = cronjob.Spec
upMap["script"] = req.Script upMap["script"] = req.Script
upMap["container_name"] = req.ContainerName
upMap["spec_type"] = req.SpecType upMap["spec_type"] = req.SpecType
upMap["week"] = req.Week upMap["week"] = req.Week
upMap["day"] = req.Day upMap["day"] = req.Day
upMap["hour"] = req.Hour upMap["hour"] = req.Hour
upMap["minute"] = req.Minute upMap["minute"] = req.Minute
upMap["second"] = req.Second
upMap["website"] = req.Website upMap["website"] = req.Website
upMap["exclusion_rules"] = req.ExclusionRules upMap["exclusion_rules"] = req.ExclusionRules
upMap["db_name"] = req.DBName upMap["db_name"] = req.DBName
@@ -343,8 +322,6 @@ func loadSpec(cronjob model.Cronjob) string {
return fmt.Sprintf("%v * * * *", cronjob.Minute) return fmt.Sprintf("%v * * * *", cronjob.Minute)
case "perNMinute": case "perNMinute":
return fmt.Sprintf("@every %vm", cronjob.Minute) return fmt.Sprintf("@every %vm", cronjob.Minute)
case "perNSecond":
return fmt.Sprintf("@every %vs", cronjob.Second)
default: default:
return "" return ""
} }

View File

@@ -5,18 +5,15 @@ import (
"fmt" "fmt"
"os" "os"
"path" "path"
"strconv"
"strings" "strings"
"sync"
"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/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@@ -32,35 +29,31 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
if len(cronjob.Script) == 0 { if len(cronjob.Script) == 0 {
return return
} }
if len(cronjob.ContainerName) != 0 { stdout, errExec := cmd.ExecWithTimeOut(cronjob.Script, 5*time.Minute)
message, err = u.handleShell(cronjob.Type, cronjob.Name, fmt.Sprintf("docker exec %s %s", cronjob.ContainerName, cronjob.Script)) if errExec != nil {
} else { err = errExec
message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script)
} }
u.HandleRmExpired("LOCAL", "", "", cronjob, nil) message = []byte(stdout)
case "curl": u.HandleRmExpired("LOCAL", "", cronjob, nil)
if len(cronjob.URL) == 0 {
return
}
message, err = u.handleShell(cronjob.Type, cronjob.Name, fmt.Sprintf("curl '%s'", cronjob.URL))
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
case "ntp":
err = u.handleNtpSync()
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":
record.File, err = u.handleBackup(cronjob, record.StartTime) record.File, err = u.HandleBackup(cronjob, record.StartTime)
case "directory": case "directory":
if len(cronjob.SourceDir) == 0 { if len(cronjob.SourceDir) == 0 {
return return
} }
record.File, err = u.handleBackup(cronjob, record.StartTime) record.File, err = u.HandleBackup(cronjob, record.StartTime)
case "cutWebsiteLog": case "curl":
record.File, err = u.handleCutWebsiteLog(cronjob, record.StartTime) if len(cronjob.URL) == 0 {
if err != nil { return
global.LOG.Errorf("cut website log file failed, err: %v", err)
} }
stdout, errCurl := cmd.ExecWithTimeOut("curl "+cronjob.URL, 5*time.Minute)
if err != nil {
err = errCurl
}
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))
@@ -76,36 +69,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
}() }()
} }
func (u *CronjobService) handleShell(cronType, cornName, script string) ([]byte, error) { func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
handleDir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronType, cornName)
if _, err := os.Stat(handleDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(handleDir, os.ModePerm); err != nil {
return nil, err
}
}
stdout, err := cmd.ExecCronjobWithTimeOut(script, handleDir, 24*time.Hour)
if err != nil {
return nil, err
}
return []byte(stdout), nil
}
func (u *CronjobService) handleNtpSync() error {
ntpServer, err := settingRepo.Get(settingRepo.WithByKey("NtpSite"))
if err != nil {
return err
}
ntime, err := ntp.GetRemoteTime(ntpServer.Value)
if err != nil {
return err
}
if err := ntp.UpdateSystemTime(ntime.Format("2006-01-02 15:04:05")); err != nil {
return err
}
return nil
}
func (u *CronjobService) handleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
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
@@ -118,14 +82,18 @@ func (u *CronjobService) handleBackup(cronjob *model.Cronjob, startTime time.Tim
switch cronjob.Type { switch cronjob.Type {
case "database": case "database":
paths, err := u.handleDatabase(*cronjob, backup, startTime) app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return "", err
}
paths, err := u.handleDatabase(*cronjob, app, backup, startTime)
return strings.Join(paths, ","), err return strings.Join(paths, ","), err
case "website": case "website":
paths, err := u.handleWebsite(*cronjob, backup, startTime) paths, err := u.handleWebsite(*cronjob, backup, startTime)
return strings.Join(paths, ","), err return strings.Join(paths, ","), err
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 := path.Join(localDir, fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name)) backupDir := fmt.Sprintf("%s/%s/%s", localDir, cronjob.Type, cronjob.Name)
itemFileDir := fmt.Sprintf("%s/%s", 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 {
@@ -142,55 +110,37 @@ func (u *CronjobService) handleBackup(cronjob *model.Cronjob, startTime time.Tim
if err != nil { if err != nil {
return "", err return "", err
} }
if len(backup.BackupPath) != 0 {
itemPath := strings.TrimPrefix(backup.BackupPath, "/")
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
itemFileDir = itemPath + itemFileDir
}
if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil { if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil {
return "", err return "", err
} }
} }
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, cronjob, client) u.HandleRmExpired(backup.Type, localDir, cronjob, client)
if backup.Type == "LOCAL" || cronjob.KeepLocal { if backup.Type == "LOCAL" || cronjob.KeepLocal {
return fmt.Sprintf("%s/%s", backupDir, fileName), nil return fmt.Sprintf("%s/%s/%s/%s", localDir, cronjob.Type, cronjob.Name, fileName), nil
} else {
return fmt.Sprintf("%s/%s", itemFileDir, fileName), nil
} }
return fmt.Sprintf("%s/%s/%s", cronjob.Type, cronjob.Name, fileName), nil
} }
} }
func (u *CronjobService) HandleRmExpired(backType, backupPath, localDir string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) { 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) 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")) 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) {
return for i := int(cronjob.RetainCopies); i < len(records); i++ {
}
for i := int(cronjob.RetainCopies); i < len(records); i++ {
if len(records[i].File) != 0 {
files := strings.Split(records[i].File, ",") files := strings.Split(records[i].File, ",")
for _, file := range files { for _, file := range files {
_ = os.Remove(file) 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))) _ = backupRepo.DeleteRecord(context.TODO(), backupRepo.WithByFileName(path.Base(file)))
if backType == "LOCAL" {
continue
}
fileItem := file
if cronjob.KeepLocal {
if len(backupPath) != 0 {
itemPath := strings.TrimPrefix(backupPath, "/")
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
fileItem = itemPath + strings.TrimPrefix(file, localDir+"/")
} else {
fileItem = strings.TrimPrefix(file, localDir+"/")
}
}
_, _ = backClient.Delete(fileItem)
} }
_ = cronjobRepo.DeleteRecord(commonRepo.WithByID(uint(records[i].ID)))
_ = os.Remove(records[i].Records)
} }
_ = cronjobRepo.DeleteRecord(commonRepo.WithByID(uint(records[i].ID)))
_ = os.Remove(records[i].Records)
} }
} }
@@ -201,21 +151,18 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
} }
} }
excludes := strings.Split(exclusionRules, ",") excludes := strings.Split(exclusionRules, ";")
excludeRules := "" excludeRules := ""
for _, exclude := range excludes { for _, exclude := range excludes {
if len(exclude) == 0 { if len(exclude) == 0 {
continue continue
} }
excludeRules += " --exclude " + exclude excludeRules += (" --exclude " + exclude)
} }
path := "" path := ""
if strings.Contains(sourceDir, "/") { if strings.Contains(sourceDir, "/") {
itemDir := strings.ReplaceAll(sourceDir[strings.LastIndex(sourceDir, "/"):], "/", "") itemDir := strings.ReplaceAll(sourceDir[strings.LastIndex(sourceDir, "/"):], "/", "")
aheadDir := sourceDir[:strings.LastIndex(sourceDir, "/")] aheadDir := strings.ReplaceAll(sourceDir, itemDir, "")
if len(aheadDir) == 0 {
aheadDir = "/"
}
path += fmt.Sprintf("-C %s %s", aheadDir, itemDir) path += fmt.Sprintf("-C %s %s", aheadDir, itemDir)
} else { } else {
path = sourceDir path = sourceDir
@@ -223,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.ExecWithTimeOut(commands, 24*time.Hour) 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)
@@ -240,7 +187,7 @@ 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.ExecWithTimeOut(commands, 24*time.Hour) 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)
@@ -248,25 +195,22 @@ func handleUnTar(sourceFile, targetDir string) error {
return nil return nil
} }
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) { func (u *CronjobService) handleDatabase(cronjob model.Cronjob, app *repo.RootInfo, backup model.BackupAccount, startTime time.Time) ([]string, error) {
var paths []string var paths []string
localDir, err := loadLocalDir() localDir, err := loadLocalDir()
if err != nil { if err != nil {
return paths, err return paths, err
} }
var dbs []model.DatabaseMysql var dblist []string
if cronjob.DBName == "all" { if cronjob.DBName == "all" {
dbs, err = mysqlRepo.List() mysqlService := NewIMysqlService()
dblist, err = mysqlService.ListDBName()
if err != nil { if err != nil {
return paths, err return paths, err
} }
} else { } else {
itemID, _ := (strconv.Atoi(cronjob.DBName)) dblist = append(dblist, cronjob.DBName)
dbs, err = mysqlRepo.List(commonRepo.WithByID(uint(itemID)))
if err != nil {
return paths, err
}
} }
var client cloud_storage.CloudStorageClient var client cloud_storage.CloudStorageClient
@@ -277,27 +221,27 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.Back
} }
} }
for _, dbInfo := range dbs { for _, dbName := range dblist {
var record model.BackupRecord var record model.BackupRecord
record.Type = "mysql" record.Type = "mysql"
record.Name = app.Name
record.Source = "LOCAL" record.Source = "LOCAL"
record.BackupType = backup.Type record.BackupType = backup.Type
record.Name = dbInfo.MysqlName backupDir := fmt.Sprintf("%s/database/mysql/%s/%s", localDir, app.Name, dbName)
backupDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", record.Name, dbInfo.Name)) record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbName, startTime.Format("20060102150405"))
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405")) if err = handleMysqlBackup(app, backupDir, dbName, record.FileName); err != nil {
if err = handleMysqlBackup(dbInfo.MysqlName, dbInfo.Name, backupDir, record.FileName); err != nil {
return paths, err return paths, err
} }
record.DetailName = dbName
record.DetailName = dbInfo.Name
record.FileDir = backupDir record.FileDir = backupDir
itemFileDir := strings.TrimPrefix(backupDir, localDir+"/") itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
if !cronjob.KeepLocal && backup.Type != "LOCAL" { if !cronjob.KeepLocal && backup.Type != "LOCAL" {
record.Source = backup.Type record.Source = backup.Type
record.FileDir = itemFileDir record.FileDir = itemFileDir
} }
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
if err := backupRepo.CreateRecord(&record); err != nil { if err := backupRepo.CreateRecord(&record); err != nil {
global.LOG.Errorf("save backup record failed, err: %v", err) global.LOG.Errorf("save backup record failed, err: %v", err)
@@ -309,91 +253,15 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.Back
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName)) _ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
}() }()
} }
if len(backup.BackupPath) != 0 {
itemPath := strings.TrimPrefix(backup.BackupPath, "/")
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
itemFileDir = itemPath + itemFileDir
}
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil { if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
return paths, err return paths, err
} }
} }
if backup.Type == "LOCAL" || cronjob.KeepLocal {
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
} else {
paths = append(paths, fmt.Sprintf("%s/%s", itemFileDir, record.FileName))
}
} }
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client) u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
return paths, nil return paths, nil
} }
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time) (string, error) {
var (
websites []string
err error
filePaths []string
)
if cronjob.Website == "all" {
websites, _ = NewIWebsiteService().GetWebsiteOptions()
if len(websites) == 0 {
return "", nil
}
} else {
websites = append(websites, cronjob.Website)
}
nginx, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return "", nil
}
baseDir := path.Join(nginx.GetPath(), "www", "sites")
fileOp := files.NewFileOp()
var wg sync.WaitGroup
wg.Add(len(websites))
for _, websiteName := range websites {
name := websiteName
go func() {
website, _ := websiteRepo.GetFirst(websiteRepo.WithDomain(name))
if website.ID == 0 {
wg.Done()
return
}
websiteLogDir := path.Join(baseDir, website.Alias, "log")
srcAccessLogPath := path.Join(websiteLogDir, "access.log")
srcErrorLogPath := path.Join(websiteLogDir, "error.log")
dstLogDir := path.Join(global.CONF.System.Backup, "log", "website", website.Alias)
if !fileOp.Stat(dstLogDir) {
_ = os.MkdirAll(dstLogDir, 0755)
}
dstName := fmt.Sprintf("%s_log_%s.gz", website.PrimaryDomain, startTime.Format("20060102150405"))
filePaths = append(filePaths, path.Join(dstLogDir, dstName))
if err = fileOp.Compress([]string{srcAccessLogPath, srcErrorLogPath}, dstLogDir, dstName, files.Gz); err != nil {
global.LOG.Errorf("There was an error in compressing the website[%s] access.log, err: %v", website.PrimaryDomain, err)
} else {
_ = fileOp.WriteFile(srcAccessLogPath, strings.NewReader(""), 0755)
_ = fileOp.WriteFile(srcErrorLogPath, strings.NewReader(""), 0755)
}
global.LOG.Infof("The website[%s] log file was successfully rotated in the directory [%s]", website.PrimaryDomain, dstLogDir)
var record model.BackupRecord
record.Type = "cutWebsiteLog"
record.Name = cronjob.Website
record.Source = "LOCAL"
record.BackupType = "LOCAL"
record.FileDir = dstLogDir
record.FileName = dstName
if err = backupRepo.CreateRecord(&record); err != nil {
global.LOG.Errorf("save backup record failed, err: %v", err)
}
wg.Done()
}()
}
wg.Wait()
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
return strings.Join(filePaths, ","), nil
}
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) { func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
var paths []string var paths []string
localDir, err := loadLocalDir() localDir, err := loadLocalDir()
@@ -429,14 +297,15 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.Backu
if err != nil { if err != nil {
return paths, err return paths, err
} }
backupDir := path.Join(localDir, fmt.Sprintf("website/%s", website.PrimaryDomain)) backupDir := fmt.Sprintf("%s/website/%s", localDir, website.PrimaryDomain)
record.FileDir = backupDir record.FileDir = backupDir
itemFileDir := strings.TrimPrefix(backupDir, localDir+"/") itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
if !cronjob.KeepLocal && backup.Type != "LOCAL" { if !cronjob.KeepLocal && backup.Type != "LOCAL" {
record.Source = backup.Type record.Source = backup.Type
record.FileDir = strings.TrimPrefix(backupDir, localDir+"/") record.FileDir = strings.ReplaceAll(backupDir, localDir+"/", "")
} }
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", website.PrimaryDomain, startTime.Format("20060102150405")) 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 { if err := handleWebsiteBackup(&website, backupDir, record.FileName); err != nil {
return paths, err return paths, err
} }
@@ -451,21 +320,11 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.Backu
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName)) _ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
}() }()
} }
if len(backup.BackupPath) != 0 {
itemPath := strings.TrimPrefix(backup.BackupPath, "/")
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
itemFileDir = itemPath + itemFileDir
}
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil { if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
return paths, err return paths, err
} }
} }
if backup.Type == "LOCAL" || cronjob.KeepLocal {
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
} else {
paths = append(paths, fmt.Sprintf("%s/%s", itemFileDir, record.FileName))
}
} }
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client) u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
return paths, nil return paths, nil
} }

View File

@@ -7,7 +7,6 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@@ -18,11 +17,8 @@ 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/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/compose" "github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/mysql"
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -31,13 +27,12 @@ import (
type MysqlService struct{} type MysqlService struct{}
type IMysqlService interface { type IMysqlService interface {
SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
ListDBOption() ([]dto.MysqlOption, error) ListDBName() ([]string, error)
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
LoadFromRemote(from string) error
ChangeAccess(info dto.ChangeDBInfo) error ChangeAccess(info dto.ChangeDBInfo) error
ChangePassword(info dto.ChangeDBInfo) error ChangePassword(info dto.ChangeDBInfo) error
UpdateVariables(updates []dto.MysqlVariablesUpdate) error UpdateVariables(updatas []dto.MysqlVariablesUpdate) error
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
UpdateDescription(req dto.UpdateDescription) error UpdateDescription(req dto.UpdateDescription) error
DeleteCheck(id uint) ([]string, error) DeleteCheck(id uint) ([]string, error)
@@ -46,20 +41,14 @@ type IMysqlService interface {
LoadVariables() (*dto.MysqlVariables, error) LoadVariables() (*dto.MysqlVariables, error)
LoadBaseInfo() (*dto.DBBaseInfo, error) LoadBaseInfo() (*dto.DBBaseInfo, error)
LoadRemoteAccess() (bool, error) LoadRemoteAccess() (bool, error)
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
} }
func NewIMysqlService() IMysqlService { func NewIMysqlService() IMysqlService {
return &MysqlService{} return &MysqlService{}
} }
func (u *MysqlService) SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) { func (u *MysqlService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info))
mysqlRepo.WithByFrom(search.From),
commonRepo.WithLikeName(search.Info),
commonRepo.WithOrderRuleBy(search.OrderBy, search.Order),
)
var dtoMysqls []dto.MysqlDBInfo var dtoMysqls []dto.MysqlDBInfo
for _, mysql := range mysqls { for _, mysql := range mysqls {
var item dto.MysqlDBInfo var item dto.MysqlDBInfo
@@ -71,115 +60,70 @@ func (u *MysqlService) SearchWithPage(search dto.MysqlDBSearch) (int64, interfac
return total, dtoMysqls, err return total, dtoMysqls, err
} }
func (u *MysqlService) ListDBOption() ([]dto.MysqlOption, error) { func (u *MysqlService) ListDBName() ([]string, error) {
mysqls, err := mysqlRepo.List() mysqls, err := mysqlRepo.List()
var dbs []dto.MysqlOption var dbNames []string
for _, mysql := range mysqls { for _, mysql := range mysqls {
var item dto.MysqlOption dbNames = append(dbNames, mysql.Name)
if err := copier.Copy(&item, &mysql); err != nil {
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
dbs = append(dbs, item)
} }
return dbs, err return dbNames, err
}
var formatMap = map[string]string{
"utf8": "utf8_general_ci",
"utf8mb4": "utf8mb4_general_ci",
"gbk": "gbk_chinese_ci",
"big5": "big5_chinese_ci",
} }
func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) { func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) {
if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format, req.Permission) { if req.Username == "root" {
return nil, buserr.New(constant.ErrCmdIllegal)
}
mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name), remoteDBRepo.WithByFrom(req.From))
if mysql.ID != 0 {
return nil, constant.ErrRecordExist
}
var createItem model.DatabaseMysql
if err := copier.Copy(&createItem, &req); err != nil {
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
if req.From == "local" && req.Username == "root" {
return nil, errors.New("Cannot set root as user name") return nil, errors.New("Cannot set root as user name")
} }
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
cli, version, err := LoadMysqlClientByFrom(req.From)
if err != nil { if err != nil {
return nil, err return nil, err
} }
mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name))
if req.From == "local" { if mysql.ID != 0 {
app, err := appInstallRepo.LoadBaseInfo("mysql", "") return nil, constant.ErrRecordExist
if err != nil {
return nil, err
}
createItem.MysqlName = app.Name
} else {
createItem.MysqlName = req.From
} }
defer cli.Close() if err := copier.Copy(&mysql, &req); err != nil {
if err := cli.Create(client.CreateInfo{ return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
Name: req.Name, }
Format: req.Format,
Username: req.Username, createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", req.Name, req.Format, formatMap[req.Format])
Password: req.Password, if err := excSQL(app.ContainerName, app.Password, createSql); err != nil {
Permission: req.Permission, if strings.Contains(err.Error(), "ERROR 1007") {
Version: version, return nil, buserr.New(constant.ErrDatabaseIsExist)
Timeout: 300, }
}); err != nil { return nil, err
}
tmpPermission := req.Permission
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
if strings.Contains(err.Error(), "ERROR 1396") {
return nil, buserr.New(constant.ErrUserIsExist)
}
return nil, err
}
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" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
}
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
return nil, err return nil, err
} }
global.LOG.Infof("create database %s successful!", req.Name) global.LOG.Infof("create database %s successful!", req.Name)
if err := mysqlRepo.Create(ctx, &createItem); err != nil { mysql.MysqlName = app.Name
if err := mysqlRepo.Create(ctx, &mysql); err != nil {
return nil, err return nil, err
} }
return &createItem, nil return &mysql, nil
}
func (u *MysqlService) LoadFromRemote(from string) error {
client, version, err := LoadMysqlClientByFrom(from)
if err != nil {
return err
}
mysqlName := from
if from == "local" {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
mysqlName = app.Name
}
databases, err := mysqlRepo.List(remoteDBRepo.WithByFrom(from))
if err != nil {
return err
}
datas, err := client.SyncDB(version)
if err != nil {
return err
}
for _, data := range datas {
hasOld := false
for _, oldData := range databases {
if strings.EqualFold(oldData.Name, data.Name) {
hasOld = true
break
}
}
if !hasOld {
var createItem model.DatabaseMysql
if err := copier.Copy(&createItem, &data); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
createItem.MysqlName = mysqlName
if err := mysqlRepo.Create(context.Background(), &createItem); err != nil {
return err
}
}
}
return nil
} }
func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error { func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
@@ -188,62 +132,46 @@ func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
func (u *MysqlService) DeleteCheck(id uint) ([]string, error) { func (u *MysqlService) DeleteCheck(id uint) ([]string, error) {
var appInUsed []string var appInUsed []string
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return appInUsed, err
}
db, err := mysqlRepo.Get(commonRepo.WithByID(id)) db, err := mysqlRepo.Get(commonRepo.WithByID(id))
if err != nil { if err != nil {
return appInUsed, err return appInUsed, err
} }
if db.From == "local" { apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(db.ID))
app, err := appInstallRepo.LoadBaseInfo("mysql", "") for _, app := range apps {
if err != nil { appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
return appInUsed, err if appInstall.ID != 0 {
} appInUsed = append(appInUsed, appInstall.Name)
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(db.ID))
for _, app := range apps {
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
if appInstall.ID != 0 {
appInUsed = append(appInUsed, appInstall.Name)
}
}
} else {
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(db.ID))
for _, app := range apps {
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
if appInstall.ID != 0 {
appInUsed = append(appInUsed, appInstall.Name)
}
} }
} }
return appInUsed, nil return appInUsed, nil
} }
func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error { func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error {
db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
if err != nil && !req.ForceDelete {
return err
}
cli, version, err := LoadMysqlClientByFrom(db.From)
if err != nil {
return err
}
defer cli.Close()
if err := cli.Delete(client.DeleteInfo{
Name: db.Name,
Version: version,
Username: db.Username,
Permission: db.Permission,
Timeout: 300,
}); err != nil {
return err
}
app, err := appInstallRepo.LoadBaseInfo("mysql", "") app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil && !req.ForceDelete { if err != nil && !req.ForceDelete {
return err return err
} }
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/mysql/%s/%s", app.Name, db.Name)) db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
if err != nil && !req.ForceDelete {
return err
}
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
}
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
return err
}
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
uploadDir := fmt.Sprintf("%s/1panel/uploads/database/mysql/%s/%s", global.CONF.System.BaseDir, app.Name, db.Name)
if _, err := os.Stat(uploadDir); err == nil { if _, err := os.Stat(uploadDir); err == nil {
_ = os.RemoveAll(uploadDir) _ = os.RemoveAll(uploadDir)
} }
@@ -252,7 +180,7 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
if err != nil && !req.ForceDelete { if err != nil && !req.ForceDelete {
return err return err
} }
backupDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", db.MysqlName, db.Name)) backupDir := fmt.Sprintf("%s/database/mysql/%s/%s", localDir, db.MysqlName, db.Name)
if _, err := os.Stat(backupDir); err == nil { if _, err := os.Stat(backupDir); err == nil {
_ = os.RemoveAll(backupDir) _ = os.RemoveAll(backupDir)
} }
@@ -265,48 +193,27 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
} }
func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error { func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
if cmd.CheckIllegal(info.Value) {
return buserr.New(constant.ErrCmdIllegal)
}
cli, version, err := LoadMysqlClientByFrom(info.From)
if err != nil {
return err
}
defer cli.Close()
var ( var (
mysqlData model.DatabaseMysql mysql model.DatabaseMysql
passwordInfo client.PasswordChangeInfo err error
) )
passwordInfo.Password = info.Value
passwordInfo.Timeout = 300
passwordInfo.Version = version
if info.ID != 0 { if info.ID != 0 {
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID)) mysql, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
if err != nil { if err != nil {
return err return err
} }
passwordInfo.Name = mysqlData.Name
passwordInfo.Username = mysqlData.Username
passwordInfo.Permission = mysqlData.Permission
} else {
passwordInfo.Username = "root"
} }
if err := cli.ChangePassword(passwordInfo); err != nil { app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err return err
} }
passwordChangeCMD := fmt.Sprintf("set password for '%s'@'%s' = password('%s')", mysql.Username, mysql.Permission, info.Value)
if app.Version != "5.7.39" {
passwordChangeCMD = fmt.Sprintf("ALTER USER '%s'@'%s' IDENTIFIED WITH mysql_native_password BY '%s';", mysql.Username, mysql.Permission, info.Value)
}
if info.ID != 0 { if info.ID != 0 {
var appRess []model.AppInstallResource appRess, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(mysql.ID))
if info.From == "local" {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
appRess, _ = appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(mysqlData.ID))
} else {
appRess, _ = appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(mysqlData.ID))
}
for _, appRes := range appRess { for _, appRes := range appRess {
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(appRes.AppInstallId)) appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(appRes.AppInstallId))
if err != nil { if err != nil {
@@ -322,11 +229,29 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
return err return err
} }
} }
if err := excuteSql(app.ContainerName, app.Password, passwordChangeCMD); err != nil {
return err
}
global.LOG.Info("excute password change sql successful") global.LOG.Info("excute password change sql successful")
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"password": info.Value}) _ = mysqlRepo.Update(mysql.ID, map[string]interface{}{"password": info.Value})
return nil return nil
} }
hosts, err := excuteSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
if err != nil {
return err
}
for _, host := range hosts {
if host == "%" || host == "localhost" {
passwordRootChangeCMD := fmt.Sprintf("set password for 'root'@'%s' = password('%s')", host, info.Value)
if app.Version != "5.7.39" {
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified with mysql_native_password BY '%s';", host, info.Value)
}
if err := excuteSql(app.ContainerName, app.Password, passwordRootChangeCMD); err != nil {
return err
}
}
}
if err := updateInstallInfoInDB("mysql", "", "password", false, info.Value); err != nil { if err := updateInstallInfoInDB("mysql", "", "password", false, info.Value); err != nil {
return err return err
} }
@@ -337,42 +262,57 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
} }
func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error { func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
if cmd.CheckIllegal(info.Value) {
return buserr.New(constant.ErrCmdIllegal)
}
cli, version, err := LoadMysqlClientByFrom(info.From)
if err != nil {
return err
}
defer cli.Close()
var ( var (
mysqlData model.DatabaseMysql mysql model.DatabaseMysql
accessInfo client.AccessChangeInfo err error
) )
accessInfo.Permission = info.Value
accessInfo.Timeout = 300
accessInfo.Version = version
if info.ID != 0 { if info.ID != 0 {
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID)) mysql, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
if err != nil { if err != nil {
return err return err
} }
accessInfo.Name = mysqlData.Name
accessInfo.Username = mysqlData.Username
accessInfo.Password = mysqlData.Password
accessInfo.OldPermission = mysqlData.Permission
} else {
accessInfo.Username = "root"
} }
if err := cli.ChangeAccess(accessInfo); err != nil { app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err return err
} }
if info.ID == 0 {
if mysqlData.ID != 0 { mysql.Name = "*"
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"permission": info.Value}) mysql.Username = "root"
mysql.Permission = "%"
mysql.Password = app.Password
} }
if info.Value != mysql.Permission {
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", mysql.Username, mysql.Permission)); err != nil {
return err
}
if info.ID == 0 {
return 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
}
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" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
}
if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
return err
}
if err := excuteSql(app.ContainerName, app.Password, "flush privileges"); err != nil {
return err
}
if info.ID == 0 {
return nil
}
_ = mysqlRepo.Update(mysql.ID, map[string]interface{}{"permission": info.Value})
return nil return nil
} }
@@ -396,7 +336,7 @@ func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error {
return nil return nil
} }
func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error { func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error {
app, err := appInstallRepo.LoadBaseInfo("mysql", "") app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil { if err != nil {
return err return err
@@ -411,8 +351,8 @@ func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error
files = strings.Split(string(lineBytes), "\n") files = strings.Split(string(lineBytes), "\n")
group := "[mysqld]" group := "[mysqld]"
for _, info := range updates { for _, info := range updatas {
if !strings.HasPrefix(app.Version, "5.7") && !strings.HasPrefix(app.Version, "5.6") { if app.Version != "5.7.39" {
if info.Param == "query_cache_size" { if info.Param == "query_cache_size" {
continue continue
} }
@@ -535,26 +475,6 @@ func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
return &info, nil return &info, nil
} }
func (u *MysqlService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
filePath := ""
switch req.Type {
case "mysql-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
case "redis-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
case "slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) { func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command) cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
@@ -584,6 +504,31 @@ func excuteSqlForRows(containerName, password, command string) ([]string, error)
return strings.Split(stdStr, "\n"), nil return strings.Split(stdStr, "\n"), nil
} }
func excuteSql(containerName, password, command string) error {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput()
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
return errors.New(stdStr)
}
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
@@ -624,41 +569,3 @@ func updateMyCnf(oldFiles []string, group string, param string, value interface{
} }
return newFiles return newFiles
} }
func LoadMysqlClientByFrom(from string) (mysql.MysqlClient, string, error) {
var (
dbInfo client.DBInfo
version string
err error
)
dbInfo.From = from
dbInfo.Timeout = 300
if from != "local" {
databaseItem, err := remoteDBRepo.Get(commonRepo.WithByName(from))
if err != nil {
return nil, "", err
}
dbInfo.Address = databaseItem.Address
dbInfo.Port = databaseItem.Port
dbInfo.Username = databaseItem.Username
dbInfo.Password = databaseItem.Password
version = databaseItem.Version
} else {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return nil, "", err
}
dbInfo.Address = app.ContainerName
dbInfo.Username = "root"
dbInfo.Password = app.Password
version = app.Version
}
cli, err := mysql.NewMysqlClient(dbInfo)
if err != nil {
return nil, "", err
}
return cli, version, nil
}

View File

@@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -164,7 +163,7 @@ func (u *RedisService) SearchBackupListWithPage(req dto.PageInfo) (int64, interf
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err
} }
backupDir := path.Join(localDir, fmt.Sprintf("database/redis/%s", redisInfo.Name)) backupDir := fmt.Sprintf("%s/database/redis/%s", localDir, redisInfo.Name)
_ = filepath.Walk(backupDir, func(path string, info os.FileInfo, err error) error { _ = filepath.Walk(backupDir, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return nil return nil

View File

@@ -4,7 +4,6 @@ import (
"bufio" "bufio"
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"path" "path"
"strings" "strings"
@@ -19,8 +18,7 @@ import (
type DockerService struct{} type DockerService struct{}
type IDockerService interface { type IDockerService interface {
UpdateConf(req dto.SettingUpdate) error UpdateConf(req dto.DaemonJsonConf) error
UpdateLogOption(req dto.LogOption) error
UpdateConfByFile(info dto.DaemonJsonUpdateByFile) error UpdateConfByFile(info dto.DaemonJsonUpdateByFile) error
LoadDockerStatus() string LoadDockerStatus() string
LoadDockerConf() *dto.DaemonJsonConf LoadDockerConf() *dto.DaemonJsonConf
@@ -32,54 +30,46 @@ func NewIDockerService() IDockerService {
} }
type daemonJsonItem struct { type daemonJsonItem struct {
Status string `json:"status"` Status string `json:"status"`
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"` IPTables bool `json:"iptables"`
ExecOpts []string `json:"exec-opts"` ExecOpts []string `json:"exec-opts"`
LogOption logOption `json:"log-opts"`
}
type logOption struct {
LogMaxSize string `json:"max-size"`
LogMaxFile string `json:"max-file"`
} }
func (u *DockerService) LoadDockerStatus() string { func (u *DockerService) LoadDockerStatus() string {
client, err := docker.NewDockerClient() status := constant.StatusRunning
if err != nil { stdout, err := cmd.Exec("systemctl is-active docker")
return constant.Stopped if string(stdout) != "active\n" || err != nil {
} status = constant.Stopped
if _, err := client.Ping(context.Background()); err != nil {
return constant.Stopped
} }
return constant.StatusRunning return status
} }
func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf { func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
ctx := context.Background()
var data dto.DaemonJsonConf var data dto.DaemonJsonConf
data.IPTables = true data.IPTables = true
data.Status = constant.StatusRunning data.Status = constant.StatusRunning
data.Version = "-" stdout, err := cmd.Exec("systemctl is-active docker")
client, err := docker.NewDockerClient() if string(stdout) != "active\n" || err != nil {
if err != nil {
data.Status = constant.Stopped data.Status = constant.Stopped
} else {
if _, err := client.Ping(ctx); err != nil {
data.Status = constant.Stopped
}
itemVersion, err := client.ServerVersion(ctx)
if err == nil {
data.Version = itemVersion.Version
}
} }
data.IsSwarm = false data.IsSwarm = false
stdout2, _ := cmd.Exec("docker info | grep Swarm") stdout2, _ := cmd.Exec("docker info | grep Swarm")
if string(stdout2) == " Swarm: active\n" { if string(stdout2) == " Swarm: active\n" {
data.IsSwarm = true data.IsSwarm = true
} }
data.Version = "-"
client, err := docker.NewDockerClient()
if err == nil {
ctx := context.Background()
itemVersion, err := client.ServerVersion(ctx)
if err == nil {
data.Version = itemVersion.Version
}
}
if _, err := os.Stat(constant.DaemonJsonPath); err != nil { if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
return &data return &data
} }
@@ -88,19 +78,18 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
return &data return &data
} }
var conf daemonJsonItem var conf daemonJsonItem
daemonMap := make(map[string]interface{}) deamonMap := make(map[string]interface{})
if err := json.Unmarshal(file, &daemonMap); err != nil { if err := json.Unmarshal(file, &deamonMap); err != nil {
return &data return &data
} }
arr, err := json.Marshal(daemonMap) arr, err := json.Marshal(deamonMap)
if err != nil { if err != nil {
return &data return &data
} }
if err := json.Unmarshal(arr, &conf); err != nil { if err := json.Unmarshal(arr, &conf); err != nil {
fmt.Println(err)
return &data return &data
} }
if _, ok := daemonMap["iptables"]; !ok { if _, ok := deamonMap["iptables"]; !ok {
conf.IPTables = true conf.IPTables = true
} }
data.CgroupDriver = "cgroupfs" data.CgroupDriver = "cgroupfs"
@@ -110,8 +99,6 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
break break
} }
} }
data.LogMaxSize = conf.LogOption.LogMaxSize
data.LogMaxFile = conf.LogOption.LogMaxFile
data.Mirrors = conf.Mirrors data.Mirrors = conf.Mirrors
data.Registries = conf.Registries data.Registries = conf.Registries
data.IPTables = conf.IPTables data.IPTables = conf.IPTables
@@ -119,7 +106,7 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
return &data return &data
} }
func (u *DockerService) UpdateConf(req dto.SettingUpdate) error { func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) { if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil { if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err return err
@@ -131,98 +118,50 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
if err != nil { if err != nil {
return err return err
} }
daemonMap := make(map[string]interface{}) deamonMap := make(map[string]interface{})
_ = json.Unmarshal(file, &daemonMap) _ = json.Unmarshal(file, &deamonMap)
switch req.Key { if len(req.Registries) == 0 {
case "Registries": delete(deamonMap, "insecure-registries")
req.Value = strings.TrimSuffix(req.Value, ",") } else {
if len(req.Value) == 0 { deamonMap["insecure-registries"] = req.Registries
delete(daemonMap, "insecure-registries") }
} else { if len(req.Mirrors) == 0 {
daemonMap["insecure-registries"] = strings.Split(req.Value, ",") delete(deamonMap, "registry-mirrors")
} } else {
case "Mirrors": deamonMap["registry-mirrors"] = req.Mirrors
req.Value = strings.TrimSuffix(req.Value, ",") }
if len(req.Value) == 0 { if !req.LiveRestore {
delete(daemonMap, "registry-mirrors") delete(deamonMap, "live-restore")
} else { } else {
daemonMap["registry-mirrors"] = strings.Split(req.Value, ",") deamonMap["live-restore"] = req.LiveRestore
} }
case "LogOption": if req.IPTables {
if req.Value == "disable" { delete(deamonMap, "iptables")
delete(daemonMap, "log-opts") } else {
} deamonMap["iptables"] = false
case "LiveRestore": }
if req.Value == "disable" { if opts, ok := deamonMap["exec-opts"]; ok {
delete(daemonMap, "live-restore") if optsValue, isArray := opts.([]interface{}); isArray {
} else { for i := 0; i < len(optsValue); i++ {
daemonMap["live-restore"] = true if opt, isStr := optsValue[i].(string); isStr {
} if strings.HasPrefix(opt, "native.cgroupdriver=") {
case "IPtables": optsValue[i] = "native.cgroupdriver=" + req.CgroupDriver
if req.Value == "enable" { break
delete(daemonMap, "iptables")
} else {
daemonMap["iptables"] = false
}
case "Dirver":
if opts, ok := daemonMap["exec-opts"]; ok {
if optsValue, isArray := opts.([]interface{}); isArray {
for i := 0; i < len(optsValue); i++ {
if opt, isStr := optsValue[i].(string); isStr {
if strings.HasPrefix(opt, "native.cgroupdriver=") {
optsValue[i] = "native.cgroupdriver=" + req.Value
break
}
} }
} }
} }
} else { }
if req.Value == "systemd" { } else {
daemonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"} if req.CgroupDriver == "systemd" {
} deamonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
} }
} }
if len(daemonMap) == 0 { if len(deamonMap) == 0 {
_ = os.Remove(constant.DaemonJsonPath) _ = os.Remove(constant.DaemonJsonPath)
return nil return nil
} }
newJson, err := json.MarshalIndent(daemonMap, "", "\t") newJson, err := json.MarshalIndent(deamonMap, "", "\t")
if err != nil {
return err
}
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
return err
}
stdout, err := cmd.Exec("systemctl restart docker")
if err != nil {
return errors.New(string(stdout))
}
return nil
}
func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
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.ReadFile(constant.DaemonJsonPath)
if err != nil {
return err
}
daemonMap := make(map[string]interface{})
_ = json.Unmarshal(file, &daemonMap)
changeLogOption(daemonMap, req.LogMaxFile, req.LogMaxSize)
if len(daemonMap) == 0 {
_ = os.Remove(constant.DaemonJsonPath)
return nil
}
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
if err != nil { if err != nil {
return err return err
} }
@@ -267,7 +206,10 @@ func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
func (u *DockerService) OperateDocker(req dto.DockerOperation) error { func (u *DockerService) OperateDocker(req dto.DockerOperation) error {
service := "docker" service := "docker"
if req.Operation == "stop" { if req.Operation == "stop" {
service = "docker.socket" service = "docker.service"
if req.StopSocket {
service = "docker.socket"
}
} }
stdout, err := cmd.Execf("systemctl %s %s ", req.Operation, service) stdout, err := cmd.Execf("systemctl %s %s ", req.Operation, service)
if err != nil { if err != nil {
@@ -275,52 +217,3 @@ func (u *DockerService) OperateDocker(req dto.DockerOperation) error {
} }
return nil return nil
} }
func changeLogOption(daemonMap map[string]interface{}, logMaxFile, logMaxSize string) {
if opts, ok := daemonMap["log-opts"]; ok {
if len(logMaxFile) != 0 || len(logMaxSize) != 0 {
daemonMap["log-driver"] = "json-file"
}
optsMap, isMap := opts.(map[string]interface{})
if isMap {
if len(logMaxFile) != 0 {
optsMap["max-file"] = logMaxFile
} else {
delete(optsMap, "max-file")
}
if len(logMaxSize) != 0 {
optsMap["max-size"] = logMaxSize
} else {
delete(optsMap, "max-size")
}
if len(optsMap) == 0 {
delete(daemonMap, "log-opts")
}
} else {
optsMap := make(map[string]interface{})
if len(logMaxFile) != 0 {
optsMap["max-file"] = logMaxFile
}
if len(logMaxSize) != 0 {
optsMap["max-size"] = logMaxSize
}
if len(optsMap) != 0 {
daemonMap["log-opts"] = optsMap
}
}
} else {
if len(logMaxFile) != 0 || len(logMaxSize) != 0 {
daemonMap["log-driver"] = "json-file"
}
optsMap := make(map[string]interface{})
if len(logMaxFile) != 0 {
optsMap["max-file"] = logMaxFile
}
if len(logMaxSize) != 0 {
optsMap["max-size"] = logMaxSize
}
if len(optsMap) != 0 {
daemonMap["log-opts"] = optsMap
}
}
}

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