mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 08:00:27 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8e344db76 | ||
|
|
2c3a8dd6af | ||
|
|
86e5fc36f4 | ||
|
|
858cefc0c9 | ||
|
|
4535c0b90b | ||
|
|
136489e346 | ||
|
|
e2882fd1cc | ||
|
|
dba97076df | ||
|
|
000bcd37c1 | ||
|
|
bf28223745 | ||
|
|
1fed5c4d15 |
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.2'
|
||||
node-version: '18.14'
|
||||
- name: Build Web
|
||||
run: |
|
||||
cd frontend && npm install && npm run build:pro
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.21.x'
|
||||
go-version: '1.20.x'
|
||||
- name: Build Release
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
|
||||
+7
-9
@@ -21,6 +21,13 @@ build/1panel
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# NetBeans
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
@@ -37,15 +44,6 @@ cmd/server/web/monacoeditorwork
|
||||
cmd/server/web/index.html
|
||||
frontend/auto-imports.d.ts
|
||||
frontend/components.d.ts
|
||||
frontend/src/xpack
|
||||
backend/xpack
|
||||
backend/router/entry_xpack.go
|
||||
backend/server/init_xpack.go
|
||||
plugins/openresty/waf/db
|
||||
plugins/openresty/waf/data
|
||||
plugins/openresty/waf/sites
|
||||
plugins/openresty/waf/conf/websites.json
|
||||
|
||||
|
||||
.history/
|
||||
dist/
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
------------------------------
|
||||
|
||||
1Panel 是新一代的 Linux 服务器运维管理面板。
|
||||
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
|
||||
|
||||
- **高效管理**:用户可以通过 Web 图形界面轻松管理 Linux 服务器,实现主机监控、文件管理、数据库管理、容器管理等功能;
|
||||
- **快速建站**:深度集成开源建站软件 WordPress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等操作一键搞定;
|
||||
- **应用商店**:精选上架各类高质量的开源工具和应用软件,协助用户轻松安装并升级;
|
||||
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供防火墙和日志审计等功能;
|
||||
- **一键备份**:支持一键备份和恢复,用户可以将数据备份到各类云端存储介质,永不丢失。
|
||||
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等一键搞定;
|
||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理等;
|
||||
- **安全可靠**:基于容器来管理和部署应用,最小漏洞暴露面,提供防火墙和日志审计等功能;
|
||||
- **一键备份**:支持一键备份和恢复,备份数据到各类云端存储,永不丢失;
|
||||
- **应用商店**:精选各类高质量开源工具和应用软件,助力您轻松安装和升级。
|
||||
|
||||
## UI 展示
|
||||
|
||||
@@ -63,7 +63,7 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2014-2024 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
|
||||
+1
-1
@@ -16,6 +16,6 @@ All security bugs should be reported to the contact as below:
|
||||
- wanghe@fit2cloud.com
|
||||
- zhengkun@fit2cloud.com
|
||||
- support@fit2cloud.com
|
||||
- +86 400-052-0755
|
||||
- 400-052-0755
|
||||
|
||||
Thanks for your support!
|
||||
|
||||
@@ -6,6 +6,7 @@ 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"
|
||||
)
|
||||
|
||||
@@ -71,6 +72,10 @@ func (b *BaseApi) CheckAppInstalled(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
checkData, err := appInstallService.CheckExist(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
|
||||
@@ -49,17 +49,6 @@ func (b *BaseApi) CreateBackup(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
// @Summary Refresh OneDrive token
|
||||
// @Description 刷新 OneDrive token
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/backup/refresh/onedrive [post]
|
||||
func (b *BaseApi) RefreshOneDriveToken(c *gin.Context) {
|
||||
backupService.Run()
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
// @Summary List buckets
|
||||
// @Description 获取 bucket 列表
|
||||
@@ -102,16 +91,16 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
|
||||
// @Summary Load OneDrive info
|
||||
// @Description 获取 OneDrive 信息
|
||||
// @Accept json
|
||||
// @Success 200 {object} dto.OneDriveInfo
|
||||
// @Success 200 string clientID
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/backup/onedrive [get]
|
||||
func (b *BaseApi) LoadOneDriveInfo(c *gin.Context) {
|
||||
data, err := backupService.LoadOneDriveInfo()
|
||||
clientID, err := backupService.LoadOneDriveInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
helper.SuccessWithData(c, clientID)
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
@@ -162,32 +151,6 @@ func (b *BaseApi) SearchBackupRecords(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
// @Summary Page backup records by cronjob
|
||||
// @Description 通过计划任务获取备份记录列表分页
|
||||
// @Accept json
|
||||
// @Param request body dto.RecordSearchByCronjob true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/backup/record/search/bycronjob [post]
|
||||
func (b *BaseApi) SearchBackupRecordsByCronjob(c *gin.Context) {
|
||||
var req dto.RecordSearchByCronjob
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := backupService.SearchRecordsByCronjobWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
// @Summary Download backup record
|
||||
// @Description 下载备份记录
|
||||
@@ -302,7 +265,12 @@ func (b *BaseApi) LoadFilesFromBackup(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
data := backupService.ListFiles(req)
|
||||
data, err := backupService.ListFiles(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
@@ -313,7 +281,7 @@ func (b *BaseApi) LoadFilesFromBackup(c *gin.Context) {
|
||||
// @Param request body dto.CommonBackup true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/backup/backup [post]
|
||||
// @Router /settings/backup/ [post]
|
||||
// @x-panel-log {"bodyKeys":["type","name","detailName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"备份 [type] 数据 [name][detailName]","formatEN":"backup [type] data [name][detailName]"}
|
||||
func (b *BaseApi) Backup(c *gin.Context) {
|
||||
var req dto.CommonBackup
|
||||
@@ -332,11 +300,6 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
if err := backupService.PostgresqlBackup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case "website":
|
||||
if err := backupService.WebsiteBackup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -366,23 +329,20 @@ func (b *BaseApi) Recover(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
req.File = downloadPath
|
||||
switch req.Type {
|
||||
case "mysql", "mariadb":
|
||||
if err := backupService.MysqlRecover(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
if err := backupService.PostgresqlRecover(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case "website":
|
||||
if err := backupService.WebsiteRecover(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -423,11 +383,6 @@ func (b *BaseApi) RecoverByUpload(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
if err := backupService.PostgresqlRecoverByUpload(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case "app":
|
||||
if err := backupService.AppRecover(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
|
||||
@@ -95,13 +95,17 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /cronjobs/records/log [post]
|
||||
// @Router /cronjob/record/log [post]
|
||||
func (b *BaseApi) LoadRecordLog(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
content := cronjobService.LoadRecordLog(req)
|
||||
content, err := cronjobService.LoadRecordLog(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, content)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,22 +8,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary Load os info
|
||||
// @Description 获取服务器基础数据
|
||||
// @Accept json
|
||||
// @Success 200 {object} dto.OsInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /dashboard/base/os [get]
|
||||
func (b *BaseApi) LoadDashboardOsInfo(c *gin.Context) {
|
||||
data, err := dashboardService.LoadOsInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary Load dashboard base info
|
||||
// @Description 获取首页基础数据
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -23,14 +21,6 @@ func (b *BaseApi) CreateDatabase(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if req.SSL {
|
||||
key, _ := base64.StdEncoding.DecodeString(req.ClientKey)
|
||||
req.ClientKey = string(key)
|
||||
cert, _ := base64.StdEncoding.DecodeString(req.ClientCert)
|
||||
req.ClientCert = string(cert)
|
||||
ca, _ := base64.StdEncoding.DecodeString(req.RootCert)
|
||||
req.RootCert = string(ca)
|
||||
}
|
||||
|
||||
if err := databaseService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -53,14 +43,6 @@ func (b *BaseApi) CheckDatabase(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if req.SSL {
|
||||
clientKey, _ := base64.StdEncoding.DecodeString(req.ClientKey)
|
||||
req.ClientKey = string(clientKey)
|
||||
clientCert, _ := base64.StdEncoding.DecodeString(req.ClientCert)
|
||||
req.ClientCert = string(clientCert)
|
||||
rootCert, _ := base64.StdEncoding.DecodeString(req.RootCert)
|
||||
req.RootCert = string(rootCert)
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, databaseService.CheckDatabase(req))
|
||||
}
|
||||
@@ -112,27 +94,6 @@ func (b *BaseApi) ListDatabase(c *gin.Context) {
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary List databases
|
||||
// @Description 获取数据库列表
|
||||
// @Success 200 {array} dto.DatabaseItem
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/db/item/:type [get]
|
||||
func (b *BaseApi) LoadDatabaseItems(c *gin.Context) {
|
||||
dbType, err := helper.GetStrParamByKey(c, "type")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
list, err := databaseService.LoadItems(dbType)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary Get databases
|
||||
// @Description 获取远程数据库
|
||||
@@ -212,14 +173,6 @@ func (b *BaseApi) UpdateDatabase(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if req.SSL {
|
||||
cKey, _ := base64.StdEncoding.DecodeString(req.ClientKey)
|
||||
req.ClientKey = string(cKey)
|
||||
cCert, _ := base64.StdEncoding.DecodeString(req.ClientCert)
|
||||
req.ClientCert = string(cCert)
|
||||
ca, _ := base64.StdEncoding.DecodeString(req.RootCert)
|
||||
req.RootCert = string(ca)
|
||||
}
|
||||
|
||||
if err := databaseService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
|
||||
@@ -1,75 +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/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Database Common
|
||||
// @Summary Load base info
|
||||
// @Description 获取数据库基础信息
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithNameAndType true "request"
|
||||
// @Success 200 {object} dto.DBBaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/common/info [post]
|
||||
func (b *BaseApi) LoadDBBaseInfo(c *gin.Context) {
|
||||
var req dto.OperationWithNameAndType
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := dbCommonService.LoadBaseInfo(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Database Common
|
||||
// @Summary Load Database conf
|
||||
// @Description 获取数据库配置文件
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithNameAndType true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/common/load/file [post]
|
||||
func (b *BaseApi) LoadDBFile(c *gin.Context) {
|
||||
var req dto.OperationWithNameAndType
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
content, err := dbCommonService.LoadDatabaseFile(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, content)
|
||||
}
|
||||
|
||||
// @Tags Database Common
|
||||
// @Summary Update conf by upload file
|
||||
// @Description 上传替换配置文件
|
||||
// @Accept json
|
||||
// @Param request body dto.DBConfUpdateByFile true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/common/update/conf [post]
|
||||
// @x-panel-log {"bodyKeys":["type","database"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 [type] 数据库 [database] 配置信息","formatEN":"update the [type] [database] database configuration information"}
|
||||
func (b *BaseApi) UpdateDBConfByFile(c *gin.Context) {
|
||||
var req dto.DBConfUpdateByFile
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := dbCommonService.UpdateConfByFile(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
@@ -41,37 +41,6 @@ func (b *BaseApi) CreateMysql(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Mysql
|
||||
// @Summary Bind user of mysql database
|
||||
// @Description 绑定 mysql 数据库用户
|
||||
// @Accept json
|
||||
// @Param request body dto.BindUser true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/bind [post]
|
||||
// @x-panel-log {"bodyKeys":["database", "username"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"绑定 mysql 数据库名 [database] [username]","formatEN":"bind mysql database [database] [username]"}
|
||||
func (b *BaseApi) BindUser(c *gin.Context) {
|
||||
var req dto.BindUser
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
|
||||
if err := mysqlService.BindUser(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Mysql
|
||||
// @Summary Update mysql database description
|
||||
// @Description 更新 mysql 数据库库描述信息
|
||||
@@ -169,6 +138,29 @@ func (b *BaseApi) UpdateMysqlVariables(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Mysql
|
||||
// @Summary Update mysql conf by upload file
|
||||
// @Description 上传替换 mysql 配置文件
|
||||
// @Accept json
|
||||
// @Param request body dto.MysqlConfUpdateByFile true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/conffile/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 mysql 数据库配置信息","formatEN":"update the mysql database configuration information"}
|
||||
func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) {
|
||||
var req dto.MysqlConfUpdateByFile
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := mysqlService.UpdateConfByFile(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Mysql
|
||||
// @Summary Page mysql databases
|
||||
// @Description 获取 mysql 数据库列表分页
|
||||
@@ -281,6 +273,51 @@ func (b *BaseApi) DeleteMysql(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Mysql
|
||||
// @Summary Load mysql base info
|
||||
// @Description 获取 mysql 基础信息
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithNameAndType true "request"
|
||||
// @Success 200 {object} dto.DBBaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/baseinfo [post]
|
||||
func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
|
||||
var req dto.OperationWithNameAndType
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := mysqlService.LoadBaseInfo(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
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 := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
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
|
||||
// @Summary Load mysql remote access
|
||||
// @Description 获取 mysql 远程访问权限
|
||||
@@ -294,6 +331,7 @@ func (b *BaseApi) LoadRemoteAccess(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
isRemote, err := mysqlService.LoadRemoteAccess(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Create postgresql database
|
||||
// @Description 创建 postgresql 数据库
|
||||
// @Accept json
|
||||
// @Param request body dto.PostgresqlDBCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg [post]
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 postgresql 数据库 [name]","formatEN":"create postgresql database [name]"}
|
||||
func (b *BaseApi) CreatePostgresql(c *gin.Context) {
|
||||
var req dto.PostgresqlDBCreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
|
||||
if _, err := postgresqlService.Create(context.Background(), req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Bind postgresql user
|
||||
// @Description 绑定 postgresql 数据库用户
|
||||
// @Accept json
|
||||
// @Param request body dto.PostgresqlBindUser true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/bind [post]
|
||||
// @x-panel-log {"bodyKeys":["name", "username"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"绑定 postgresql 数据库 [name] 用户 [username]","formatEN":"bind postgresql database [name] user [username]"}
|
||||
func (b *BaseApi) BindPostgresqlUser(c *gin.Context) {
|
||||
var req dto.PostgresqlBindUser
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := postgresqlService.BindUser(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Update postgresql database description
|
||||
// @Description 更新 postgresql 数据库库描述信息
|
||||
// @Accept json
|
||||
// @Param request body dto.UpdateDescription true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/description [post]
|
||||
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_postgresqls","output_column":"name","output_value":"name"}],"formatZH":"postgresql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the postgresql database [name] is modified => [description]"}
|
||||
func (b *BaseApi) UpdatePostgresqlDescription(c *gin.Context) {
|
||||
var req dto.UpdateDescription
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := postgresqlService.UpdateDescription(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Change postgresql privileges
|
||||
// @Description 修改 postgresql 用户权限
|
||||
// @Accept json
|
||||
// @Param request body dto.ChangeDBInfo true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/privileges [post]
|
||||
// @x-panel-log {"bodyKeys":["database", "username"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新数据库 [database] 用户 [username] 权限","formatEN":"Update [user] privileges of database [database]"}
|
||||
func (b *BaseApi) ChangePostgresqlPrivileges(c *gin.Context) {
|
||||
var req dto.PostgresqlPrivileges
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := postgresqlService.ChangePrivileges(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Change postgresql password
|
||||
// @Description 修改 postgresql 密码
|
||||
// @Accept json
|
||||
// @Param request body dto.ChangeDBInfo true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/password [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_postgresqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 密码","formatEN":"Update database [name] password"}
|
||||
func (b *BaseApi) ChangePostgresqlPassword(c *gin.Context) {
|
||||
var req dto.ChangeDBInfo
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Value) != 0 {
|
||||
value, err := base64.StdEncoding.DecodeString(req.Value)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Value = string(value)
|
||||
}
|
||||
|
||||
if err := postgresqlService.ChangePassword(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Page postgresql databases
|
||||
// @Description 获取 postgresql 数据库列表分页
|
||||
// @Accept json
|
||||
// @Param request body dto.PostgresqlDBSearch true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/search [post]
|
||||
func (b *BaseApi) SearchPostgresql(c *gin.Context) {
|
||||
var req dto.PostgresqlDBSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := postgresqlService.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 Postgresql
|
||||
// @Summary Load postgresql database from remote
|
||||
// @Description 从服务器获取
|
||||
// @Accept json
|
||||
// @Param request body dto.PostgresqlLoadDB true "request"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/:database/load [post]
|
||||
func (b *BaseApi) LoadPostgresqlDBFromRemote(c *gin.Context) {
|
||||
database, err := helper.GetStrParamByKey(c, "database")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := postgresqlService.LoadFromRemote(database); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Check before delete postgresql database
|
||||
// @Description Postgresql 数据库删除前检查
|
||||
// @Accept json
|
||||
// @Param request body dto.PostgresqlDBDeleteCheck true "request"
|
||||
// @Success 200 {array} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/del/check [post]
|
||||
func (b *BaseApi) DeleteCheckPostgresql(c *gin.Context) {
|
||||
var req dto.PostgresqlDBDeleteCheck
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
apps, err := postgresqlService.DeleteCheck(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, apps)
|
||||
}
|
||||
|
||||
// @Tags Database Postgresql
|
||||
// @Summary Delete postgresql database
|
||||
// @Description 删除 postgresql 数据库
|
||||
// @Accept json
|
||||
// @Param request body dto.PostgresqlDBDelete true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/pg/del [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_postgresqls","output_column":"name","output_value":"name"}],"formatZH":"删除 postgresql 数据库 [name]","formatEN":"delete postgresql database [name]"}
|
||||
func (b *BaseApi) DeletePostgresql(c *gin.Context) {
|
||||
var req dto.PostgresqlDBDelete
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
tx, ctx := helper.GetTxAndContext()
|
||||
if err := postgresqlService.Delete(ctx, req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
tx.Commit()
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"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/utils/compose"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -157,3 +161,45 @@ func (b *BaseApi) RedisBackupList(c *gin.Context) {
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Database Redis
|
||||
// @Summary Update redis conf by file
|
||||
// @Description 上传更新 redis 配置信息
|
||||
// @Accept json
|
||||
// @Param request body dto.RedisConfUpdateByFile true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/redis/conffile/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 redis 数据库配置信息","formatEN":"update the redis database configuration information"}
|
||||
func (b *BaseApi) UpdateRedisConfByFile(c *gin.Context) {
|
||||
var req dto.RedisConfUpdateByFile
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
redisInfo, err := redisService.LoadConf()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", constant.AppInstallDir, redisInfo.Name)
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
|
||||
if req.RestartNow {
|
||||
composeDir := fmt.Sprintf("%s/redis/%s/docker-compose.yml", constant.AppInstallDir, redisInfo.Name)
|
||||
if _, err := compose.Restart(composeDir); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Load device base info
|
||||
// @Description 获取设备基础信息
|
||||
// @Success 200 {object} dto.DeviceBaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/base [post]
|
||||
func (b *BaseApi) LoadDeviceBaseInfo(c *gin.Context) {
|
||||
data, err := deviceService.LoadBaseInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary list time zone options
|
||||
// @Description 获取系统可用时区选项
|
||||
// @Accept json
|
||||
// @Success 200 {Array} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/zone/options [get]
|
||||
func (b *BaseApi) LoadTimeOption(c *gin.Context) {
|
||||
list, err := deviceService.LoadTimeZone()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary load conf
|
||||
// @Description 获取系统配置文件
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/conf [post]
|
||||
func (b *BaseApi) LoadDeviceConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list, err := deviceService.LoadConf(req.Name)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device conf by file
|
||||
// @Description 通过文件修改配置
|
||||
// @Accept json
|
||||
// @Param request body dto.UpdateByNameAndFile true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/byconf [post]
|
||||
func (b *BaseApi) UpdateDeviceByFile(c *gin.Context) {
|
||||
var req dto.UpdateByNameAndFile
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := deviceService.UpdateByConf(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device
|
||||
// @Description 修改系统参数
|
||||
// @Accept json
|
||||
// @Param request body dto.SettingUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/conf [post]
|
||||
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改主机参数 [key] => [value]","formatEN":"update device conf [key] => [value]"}
|
||||
func (b *BaseApi) UpdateDeviceConf(c *gin.Context) {
|
||||
var req dto.SettingUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := deviceService.Update(req.Key, req.Value); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device hosts
|
||||
// @Description 修改系统 hosts
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/host [post]
|
||||
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改主机 Host [key] => [value]","formatEN":"update device host [key] => [value]"}
|
||||
func (b *BaseApi) UpdateDeviceHost(c *gin.Context) {
|
||||
var req []dto.HostHelper
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := deviceService.UpdateHosts(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device passwd
|
||||
// @Description 修改系统密码
|
||||
// @Accept json
|
||||
// @Param request body dto.ChangePasswd true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/passwd [post]
|
||||
func (b *BaseApi) UpdateDevicePasswd(c *gin.Context) {
|
||||
var req dto.ChangePasswd
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if len(req.Passwd) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Passwd)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Passwd = string(password)
|
||||
}
|
||||
if err := deviceService.UpdatePasswd(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device swap
|
||||
// @Description 修改系统 Swap
|
||||
// @Accept json
|
||||
// @Param request body dto.SwapHelper true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/swap [post]
|
||||
// @x-panel-log {"bodyKeys":["operate","path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 主机 swap [path]","formatEN":"[operate] device swap [path]"}
|
||||
func (b *BaseApi) UpdateDeviceSwap(c *gin.Context) {
|
||||
var req dto.SwapHelper
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := deviceService.UpdateSwap(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Check device DNS conf
|
||||
// @Description 检查系统 DNS 配置可用性
|
||||
// @Accept json
|
||||
// @Param request body dto.SettingUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/check/dns [post]
|
||||
func (b *BaseApi) CheckDNS(c *gin.Context) {
|
||||
var req dto.SettingUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := deviceService.CheckDNS(req.Key, req.Value)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Scan system
|
||||
// @Description 扫描系统垃圾文件
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/scan [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"扫描系统垃圾文件","formatEN":"scan System Junk Files"}
|
||||
func (b *BaseApi) ScanSystem(c *gin.Context) {
|
||||
helper.SuccessWithData(c, deviceService.Scan())
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Clean system
|
||||
// @Description 清理系统垃圾文件
|
||||
// @Accept json
|
||||
// @Param request body []dto.Clean true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clean [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清理系统垃圾文件","formatEN":"Clean system junk files"}
|
||||
func (b *BaseApi) SystemClean(c *gin.Context) {
|
||||
var req []dto.Clean
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
deviceService.Clean(req)
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
|
||||
// @Param request body dto.LogOption true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /containers/logoption/update [post]
|
||||
// @Router /containers/daemonjson/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 日志配置","formatEN":"Updated the docker daemon.json log option"}
|
||||
func (b *BaseApi) UpdateLogOption(c *gin.Context) {
|
||||
var req dto.LogOption
|
||||
@@ -99,29 +99,6 @@ func (b *BaseApi) UpdateLogOption(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Container Docker
|
||||
// @Summary Update docker daemon.json ipv6 option
|
||||
// @Description 修改 docker ipv6 配置
|
||||
// @Accept json
|
||||
// @Param request body dto.LogOption true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /containers/ipv6option/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json ipv6 配置","formatEN":"Updated the docker daemon.json ipv6 option"}
|
||||
func (b *BaseApi) UpdateIpv6Option(c *gin.Context) {
|
||||
var req dto.Ipv6Option
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := dockerService.UpdateIpv6Option(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Container Docker
|
||||
// @Summary Update docker daemon.json by upload file
|
||||
// @Description 上传替换 docker 配置文件
|
||||
|
||||
@@ -21,11 +21,9 @@ var (
|
||||
imageService = service.NewIImageService()
|
||||
dockerService = service.NewIDockerService()
|
||||
|
||||
dbCommonService = service.NewIDBCommonService()
|
||||
mysqlService = service.NewIMysqlService()
|
||||
postgresqlService = service.NewIPostgresqlService()
|
||||
databaseService = service.NewIDatabaseService()
|
||||
redisService = service.NewIRedisService()
|
||||
mysqlService = service.NewIMysqlService()
|
||||
databaseService = service.NewIDatabaseService()
|
||||
redisService = service.NewIRedisService()
|
||||
|
||||
cronjobService = service.NewICronjobService()
|
||||
|
||||
@@ -35,9 +33,6 @@ var (
|
||||
sshService = service.NewISSHService()
|
||||
firewallService = service.NewIFirewallService()
|
||||
|
||||
deviceService = service.NewIDeviceService()
|
||||
fail2banService = service.NewIFail2BanService()
|
||||
|
||||
settingService = service.NewISettingService()
|
||||
backupService = service.NewIBackupService()
|
||||
|
||||
@@ -54,14 +49,11 @@ var (
|
||||
snapshotService = service.NewISnapshotService()
|
||||
upgradeService = service.NewIUpgradeService()
|
||||
|
||||
runtimeService = service.NewRuntimeService()
|
||||
processService = service.NewIProcessService()
|
||||
phpExtensionsService = service.NewIPHPExtensionsService()
|
||||
runtimeService = service.NewRuntimeService()
|
||||
processService = service.NewIProcessService()
|
||||
|
||||
hostToolService = service.NewIHostToolService()
|
||||
|
||||
recycleBinService = service.NewIRecycleBinService()
|
||||
favoriteService = service.NewIFavoriteService()
|
||||
|
||||
websiteCAService = service.NewIWebsiteCAService()
|
||||
)
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"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/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Fail2ban
|
||||
// @Summary Load fail2ban base info
|
||||
// @Description 获取 Fail2ban 基础信息
|
||||
// @Success 200 {object} dto.Fail2BanBaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/fail2ban/base [get]
|
||||
func (b *BaseApi) LoadFail2BanBaseInfo(c *gin.Context) {
|
||||
data, err := fail2banService.LoadBaseInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Fail2ban
|
||||
// @Summary Page fail2ban ip list
|
||||
// @Description 获取 Fail2ban ip
|
||||
// @Accept json
|
||||
// @Param request body dto.Fail2BanSearch true "request"
|
||||
// @Success 200 {Array} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/fail2ban/search [post]
|
||||
func (b *BaseApi) SearchFail2Ban(c *gin.Context) {
|
||||
var req dto.Fail2BanSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list, err := fail2banService.Search(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Fail2ban
|
||||
// @Summary Operate fail2ban
|
||||
// @Description 修改 Fail2ban 状态
|
||||
// @Accept json
|
||||
// @Param request body dto.Operate true "request"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/fail2ban/operate [post]
|
||||
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] Fail2ban","formatEN":"[operation] Fail2ban"}
|
||||
func (b *BaseApi) OperateFail2Ban(c *gin.Context) {
|
||||
var req dto.Operate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := fail2banService.Operate(req.Operation); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Fail2ban
|
||||
// @Summary Operate sshd of fail2ban
|
||||
// @Description 配置 sshd
|
||||
// @Accept json
|
||||
// @Param request body dto.Operate true "request"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/fail2ban/operate/sshd [post]
|
||||
func (b *BaseApi) OperateSSHD(c *gin.Context) {
|
||||
var req dto.Fail2BanSet
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := fail2banService.OperateSSHD(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Fail2ban
|
||||
// @Summary Update fail2ban conf
|
||||
// @Description 修改 Fail2ban 配置
|
||||
// @Accept json
|
||||
// @Param request body dto.Fail2BanUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/fail2ban/update [post]
|
||||
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 Fail2ban 配置 [key] => [value]","formatEN":"update fail2ban conf [key] => [value]"}
|
||||
func (b *BaseApi) UpdateFail2BanConf(c *gin.Context) {
|
||||
var req dto.Fail2BanUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := fail2banService.UpdateConf(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Fail2ban
|
||||
// @Summary Load fail2ban conf
|
||||
// @Description 获取 fail2ban 配置文件
|
||||
// @Accept json
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/fail2ban/load/conf [get]
|
||||
func (b *BaseApi) LoadFail2BanConf(c *gin.Context) {
|
||||
path := "/etc/fail2ban/jail.local"
|
||||
file, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, string(file))
|
||||
}
|
||||
|
||||
// @Tags Fail2ban
|
||||
// @Summary Update fail2ban conf by file
|
||||
// @Description 通过文件修改 fail2ban 配置
|
||||
// @Accept json
|
||||
// @Param request body dto.UpdateByFile true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/fail2ban/update/byconf [post]
|
||||
func (b *BaseApi) UpdateFail2BanConfByFile(c *gin.Context) {
|
||||
var req dto.UpdateByFile
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := fail2banService.UpdateConfByFile(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
@@ -422,9 +422,11 @@ func (b *BaseApi) MoveFile(c *gin.Context) {
|
||||
// @Summary Download file
|
||||
// @Description 下载文件
|
||||
// @Accept json
|
||||
// @Param request body request.FileDownload true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/download [get]
|
||||
// @Router /files/download [post]
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
|
||||
func (b *BaseApi) Download(c *gin.Context) {
|
||||
filePath := c.Query("path")
|
||||
file, err := os.Open(filePath)
|
||||
@@ -683,7 +685,7 @@ func (b *BaseApi) Keys(c *gin.Context) {
|
||||
|
||||
// @Tags File
|
||||
// @Summary Read file by Line
|
||||
// @Description 按行读取日志文件
|
||||
// @Description 按行读取文件
|
||||
// @Param request body request.FileReadByLineReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
@@ -693,11 +695,15 @@ func (b *BaseApi) ReadFileByLine(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
res, err := fileService.ReadLogByLine(req)
|
||||
lines, end, err := files.ReadFileByLine(req.Path, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
res := response.FileLineContent{
|
||||
End: end,
|
||||
}
|
||||
res.Path = req.Path
|
||||
res.Content = strings.Join(lines, "\n")
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
|
||||
@@ -35,24 +35,8 @@ func (b *BaseApi) SearchImage(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags Container Image
|
||||
// @Summary List all images
|
||||
// @Description 获取所有镜像列表
|
||||
// @Produce json
|
||||
// @Success 200 {array} dto.ImageInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /containers/image/all [get]
|
||||
func (b *BaseApi) ListAllImage(c *gin.Context) {
|
||||
list, err := imageService.ListAll()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Container Image
|
||||
// @Summary load images options
|
||||
// @Description 获取镜像名称列表
|
||||
// @Summary List images
|
||||
// @Description 获取镜像列表
|
||||
// @Produce json
|
||||
// @Success 200 {array} dto.Options
|
||||
// @Security ApiKeyAuth
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
// @Description 获取 OpenResty 配置信息
|
||||
// @Success 200 {object} response.FileInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty [get]
|
||||
// @Router /openResty [get]
|
||||
func (b *BaseApi) GetNginx(c *gin.Context) {
|
||||
fileInfo, err := nginxService.GetNginxConfig()
|
||||
if err != nil {
|
||||
@@ -29,7 +29,7 @@ func (b *BaseApi) GetNginx(c *gin.Context) {
|
||||
// @Param request body request.NginxScopeReq true "request"
|
||||
// @Success 200 {array} response.NginxParam
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/scope [post]
|
||||
// @Router /openResty/scope [post]
|
||||
func (b *BaseApi) GetNginxConfigByScope(c *gin.Context) {
|
||||
var req request.NginxScopeReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
@@ -51,7 +51,7 @@ func (b *BaseApi) GetNginxConfigByScope(c *gin.Context) {
|
||||
// @Param request body request.NginxConfigUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/update [post]
|
||||
// @Router /openResty/update [post]
|
||||
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新 nginx 配置 [domain]","formatEN":"Update nginx conf [domain]"}
|
||||
func (b *BaseApi) UpdateNginxConfigByScope(c *gin.Context) {
|
||||
var req request.NginxConfigUpdate
|
||||
@@ -70,7 +70,7 @@ func (b *BaseApi) UpdateNginxConfigByScope(c *gin.Context) {
|
||||
// @Description 获取 OpenResty 状态信息
|
||||
// @Success 200 {object} response.NginxStatus
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/status [get]
|
||||
// @Router /openResty/status [get]
|
||||
func (b *BaseApi) GetNginxStatus(c *gin.Context) {
|
||||
res, err := nginxService.GetStatus()
|
||||
if err != nil {
|
||||
@@ -87,7 +87,7 @@ func (b *BaseApi) GetNginxStatus(c *gin.Context) {
|
||||
// @Param request body request.NginxConfigFileUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/file [post]
|
||||
// @Router /openResty/file [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 nginx 配置","formatEN":"Update nginx conf"}
|
||||
func (b *BaseApi) UpdateNginxFile(c *gin.Context) {
|
||||
var req request.NginxConfigFileUpdate
|
||||
@@ -101,18 +101,3 @@ func (b *BaseApi) UpdateNginxFile(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags OpenResty
|
||||
// @Summary Clear OpenResty proxy cache
|
||||
// @Description 清理 OpenResty 代理缓存
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/clear [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清理 Openresty 代理缓存","formatEN":"Clear nginx proxy cache"}
|
||||
func (b *BaseApi) ClearNginxProxyCache(c *gin.Context) {
|
||||
if err := nginxService.ClearProxyCache(); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
@@ -1,103 +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/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags PHP Extensions
|
||||
// @Summary Page Extensions
|
||||
// @Description Page Extensions
|
||||
// @Accept json
|
||||
// @Param request body request.PHPExtensionsSearch true "request"
|
||||
// @Success 200 {array} response.PHPExtensionsDTO
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/php/extensions/search [post]
|
||||
func (b *BaseApi) PagePHPExtensions(c *gin.Context) {
|
||||
var req request.PHPExtensionsSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if req.All {
|
||||
list, err := phpExtensionsService.List()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, list)
|
||||
} else {
|
||||
total, list, err := phpExtensionsService.Page(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Total: total,
|
||||
Items: list,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @Tags PHP Extensions
|
||||
// @Summary Create Extensions
|
||||
// @Description Create Extensions
|
||||
// @Accept json
|
||||
// @Param request body request.PHPExtensionsCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/php/extensions [post]
|
||||
func (b *BaseApi) CreatePHPExtensions(c *gin.Context) {
|
||||
var req request.PHPExtensionsCreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := phpExtensionsService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags PHP Extensions
|
||||
// @Summary Update Extensions
|
||||
// @Description Update Extensions
|
||||
// @Accept json
|
||||
// @Param request body request.PHPExtensionsUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/php/extensions/update [post]
|
||||
func (b *BaseApi) UpdatePHPExtensions(c *gin.Context) {
|
||||
var req request.PHPExtensionsUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := phpExtensionsService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags PHP Extensions
|
||||
// @Summary Delete Extensions
|
||||
// @Description Delete Extensions
|
||||
// @Accept json
|
||||
// @Param request body request.PHPExtensionsDelete true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/php/extensions/del [post]
|
||||
func (b *BaseApi) DeletePHPExtensions(c *gin.Context) {
|
||||
var req request.PHPExtensionsDelete
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := phpExtensionsService.Delete(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
@@ -68,19 +68,3 @@ func (b *BaseApi) ClearRecycleBinFile(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Get RecycleBin status
|
||||
// @Description 获取回收站状态
|
||||
// @Accept json
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/recycle/status [get]
|
||||
func (b *BaseApi) GetRecycleStatus(c *gin.Context) {
|
||||
settingInfo, err := settingService.GetSettingInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, settingInfo.FileRecycleBin)
|
||||
}
|
||||
|
||||
@@ -46,12 +46,11 @@ func (b *BaseApi) CreateRuntime(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
ssl, err := runtimeService.Create(req)
|
||||
if err != nil {
|
||||
if err := runtimeService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, ssl)
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
|
||||
@@ -217,6 +217,43 @@ func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
|
||||
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
|
||||
// @Summary Sync system time
|
||||
// @Description 系统时间同步
|
||||
// @Accept json
|
||||
// @Param request body dto.SyncTime true "request"
|
||||
// @Success 200 {string} ntime
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/time/sync [post]
|
||||
// @x-panel-log {"bodyKeys":["ntpSite"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"系统时间同步[ntpSite]","formatEN":"sync system time [ntpSite]"}
|
||||
func (b *BaseApi) SyncTime(c *gin.Context) {
|
||||
var req dto.SyncTime
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := settingService.SyncTime(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load local backup dir
|
||||
// @Description 获取安装根目录
|
||||
@@ -251,6 +288,37 @@ func (b *BaseApi) CleanMonitor(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Scan system
|
||||
// @Description 扫描系统垃圾文件
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/scan [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"扫描系统垃圾文件","formatEN":"scan System Junk Files"}
|
||||
func (b *BaseApi) ScanSystem(c *gin.Context) {
|
||||
helper.SuccessWithData(c, settingService.SystemScan())
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary System clean
|
||||
// @Description 清理系统垃圾文件
|
||||
// @Accept json
|
||||
// @Param request body []dto.Clean true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/clean [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清理系统垃圾文件","formatEN":"Clean system junk files"}
|
||||
func (b *BaseApi) SystemClean(c *gin.Context) {
|
||||
var req []dto.Clean
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
settingService.SystemClean(req)
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load mfa info
|
||||
// @Description 获取 mfa 信息
|
||||
|
||||
@@ -131,6 +131,28 @@ func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags SSH
|
||||
// @Summary Analysis host SSH logs
|
||||
// @Description 分析 SSH 登录日志
|
||||
// @Accept json
|
||||
// @Param request body dto.SearchForAnalysis true "request"
|
||||
// @Success 200 {array} dto.SSHLogAnalysis
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /host/ssh/log/analysis [post]
|
||||
func (b *BaseApi) AnalysisLog(c *gin.Context) {
|
||||
var req dto.SearchForAnalysis
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := sshService.AnalysisLog(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags SSH
|
||||
// @Summary Load host SSH logs
|
||||
// @Description 获取 SSH 登录日志
|
||||
|
||||
@@ -55,6 +55,7 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
sws, err := terminal.NewLogicSshWsSession(cols, rows, true, connInfo.Client, wsConn)
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
@@ -105,7 +106,7 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
||||
defer killBash(redisConf.ContainerName, commands, pidMap)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
@@ -173,7 +174,7 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
||||
defer killBash(containerID, command, pidMap)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, true)
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func (b *BaseApi) GetNotesByVersion(c *gin.Context) {
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/upgrade [post]
|
||||
// @x-panel-log {"bodyKeys":["version"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新系统 => [version]","formatEN":"upgrade system => [version]"}
|
||||
// @x-panel-log {"bodyKeys":["version"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新系统 => [version]","formatEN":"upgrade service => [version]"}
|
||||
func (b *BaseApi) Upgrade(c *gin.Context) {
|
||||
var req dto.Upgrade
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
|
||||
@@ -1,144 +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/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Website CA
|
||||
// @Summary Page website ca
|
||||
// @Description 获取网站 ca 列表分页
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteCASearch true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ca/search [post]
|
||||
func (b *BaseApi) PageWebsiteCA(c *gin.Context) {
|
||||
var req request.WebsiteCASearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
total, cas, err := websiteCAService.Page(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Total: total,
|
||||
Items: cas,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Website CA
|
||||
// @Summary Create website ca
|
||||
// @Description 创建网站 ca
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteCACreate true "request"
|
||||
// @Success 200 {object} request.WebsiteCACreate
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ca [post]
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建网站 ca [name]","formatEN":"Create website ca [name]"}
|
||||
func (b *BaseApi) CreateWebsiteCA(c *gin.Context) {
|
||||
var req request.WebsiteCACreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
res, err := websiteCAService.Create(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website CA
|
||||
// @Summary Get website ca
|
||||
// @Description 获取网站 ca
|
||||
// @Accept json
|
||||
// @Param id path int true "id"
|
||||
// @Success 200 {object} response.WebsiteCADTO
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ca/{id} [get]
|
||||
func (b *BaseApi) GetWebsiteCA(c *gin.Context) {
|
||||
id, err := helper.GetParamID(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res, err := websiteCAService.GetCA(id)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website CA
|
||||
// @Summary Delete website ca
|
||||
// @Description 删除网站 ca
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteCommonReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ca/del [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_cas","output_column":"name","output_value":"name"}],"formatZH":"删除网站 ca [name]","formatEN":"Delete website ca [name]"}
|
||||
func (b *BaseApi) DeleteWebsiteCA(c *gin.Context) {
|
||||
var req request.WebsiteCommonReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteCAService.Delete(req.ID); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website CA
|
||||
// @Summary Obtain SSL
|
||||
// @Description 自签 SSL 证书
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteCAObtain true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ca/obtain [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_cas","output_column":"name","output_value":"name"}],"formatZH":"自签 SSL 证书 [name]","formatEN":"Obtain SSL [name]"}
|
||||
func (b *BaseApi) ObtainWebsiteCA(c *gin.Context) {
|
||||
var req request.WebsiteCAObtain
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err := websiteCAService.ObtainSSL(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website CA
|
||||
// @Summary Obtain SSL
|
||||
// @Description 续签 SSL 证书
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteCAObtain true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ca/renew [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_cas","output_column":"name","output_value":"name"}],"formatZH":"自签 SSL 证书 [name]","formatEN":"Obtain SSL [name]"}
|
||||
func (b *BaseApi) RenewWebsiteCA(c *gin.Context) {
|
||||
var req request.WebsiteCARenew
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err := websiteCAService.ObtainSSL(request.WebsiteCAObtain{
|
||||
SSLID: req.SSLID,
|
||||
Renew: true,
|
||||
Unit: "year",
|
||||
Time: 1,
|
||||
}); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -69,24 +66,24 @@ func (b *BaseApi) CreateWebsiteSSL(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
// @Summary Apply ssl
|
||||
// @Description 申请证书
|
||||
// @Summary Reset website ssl
|
||||
// @Description 重置网站 ssl
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteSSLApply true "request"
|
||||
// @Param request body request.WebsiteSSLRenew true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ssl/obtain [post]
|
||||
// @x-panel-log {"bodyKeys":["ID"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ID","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"申请证书 [domain]","formatEN":"apply ssl [domain]"}
|
||||
func (b *BaseApi) ApplyWebsiteSSL(c *gin.Context) {
|
||||
var req request.WebsiteSSLApply
|
||||
// @Router /websites/ssl/renew [post]
|
||||
// @x-panel-log {"bodyKeys":["SSLId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"SSLId","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"重置 ssl [domain]","formatEN":"Renew ssl [domain]"}
|
||||
func (b *BaseApi) RenewWebsiteSSL(c *gin.Context) {
|
||||
var req request.WebsiteSSLRenew
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteSSLService.ObtainSSL(req); err != nil {
|
||||
if err := websiteSSLService.Renew(req.SSLID); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
@@ -114,17 +111,17 @@ func (b *BaseApi) GetDNSResolve(c *gin.Context) {
|
||||
// @Summary Delete website ssl
|
||||
// @Description 删除网站 ssl
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteBatchDelReq true "request"
|
||||
// @Param request body request.WebsiteResourceReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ssl/del [post]
|
||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"}
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"}
|
||||
func (b *BaseApi) DeleteWebsiteSSL(c *gin.Context) {
|
||||
var req request.WebsiteBatchDelReq
|
||||
var req request.WebsiteResourceReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteSSLService.Delete(req.IDs); err != nil {
|
||||
if err := websiteSSLService.Delete(req.ID); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
@@ -216,32 +213,3 @@ func (b *BaseApi) UploadWebsiteSSL(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
// @Summary Download SSL file
|
||||
// @Description 下载证书文件
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteResourceReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ssl/download [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"下载证书文件 [domain]","formatEN":"download ssl file [domain]"}
|
||||
func (b *BaseApi) DownloadWebsiteSSL(c *gin.Context) {
|
||||
var req request.WebsiteResourceReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
file, err := websiteSSLService.DownloadFile(req.ID)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -13,18 +13,12 @@ type AppDatabase struct {
|
||||
|
||||
type AuthParam struct {
|
||||
RootPassword string `json:"PANEL_DB_ROOT_PASSWORD"`
|
||||
RootUser string `json:"PANEL_DB_ROOT_USER"`
|
||||
}
|
||||
|
||||
type RedisAuthParam struct {
|
||||
RootPassword string `json:"PANEL_REDIS_ROOT_PASSWORD"`
|
||||
}
|
||||
|
||||
type MinioAuthParam struct {
|
||||
RootPassword string `json:"PANEL_MINIO_ROOT_PASSWORD"`
|
||||
RootUser string `json:"PANEL_MINIO_ROOT_USER"`
|
||||
}
|
||||
|
||||
type ContainerExec struct {
|
||||
ContainerName string `json:"containerName"`
|
||||
DbParam AppDatabase `json:"dbParam"`
|
||||
|
||||
@@ -21,24 +21,18 @@ type BackupInfo struct {
|
||||
Vars string `json:"vars"`
|
||||
}
|
||||
|
||||
type OneDriveInfo struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
RedirectUri string `json:"redirect_uri"`
|
||||
}
|
||||
|
||||
type BackupSearchFile struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
}
|
||||
|
||||
type CommonBackup struct {
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
}
|
||||
type CommonRecover struct {
|
||||
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive WebDAV"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"`
|
||||
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
File string `json:"file"`
|
||||
@@ -51,11 +45,6 @@ type RecordSearch struct {
|
||||
DetailName string `json:"detailName"`
|
||||
}
|
||||
|
||||
type RecordSearchByCronjob struct {
|
||||
PageInfo
|
||||
CronjobID uint `json:"cronjobID" validate:"required"`
|
||||
}
|
||||
|
||||
type BackupRecords struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
@@ -63,11 +52,10 @@ type BackupRecords struct {
|
||||
BackupType string `json:"backupType"`
|
||||
FileDir string `json:"fileDir"`
|
||||
FileName string `json:"fileName"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
type DownloadRecord struct {
|
||||
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive WebDAV"`
|
||||
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive"`
|
||||
FileDir string `json:"fileDir" validate:"required"`
|
||||
FileName string `json:"fileName" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package dto
|
||||
|
||||
type SearchCommandWithPage struct {
|
||||
SearchWithPage
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
GroupID uint `json:"groupID"`
|
||||
Info string `json:"info"`
|
||||
}
|
||||
|
||||
@@ -41,15 +41,6 @@ type DeleteByName struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type UpdateByFile struct {
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type UpdateByNameAndFile struct {
|
||||
Name string `json:"name"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type OperationWithNameAndType struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
|
||||
@@ -4,12 +4,11 @@ import "time"
|
||||
|
||||
type PageContainer struct {
|
||||
PageInfo
|
||||
Name string `json:"name"`
|
||||
State string `json:"state" validate:"required,oneof=all created running paused restarting removing exited dead"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
Filters string `json:"filters"`
|
||||
ExcludeAppStore bool `json:"excludeAppStore"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state" validate:"required,oneof=all created running paused restarting removing exited dead"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
Filters string `json:"filters"`
|
||||
}
|
||||
|
||||
type InspectReq struct {
|
||||
@@ -31,15 +30,11 @@ type ContainerInfo struct {
|
||||
|
||||
IsFromApp bool `json:"isFromApp"`
|
||||
IsFromCompose bool `json:"isFromCompose"`
|
||||
|
||||
AppName string `json:"appName"`
|
||||
AppInstallName string `json:"appInstallName"`
|
||||
Websites []string `json:"websites"`
|
||||
}
|
||||
|
||||
type ResourceLimit struct {
|
||||
CPU int `json:"cpu"`
|
||||
Memory uint64 `json:"memory"`
|
||||
CPU int `json:"cpu"`
|
||||
Memory int `json:"memory"`
|
||||
}
|
||||
|
||||
type ContainerOperate struct {
|
||||
@@ -57,7 +52,6 @@ type ContainerOperate struct {
|
||||
CPUShares int64 `json:"cpuShares"`
|
||||
NanoCPUs float64 `json:"nanoCPUs"`
|
||||
Memory float64 `json:"memory"`
|
||||
Privileged bool `json:"privileged"`
|
||||
AutoRemove bool `json:"autoRemove"`
|
||||
Volumes []VolumeHelper `json:"volumes"`
|
||||
Labels []string `json:"labels"`
|
||||
@@ -141,21 +135,13 @@ type Network struct {
|
||||
Attachable bool `json:"attachable"`
|
||||
}
|
||||
type NetworkCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Driver string `json:"driver" validate:"required"`
|
||||
Options []string `json:"options"`
|
||||
Ipv4 bool `json:"ipv4"`
|
||||
Subnet string `json:"subnet"`
|
||||
Gateway string `json:"gateway"`
|
||||
IPRange string `json:"ipRange"`
|
||||
AuxAddress []SettingUpdate `json:"auxAddress"`
|
||||
|
||||
Ipv6 bool `json:"ipv6"`
|
||||
SubnetV6 string `json:"subnetV6"`
|
||||
GatewayV6 string `json:"gatewayV6"`
|
||||
IPRangeV6 string `json:"ipRangeV6"`
|
||||
AuxAddressV6 []SettingUpdate `json:"auxAddressV6"`
|
||||
Labels []string `json:"labels"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Driver string `json:"driver" validate:"required"`
|
||||
Options []string `json:"options"`
|
||||
Subnet string `json:"subnet"`
|
||||
Gateway string `json:"gateway"`
|
||||
IPRange string `json:"ipRange"`
|
||||
Labels []string `json:"labels"`
|
||||
}
|
||||
|
||||
type Volume struct {
|
||||
@@ -173,7 +159,6 @@ type VolumeCreate struct {
|
||||
}
|
||||
|
||||
type BatchDelete struct {
|
||||
Force bool `json:"force"`
|
||||
Names []string `json:"names" validate:"required"`
|
||||
}
|
||||
|
||||
|
||||
+43
-33
@@ -3,43 +3,49 @@ package dto
|
||||
import "time"
|
||||
|
||||
type CronjobCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
SpecType string `json:"specType" validate:"required"`
|
||||
Week int `json:"week" validate:"number,max=6,min=0"`
|
||||
Day int `json:"day" validate:"number"`
|
||||
Hour int `json:"hour" validate:"number"`
|
||||
Minute int `json:"minute" validate:"number"`
|
||||
Second int `json:"second" validate:"number"`
|
||||
|
||||
Script string `json:"script"`
|
||||
ContainerName string `json:"containerName"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBType string `json:"dbType"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
|
||||
BackupAccounts string `json:"backupAccounts"`
|
||||
DefaultDownload string `json:"defaultDownload"`
|
||||
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
|
||||
KeepLocal bool `json:"keepLocal"`
|
||||
TargetDirID int `json:"targetDirID"`
|
||||
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
|
||||
}
|
||||
|
||||
type CronjobUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
SpecType string `json:"specType" validate:"required"`
|
||||
Week int `json:"week" validate:"number,max=6,min=0"`
|
||||
Day int `json:"day" validate:"number"`
|
||||
Hour int `json:"hour" validate:"number"`
|
||||
Minute int `json:"minute" validate:"number"`
|
||||
Second int `json:"second" validate:"number"`
|
||||
|
||||
Script string `json:"script"`
|
||||
ContainerName string `json:"containerName"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBType string `json:"dbType"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
|
||||
BackupAccounts string `json:"backupAccounts"`
|
||||
DefaultDownload string `json:"defaultDownload"`
|
||||
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
|
||||
KeepLocal bool `json:"keepLocal"`
|
||||
TargetDirID int `json:"targetDirID"`
|
||||
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
|
||||
}
|
||||
|
||||
type CronjobUpdateStatus struct {
|
||||
@@ -53,7 +59,6 @@ type CronjobDownload struct {
|
||||
}
|
||||
|
||||
type CronjobClean struct {
|
||||
IsDelete bool `json:"isDelete"`
|
||||
CleanData bool `json:"cleanData"`
|
||||
CronjobID uint `json:"cronjobID" validate:"required"`
|
||||
}
|
||||
@@ -64,23 +69,28 @@ type CronjobBatchDelete struct {
|
||||
}
|
||||
|
||||
type CronjobInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Spec string `json:"spec"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SpecType string `json:"specType"`
|
||||
Week int `json:"week"`
|
||||
Day int `json:"day"`
|
||||
Hour int `json:"hour"`
|
||||
Minute int `json:"minute"`
|
||||
Second int `json:"second"`
|
||||
|
||||
Script string `json:"script"`
|
||||
ContainerName string `json:"containerName"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBType string `json:"dbType"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
BackupAccounts string `json:"backupAccounts"`
|
||||
DefaultDownload string `json:"defaultDownload"`
|
||||
RetainCopies int `json:"retainCopies"`
|
||||
Script string `json:"script"`
|
||||
ContainerName string `json:"containerName"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
KeepLocal bool `json:"keepLocal"`
|
||||
TargetDir string `json:"targetDir"`
|
||||
TargetDirID int `json:"targetDirID"`
|
||||
RetainCopies int `json:"retainCopies"`
|
||||
|
||||
LastRecordTime string `json:"lastRecordTime"`
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -24,14 +24,6 @@ type DashboardBase struct {
|
||||
CurrentInfo DashboardCurrent `json:"currentInfo"`
|
||||
}
|
||||
|
||||
type OsInfo struct {
|
||||
OS string `json:"os"`
|
||||
Platform string `json:"platform"`
|
||||
PlatformFamily string `json:"platformFamily"`
|
||||
KernelArch string `json:"kernelArch"`
|
||||
KernelVersion string `json:"kernelVersion"`
|
||||
}
|
||||
|
||||
type DashboardCurrent struct {
|
||||
Uptime uint64 `json:"uptime"`
|
||||
TimeSinceUptime string `json:"timeSinceUptime"`
|
||||
@@ -51,12 +43,7 @@ type DashboardCurrent struct {
|
||||
MemoryTotal uint64 `json:"memoryTotal"`
|
||||
MemoryAvailable uint64 `json:"memoryAvailable"`
|
||||
MemoryUsed uint64 `json:"memoryUsed"`
|
||||
MemoryUsedPercent float64 `json:"memoryUsedPercent"`
|
||||
|
||||
SwapMemoryTotal uint64 `json:"swapMemoryTotal"`
|
||||
SwapMemoryAvailable uint64 `json:"swapMemoryAvailable"`
|
||||
SwapMemoryUsed uint64 `json:"swapMemoryUsed"`
|
||||
SwapMemoryUsedPercent float64 `json:"swapMemoryUsedPercent"`
|
||||
MemoryUsedPercent float64 `json:"MemoryUsedPercent"`
|
||||
|
||||
IOReadBytes uint64 `json:"ioReadBytes"`
|
||||
IOWriteBytes uint64 `json:"ioWriteBytes"`
|
||||
|
||||
+45
-83
@@ -2,27 +2,6 @@ package dto
|
||||
|
||||
import "time"
|
||||
|
||||
// common
|
||||
type DBConfUpdateByFile struct {
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql redis"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
type ChangeDBInfo struct {
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Value string `json:"value" validate:"required"`
|
||||
}
|
||||
|
||||
type DBBaseInfo struct {
|
||||
Name string `json:"name"`
|
||||
ContainerName string `json:"containerName"`
|
||||
Port int64 `json:"port"`
|
||||
}
|
||||
|
||||
// mysql
|
||||
type MysqlDBSearch struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
@@ -64,14 +43,6 @@ type MysqlDBCreate struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type BindUser struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
DB string `json:"db" validate:"required"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
Permission string `json:"permission" validate:"required"`
|
||||
}
|
||||
|
||||
type MysqlLoadDB struct {
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
@@ -162,6 +133,25 @@ type MysqlVariablesUpdateHelper struct {
|
||||
Param string `json:"param"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
type MysqlConfUpdateByFile struct {
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type ChangeDBInfo struct {
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Value string `json:"value" validate:"required"`
|
||||
}
|
||||
|
||||
type DBBaseInfo struct {
|
||||
Name string `json:"name"`
|
||||
ContainerName string `json:"containerName"`
|
||||
Port int64 `json:"port"`
|
||||
}
|
||||
|
||||
// redis
|
||||
type ChangeRedisPass struct {
|
||||
@@ -237,24 +227,17 @@ type DatabaseSearch struct {
|
||||
}
|
||||
|
||||
type DatabaseInfo struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Name string `json:"name" validate:"max=256"`
|
||||
From string `json:"from"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Address string `json:"address"`
|
||||
Port uint `json:"port"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
|
||||
SSL bool `json:"ssl"`
|
||||
RootCert string `json:"rootCert"`
|
||||
ClientKey string `json:"clientKey"`
|
||||
ClientCert string `json:"clientCert"`
|
||||
SkipVerify bool `json:"skipVerify"`
|
||||
|
||||
Description string `json:"description"`
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Name string `json:"name" validate:"max=256"`
|
||||
From string `json:"from"`
|
||||
Type string `json:"type"`
|
||||
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 DatabaseOption struct {
|
||||
@@ -266,47 +249,26 @@ type DatabaseOption struct {
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
type DatabaseItem struct {
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from"`
|
||||
Database string `json:"database"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type DatabaseCreate struct {
|
||||
Name string `json:"name" validate:"required,max=256"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
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"`
|
||||
|
||||
SSL bool `json:"ssl"`
|
||||
RootCert string `json:"rootCert"`
|
||||
ClientKey string `json:"clientKey"`
|
||||
ClientCert string `json:"clientCert"`
|
||||
SkipVerify bool `json:"skipVerify"`
|
||||
|
||||
Name string `json:"name" validate:"required,max=256"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
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 DatabaseUpdate struct {
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
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"`
|
||||
|
||||
SSL bool `json:"ssl"`
|
||||
RootCert string `json:"rootCert"`
|
||||
ClientKey string `json:"clientKey"`
|
||||
ClientCert string `json:"clientCert"`
|
||||
SkipVerify bool `json:"skipVerify"`
|
||||
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
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"`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
package dto
|
||||
|
||||
import "time"
|
||||
|
||||
type PostgresqlDBSearch struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
}
|
||||
|
||||
type PostgresqlDBInfo struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Name string `json:"name"`
|
||||
From string `json:"from"`
|
||||
PostgresqlName string `json:"postgresqlName"`
|
||||
Format string `json:"format"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
SuperUser bool `json:"superUser"`
|
||||
BackupCount int `json:"backupCount"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type PostgresqlOption struct {
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from"`
|
||||
Type string `json:"type"`
|
||||
Database string `json:"database"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type PostgresqlDBCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Format string `json:"format"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
SuperUser bool `json:"superUser"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type PostgresqlBindUser struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
SuperUser bool `json:"superUser"`
|
||||
}
|
||||
|
||||
type PostgresqlPrivileges struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
SuperUser bool `json:"superUser"`
|
||||
}
|
||||
|
||||
type PostgresqlLoadDB struct {
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Type string `json:"type" validate:"required,oneof=postgresql"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
}
|
||||
|
||||
type PostgresqlDBDeleteCheck struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=postgresql"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
}
|
||||
|
||||
type PostgresqlDBDelete struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=postgresql"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
}
|
||||
|
||||
type PostgresqlConfUpdateByFile struct {
|
||||
Type string `json:"type" validate:"required,oneof=postgresql mariadb"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package dto
|
||||
|
||||
type DeviceBaseInfo struct {
|
||||
DNS []string `json:"dns"`
|
||||
Hosts []HostHelper `json:"hosts"`
|
||||
Hostname string `json:"hostname"`
|
||||
TimeZone string `json:"timeZone"`
|
||||
LocalTime string `json:"localTime"`
|
||||
Ntp string `json:"ntp"`
|
||||
User string `json:"user"`
|
||||
|
||||
SwapMemoryTotal uint64 `json:"swapMemoryTotal"`
|
||||
SwapMemoryAvailable uint64 `json:"swapMemoryAvailable"`
|
||||
SwapMemoryUsed uint64 `json:"swapMemoryUsed"`
|
||||
MaxSize uint64 `json:"maxSize"`
|
||||
|
||||
SwapDetails []SwapHelper `json:"swapDetails"`
|
||||
}
|
||||
|
||||
type HostHelper struct {
|
||||
IP string `json:"ip"`
|
||||
Host string `json:"host"`
|
||||
}
|
||||
|
||||
type SwapHelper struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Size uint64 `json:"size"`
|
||||
Used string `json:"used"`
|
||||
|
||||
IsNew bool `json:"isNew"`
|
||||
}
|
||||
|
||||
type TimeZoneOptions struct {
|
||||
From string `json:"from"`
|
||||
Zones []string `json:"zones"`
|
||||
}
|
||||
|
||||
type ChangePasswd struct {
|
||||
User string `json:"user"`
|
||||
Passwd string `json:"passwd"`
|
||||
}
|
||||
@@ -14,11 +14,6 @@ type DaemonJsonConf struct {
|
||||
IPTables bool `json:"iptables"`
|
||||
CgroupDriver string `json:"cgroupDriver"`
|
||||
|
||||
Ipv6 bool `json:"ipv6"`
|
||||
FixedCidrV6 string `json:"fixedCidrV6"`
|
||||
Ip6Tables bool `json:"ip6Tables"`
|
||||
Experimental bool `json:"experimental"`
|
||||
|
||||
LogMaxSize string `json:"logMaxSize"`
|
||||
LogMaxFile string `json:"logMaxFile"`
|
||||
}
|
||||
@@ -28,12 +23,6 @@ type LogOption struct {
|
||||
LogMaxFile string `json:"logMaxFile"`
|
||||
}
|
||||
|
||||
type Ipv6Option struct {
|
||||
FixedCidrV6 string `json:"fixedCidrV6"`
|
||||
Ip6Tables bool `json:"ip6Tables" validate:"required"`
|
||||
Experimental bool `json:"experimental"`
|
||||
}
|
||||
|
||||
type DockerOperation struct {
|
||||
Operation string `json:"operation" validate:"required,oneof=start restart stop"`
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package dto
|
||||
|
||||
type Fail2BanBaseInfo struct {
|
||||
IsEnable bool `json:"isEnable"`
|
||||
IsActive bool `json:"isActive"`
|
||||
IsExist bool `json:"isExist"`
|
||||
Version string `json:"version"`
|
||||
|
||||
Port int `json:"port"`
|
||||
MaxRetry int `json:"maxRetry"`
|
||||
BanTime string `json:"banTime"`
|
||||
FindTime string `json:"findTime"`
|
||||
BanAction string `json:"banAction"`
|
||||
LogPath string `json:"logPath"`
|
||||
}
|
||||
|
||||
type Fail2BanSearch struct {
|
||||
Status string `json:"status" validate:"required,oneof=banned ignore"`
|
||||
}
|
||||
|
||||
type Fail2BanUpdate struct {
|
||||
Key string `json:"key" validate:"required,oneof=port bantime findtime maxretry banaction logpath port"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type Fail2BanSet struct {
|
||||
IPs []string `json:"ips"`
|
||||
Operate string `json:"operate" validate:"required,oneof=banned ignore"`
|
||||
}
|
||||
@@ -16,7 +16,7 @@ type RuleSearch struct {
|
||||
}
|
||||
|
||||
type FirewallOperation struct {
|
||||
Operation string `json:"operation" validate:"required,oneof=start stop restart disablePing enablePing"`
|
||||
Operation string `json:"operation" validate:"required,oneof=start stop disablePing enablePing"`
|
||||
}
|
||||
|
||||
type PortRuleOperate struct {
|
||||
|
||||
@@ -27,6 +27,7 @@ type ImagePull struct {
|
||||
}
|
||||
|
||||
type ImageTag struct {
|
||||
RepoID uint `json:"repoID"`
|
||||
SourceID string `json:"sourceID" validate:"required"`
|
||||
TargetName string `json:"targetName" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ type AppContainerConfig struct {
|
||||
EditCompose bool `json:"editCompose"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
HostMode bool `json:"hostMode"`
|
||||
PullImage bool `json:"pullImage"`
|
||||
}
|
||||
|
||||
type AppInstalledSearch struct {
|
||||
@@ -68,7 +67,6 @@ type AppInstalledOperate struct {
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
DeleteDB bool `json:"deleteDB"`
|
||||
Backup bool `json:"backup"`
|
||||
PullImage bool `json:"pullImage"`
|
||||
}
|
||||
|
||||
type AppInstalledUpdate struct {
|
||||
|
||||
@@ -64,7 +64,7 @@ type FileDeCompress struct {
|
||||
|
||||
type FileEdit struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Content string `json:"content"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
}
|
||||
|
||||
type FileRename struct {
|
||||
@@ -77,10 +77,9 @@ type FilePathCheck struct {
|
||||
}
|
||||
|
||||
type FileWget struct {
|
||||
Url string `json:"url" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
IgnoreCertificate bool `json:"ignoreCertificate"`
|
||||
Url string `json:"url" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type FileMove struct {
|
||||
@@ -119,11 +118,9 @@ type FileRoleUpdate struct {
|
||||
}
|
||||
|
||||
type FileReadByLineReq struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Page int `json:"page" validate:"required"`
|
||||
PageSize int `json:"pageSize" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type FileExistReq struct {
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package request
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
|
||||
type PHPExtensionsSearch struct {
|
||||
dto.PageInfo
|
||||
All bool `json:"all"`
|
||||
}
|
||||
|
||||
type PHPExtensionsCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Extensions string `json:"extensions" validate:"required"`
|
||||
}
|
||||
|
||||
type PHPExtensionsUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Extensions string `json:"extensions" validate:"required"`
|
||||
}
|
||||
|
||||
type PHPExtensionsDelete struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
@@ -210,7 +210,7 @@ type WebsiteRedirectReq struct {
|
||||
type WebsiteWafFileUpdate struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=cc ip_white ip_block url_white url_block cookie_block args_check post_check ua_check file_ext_block user_agent"`
|
||||
Type 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"`
|
||||
}
|
||||
|
||||
type WebsiteCommonReq struct {
|
||||
|
||||
@@ -14,12 +14,6 @@ type WebsiteSSLCreate struct {
|
||||
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
KeyType string `json:"keyType"`
|
||||
Apply bool `json:"apply"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
ID uint `json:"id"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type WebsiteDNSReq struct {
|
||||
@@ -31,17 +25,8 @@ type WebsiteSSLRenew struct {
|
||||
SSLID uint `json:"SSLId" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteSSLApply struct {
|
||||
ID uint `json:"ID" validate:"required"`
|
||||
SkipDNSCheck bool `json:"SkipDNSCheck"`
|
||||
}
|
||||
|
||||
type WebsiteAcmeAccountCreate struct {
|
||||
Email string `json:"email" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=letsencrypt zerossl buypass google"`
|
||||
KeyType string `json:"keyType" validate:"required,oneof=P256 P384 2048 3072 4096 8192"`
|
||||
EabKid string `json:"eabKid"`
|
||||
EabHmacKey string `json:"eabHmacKey"`
|
||||
Email string `json:"email" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteDnsAccountCreate struct {
|
||||
@@ -61,14 +46,9 @@ type WebsiteResourceReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteBatchDelReq struct {
|
||||
IDs []uint `json:"ids" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteSSLUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
Description string `json:"description"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
}
|
||||
|
||||
type WebsiteSSLUpload struct {
|
||||
@@ -77,39 +57,4 @@ type WebsiteSSLUpload struct {
|
||||
PrivateKeyPath string `json:"privateKeyPath"`
|
||||
CertificatePath string `json:"certificatePath"`
|
||||
Type string `json:"type" validate:"required,oneof=paste local"`
|
||||
SSLID uint `json:"sslID"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type WebsiteCASearch struct {
|
||||
dto.PageInfo
|
||||
}
|
||||
|
||||
type WebsiteCACreate struct {
|
||||
CommonName string `json:"commonName" validate:"required"`
|
||||
Country string `json:"country" validate:"required"`
|
||||
Organization string `json:"organization" validate:"required"`
|
||||
OrganizationUint string `json:"organizationUint"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
KeyType string `json:"keyType" validate:"required,oneof=P256 P384 2048 3072 4096 8192"`
|
||||
Province string `json:"province" `
|
||||
City string `json:"city"`
|
||||
}
|
||||
|
||||
type WebsiteCAObtain struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Domains string `json:"domains" validate:"required"`
|
||||
KeyType string `json:"keyType" validate:"required,oneof=P256 P384 2048 3072 4096 8192"`
|
||||
Time int `json:"time" validate:"required"`
|
||||
Unit string `json:"unit" validate:"required"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
Renew bool `json:"renew"`
|
||||
SSLID uint `json:"sslID"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type WebsiteCARenew struct {
|
||||
SSLID uint `json:"SSLID" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
)
|
||||
@@ -73,11 +72,9 @@ type AppInstalledDTO struct {
|
||||
}
|
||||
|
||||
type DatabaseConn struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
ContainerName string `json:"containerName"`
|
||||
ServiceName string `json:"serviceName"`
|
||||
Port int64 `json:"port"`
|
||||
Password string `json:"password"`
|
||||
ServiceName string `json:"serviceName"`
|
||||
Port int64 `json:"port"`
|
||||
}
|
||||
|
||||
type AppService struct {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package response
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
|
||||
type PHPExtensionsDTO struct {
|
||||
model.PHPExtensions
|
||||
}
|
||||
@@ -13,12 +13,6 @@ type WebsiteDTO struct {
|
||||
RuntimeName string `json:"runtimeName"`
|
||||
}
|
||||
|
||||
type WebsiteOption struct {
|
||||
ID uint `json:"id"`
|
||||
PrimaryDomain string `json:"primaryDomain"`
|
||||
Alias string `json:"alias"`
|
||||
}
|
||||
|
||||
type WebsitePreInstallCheck struct {
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -4,7 +4,6 @@ import "github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
|
||||
type WebsiteSSLDTO struct {
|
||||
model.WebsiteSSL
|
||||
LogPath string `json:"logPath"`
|
||||
}
|
||||
|
||||
type WebsiteDNSRes struct {
|
||||
@@ -22,13 +21,3 @@ type WebsiteDnsAccountDTO struct {
|
||||
model.WebsiteDnsAccount
|
||||
Authorization map[string]string `json:"authorization"`
|
||||
}
|
||||
|
||||
type WebsiteCADTO struct {
|
||||
model.WebsiteCA
|
||||
CommonName string `json:"commonName" `
|
||||
Country string `json:"country"`
|
||||
Organization string `json:"organization"`
|
||||
OrganizationUint string `json:"organizationUint"`
|
||||
Province string `json:"province" `
|
||||
City string `json:"city"`
|
||||
}
|
||||
|
||||
+16
-21
@@ -3,11 +3,10 @@ package dto
|
||||
import "time"
|
||||
|
||||
type SettingInfo struct {
|
||||
UserName string `json:"userName"`
|
||||
Email string `json:"email"`
|
||||
SystemIP string `json:"systemIP"`
|
||||
SystemVersion string `json:"systemVersion"`
|
||||
DockerSockPath string `json:"dockerSockPath"`
|
||||
UserName string `json:"userName"`
|
||||
Email string `json:"email"`
|
||||
SystemIP string `json:"systemIP"`
|
||||
SystemVersion string `json:"systemVersion"`
|
||||
|
||||
SessionTimeout string `json:"sessionTimeout"`
|
||||
LocalTime string `json:"localTime"`
|
||||
@@ -50,8 +49,6 @@ type SettingInfo struct {
|
||||
AppStoreVersion string `json:"appStoreVersion"`
|
||||
AppStoreLastModified string `json:"appStoreLastModified"`
|
||||
AppStoreSyncStatus string `json:"appStoreSyncStatus"`
|
||||
|
||||
FileRecycleBin string `json:"fileRecycleBin"`
|
||||
}
|
||||
|
||||
type SettingUpdate struct {
|
||||
@@ -60,7 +57,7 @@ type SettingUpdate struct {
|
||||
}
|
||||
|
||||
type SSLUpdate struct {
|
||||
SSLType string `json:"sslType" validate:"required,oneof=self select import import-paste import-local"`
|
||||
SSLType string `json:"sslType"`
|
||||
Domain string `json:"domain"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=enable disable"`
|
||||
Cert string `json:"cert"`
|
||||
@@ -99,10 +96,9 @@ type SnapshotStatus struct {
|
||||
}
|
||||
|
||||
type SnapshotCreate struct {
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from" validate:"required"`
|
||||
DefaultDownload string `json:"defaultDownload" validate:"required"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO COS KODO OneDrive"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
}
|
||||
type SnapshotRecover struct {
|
||||
IsNew bool `json:"isNew"`
|
||||
@@ -115,15 +111,14 @@ type SnapshotImport struct {
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
}
|
||||
type SnapshotInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
From string `json:"from"`
|
||||
DefaultDownload string `json:"defaultDownload"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Version string `json:"version"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
From string `json:"from"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Version string `json:"version"`
|
||||
|
||||
InterruptStep string `json:"interruptStep"`
|
||||
RecoverStatus string `json:"recoverStatus"`
|
||||
|
||||
@@ -44,6 +44,26 @@ type SSHLog struct {
|
||||
FailedCount int `json:"failedCount"`
|
||||
}
|
||||
|
||||
type SearchForAnalysis struct {
|
||||
PageInfo
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=Success Failed"`
|
||||
}
|
||||
|
||||
type AnalysisRes struct {
|
||||
Total int64 `json:"total"`
|
||||
Items []SSHLogAnalysis `json:"items"`
|
||||
SuccessfulCount int `json:"successfulCount"`
|
||||
FailedCount int `json:"failedCount"`
|
||||
}
|
||||
|
||||
type SSHLogAnalysis struct {
|
||||
Address string `json:"address"`
|
||||
Area string `json:"area"`
|
||||
SuccessfulCount int `json:"successfulCount"`
|
||||
FailedCount int `json:"failedCount"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type SSHHistory struct {
|
||||
Date time.Time `json:"date"`
|
||||
DateStr string `json:"dateStr"`
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
BaseModel
|
||||
Name string `json:"name" gorm:"type:varchar(64);not null"`
|
||||
@@ -30,14 +24,3 @@ type App struct {
|
||||
TagsKey []string `json:"tags" yaml:"tags" gorm:"-"`
|
||||
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
||||
}
|
||||
|
||||
func (i *App) IsLocalApp() bool {
|
||||
return i.Resource == constant.ResourceLocal
|
||||
}
|
||||
func (i *App) GetAppResourcePath() string {
|
||||
if i.IsLocalApp() {
|
||||
//这里要去掉本地应用的local前缀
|
||||
return filepath.Join(constant.LocalAppResourceDir, strings.TrimPrefix(i.Key, "local"))
|
||||
}
|
||||
return filepath.Join(constant.RemoteAppResourceDir, i.Key)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ type BackupAccount struct {
|
||||
|
||||
type BackupRecord struct {
|
||||
BaseModel
|
||||
From string `gorm:"type:varchar(64)" json:"from"`
|
||||
CronjobID uint `gorm:"type:decimal" json:"cronjobID"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||
DetailName string `gorm:"type:varchar(256)" json:"detailName"`
|
||||
|
||||
@@ -5,31 +5,32 @@ import "time"
|
||||
type Cronjob struct {
|
||||
BaseModel
|
||||
|
||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Spec string `gorm:"type:varchar(64);not null" json:"spec"`
|
||||
Name string `gorm:"type:varchar(64);not null;unique" json:"name"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
SpecType string `gorm:"type:varchar(64);not null" json:"specType"`
|
||||
Spec string `gorm:"type:varchar(64);not null" json:"spec"`
|
||||
Week uint64 `gorm:"type:decimal" json:"week"`
|
||||
Day uint64 `gorm:"type:decimal" json:"day"`
|
||||
Hour uint64 `gorm:"type:decimal" json:"hour"`
|
||||
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"`
|
||||
Website string `gorm:"type:varchar(64)" json:"website"`
|
||||
AppID string `gorm:"type:varchar(64)" json:"appID"`
|
||||
DBType string `gorm:"type:varchar(64)" json:"dbType"`
|
||||
DBName string `gorm:"type:varchar(64)" json:"dbName"`
|
||||
URL string `gorm:"type:varchar(256)" json:"url"`
|
||||
SourceDir string `gorm:"type:varchar(256)" json:"sourceDir"`
|
||||
ExclusionRules string `gorm:"longtext" json:"exclusionRules"`
|
||||
|
||||
// 已废弃
|
||||
KeepLocal bool `gorm:"type:varchar(64)" json:"keepLocal"`
|
||||
TargetDirID uint64 `gorm:"type:decimal" json:"targetDirID"`
|
||||
KeepLocal bool `gorm:"type:varchar(64)" json:"keepLocal"`
|
||||
TargetDirID uint64 `gorm:"type:decimal" json:"targetDirID"`
|
||||
RetainCopies uint64 `gorm:"type:decimal" json:"retainCopies"`
|
||||
|
||||
BackupAccounts string `gorm:"type:varchar(64)" json:"backupAccounts"`
|
||||
DefaultDownload string `gorm:"type:varchar(64)" json:"defaultDownload"`
|
||||
RetainCopies uint64 `gorm:"type:decimal" json:"retainCopies"`
|
||||
|
||||
Status string `gorm:"type:varchar(64)" json:"status"`
|
||||
EntryIDs string `gorm:"type:varchar(64)" json:"entryIDs"`
|
||||
Records []JobRecords `json:"records"`
|
||||
Status string `gorm:"type:varchar(64)" json:"status"`
|
||||
EntryID uint64 `gorm:"type:decimal" json:"entryID"`
|
||||
Records []JobRecords `json:"records"`
|
||||
}
|
||||
|
||||
type JobRecords struct {
|
||||
|
||||
@@ -11,12 +11,5 @@ type Database struct {
|
||||
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)"`
|
||||
|
||||
SSL bool `json:"ssl"`
|
||||
RootCert string `json:"rootCert" gorm:"type:longText"`
|
||||
ClientKey string `json:"clientKey" gorm:"type:longText"`
|
||||
ClientCert string `json:"clientCert" gorm:"type:longText"`
|
||||
SkipVerify bool `json:"skipVerify"`
|
||||
|
||||
Description string `json:"description" gorm:"type:varchar(256);"`
|
||||
Description string `json:"description" gorm:"type:varchar(256);"`
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package model
|
||||
|
||||
type DatabasePostgresql struct {
|
||||
BaseModel
|
||||
Name string `json:"name" gorm:"type:varchar(256);not null"`
|
||||
From string `json:"from" gorm:"type:varchar(256);not null;default:local"`
|
||||
PostgresqlName string `json:"postgresqlName" 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"`
|
||||
Password string `json:"password" gorm:"type:varchar(256);not null"`
|
||||
SuperUser bool `json:"superUser" gorm:"type:varchar(64)" `
|
||||
Description string `json:"description" gorm:"type:varchar(256);"`
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package model
|
||||
|
||||
type PHPExtensions struct {
|
||||
BaseModel
|
||||
Name string ` json:"name" gorm:"not null"`
|
||||
Extensions string `json:"extensions" gorm:"not null"`
|
||||
}
|
||||
@@ -2,13 +2,12 @@ package model
|
||||
|
||||
type Snapshot struct {
|
||||
BaseModel
|
||||
Name string `json:"name" gorm:"type:varchar(64);not null;unique"`
|
||||
Description string `json:"description" gorm:"type:varchar(256)"`
|
||||
From string `json:"from"`
|
||||
DefaultDownload string `json:"defaultDownload" gorm:"type:varchar(64)"`
|
||||
Status string `json:"status" gorm:"type:varchar(64)"`
|
||||
Message string `json:"message" gorm:"type:varchar(256)"`
|
||||
Version string `json:"version" gorm:"type:varchar(256)"`
|
||||
Name string `json:"name" gorm:"type:varchar(64);not null;unique"`
|
||||
Description string `json:"description" gorm:"type:varchar(256)"`
|
||||
From string `json:"from"`
|
||||
Status string `json:"status" gorm:"type:varchar(64)"`
|
||||
Message string `json:"message" gorm:"type:varchar(256)"`
|
||||
Version string `json:"version" gorm:"type:varchar(256)"`
|
||||
|
||||
InterruptStep string `json:"interruptStep" gorm:"type:varchar(64)"`
|
||||
RecoverStatus string `json:"recoverStatus" gorm:"type:varchar(64)"`
|
||||
|
||||
@@ -2,13 +2,9 @@ package model
|
||||
|
||||
type WebsiteAcmeAccount struct {
|
||||
BaseModel
|
||||
Email string `gorm:"not null" json:"email"`
|
||||
URL string `gorm:"not null" json:"url"`
|
||||
PrivateKey string `gorm:"not null" json:"-"`
|
||||
Type string `gorm:"not null;default:letsencrypt" json:"type"`
|
||||
EabKid string `gorm:"default:null;" json:"eabKid"`
|
||||
EabHmacKey string `gorm:"default:null" json:"eabHmacKey"`
|
||||
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
||||
Email string `gorm:"type:varchar(256);not null" json:"email"`
|
||||
URL string `gorm:"type:varchar(256);not null" json:"url"`
|
||||
PrivateKey string `gorm:"type:longtext;not null" json:"-"`
|
||||
}
|
||||
|
||||
func (w WebsiteAcmeAccount) TableName() string {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package model
|
||||
|
||||
type WebsiteCA struct {
|
||||
BaseModel
|
||||
CSR string `gorm:"not null;" json:"csr"`
|
||||
Name string `gorm:"not null;" json:"name"`
|
||||
PrivateKey string `gorm:"not null" json:"privateKey"`
|
||||
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
import "time"
|
||||
|
||||
type WebsiteSSL struct {
|
||||
BaseModel
|
||||
@@ -19,26 +14,14 @@ type WebsiteSSL struct {
|
||||
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
|
||||
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
|
||||
CaID uint `gorm:"type:integer;not null;default:0" json:"caId"`
|
||||
AutoRenew bool `gorm:"type:varchar(64);not null" json:"autoRenew"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
StartDate time.Time `json:"startDate"`
|
||||
Status string `gorm:"not null;default:ready" json:"status"`
|
||||
Message string `json:"message"`
|
||||
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
||||
PushDir bool `gorm:"not null;default:0" json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
Description string `json:"description"`
|
||||
|
||||
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
|
||||
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
|
||||
Websites []Website `json:"websites" gorm:"-:migration"`
|
||||
}
|
||||
|
||||
func (w WebsiteSSL) TableName() string {
|
||||
return "website_ssls"
|
||||
}
|
||||
|
||||
func (w WebsiteSSL) GetLogPath() string {
|
||||
return path.Join(constant.SSLLogDir, fmt.Sprintf("%s-ssl-%d.log", w.PrimaryDomain, w.ID))
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ type IAppRepo interface {
|
||||
OrderByRecommend() DBOption
|
||||
GetRecommend() DBOption
|
||||
WithResource(resource string) DBOption
|
||||
WithLikeName(name string) DBOption
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.App, error)
|
||||
GetFirst(opts ...DBOption) (model.App, error)
|
||||
GetBy(opts ...DBOption) ([]model.App, error)
|
||||
@@ -32,15 +31,6 @@ func NewIAppRepo() IAppRepo {
|
||||
return &AppRepo{}
|
||||
}
|
||||
|
||||
func (a AppRepo) WithLikeName(name string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if len(name) == 0 {
|
||||
return g
|
||||
}
|
||||
return g.Where("name like ? or short_desc_zh like ? or short_desc_en like ?", "%"+name+"%", "%"+name+"%", "%"+name+"%")
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppRepo) WithKey(key string) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("key = ?", key)
|
||||
|
||||
@@ -3,7 +3,6 @@ package repo
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
@@ -171,7 +170,6 @@ type RootInfo struct {
|
||||
Env string `json:"env"`
|
||||
Key string `json:"key"`
|
||||
Version string `json:"version"`
|
||||
AppPath string `json:"app_path"`
|
||||
}
|
||||
|
||||
func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error) {
|
||||
@@ -207,7 +205,7 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
||||
if ok {
|
||||
info.Password = password
|
||||
}
|
||||
case "mongodb", constant.AppPostgresql:
|
||||
case "mongodb", "postgresql":
|
||||
user, ok := envMap["PANEL_DB_ROOT_USER"].(string)
|
||||
if ok {
|
||||
info.UserName = user
|
||||
@@ -232,7 +230,5 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
||||
info.Param = appInstall.Param
|
||||
info.Version = appInstall.Version
|
||||
info.Key = app.Key
|
||||
appInstall.App = app
|
||||
info.AppPath = appInstall.GetAppPath()
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"gorm.io/gorm"
|
||||
@@ -20,11 +19,9 @@ type IBackupRepo interface {
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
Delete(opts ...DBOption) error
|
||||
DeleteRecord(ctx context.Context, opts ...DBOption) error
|
||||
UpdateRecord(record *model.BackupRecord) error
|
||||
WithByDetailName(detailName string) DBOption
|
||||
WithByFileName(fileName string) DBOption
|
||||
WithByType(backupType string) DBOption
|
||||
WithByCronID(cronjobID uint) DBOption
|
||||
}
|
||||
|
||||
func NewIBackupRepo() IBackupRepo {
|
||||
@@ -108,10 +105,6 @@ func (u *BackupRepo) CreateRecord(record *model.BackupRecord) error {
|
||||
return global.DB.Create(record).Error
|
||||
}
|
||||
|
||||
func (u *BackupRepo) UpdateRecord(record *model.BackupRecord) error {
|
||||
return global.DB.Save(record).Error
|
||||
}
|
||||
|
||||
func (u *BackupRepo) Update(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.BackupAccount{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
@@ -127,9 +120,3 @@ func (u *BackupRepo) Delete(opts ...DBOption) error {
|
||||
func (u *BackupRepo) DeleteRecord(ctx context.Context, opts ...DBOption) error {
|
||||
return getTx(ctx, opts...).Delete(&model.BackupRecord{}).Error
|
||||
}
|
||||
|
||||
func (u *BackupRepo) WithByCronID(cronjobID uint) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("cronjob_id = ?", cronjobID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,7 @@ type ICronjobRepo interface {
|
||||
Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error)
|
||||
Create(cronjob *model.Cronjob) error
|
||||
WithByJobID(id int) DBOption
|
||||
WithByDbName(name string) DBOption
|
||||
WithByDefaultDownload(account string) DBOption
|
||||
WithByBackupID(id uint) DBOption
|
||||
WithByRecordDropID(id int) DBOption
|
||||
WithByRecordFile(file string) DBOption
|
||||
Save(id uint, cronjob model.Cronjob) error
|
||||
@@ -29,7 +28,6 @@ type ICronjobRepo interface {
|
||||
Delete(opts ...DBOption) error
|
||||
DeleteRecord(opts ...DBOption) error
|
||||
StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords
|
||||
UpdateRecords(id uint, vars map[string]interface{}) error
|
||||
EndRecords(record model.JobRecords, status, message, records string)
|
||||
PageRecords(page, size int, opts ...DBOption) (int64, []model.JobRecords, error)
|
||||
}
|
||||
@@ -118,15 +116,9 @@ func (c *CronjobRepo) WithByJobID(id int) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CronjobRepo) WithByDbName(name string) DBOption {
|
||||
func (c *CronjobRepo) WithByBackupID(id uint) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("db_name = ?", name)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CronjobRepo) WithByDefaultDownload(account string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("default_download = ?", account)
|
||||
return g.Where("target_dir_id = ?", id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,10 +164,6 @@ func (u *CronjobRepo) Update(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.Cronjob{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
|
||||
func (u *CronjobRepo) UpdateRecords(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.JobRecords{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
|
||||
func (u *CronjobRepo) Delete(opts ...DBOption) error {
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type PostgresqlRepo struct{}
|
||||
|
||||
type IPostgresqlRepo interface {
|
||||
Get(opts ...DBOption) (model.DatabasePostgresql, error)
|
||||
WithByPostgresqlName(postgresqlName string) DBOption
|
||||
WithByFrom(from string) DBOption
|
||||
List(opts ...DBOption) ([]model.DatabasePostgresql, error)
|
||||
Page(limit, offset int, opts ...DBOption) (int64, []model.DatabasePostgresql, error)
|
||||
Create(ctx context.Context, postgresql *model.DatabasePostgresql) error
|
||||
Delete(ctx context.Context, opts ...DBOption) error
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
DeleteLocal(ctx context.Context) error
|
||||
}
|
||||
|
||||
func NewIPostgresqlRepo() IPostgresqlRepo {
|
||||
return &PostgresqlRepo{}
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) Get(opts ...DBOption) (model.DatabasePostgresql, error) {
|
||||
var postgresql model.DatabasePostgresql
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
if err := db.First(&postgresql).Error; err != nil {
|
||||
return postgresql, err
|
||||
}
|
||||
|
||||
pass, err := encrypt.StringDecrypt(postgresql.Password)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("decrypt database db %s password failed, err: %v", postgresql.Name, err)
|
||||
}
|
||||
postgresql.Password = pass
|
||||
return postgresql, err
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) List(opts ...DBOption) ([]model.DatabasePostgresql, error) {
|
||||
var postgresqls []model.DatabasePostgresql
|
||||
db := global.DB.Model(&model.DatabasePostgresql{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
if err := db.Find(&postgresqls).Error; err != nil {
|
||||
return postgresqls, err
|
||||
}
|
||||
for i := 0; i < len(postgresqls); i++ {
|
||||
pass, err := encrypt.StringDecrypt(postgresqls[i].Password)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("decrypt database db %s password failed, err: %v", postgresqls[i].Name, err)
|
||||
}
|
||||
postgresqls[i].Password = pass
|
||||
}
|
||||
return postgresqls, nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) Page(page, size int, opts ...DBOption) (int64, []model.DatabasePostgresql, error) {
|
||||
var postgresqls []model.DatabasePostgresql
|
||||
db := global.DB.Model(&model.DatabasePostgresql{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
if err := db.Limit(size).Offset(size * (page - 1)).Find(&postgresqls).Error; err != nil {
|
||||
return count, postgresqls, err
|
||||
}
|
||||
for i := 0; i < len(postgresqls); i++ {
|
||||
pass, err := encrypt.StringDecrypt(postgresqls[i].Password)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("decrypt database db %s password failed, err: %v", postgresqls[i].Name, err)
|
||||
}
|
||||
postgresqls[i].Password = pass
|
||||
}
|
||||
return count, postgresqls, nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) Create(ctx context.Context, postgresql *model.DatabasePostgresql) error {
|
||||
pass, err := encrypt.StringEncrypt(postgresql.Password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decrypt database db %s password failed, err: %v", postgresql.Name, err)
|
||||
}
|
||||
postgresql.Password = pass
|
||||
return getTx(ctx).Create(postgresql).Error
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) Delete(ctx context.Context, opts ...DBOption) error {
|
||||
return getTx(ctx, opts...).Delete(&model.DatabasePostgresql{}).Error
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) DeleteLocal(ctx context.Context) error {
|
||||
return getTx(ctx).Where("`from` = ?", "local").Delete(&model.DatabasePostgresql{}).Error
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) Update(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.DatabasePostgresql{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) WithByPostgresqlName(postgresqlName string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("postgresql_name = ?", postgresqlName)
|
||||
}
|
||||
}
|
||||
|
||||
func (u *PostgresqlRepo) WithByFrom(from string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if len(from) != 0 {
|
||||
return g.Where("`from` = ?", from)
|
||||
}
|
||||
return g
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
)
|
||||
|
||||
type PHPExtensionsRepo struct {
|
||||
}
|
||||
|
||||
type IPHPExtensionsRepo interface {
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.PHPExtensions, error)
|
||||
Save(extension *model.PHPExtensions) error
|
||||
Create(extension *model.PHPExtensions) error
|
||||
GetFirst(opts ...DBOption) (model.PHPExtensions, error)
|
||||
DeleteBy(opts ...DBOption) error
|
||||
List() ([]model.PHPExtensions, error)
|
||||
}
|
||||
|
||||
func NewIPHPExtensionsRepo() IPHPExtensionsRepo {
|
||||
return &PHPExtensionsRepo{}
|
||||
}
|
||||
|
||||
func (p *PHPExtensionsRepo) Page(page, size int, opts ...DBOption) (int64, []model.PHPExtensions, error) {
|
||||
var (
|
||||
phpExtensions []model.PHPExtensions
|
||||
)
|
||||
db := getDb(opts...).Model(&model.PHPExtensions{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&phpExtensions).Error
|
||||
return count, phpExtensions, err
|
||||
}
|
||||
|
||||
func (p *PHPExtensionsRepo) List() ([]model.PHPExtensions, error) {
|
||||
var (
|
||||
phpExtensions []model.PHPExtensions
|
||||
)
|
||||
err := getDb().Model(&model.PHPExtensions{}).Find(&phpExtensions).Error
|
||||
return phpExtensions, err
|
||||
}
|
||||
|
||||
func (p *PHPExtensionsRepo) Save(extension *model.PHPExtensions) error {
|
||||
return getDb().Save(&extension).Error
|
||||
}
|
||||
|
||||
func (p *PHPExtensionsRepo) Create(extension *model.PHPExtensions) error {
|
||||
return getDb().Create(&extension).Error
|
||||
}
|
||||
|
||||
func (p *PHPExtensionsRepo) GetFirst(opts ...DBOption) (model.PHPExtensions, error) {
|
||||
var extension model.PHPExtensions
|
||||
db := getDb(opts...).Model(&model.PHPExtensions{})
|
||||
err := db.First(&extension).Error
|
||||
return extension, err
|
||||
}
|
||||
|
||||
func (p *PHPExtensionsRepo) DeleteBy(opts ...DBOption) error {
|
||||
return getDb(opts...).Delete(&model.PHPExtensions{}).Error
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func (w *WebsiteRepo) Page(page, size int, opts ...DBOption) (int64, []model.Web
|
||||
|
||||
func (w *WebsiteRepo) List(opts ...DBOption) ([]model.Website, error) {
|
||||
var websites []model.Website
|
||||
err := getDb(opts...).Model(&model.Website{}).Preload("Domains").Preload("WebsiteSSL").Find(&websites).Error
|
||||
err := getDb(opts...).Model(&model.Website{}).Preload("WebsiteSSL").Find(&websites).Error
|
||||
return websites, err
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ type IAcmeAccountRepo interface {
|
||||
Save(account model.WebsiteAcmeAccount) error
|
||||
DeleteBy(opts ...DBOption) error
|
||||
WithEmail(email string) DBOption
|
||||
WithType(acType string) DBOption
|
||||
}
|
||||
|
||||
func NewIAcmeAccountRepo() IAcmeAccountRepo {
|
||||
@@ -27,11 +26,6 @@ func (w *WebsiteAcmeAccountRepo) WithEmail(email string) DBOption {
|
||||
return db.Where("email = ?", email)
|
||||
}
|
||||
}
|
||||
func (w *WebsiteAcmeAccountRepo) WithType(acType string) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("type = ?", acType)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebsiteAcmeAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteAcmeAccount, error) {
|
||||
var accounts []model.WebsiteAcmeAccount
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
)
|
||||
|
||||
type WebsiteCARepo struct {
|
||||
}
|
||||
|
||||
func NewIWebsiteCARepo() IWebsiteCARepo {
|
||||
return &WebsiteCARepo{}
|
||||
}
|
||||
|
||||
type IWebsiteCARepo interface {
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteCA, error)
|
||||
GetFirst(opts ...DBOption) (model.WebsiteCA, error)
|
||||
List(opts ...DBOption) ([]model.WebsiteCA, error)
|
||||
Create(ctx context.Context, ca *model.WebsiteCA) error
|
||||
DeleteBy(opts ...DBOption) error
|
||||
}
|
||||
|
||||
func (w WebsiteCARepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteCA, error) {
|
||||
var caList []model.WebsiteCA
|
||||
db := getDb(opts...).Model(&model.WebsiteCA{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&caList).Error
|
||||
return count, caList, err
|
||||
}
|
||||
|
||||
func (w WebsiteCARepo) GetFirst(opts ...DBOption) (model.WebsiteCA, error) {
|
||||
var ca model.WebsiteCA
|
||||
db := getDb(opts...).Model(&model.WebsiteCA{})
|
||||
if err := db.First(&ca).Error; err != nil {
|
||||
return ca, err
|
||||
}
|
||||
return ca, nil
|
||||
}
|
||||
|
||||
func (w WebsiteCARepo) List(opts ...DBOption) ([]model.WebsiteCA, error) {
|
||||
var caList []model.WebsiteCA
|
||||
db := getDb(opts...).Model(&model.WebsiteCA{})
|
||||
err := db.Find(&caList).Error
|
||||
return caList, err
|
||||
}
|
||||
|
||||
func (w WebsiteCARepo) Create(ctx context.Context, ca *model.WebsiteCA) error {
|
||||
return getTx(ctx).Create(ca).Error
|
||||
}
|
||||
|
||||
func (w WebsiteCARepo) DeleteBy(opts ...DBOption) error {
|
||||
return getDb(opts...).Delete(&model.WebsiteCA{}).Error
|
||||
}
|
||||
@@ -14,12 +14,11 @@ type ISSLRepo interface {
|
||||
WithByAlias(alias string) DBOption
|
||||
WithByAcmeAccountId(acmeAccountId uint) DBOption
|
||||
WithByDnsAccountId(dnsAccountId uint) DBOption
|
||||
WithByCAID(caID uint) DBOption
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteSSL, error)
|
||||
GetFirst(opts ...DBOption) (*model.WebsiteSSL, error)
|
||||
GetFirst(opts ...DBOption) (model.WebsiteSSL, error)
|
||||
List(opts ...DBOption) ([]model.WebsiteSSL, error)
|
||||
Create(ctx context.Context, ssl *model.WebsiteSSL) error
|
||||
Save(ssl *model.WebsiteSSL) error
|
||||
Save(ssl model.WebsiteSSL) error
|
||||
DeleteBy(opts ...DBOption) error
|
||||
}
|
||||
|
||||
@@ -44,25 +43,19 @@ func (w WebsiteSSLRepo) WithByDnsAccountId(dnsAccountId uint) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) WithByCAID(caID uint) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("ca_id = ?", caID)
|
||||
}
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteSSL, error) {
|
||||
var sslList []model.WebsiteSSL
|
||||
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("AcmeAccount").Preload("DnsAccount").Preload("Websites").Find(&sslList).Error
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("AcmeAccount").Preload("Websites").Find(&sslList).Error
|
||||
return count, sslList, err
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (*model.WebsiteSSL, error) {
|
||||
var website *model.WebsiteSSL
|
||||
func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (model.WebsiteSSL, error) {
|
||||
var website model.WebsiteSSL
|
||||
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
||||
if err := db.Preload("AcmeAccount").Preload("DnsAccount").First(&website).Error; err != nil {
|
||||
if err := db.Preload("AcmeAccount").First(&website).Error; err != nil {
|
||||
return website, err
|
||||
}
|
||||
return website, nil
|
||||
@@ -71,7 +64,7 @@ func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (*model.WebsiteSSL, error) {
|
||||
func (w WebsiteSSLRepo) List(opts ...DBOption) ([]model.WebsiteSSL, error) {
|
||||
var websites []model.WebsiteSSL
|
||||
db := getDb(opts...).Model(&model.WebsiteSSL{})
|
||||
if err := db.Preload("AcmeAccount").Preload("DnsAccount").Find(&websites).Error; err != nil {
|
||||
if err := db.Preload("AcmeAccount").Find(&websites).Error; err != nil {
|
||||
return websites, err
|
||||
}
|
||||
return websites, nil
|
||||
@@ -81,7 +74,7 @@ func (w WebsiteSSLRepo) Create(ctx context.Context, ssl *model.WebsiteSSL) error
|
||||
return getTx(ctx).Create(ssl).Error
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) Save(ssl *model.WebsiteSSL) error {
|
||||
func (w WebsiteSSLRepo) Save(ssl model.WebsiteSSL) error {
|
||||
return getDb().Save(&ssl).Error
|
||||
}
|
||||
|
||||
|
||||
+14
-15
@@ -8,7 +8,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -53,7 +53,7 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
|
||||
var opts []repo.DBOption
|
||||
opts = append(opts, appRepo.OrderByRecommend())
|
||||
if req.Name != "" {
|
||||
opts = append(opts, appRepo.WithLikeName(req.Name))
|
||||
opts = append(opts, commonRepo.WithLikeName(req.Name))
|
||||
}
|
||||
if req.Type != "" {
|
||||
opts = append(opts, appRepo.WithType(req.Type))
|
||||
@@ -61,7 +61,7 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
|
||||
if req.Recommend {
|
||||
opts = append(opts, appRepo.GetRecommend())
|
||||
}
|
||||
if req.Resource != "" && req.Resource != "all" {
|
||||
if req.Resource != "" {
|
||||
opts = append(opts, appRepo.WithResource(req.Resource))
|
||||
}
|
||||
if len(req.Tags) != 0 {
|
||||
@@ -173,8 +173,7 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
|
||||
return appDetailDTO, err
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
|
||||
versionPath := filepath.Join(app.GetAppResourcePath(), detail.Version)
|
||||
versionPath := path.Join(constant.AppResourceDir, app.Resource, app.Key, detail.Version)
|
||||
if !fileOp.Stat(versionPath) || detail.Update {
|
||||
if err = downloadApp(app, detail, nil); err != nil {
|
||||
return appDetailDTO, err
|
||||
@@ -182,8 +181,8 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
|
||||
}
|
||||
switch app.Type {
|
||||
case constant.RuntimePHP:
|
||||
buildPath := filepath.Join(versionPath, "build")
|
||||
paramsPath := filepath.Join(buildPath, "config.json")
|
||||
buildPath := path.Join(versionPath, "build")
|
||||
paramsPath := path.Join(buildPath, "config.json")
|
||||
if !fileOp.Stat(paramsPath) {
|
||||
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
|
||||
}
|
||||
@@ -196,7 +195,7 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
|
||||
return appDetailDTO, err
|
||||
}
|
||||
appDetailDTO.Params = paramMap
|
||||
composePath := filepath.Join(buildPath, "docker-compose.yml")
|
||||
composePath := path.Join(buildPath, "docker-compose.yml")
|
||||
if !fileOp.Stat(composePath) {
|
||||
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
|
||||
}
|
||||
@@ -224,7 +223,7 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
|
||||
}
|
||||
|
||||
if appDetailDTO.DockerCompose == "" {
|
||||
filename := filepath.Base(appDetailDTO.DownloadUrl)
|
||||
filename := path.Base(appDetailDTO.DownloadUrl)
|
||||
dockerComposeUrl := fmt.Sprintf("%s%s", strings.TrimSuffix(appDetailDTO.DownloadUrl, filename), "docker-compose.yml")
|
||||
composeRes, err := http.Get(dockerComposeUrl)
|
||||
if err != nil {
|
||||
@@ -397,7 +396,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
}
|
||||
index++
|
||||
}
|
||||
if app.Limit == 0 && appInstall.Name != serviceName && len(servicesMap) == 1 {
|
||||
if app.Limit == 0 && appInstall.Name != serviceName {
|
||||
servicesMap[appInstall.Name] = servicesMap[serviceName]
|
||||
delete(servicesMap, serviceName)
|
||||
serviceName = appInstall.Name
|
||||
@@ -459,7 +458,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
if err = runScript(appInstall, "init"); err != nil {
|
||||
return
|
||||
}
|
||||
upApp(appInstall, req.PullImage)
|
||||
upApp(appInstall)
|
||||
}()
|
||||
go updateToolApp(appInstall)
|
||||
return
|
||||
@@ -490,7 +489,7 @@ func (a AppService) SyncAppListFromLocal() {
|
||||
}
|
||||
for _, dirEntry := range dirEntries {
|
||||
if dirEntry.IsDir() {
|
||||
appDir := filepath.Join(localAppDir, dirEntry.Name())
|
||||
appDir := path.Join(localAppDir, dirEntry.Name())
|
||||
appDirEntries, err := os.ReadDir(appDir)
|
||||
if err != nil {
|
||||
global.LOG.Errorf(i18n.GetMsgWithMap("ErrAppDirNull", map[string]interface{}{"name": dirEntry.Name(), "err": err.Error()}))
|
||||
@@ -508,7 +507,7 @@ func (a AppService) SyncAppListFromLocal() {
|
||||
Version: appDirEntry.Name(),
|
||||
Status: constant.AppNormal,
|
||||
}
|
||||
versionDir := filepath.Join(appDir, appDirEntry.Name())
|
||||
versionDir := path.Join(appDir, appDirEntry.Name())
|
||||
if err = handleLocalAppDetail(versionDir, &appDetail); err != nil {
|
||||
global.LOG.Errorf(i18n.GetMsgWithMap("LocalAppVersionErr", map[string]interface{}{"name": app.Name, "version": appDetail.Version, "err": err.Error()}))
|
||||
continue
|
||||
@@ -743,7 +742,7 @@ func getAppFromRepo(downloadPath string) error {
|
||||
downloadUrl := downloadPath
|
||||
global.LOG.Infof("[AppStore] download file from %s", downloadUrl)
|
||||
fileOp := files.NewFileOp()
|
||||
packagePath := filepath.Join(constant.ResourceDir, filepath.Base(downloadUrl))
|
||||
packagePath := path.Join(constant.ResourceDir, path.Base(downloadUrl))
|
||||
if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -761,7 +760,7 @@ func getAppList() (*dto.AppList, error) {
|
||||
if err := getAppFromRepo(fmt.Sprintf("%s/%s/1panel.json.zip", global.CONF.System.AppRepo, global.CONF.System.Mode)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listFile := filepath.Join(constant.ResourceDir, "1panel.json")
|
||||
listFile := path.Join(constant.ResourceDir, "1panel.json")
|
||||
content, err := os.ReadFile(listFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -8,10 +8,11 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
@@ -150,7 +151,7 @@ func (a *AppInstallService) CheckExist(req request.AppInstalledInfo) (*response.
|
||||
if reflect.DeepEqual(appInstall, model.AppInstall{}) {
|
||||
return res, nil
|
||||
}
|
||||
if err = syncAppInstallStatus(&appInstall); err != nil {
|
||||
if err = syncByID(appInstall.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -182,11 +183,9 @@ func (a *AppInstallService) LoadConnInfo(req dto.OperationWithNameAndType) (resp
|
||||
if err != nil {
|
||||
return data, nil
|
||||
}
|
||||
data.Username = app.UserName
|
||||
data.Password = app.Password
|
||||
data.ServiceName = app.ServiceName
|
||||
data.Port = app.Port
|
||||
data.ContainerName = app.ContainerName
|
||||
return data, nil
|
||||
}
|
||||
|
||||
@@ -240,30 +239,28 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
if err != nil {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
return syncAppInstallStatus(&install)
|
||||
return syncByID(install.ID)
|
||||
case constant.Stop:
|
||||
out, err := compose.Stop(dockerComposePath)
|
||||
if err != nil {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
return syncAppInstallStatus(&install)
|
||||
return syncByID(install.ID)
|
||||
case constant.Restart:
|
||||
out, err := compose.Restart(dockerComposePath)
|
||||
if err != nil {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
return syncAppInstallStatus(&install)
|
||||
return syncByID(install.ID)
|
||||
case constant.Delete:
|
||||
if err := deleteAppInstall(install, req.DeleteBackup, req.ForceDelete, req.DeleteDB); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
case constant.Sync:
|
||||
return syncAppInstallStatus(&install)
|
||||
return syncByID(install.ID)
|
||||
case constant.Upgrade:
|
||||
return upgradeInstall(install.ID, req.DetailId, req.Backup, req.PullImage)
|
||||
case constant.Reload:
|
||||
return opNginx(install.ContainerName, constant.NginxReload)
|
||||
return upgradeInstall(install.ID, req.DetailId, req.Backup)
|
||||
default:
|
||||
return errors.New("operate not support")
|
||||
}
|
||||
@@ -411,7 +408,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
||||
return err
|
||||
}
|
||||
for _, i := range allList {
|
||||
if i.Status == constant.Installing || i.Status == constant.Upgrading || i.Status == constant.Rebuilding {
|
||||
if i.Status == constant.Installing || i.Status == constant.Upgrading {
|
||||
if systemInit {
|
||||
i.Status = constant.Error
|
||||
i.Message = "1Panel restart causes the task to terminate"
|
||||
@@ -420,7 +417,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
||||
continue
|
||||
}
|
||||
if !systemInit {
|
||||
if err = syncAppInstallStatus(&i); err != nil {
|
||||
if err := syncByID(i.ID); err != nil {
|
||||
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -431,9 +428,6 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
||||
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
||||
var res []response.AppService
|
||||
if DatabaseKeys[key] > 0 {
|
||||
if key == constant.AppPostgres {
|
||||
key = constant.AppPostgresql
|
||||
}
|
||||
dbs, _ := databaseRepo.GetList(commonRepo.WithByType(key))
|
||||
if len(dbs) == 0 {
|
||||
return res, nil
|
||||
@@ -511,9 +505,6 @@ func (a *AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion,
|
||||
})
|
||||
}
|
||||
}
|
||||
sort.Slice(versions, func(i, j int) bool {
|
||||
return common.CompareVersion(versions[i].Version, versions[j].Version)
|
||||
})
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
@@ -527,7 +518,7 @@ func (a *AppInstallService) ChangeAppPort(req request.PortUpdate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := updateInstallInfoInDB(req.Key, req.Name, "port", strconv.FormatInt(req.Port, 10)); err != nil {
|
||||
if err := updateInstallInfoInDB(req.Key, req.Name, "port", true, strconv.FormatInt(req.Port, 10)); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -639,11 +630,10 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
||||
for _, form := range appForm.FormFields {
|
||||
if v, ok := envs[form.EnvKey]; ok {
|
||||
appParam := response.AppParam{
|
||||
Edit: false,
|
||||
Key: form.EnvKey,
|
||||
Rule: form.Rule,
|
||||
Type: form.Type,
|
||||
Multiple: form.Multiple,
|
||||
Edit: false,
|
||||
Key: form.EnvKey,
|
||||
Rule: form.Rule,
|
||||
Type: form.Type,
|
||||
}
|
||||
if form.Edit {
|
||||
appParam.Edit = true
|
||||
@@ -655,20 +645,10 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
||||
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
||||
appParam.ShowValue = appInstall.Name
|
||||
} else if form.Type == "select" {
|
||||
if form.Multiple {
|
||||
if v == "" {
|
||||
appParam.Value = []string{}
|
||||
} else {
|
||||
if str, ok := v.(string); ok {
|
||||
appParam.Value = strings.Split(str, ",")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, fv := range form.Values {
|
||||
if fv.Value == v {
|
||||
appParam.ShowValue = fv.Label
|
||||
break
|
||||
}
|
||||
for _, fv := range form.Values {
|
||||
if fv.Value == v {
|
||||
appParam.ShowValue = fv.Label
|
||||
break
|
||||
}
|
||||
}
|
||||
appParam.Values = form.Values
|
||||
@@ -676,15 +656,14 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
||||
params = append(params, 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,
|
||||
Multiple: form.Multiple,
|
||||
Edit: form.Edit,
|
||||
Key: form.EnvKey,
|
||||
Rule: form.Rule,
|
||||
Type: form.Type,
|
||||
LabelZh: form.LabelZh,
|
||||
LabelEn: form.LabelEn,
|
||||
Value: form.Default,
|
||||
Values: form.Values,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -700,11 +679,15 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func syncAppInstallStatus(appInstall *model.AppInstall) error {
|
||||
if appInstall.Status == constant.Installing || appInstall.Status == constant.Rebuilding || appInstall.Status == constant.Upgrading {
|
||||
func syncByID(installID uint) error {
|
||||
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if appInstall.Status == constant.Installing {
|
||||
return nil
|
||||
}
|
||||
containerNames, err := getContainerNames(*appInstall)
|
||||
containerNames, err := getContainerNames(appInstall)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -716,67 +699,75 @@ func syncAppInstallStatus(appInstall *model.AppInstall) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
runningCount int
|
||||
exitedCount int
|
||||
pausedCount int
|
||||
exitedContainerNames []string
|
||||
total = len(containerNames)
|
||||
count = len(containers)
|
||||
errorContainers []string
|
||||
notFoundContainers []string
|
||||
runningContainers []string
|
||||
exitedContainers []string
|
||||
)
|
||||
|
||||
foundNames := make(map[string]bool)
|
||||
for _, con := range containers {
|
||||
foundNames[con.Names[0]] = true
|
||||
switch con.State {
|
||||
for _, n := range containers {
|
||||
switch n.State {
|
||||
case "exited":
|
||||
exitedContainerNames = append(exitedContainerNames, strings.TrimPrefix(con.Names[0], "/"))
|
||||
exitedCount++
|
||||
exitedContainers = append(exitedContainers, n.Names[0])
|
||||
case "running":
|
||||
runningCount++
|
||||
case "paused":
|
||||
pausedCount++
|
||||
runningContainers = append(runningContainers, n.Names[0])
|
||||
default:
|
||||
errorContainers = append(errorContainers, n.Names[0])
|
||||
}
|
||||
}
|
||||
|
||||
var notFoundNames []string
|
||||
for _, name := range containerNames {
|
||||
if !foundNames["/"+name] {
|
||||
notFoundNames = append(notFoundNames, name)
|
||||
exist := false
|
||||
for _, container := range containers {
|
||||
if common.ExistWithStrArray(name, container.Names) {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
notFoundContainers = append(notFoundContainers, name)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case count == 0:
|
||||
containerCount := len(containers)
|
||||
errCount := len(errorContainers)
|
||||
notFoundCount := len(notFoundContainers)
|
||||
existedCount := len(exitedContainers)
|
||||
normalCount := len(containerNames)
|
||||
runningCount := len(runningContainers)
|
||||
|
||||
if containerCount == 0 {
|
||||
appInstall.Status = constant.Error
|
||||
appInstall.Message = buserr.WithName("ErrContainerNotFound", strings.Join(containerNames, ",")).Error()
|
||||
case exitedCount == total:
|
||||
appInstall.Status = constant.Stopped
|
||||
case runningCount == total:
|
||||
appInstall.Message = i18n.GetMsgWithMap("ErrContainerNotFound", map[string]interface{}{"name": strings.Join(containerNames, ",")})
|
||||
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||
}
|
||||
if errCount == 0 && existedCount == 0 && notFoundCount == 0 {
|
||||
appInstall.Status = constant.Running
|
||||
case pausedCount == total:
|
||||
appInstall.Status = constant.Paused
|
||||
default:
|
||||
var msg string
|
||||
if exitedCount > 0 {
|
||||
msg = buserr.WithName("ErrContainerMsg", strings.Join(exitedContainerNames, ",")).Error()
|
||||
}
|
||||
if len(notFoundNames) > 0 {
|
||||
msg += buserr.WithName("ErrContainerNotFound", strings.Join(notFoundNames, ",")).Error()
|
||||
}
|
||||
if msg == "" {
|
||||
msg = buserr.New("ErrAppWarn").Error()
|
||||
}
|
||||
appInstall.Message = msg
|
||||
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||
}
|
||||
if existedCount == normalCount {
|
||||
appInstall.Status = constant.Stopped
|
||||
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||
}
|
||||
if errCount == normalCount {
|
||||
appInstall.Status = constant.Error
|
||||
}
|
||||
if runningCount < normalCount {
|
||||
appInstall.Status = constant.UnHealthy
|
||||
}
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
|
||||
return nil
|
||||
var errMsg string
|
||||
if errCount > 0 {
|
||||
errMsg += i18n.GetMsgWithMap("ErrContainerMsg", map[string]interface{}{"name": strings.Join(errorContainers, ",")})
|
||||
}
|
||||
if notFoundCount > 0 {
|
||||
errMsg += i18n.GetMsgWithMap("ErrContainerNotFound", map[string]interface{}{"name": strings.Join(notFoundContainers, ",")})
|
||||
}
|
||||
appInstall.Message = errMsg
|
||||
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||
}
|
||||
|
||||
func updateInstallInfoInDB(appKey, appName, param string, value interface{}) error {
|
||||
func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value interface{}) error {
|
||||
if param != "password" && param != "port" && param != "user-password" {
|
||||
return nil
|
||||
}
|
||||
@@ -784,7 +775,7 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
envPath := fmt.Sprintf("%s/%s/.env", appInstall.AppPath, appInstall.Name)
|
||||
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, appKey, appInstall.Name)
|
||||
lineBytes, err := os.ReadFile(envPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -793,7 +784,7 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
|
||||
envKey := ""
|
||||
switch param {
|
||||
case "password":
|
||||
if appKey == "mysql" || appKey == "mariadb" || appKey == "postgresql" {
|
||||
if appKey == "mysql" || appKey == "mariadb" {
|
||||
envKey = "PANEL_DB_ROOT_PASSWORD="
|
||||
} else {
|
||||
envKey = "PANEL_REDIS_ROOT_PASSWORD="
|
||||
|
||||
+147
-260
@@ -110,22 +110,17 @@ func checkPortExist(port int) error {
|
||||
}
|
||||
|
||||
var DatabaseKeys = map[string]uint{
|
||||
constant.AppMysql: 3306,
|
||||
constant.AppMariaDB: 3306,
|
||||
constant.AppPostgresql: 5432,
|
||||
constant.AppPostgres: 5432,
|
||||
constant.AppMongodb: 27017,
|
||||
constant.AppRedis: 6379,
|
||||
constant.AppMemcached: 11211,
|
||||
}
|
||||
|
||||
var ToolKeys = map[string]uint{
|
||||
"minio": 9001,
|
||||
"mysql": 3306,
|
||||
"mariadb": 3306,
|
||||
"postgresql": 5432,
|
||||
"mongodb": 27017,
|
||||
"redis": 6379,
|
||||
"memcached": 11211,
|
||||
}
|
||||
|
||||
func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall, params map[string]interface{}) error {
|
||||
var dbConfig dto.AppDatabase
|
||||
if DatabaseKeys[app.Key] > 0 {
|
||||
if app.Type == "runtime" && DatabaseKeys[app.Key] > 0 {
|
||||
database := &model.Database{
|
||||
AppInstallID: appInstall.ID,
|
||||
Name: appInstall.Name,
|
||||
@@ -155,9 +150,17 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
}
|
||||
|
||||
switch app.Key {
|
||||
case constant.AppMysql, constant.AppMariaDB, constant.AppPostgresql, constant.AppMongodb:
|
||||
case "mysql", "mariadb", "postgresql", "mongodb":
|
||||
if password, ok := params["PANEL_DB_ROOT_PASSWORD"]; ok {
|
||||
if password != "" {
|
||||
authParam := dto.AuthParam{
|
||||
RootPassword: password.(string),
|
||||
}
|
||||
authByte, err := json.Marshal(authParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appInstall.Param = string(authByte)
|
||||
database.Password = password.(string)
|
||||
if app.Key == "mysql" || app.Key == "mariadb" {
|
||||
database.Username = "root"
|
||||
@@ -165,19 +168,9 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
if rootUser, ok := params["PANEL_DB_ROOT_USER"]; ok {
|
||||
database.Username = rootUser.(string)
|
||||
}
|
||||
authParam := dto.AuthParam{
|
||||
RootPassword: password.(string),
|
||||
RootUser: database.Username,
|
||||
}
|
||||
authByte, err := json.Marshal(authParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appInstall.Param = string(authByte)
|
||||
|
||||
}
|
||||
}
|
||||
case constant.AppRedis:
|
||||
case "redis":
|
||||
if password, ok := params["PANEL_REDIS_ROOT_PASSWORD"]; ok {
|
||||
if password != "" {
|
||||
authParam := dto.RedisAuthParam{
|
||||
@@ -196,23 +189,6 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ToolKeys[app.Key] > 0 {
|
||||
if app.Key == "minio" {
|
||||
authParam := dto.MinioAuthParam{}
|
||||
if password, ok := params["PANEL_MINIO_ROOT_PASSWORD"]; ok {
|
||||
authParam.RootPassword = password.(string)
|
||||
}
|
||||
if rootUser, ok := params["PANEL_MINIO_ROOT_USER"]; ok {
|
||||
authParam.RootUser = rootUser.(string)
|
||||
}
|
||||
authByte, err := json.Marshal(authParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appInstall.Param = string(authByte)
|
||||
}
|
||||
}
|
||||
|
||||
if app.Type == "website" || app.Type == "tool" {
|
||||
paramByte, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
@@ -234,55 +210,28 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
}
|
||||
var resourceId uint
|
||||
if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" {
|
||||
switch database.Type {
|
||||
case constant.AppPostgresql, constant.AppPostgres:
|
||||
iPostgresqlRepo := repo.NewIPostgresqlRepo()
|
||||
oldPostgresqlDb, _ := iPostgresqlRepo.Get(commonRepo.WithByName(dbConfig.DbName), iPostgresqlRepo.WithByFrom(constant.ResourceLocal))
|
||||
resourceId = oldPostgresqlDb.ID
|
||||
if oldPostgresqlDb.ID > 0 {
|
||||
if oldPostgresqlDb.Username != dbConfig.DbUser || oldPostgresqlDb.Password != dbConfig.Password {
|
||||
return buserr.New(constant.ErrDbUserNotValid)
|
||||
}
|
||||
} else {
|
||||
var createPostgresql dto.PostgresqlDBCreate
|
||||
createPostgresql.Name = dbConfig.DbName
|
||||
createPostgresql.Username = dbConfig.DbUser
|
||||
createPostgresql.Database = database.Name
|
||||
createPostgresql.Format = "UTF8"
|
||||
createPostgresql.Password = dbConfig.Password
|
||||
createPostgresql.From = database.From
|
||||
createPostgresql.SuperUser = true
|
||||
pgdb, err := NewIPostgresqlService().Create(ctx, createPostgresql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceId = pgdb.ID
|
||||
iMysqlRepo := repo.NewIMysqlRepo()
|
||||
oldMysqlDb, _ := iMysqlRepo.Get(commonRepo.WithByName(dbConfig.DbName), iMysqlRepo.WithByFrom(constant.ResourceLocal))
|
||||
resourceId = oldMysqlDb.ID
|
||||
if oldMysqlDb.ID > 0 {
|
||||
if oldMysqlDb.Username != dbConfig.DbUser || oldMysqlDb.Password != dbConfig.Password {
|
||||
return buserr.New(constant.ErrDbUserNotValid)
|
||||
}
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
iMysqlRepo := repo.NewIMysqlRepo()
|
||||
oldMysqlDb, _ := iMysqlRepo.Get(commonRepo.WithByName(dbConfig.DbName), iMysqlRepo.WithByFrom(constant.ResourceLocal))
|
||||
resourceId = oldMysqlDb.ID
|
||||
if oldMysqlDb.ID > 0 {
|
||||
if oldMysqlDb.Username != dbConfig.DbUser || oldMysqlDb.Password != dbConfig.Password {
|
||||
return buserr.New(constant.ErrDbUserNotValid)
|
||||
}
|
||||
} else {
|
||||
var createMysql dto.MysqlDBCreate
|
||||
createMysql.Name = dbConfig.DbName
|
||||
createMysql.Username = dbConfig.DbUser
|
||||
createMysql.Database = database.Name
|
||||
createMysql.Format = "utf8mb4"
|
||||
createMysql.Permission = "%"
|
||||
createMysql.Password = dbConfig.Password
|
||||
createMysql.From = database.From
|
||||
mysqldb, err := NewIMysqlService().Create(ctx, createMysql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceId = mysqldb.ID
|
||||
} else {
|
||||
var createMysql dto.MysqlDBCreate
|
||||
createMysql.Name = dbConfig.DbName
|
||||
createMysql.Username = dbConfig.DbUser
|
||||
createMysql.Database = database.Name
|
||||
createMysql.Format = "utf8mb4"
|
||||
createMysql.Permission = "%"
|
||||
createMysql.Password = dbConfig.Password
|
||||
createMysql.From = database.From
|
||||
mysqldb, err := NewIMysqlService().Create(ctx, createMysql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceId = mysqldb.ID
|
||||
}
|
||||
|
||||
}
|
||||
var installResource model.AppInstallResource
|
||||
installResource.ResourceId = resourceId
|
||||
@@ -354,8 +303,8 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
|
||||
websiteApp, _ := appRepo.GetFirst(commonRepo.WithByID(websiteAppInstall.AppId))
|
||||
if websiteApp.Type == constant.RuntimePHP {
|
||||
go func() {
|
||||
_, _ = compose.Down(websiteAppInstall.GetComposePath())
|
||||
_ = op.DeleteDir(websiteAppInstall.GetPath())
|
||||
_, _ = compose.Down(install.GetComposePath())
|
||||
_ = op.DeleteDir(install.GetPath())
|
||||
}()
|
||||
_ = appInstallRepo.Delete(ctx, websiteAppInstall)
|
||||
}
|
||||
@@ -366,8 +315,6 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
|
||||
_ = websiteDomainRepo.DeleteAll(ctx)
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
|
||||
case constant.AppPostgresql:
|
||||
_ = postgresqlRepo.Delete(ctx, postgresqlRepo.WithByPostgresqlName(install.Name))
|
||||
}
|
||||
|
||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
|
||||
@@ -389,56 +336,38 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
|
||||
}
|
||||
|
||||
func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, forceDelete bool, deleteBackup bool) error {
|
||||
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if len(resources) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, re := range resources {
|
||||
if deleteDB {
|
||||
switch re.Key {
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
mysqlService := NewIMysqlService()
|
||||
database, _ := mysqlRepo.Get(commonRepo.WithByID(re.ResourceId))
|
||||
if reflect.DeepEqual(database, model.DatabaseMysql{}) {
|
||||
continue
|
||||
}
|
||||
if err := mysqlService.Delete(ctx, dto.MysqlDBDelete{
|
||||
ID: database.ID,
|
||||
ForceDelete: forceDelete,
|
||||
DeleteBackup: deleteBackup,
|
||||
Type: re.Key,
|
||||
Database: database.MysqlName,
|
||||
}); err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
pgsqlService := NewIPostgresqlService()
|
||||
database, _ := postgresqlRepo.Get(commonRepo.WithByID(re.ResourceId))
|
||||
if reflect.DeepEqual(database, model.DatabasePostgresql{}) {
|
||||
continue
|
||||
}
|
||||
if err := pgsqlService.Delete(ctx, dto.PostgresqlDBDelete{
|
||||
ID: database.ID,
|
||||
ForceDelete: forceDelete,
|
||||
DeleteBackup: deleteBackup,
|
||||
Type: re.Key,
|
||||
Database: database.PostgresqlName,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
mysqlService := NewIMysqlService()
|
||||
if (re.Key == constant.AppMysql || re.Key == constant.AppMariaDB) && deleteDB {
|
||||
database, _ := mysqlRepo.Get(commonRepo.WithByID(re.ResourceId))
|
||||
if reflect.DeepEqual(database, model.DatabaseMysql{}) {
|
||||
continue
|
||||
}
|
||||
if err := mysqlService.Delete(ctx, dto.MysqlDBDelete{
|
||||
ID: database.ID,
|
||||
ForceDelete: forceDelete,
|
||||
DeleteBackup: deleteBackup,
|
||||
Type: re.Key,
|
||||
Database: database.MysqlName,
|
||||
}); err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
}
|
||||
|
||||
func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installID))
|
||||
func upgradeInstall(installId uint, detailId uint, backup bool) error {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
detail, err := appDetailRepo.GetFirst(commonRepo.WithByID(detailID))
|
||||
detail, err := appDetailRepo.GetFirst(commonRepo.WithByID(detailId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -454,40 +383,23 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
}
|
||||
}
|
||||
var upErr error
|
||||
|
||||
defer func() {
|
||||
if upErr != nil {
|
||||
if backup {
|
||||
if err := NewIBackupService().AppRecover(dto.CommonRecover{Name: install.App.Key, DetailName: install.Name, Type: "app", Source: constant.ResourceLocal}); err != nil {
|
||||
global.LOG.Errorf("recover app [%s] [%s] failed %v", install.App.Key, install.Name, err)
|
||||
}
|
||||
}
|
||||
install.Status = constant.UpgradeErr
|
||||
install.Message = upErr.Error()
|
||||
_ = appInstallRepo.Save(context.Background(), &install)
|
||||
}
|
||||
}()
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
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
|
||||
}
|
||||
if detail.DockerCompose == "" {
|
||||
composeDetail, err := fileOp.GetContent(path.Join(detailDir, "docker-compose.yml"))
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
detail.DockerCompose = string(composeDetail)
|
||||
_ = appDetailRepo.Update(context.Background(), detail)
|
||||
}
|
||||
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)
|
||||
}
|
||||
@@ -497,6 +409,7 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
if stdout != nil {
|
||||
global.LOG.Infof("upgrade app [%s] [%s] cp file log : %s ", install.App.Key, install.Name, string(stdout))
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
sourceScripts := path.Join(detailDir, "scripts")
|
||||
if fileOp.Stat(sourceScripts) {
|
||||
dstScripts := path.Join(install.GetPath(), "scripts")
|
||||
@@ -506,6 +419,16 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
_, _ = scriptCmd.CombinedOutput()
|
||||
}
|
||||
|
||||
if detail.DockerCompose == "" {
|
||||
composeDetail, err := fileOp.GetContent(path.Join(detailDir, "docker-compose.yml"))
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
detail.DockerCompose = string(composeDetail)
|
||||
_ = appDetailRepo.Update(context.Background(), detail)
|
||||
}
|
||||
|
||||
composeMap := make(map[string]interface{})
|
||||
if upErr = yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); upErr != nil {
|
||||
return
|
||||
@@ -556,7 +479,25 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
|
||||
install.DockerCompose = string(composeByte)
|
||||
install.Version = detail.Version
|
||||
install.AppDetailId = detailID
|
||||
install.AppDetailId = detailId
|
||||
|
||||
images, err := getImages(install)
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
dockerCli, err := composeV2.NewClient()
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
if err = dockerCli.PullImage(image, true); err != nil {
|
||||
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if out, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
if out != "" {
|
||||
@@ -575,31 +516,6 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileOp.GetContent(install.GetEnvPath())
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
|
||||
if pullImage {
|
||||
images, err := composeV2.GetDockerComposeImages(install.Name, content, []byte(detail.DockerCompose))
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
dockerCli, err := composeV2.NewClient()
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
for _, image := range images {
|
||||
if err = dockerCli.PullImage(image, true); err != nil {
|
||||
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if upErr = fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); upErr != nil {
|
||||
return
|
||||
}
|
||||
@@ -644,6 +560,26 @@ func getContainerNames(install model.AppInstall) ([]string, error) {
|
||||
return containerNames, nil
|
||||
}
|
||||
|
||||
func getImages(install model.AppInstall) ([]string, error) {
|
||||
envStr, err := coverEnvJsonToStr(install.Env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(envStr), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imagesMap := make(map[string]struct{})
|
||||
for _, service := range project.AllServices() {
|
||||
imagesMap[service.Image] = struct{}{}
|
||||
}
|
||||
var images []string
|
||||
for k := range imagesMap {
|
||||
images = append(images, k)
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
|
||||
func coverEnvJsonToStr(envJson string) (string, error) {
|
||||
envMap := make(map[string]interface{})
|
||||
_ = json.Unmarshal([]byte(envJson), &envMap)
|
||||
@@ -687,12 +623,6 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
|
||||
envParams[k] = strconv.Itoa(int(t))
|
||||
case int:
|
||||
envParams[k] = strconv.Itoa(t)
|
||||
case []interface{}:
|
||||
strArray := make([]string, len(t))
|
||||
for i := range t {
|
||||
strArray[i] = strings.ToLower(fmt.Sprintf("%v", t[i]))
|
||||
}
|
||||
envParams[k] = strings.Join(strArray, ",")
|
||||
default:
|
||||
envParams[k] = t.(string)
|
||||
}
|
||||
@@ -700,12 +630,8 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
|
||||
}
|
||||
|
||||
func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall) (err error) {
|
||||
if app.IsLocalApp() {
|
||||
//本地应用,不去官网下载
|
||||
return nil
|
||||
}
|
||||
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
|
||||
appDownloadDir := app.GetAppResourcePath()
|
||||
appDownloadDir := path.Join(appResourceDir, app.Key)
|
||||
appVersionDir := path.Join(appDownloadDir, appDetail.Version)
|
||||
fileOp := files.NewFileOp()
|
||||
if !appDetail.Update && fileOp.Stat(appVersionDir) {
|
||||
@@ -847,36 +773,39 @@ func checkContainerNameIsExist(containerName, appDir string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func upApp(appInstall *model.AppInstall, pullImages bool) {
|
||||
func upApp(appInstall *model.AppInstall) {
|
||||
upProject := func(appInstall *model.AppInstall) (err error) {
|
||||
var (
|
||||
out string
|
||||
errMsg string
|
||||
)
|
||||
if pullImages && appInstall.App.Type != "php" {
|
||||
out, err = compose.Pull(appInstall.GetComposePath())
|
||||
if err == nil {
|
||||
var (
|
||||
out string
|
||||
errMsg string
|
||||
)
|
||||
if appInstall.App.Type != "php" {
|
||||
out, err = compose.Pull(appInstall.GetComposePath())
|
||||
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 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
|
||||
}
|
||||
return
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = compose.Up(appInstall.GetComposePath())
|
||||
if err != nil {
|
||||
if out != "" {
|
||||
appInstall.Message = errMsg + out
|
||||
}
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
if err := upProject(appInstall); err != nil {
|
||||
appInstall.Status = constant.Error
|
||||
@@ -899,12 +828,11 @@ func rebuildApp(appInstall model.AppInstall) error {
|
||||
_ = handleErr(appInstall, err, out)
|
||||
return
|
||||
}
|
||||
out, err = compose.Up(appInstall.GetComposePath())
|
||||
out, err = compose.Up(dockerComposePath)
|
||||
if err != nil {
|
||||
_ = handleErr(appInstall, err, out)
|
||||
return
|
||||
}
|
||||
|
||||
appInstall.Status = constant.Running
|
||||
_ = appInstallRepo.Save(context.Background(), &appInstall)
|
||||
}()
|
||||
@@ -969,66 +897,29 @@ func handleLocalAppDetail(versionDir string, appDetail *model.AppDetail) error {
|
||||
fileOp := files.NewFileOp()
|
||||
dockerComposePath := path.Join(versionDir, "docker-compose.yml")
|
||||
if !fileOp.Stat(dockerComposePath) {
|
||||
return buserr.WithName(constant.ErrFileNotFound, "docker-compose.yml")
|
||||
return errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "docker-compose.yml"}))
|
||||
}
|
||||
dockerComposeByte, _ := fileOp.GetContent(dockerComposePath)
|
||||
if dockerComposeByte == nil {
|
||||
return buserr.WithName(constant.ErrFileParseApp, "docker-compose.yml")
|
||||
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 buserr.WithName(constant.ErrFileNotFound, "data.yml")
|
||||
return errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "data.yml"}))
|
||||
}
|
||||
paramByte, _ := fileOp.GetContent(paramPath)
|
||||
if paramByte == nil {
|
||||
return buserr.WithName(constant.ErrFileNotFound, "data.yml")
|
||||
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml"}))
|
||||
}
|
||||
appParamConfig := dto.LocalAppParam{}
|
||||
if err := yaml.Unmarshal(paramByte, &appParamConfig); err != nil {
|
||||
return buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
||||
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml"}))
|
||||
}
|
||||
dataJson, err := json.Marshal(appParamConfig.AppParams)
|
||||
if err != nil {
|
||||
return buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
||||
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
|
||||
}
|
||||
var appParam dto.AppForm
|
||||
if err = json.Unmarshal(dataJson, &appParam); err != nil {
|
||||
return buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
||||
}
|
||||
for _, formField := range appParam.FormFields {
|
||||
if strings.Contains(formField.EnvKey, " ") {
|
||||
return buserr.WithName(constant.ErrAppParamKey, formField.EnvKey)
|
||||
}
|
||||
}
|
||||
|
||||
var dataMap map[string]interface{}
|
||||
err = yaml.Unmarshal(paramByte, &dataMap)
|
||||
if err != nil {
|
||||
return buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
||||
}
|
||||
|
||||
additionalProperties, ok := dataMap["additionalProperties"].(map[string]interface{})
|
||||
if !ok {
|
||||
return buserr.WithName(constant.ErrAppParamKey, "additionalProperties")
|
||||
}
|
||||
|
||||
formFieldsInterface, ok := additionalProperties["formFields"]
|
||||
if ok {
|
||||
formFields, ok := formFieldsInterface.([]interface{})
|
||||
if !ok {
|
||||
return buserr.WithName(constant.ErrAppParamKey, "formFields")
|
||||
}
|
||||
for _, item := range formFields {
|
||||
field := item.(map[string]interface{})
|
||||
for key, value := range field {
|
||||
if value == nil {
|
||||
return buserr.WithName(constant.ErrAppParamKey, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appDetail.Params = string(dataJson)
|
||||
return nil
|
||||
}
|
||||
@@ -1037,22 +928,22 @@ func handleLocalApp(appDir string) (app *model.App, err error) {
|
||||
fileOp := files.NewFileOp()
|
||||
configYamlPath := path.Join(appDir, "data.yml")
|
||||
if !fileOp.Stat(configYamlPath) {
|
||||
err = buserr.WithName(constant.ErrFileNotFound, "data.yml")
|
||||
err = errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "data.yml"}))
|
||||
return
|
||||
}
|
||||
iconPath := path.Join(appDir, "logo.png")
|
||||
if !fileOp.Stat(iconPath) {
|
||||
err = buserr.WithName(constant.ErrFileNotFound, "logo.png")
|
||||
err = errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "logo.png"}))
|
||||
return
|
||||
}
|
||||
configYamlByte, err := fileOp.GetContent(configYamlPath)
|
||||
if err != nil {
|
||||
err = buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
||||
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 = buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
||||
err = errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
|
||||
return
|
||||
}
|
||||
app = &localAppDefine.AppProperty
|
||||
@@ -1080,8 +971,8 @@ func handleErr(install model.AppInstall, err error, out string) error {
|
||||
if out != "" {
|
||||
install.Message = out
|
||||
reErr = errors.New(out)
|
||||
install.Status = constant.Error
|
||||
}
|
||||
install.Status = constant.Error
|
||||
_ = appInstallRepo.Save(context.Background(), &install)
|
||||
return reErr
|
||||
}
|
||||
@@ -1092,10 +983,6 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]respons
|
||||
if updated && (installed.App.Type == "php" || installed.Status == constant.Installing || (installed.App.Key == constant.AppMysql && installed.Version == "5.6.51")) {
|
||||
continue
|
||||
}
|
||||
if err := syncAppInstallStatus(&installed); err != nil {
|
||||
global.LOG.Error("sync app install status error : ", err)
|
||||
}
|
||||
|
||||
installDTO := response.AppInstalledDTO{
|
||||
AppInstall: installed,
|
||||
Path: installed.GetPath(),
|
||||
@@ -1110,7 +997,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]respons
|
||||
}
|
||||
var versions []string
|
||||
for _, detail := range details {
|
||||
if detail.IgnoreUpgrade || installed.Version == "latest" {
|
||||
if detail.IgnoreUpgrade {
|
||||
continue
|
||||
}
|
||||
if common.IsCrossVersion(installed.Version, detail.Version) && !app.CrossVersionUpdate {
|
||||
@@ -1265,7 +1152,7 @@ func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName
|
||||
if portExist {
|
||||
allowHost := "127.0.0.1"
|
||||
if req.Advanced && req.AllowPort {
|
||||
allowHost = ""
|
||||
allowHost = "0.0.0.0"
|
||||
}
|
||||
params[constant.HostIP] = allowHost
|
||||
}
|
||||
@@ -1277,7 +1164,7 @@ func getAppCommonConfig(envs map[string]interface{}) request.AppContainerConfig
|
||||
config := request.AppContainerConfig{}
|
||||
|
||||
if hostIp, ok := envs[constant.HostIP]; ok {
|
||||
config.AllowPort = hostIp.(string) != "127.0.0.1"
|
||||
config.AllowPort = hostIp.(string) == "0.0.0.0"
|
||||
} else {
|
||||
config.AllowPort = true
|
||||
}
|
||||
|
||||
@@ -109,10 +109,6 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpsSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lifeTime, err := strconv.Atoi(setting.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -133,7 +129,7 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
|
||||
sessionUser, err := global.SESSION.Get(sID)
|
||||
if err != nil {
|
||||
sID = uuid.New().String()
|
||||
c.SetCookie(constant.SessionName, sID, 0, "", "", httpsSetting.Value == "enable", true)
|
||||
c.SetCookie(constant.SessionName, sID, 0, "", "", false, false)
|
||||
err := global.SESSION.Set(sID, sessionUser, lifeTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -148,13 +144,9 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
|
||||
}
|
||||
|
||||
func (u *AuthService) LogOut(c *gin.Context) error {
|
||||
httpsSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sID, _ := c.Cookie(constant.SessionName)
|
||||
if sID != "" {
|
||||
c.SetCookie(constant.SessionName, sID, -1, "", "", httpsSetting.Value == "enable", true)
|
||||
c.SetCookie(constant.SessionName, sID, -1, "", "", false, false)
|
||||
err := global.SESSION.Delete(sID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+86
-212
@@ -6,12 +6,12 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage/client"
|
||||
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
@@ -30,8 +29,7 @@ type BackupService struct{}
|
||||
type IBackupService interface {
|
||||
List() ([]dto.BackupInfo, error)
|
||||
SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error)
|
||||
SearchRecordsByCronjobWithPage(search dto.RecordSearchByCronjob) (int64, []dto.BackupRecords, error)
|
||||
LoadOneDriveInfo() (dto.OneDriveInfo, error)
|
||||
LoadOneDriveInfo() (string, error)
|
||||
DownloadRecord(info dto.DownloadRecord) (string, error)
|
||||
Create(backupDto dto.BackupOperate) error
|
||||
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
||||
@@ -40,14 +38,11 @@ type IBackupService interface {
|
||||
BatchDeleteRecord(ids []uint) error
|
||||
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
|
||||
|
||||
ListFiles(req dto.BackupSearchFile) []string
|
||||
ListFiles(req dto.BackupSearchFile) ([]string, error)
|
||||
|
||||
MysqlBackup(db dto.CommonBackup) error
|
||||
PostgresqlBackup(db dto.CommonBackup) error
|
||||
MysqlRecover(db dto.CommonRecover) error
|
||||
PostgresqlRecover(db dto.CommonRecover) error
|
||||
MysqlRecoverByUpload(req dto.CommonRecover) error
|
||||
PostgresqlRecoverByUpload(req dto.CommonRecover) error
|
||||
|
||||
RedisBackup() error
|
||||
RedisRecover(db dto.CommonRecover) error
|
||||
@@ -57,8 +52,6 @@ type IBackupService interface {
|
||||
|
||||
AppBackup(db dto.CommonBackup) error
|
||||
AppRecover(req dto.CommonRecover) error
|
||||
|
||||
Run()
|
||||
}
|
||||
|
||||
func NewIBackupService() IBackupService {
|
||||
@@ -76,7 +69,6 @@ func (u *BackupService) List() ([]dto.BackupInfo, error) {
|
||||
dtobas = append(dtobas, u.loadByType("COS", ops))
|
||||
dtobas = append(dtobas, u.loadByType("KODO", ops))
|
||||
dtobas = append(dtobas, u.loadByType("OneDrive", ops))
|
||||
dtobas = append(dtobas, u.loadByType("WebDAV", ops))
|
||||
return dtobas, err
|
||||
}
|
||||
|
||||
@@ -88,72 +80,32 @@ func (u *BackupService) SearchRecordsWithPage(search dto.RecordSearch) (int64, [
|
||||
commonRepo.WithByType(search.Type),
|
||||
backupRepo.WithByDetailName(search.DetailName),
|
||||
)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
var dtobas []dto.BackupRecords
|
||||
for _, group := range records {
|
||||
var item dto.BackupRecords
|
||||
if err := copier.Copy(&item, &group); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
dtobas = append(dtobas, item)
|
||||
}
|
||||
|
||||
datas, err := u.loadRecordSize(records)
|
||||
sort.Slice(datas, func(i, j int) bool {
|
||||
return datas[i].CreatedAt.After(datas[j].CreatedAt)
|
||||
})
|
||||
return total, datas, err
|
||||
return total, dtobas, err
|
||||
}
|
||||
|
||||
func (u *BackupService) SearchRecordsByCronjobWithPage(search dto.RecordSearchByCronjob) (int64, []dto.BackupRecords, error) {
|
||||
total, records, err := backupRepo.PageRecord(
|
||||
search.Page, search.PageSize,
|
||||
commonRepo.WithOrderBy("created_at desc"),
|
||||
backupRepo.WithByCronID(search.CronjobID),
|
||||
)
|
||||
func (u *BackupService) LoadOneDriveInfo() (string, error) {
|
||||
OneDriveID, err := settingRepo.Get(settingRepo.WithByKey("OneDriveID"))
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
datas, err := u.loadRecordSize(records)
|
||||
sort.Slice(datas, func(i, j int) bool {
|
||||
return datas[i].CreatedAt.After(datas[j].CreatedAt)
|
||||
})
|
||||
return total, datas, err
|
||||
}
|
||||
|
||||
type loadSizeHelper struct {
|
||||
isOk bool
|
||||
backupPath string
|
||||
client cloud_storage.CloudStorageClient
|
||||
}
|
||||
|
||||
func (u *BackupService) LoadOneDriveInfo() (dto.OneDriveInfo, error) {
|
||||
var data dto.OneDriveInfo
|
||||
data.RedirectUri = constant.OneDriveRedirectURI
|
||||
clientID, err := settingRepo.Get(settingRepo.WithByKey("OneDriveID"))
|
||||
idItem, err := base64.StdEncoding.DecodeString(OneDriveID.Value)
|
||||
if err != nil {
|
||||
return data, err
|
||||
return "", err
|
||||
}
|
||||
idItem, err := base64.StdEncoding.DecodeString(clientID.Value)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
data.ClientID = string(idItem)
|
||||
clientSecret, err := settingRepo.Get(settingRepo.WithByKey("OneDriveSc"))
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
secretItem, err := base64.StdEncoding.DecodeString(clientSecret.Value)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
data.ClientSecret = string(secretItem)
|
||||
|
||||
return data, err
|
||||
return string(idItem), err
|
||||
}
|
||||
|
||||
func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error) {
|
||||
if info.Source == "LOCAL" {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path.Join(localDir, info.FileDir, info.FileName), nil
|
||||
return info.FileDir + "/" + info.FileName, nil
|
||||
}
|
||||
backup, _ := backupRepo.Get(commonRepo.WithByType(info.Source))
|
||||
if backup.ID == 0 {
|
||||
@@ -165,7 +117,7 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
|
||||
}
|
||||
varMap["bucket"] = backup.Bucket
|
||||
switch backup.Type {
|
||||
case constant.Sftp, constant.WebDAV:
|
||||
case constant.Sftp:
|
||||
varMap["username"] = backup.AccessKey
|
||||
varMap["password"] = backup.Credential
|
||||
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||
@@ -186,7 +138,9 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
|
||||
}
|
||||
srcPath := fmt.Sprintf("%s/%s", info.FileDir, info.FileName)
|
||||
if len(backup.BackupPath) != 0 {
|
||||
srcPath = path.Join(strings.TrimPrefix(backup.BackupPath, "/"), srcPath)
|
||||
itemPath := strings.TrimPrefix(backup.BackupPath, "/")
|
||||
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
|
||||
srcPath = itemPath + srcPath
|
||||
}
|
||||
if exist, _ := backClient.Exist(srcPath); exist {
|
||||
isOK, err := backClient.Download(srcPath, targetPath)
|
||||
@@ -212,13 +166,11 @@ func (u *BackupService) Create(req dto.BackupOperate) error {
|
||||
}
|
||||
}
|
||||
if req.Type != "LOCAL" {
|
||||
if _, err := u.checkBackupConn(&backup); err != nil {
|
||||
isOk, err := u.checkBackupConn(&backup)
|
||||
if err != nil || !isOk {
|
||||
return buserr.WithMap("ErrBackupCheck", map[string]interface{}{"err": err.Error()}, err)
|
||||
}
|
||||
}
|
||||
if backup.Type == constant.OneDrive {
|
||||
StartRefreshOneDriveToken()
|
||||
}
|
||||
if err := backupRepo.Create(&backup); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -231,7 +183,7 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
|
||||
return nil, err
|
||||
}
|
||||
switch backupDto.Type {
|
||||
case constant.Sftp, constant.WebDAV:
|
||||
case constant.Sftp:
|
||||
varMap["username"] = backupDto.AccessKey
|
||||
varMap["password"] = backupDto.Credential
|
||||
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||
@@ -246,14 +198,7 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
|
||||
}
|
||||
|
||||
func (u *BackupService) Delete(id uint) error {
|
||||
backup, _ := backupRepo.Get(commonRepo.WithByID(id))
|
||||
if backup.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
if backup.Type == constant.OneDrive {
|
||||
global.Cron.Remove(global.OneDriveCronID)
|
||||
}
|
||||
cronjobs, _ := cronjobRepo.List(cronjobRepo.WithByDefaultDownload(backup.Type))
|
||||
cronjobs, _ := cronjobRepo.List(cronjobRepo.WithByBackupID(id))
|
||||
if len(cronjobs) != 0 {
|
||||
return buserr.New(constant.ErrBackupInUsed)
|
||||
}
|
||||
@@ -266,18 +211,22 @@ func (u *BackupService) BatchDeleteRecord(ids []uint) error {
|
||||
return err
|
||||
}
|
||||
for _, record := range records {
|
||||
backupAccount, err := backupRepo.Get(commonRepo.WithByType(record.Source))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load backup account %s info from db failed, err: %v", record.Source, err)
|
||||
continue
|
||||
}
|
||||
client, err := u.NewClient(&backupAccount)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("new client for backup account %s failed, err: %v", record.Source, err)
|
||||
continue
|
||||
}
|
||||
if _, err = client.Delete(path.Join(record.FileDir, record.FileName)); err != nil {
|
||||
global.LOG.Errorf("remove file %s from %s failed, err: %v", path.Join(record.FileDir, record.FileName), record.Source, err)
|
||||
if record.Source == "LOCAL" {
|
||||
if err := os.Remove(record.FileDir + "/" + record.FileName); err != nil {
|
||||
global.LOG.Errorf("remove file %s failed, err: %v", record.FileDir+record.FileName, err)
|
||||
}
|
||||
} else {
|
||||
backupAccount, err := backupRepo.Get(commonRepo.WithByType(record.Source))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := u.NewClient(&backupAccount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = client.Delete(record.FileDir + record.FileName); err != nil {
|
||||
global.LOG.Errorf("remove file %s from %s failed, err: %v", record.FileDir+record.FileName, record.Source, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return backupRepo.DeleteRecord(context.Background(), commonRepo.WithIdsIn(ids))
|
||||
@@ -330,29 +279,27 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
if backup.Type == "LOCAL" {
|
||||
if dir, ok := varMap["dir"]; ok {
|
||||
if dirStr, isStr := dir.(string); isStr {
|
||||
if strings.HasSuffix(dirStr, "/") && dirStr != "/" {
|
||||
if strings.HasSuffix(dirStr, "/") {
|
||||
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
||||
}
|
||||
if err := copyDir(oldDir, dirStr); err != nil {
|
||||
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
|
||||
return err
|
||||
}
|
||||
global.CONF.System.Backup = dirStr
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) ListFiles(req dto.BackupSearchFile) []string {
|
||||
var datas []string
|
||||
func (u *BackupService) ListFiles(req dto.BackupSearchFile) ([]string, error) {
|
||||
backup, err := backupRepo.Get(backupRepo.WithByType(req.Type))
|
||||
if err != nil {
|
||||
return datas
|
||||
return nil, err
|
||||
}
|
||||
client, err := u.NewClient(&backup)
|
||||
if err != nil {
|
||||
return datas
|
||||
return nil, err
|
||||
}
|
||||
prefix := "system_snapshot"
|
||||
if len(backup.BackupPath) != 0 {
|
||||
@@ -360,15 +307,15 @@ func (u *BackupService) ListFiles(req dto.BackupSearchFile) []string {
|
||||
}
|
||||
files, err := client.ListObjects(prefix)
|
||||
if err != nil {
|
||||
global.LOG.Debugf("load files from %s failed, err: %v", req.Type, err)
|
||||
return datas
|
||||
return nil, err
|
||||
}
|
||||
var datas []string
|
||||
for _, file := range files {
|
||||
if len(file) != 0 {
|
||||
datas = append(datas, path.Base(file))
|
||||
}
|
||||
}
|
||||
return datas
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) {
|
||||
@@ -376,9 +323,12 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
|
||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if backup.Type == "LOCAL" {
|
||||
return nil, errors.New("not support")
|
||||
}
|
||||
varMap["bucket"] = backup.Bucket
|
||||
switch backup.Type {
|
||||
case constant.Sftp, constant.WebDAV:
|
||||
case constant.Sftp:
|
||||
varMap["username"] = backup.AccessKey
|
||||
varMap["password"] = backup.Credential
|
||||
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||
@@ -403,15 +353,6 @@ func (u *BackupService) loadByType(accountType string, accounts []model.BackupAc
|
||||
if err := copier.Copy(&item, &account); err != nil {
|
||||
global.LOG.Errorf("copy backup account to dto backup info failed, err: %v", err)
|
||||
}
|
||||
if account.Type == constant.OneDrive {
|
||||
varMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(item.Vars), &varMap); err != nil {
|
||||
return dto.BackupInfo{Type: accountType}
|
||||
}
|
||||
delete(varMap, "refresh_token")
|
||||
itemVars, _ := json.Marshal(varMap)
|
||||
item.Vars = string(itemVars)
|
||||
}
|
||||
return item
|
||||
}
|
||||
}
|
||||
@@ -423,68 +364,48 @@ func (u *BackupService) loadAccessToken(backup *model.BackupAccount) error {
|
||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
||||
return fmt.Errorf("unmarshal backup vars failed, err: %v", err)
|
||||
}
|
||||
token, refreshToken, err := client.RefreshToken("authorization_code", varMap)
|
||||
|
||||
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 err
|
||||
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")
|
||||
backup.Credential = token
|
||||
varMap["refresh_status"] = constant.StatusSuccess
|
||||
varMap["refresh_time"] = time.Now().Format("2006-01-02 15:04:05")
|
||||
varMap["refresh_token"] = refreshToken
|
||||
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 (u *BackupService) loadRecordSize(records []model.BackupRecord) ([]dto.BackupRecords, error) {
|
||||
var datas []dto.BackupRecords
|
||||
clientMap := make(map[string]loadSizeHelper)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < len(records); i++ {
|
||||
var item dto.BackupRecords
|
||||
if err := copier.Copy(&item, &records[i]); err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
itemPath := path.Join(records[i].FileDir, records[i].FileName)
|
||||
if _, ok := clientMap[records[i].Source]; !ok {
|
||||
backup, err := backupRepo.Get(commonRepo.WithByType(records[i].Source))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load backup model %s from db failed, err: %v", records[i].Source, err)
|
||||
clientMap[records[i].Source] = loadSizeHelper{}
|
||||
datas = append(datas, item)
|
||||
continue
|
||||
}
|
||||
client, err := u.NewClient(&backup)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load backup client %s from db failed, err: %v", records[i].Source, err)
|
||||
clientMap[records[i].Source] = loadSizeHelper{}
|
||||
datas = append(datas, item)
|
||||
continue
|
||||
}
|
||||
item.Size, _ = client.Size(path.Join(strings.TrimLeft(backup.BackupPath, "/"), itemPath))
|
||||
datas = append(datas, item)
|
||||
clientMap[records[i].Source] = loadSizeHelper{backupPath: strings.TrimLeft(backup.BackupPath, "/"), client: client, isOk: true}
|
||||
continue
|
||||
}
|
||||
if clientMap[records[i].Source].isOk {
|
||||
wg.Add(1)
|
||||
go func(index int) {
|
||||
item.Size, _ = clientMap[records[index].Source].client.Size(path.Join(clientMap[records[index].Source].backupPath, itemPath))
|
||||
datas = append(datas, item)
|
||||
wg.Done()
|
||||
}(i)
|
||||
} else {
|
||||
datas = append(datas, item)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
func loadLocalDir() (string, error) {
|
||||
backup, err := backupRepo.Get(commonRepo.WithByType("LOCAL"))
|
||||
if err != nil {
|
||||
@@ -566,50 +487,3 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
|
||||
targetPath := strings.TrimPrefix(path.Join(backup.BackupPath, "test/1panel"), "/")
|
||||
return client.Upload(fileItem, targetPath)
|
||||
}
|
||||
|
||||
func StartRefreshOneDriveToken() {
|
||||
service := NewIBackupService()
|
||||
oneDriveCronID, err := global.Cron.AddJob("0 * * * *", service)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("can not add OneDrive corn job: %s", err.Error())
|
||||
return
|
||||
}
|
||||
global.OneDriveCronID = oneDriveCronID
|
||||
}
|
||||
|
||||
func (u *BackupService) Run() {
|
||||
var backupItem model.BackupAccount
|
||||
_ = global.DB.Where("`type` = ?", "OneDrive").First(&backupItem)
|
||||
if backupItem.ID == 0 {
|
||||
return
|
||||
}
|
||||
if len(backupItem.Credential) == 0 {
|
||||
global.LOG.Error("OneDrive configuration lacks token information, please rebind.")
|
||||
return
|
||||
}
|
||||
global.LOG.Info("start to refresh token of OneDrive ...")
|
||||
varMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(backupItem.Vars), &varMap); err != nil {
|
||||
global.LOG.Errorf("Failed to refresh OneDrive token, please retry, err: %v", err)
|
||||
return
|
||||
}
|
||||
token, refreshToken, err := client.RefreshToken("refresh_token", varMap)
|
||||
varMap["refresh_status"] = constant.StatusSuccess
|
||||
varMap["refresh_time"] = time.Now().Format("2006-01-02 15:04:05")
|
||||
if err != nil {
|
||||
varMap["refresh_status"] = constant.StatusFailed
|
||||
varMap["refresh_msg"] = err.Error()
|
||||
global.LOG.Errorf("Failed to refresh OneDrive token, please retry, err: %v", err)
|
||||
return
|
||||
}
|
||||
varMap["refresh_token"] = refreshToken
|
||||
|
||||
varsItem, _ := json.Marshal(varMap)
|
||||
_ = global.DB.Model(&model.BackupAccount{}).
|
||||
Where("id = ?", backupItem.ID).
|
||||
Updates(map[string]interface{}{
|
||||
"credential": token,
|
||||
"vars": varsItem,
|
||||
}).Error
|
||||
global.LOG.Info("Successfully refreshed OneDrive token.")
|
||||
}
|
||||
|
||||
@@ -10,13 +10,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
@@ -36,10 +33,10 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) error {
|
||||
return err
|
||||
}
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("app/%s/%s", req.Name, req.DetailName)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("app/%s/%s", req.Name, req.DetailName))
|
||||
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow)
|
||||
if err := handleAppBackup(&install, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,7 +47,7 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) error {
|
||||
DetailName: req.DetailName,
|
||||
Source: "LOCAL",
|
||||
BackupType: "LOCAL",
|
||||
FileDir: itemDir,
|
||||
FileDir: backupDir,
|
||||
FileName: fileName,
|
||||
}
|
||||
|
||||
@@ -73,7 +70,7 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(req.File) {
|
||||
return buserr.WithName("ErrFileNotFound", req.File)
|
||||
return errors.New(fmt.Sprintf("%s file is not exist", req.File))
|
||||
}
|
||||
if _, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
return err
|
||||
@@ -109,21 +106,12 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
|
||||
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
for _, resource := range resources {
|
||||
switch resource.Key {
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
if resource.Key == "mysql" || resource.Key == "mariadb" {
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleMysqlBackup(db.MysqlName, resource.Key, db.Name, tmpDir, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
db, err := postgresqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handlePostgresqlBackup(db.PostgresqlName, db.Name, tmpDir, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil {
|
||||
if err := handleMysqlBackup(db.MysqlName, db.Name, tmpDir, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -202,21 +190,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
}
|
||||
switch database.Type {
|
||||
case constant.AppPostgresql:
|
||||
db, err := postgresqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handlePostgresqlRecover(dto.CommonRecover{
|
||||
Name: database.Name,
|
||||
DetailName: db.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
|
||||
}
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
if database.Type == "mysql" || database.Type == "mariadb" {
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -260,7 +234,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
_ = fileOp.DeleteDir(backPath)
|
||||
|
||||
if len(newEnvFile) != 0 {
|
||||
envPath := fmt.Sprintf("%s/%s/.env", install.GetAppPath(), install.Name)
|
||||
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 {
|
||||
return err
|
||||
@@ -304,10 +278,6 @@ func reCreateDB(dbID uint, database model.Database, oldEnv string) (*model.Datab
|
||||
Password: oldPassword,
|
||||
Permission: "%",
|
||||
})
|
||||
cronjobs, _ := cronjobRepo.List(cronjobRepo.WithByDbName(fmt.Sprintf("%v", dbID)))
|
||||
for _, job := range cronjobs {
|
||||
_ = cronjobRepo.Update(job.ID, map[string]interface{}{"db_name": fmt.Sprintf("%v", createDB.ID)})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, envMap, err
|
||||
}
|
||||
|
||||
@@ -8,14 +8,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
@@ -25,11 +23,10 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
}
|
||||
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName)
|
||||
targetDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
targetDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName))
|
||||
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow)
|
||||
|
||||
if err := handleMysqlBackup(req.Name, req.Type, req.DetailName, targetDir, fileName); err != nil {
|
||||
if err := handleMysqlBackup(req.Name, req.DetailName, targetDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -39,7 +36,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
DetailName: req.DetailName,
|
||||
Source: "LOCAL",
|
||||
BackupType: "LOCAL",
|
||||
FileDir: itemDir,
|
||||
FileDir: targetDir,
|
||||
FileName: fileName,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
@@ -100,20 +97,18 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleMysqlBackup(database, dbType, dbName, targetDir, fileName string) error {
|
||||
func handleMysqlBackup(database, dbName, targetDir, fileName string) error {
|
||||
dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByMysqlName(database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, version, err := LoadMysqlClientByFrom(database)
|
||||
cli, _, err := LoadMysqlClientByFrom(database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
backupInfo := client.BackupInfo{
|
||||
Name: dbName,
|
||||
Type: dbType,
|
||||
Version: version,
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: targetDir,
|
||||
FileName: fileName,
|
||||
@@ -130,13 +125,13 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
isOk := false
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(req.File) {
|
||||
return buserr.WithName("ErrFileNotFound", 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, version, err := LoadMysqlClientByFrom(req.Name)
|
||||
cli, _, err := LoadMysqlClientByFrom(req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -145,8 +140,6 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
|
||||
if err := cli.Backup(client.BackupInfo{
|
||||
Name: req.DetailName,
|
||||
Type: req.Type,
|
||||
Version: version,
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: path.Dir(rollbackFile),
|
||||
FileName: path.Base(rollbackFile),
|
||||
@@ -160,8 +153,6 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := cli.Recover(client.RecoverInfo{
|
||||
Name: req.DetailName,
|
||||
Type: req.Type,
|
||||
Version: version,
|
||||
Format: dbInfo.Format,
|
||||
SourceFile: rollbackFile,
|
||||
|
||||
@@ -178,8 +169,6 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
}
|
||||
if err := cli.Recover(client.RecoverInfo{
|
||||
Name: req.DetailName,
|
||||
Type: req.Type,
|
||||
Version: version,
|
||||
Format: dbInfo.Format,
|
||||
SourceFile: req.File,
|
||||
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
pgclient "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
)
|
||||
|
||||
func (u *BackupService) PostgresqlBackup(req dto.CommonBackup) error {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName)
|
||||
targetDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
|
||||
if err := handlePostgresqlBackup(req.Name, req.DetailName, targetDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record := &model.BackupRecord{
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
DetailName: req.DetailName,
|
||||
Source: "LOCAL",
|
||||
BackupType: "LOCAL",
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (u *BackupService) PostgresqlRecover(req dto.CommonRecover) error {
|
||||
if err := handlePostgresqlRecover(req, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
file := req.File
|
||||
fileName := path.Base(req.File)
|
||||
if strings.HasSuffix(fileName, ".tar.gz") {
|
||||
fileNameItem := time.Now().Format("20060102150405")
|
||||
dstDir := fmt.Sprintf("%s/%s", path.Dir(req.File), fileNameItem)
|
||||
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dstDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err)
|
||||
}
|
||||
}
|
||||
if err := handleUnTar(req.File, dstDir); err != nil {
|
||||
_ = os.RemoveAll(dstDir)
|
||||
return err
|
||||
}
|
||||
global.LOG.Infof("decompress file %s successful, now start to check test.sql is exist", req.File)
|
||||
hasTestSql := false
|
||||
_ = filepath.Walk(dstDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if !info.IsDir() && info.Name() == "test.sql" {
|
||||
hasTestSql = true
|
||||
file = path
|
||||
fileName = "test.sql"
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if !hasTestSql {
|
||||
_ = os.RemoveAll(dstDir)
|
||||
return fmt.Errorf("no such file named test.sql in %s", fileName)
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(dstDir)
|
||||
}()
|
||||
}
|
||||
|
||||
req.File = path.Dir(file) + "/" + fileName
|
||||
if err := handlePostgresqlRecover(req, false); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("recover from uploads successful!")
|
||||
return nil
|
||||
}
|
||||
func handlePostgresqlBackup(database, dbName, targetDir, fileName string) error {
|
||||
cli, err := LoadPostgresqlClientByFrom(database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
backupInfo := pgclient.BackupInfo{
|
||||
Name: dbName,
|
||||
TargetDir: targetDir,
|
||||
FileName: fileName,
|
||||
|
||||
Timeout: 300,
|
||||
}
|
||||
if err := cli.Backup(backupInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
isOk := false
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(req.File) {
|
||||
return buserr.WithName("ErrFileNotFound", req.File)
|
||||
}
|
||||
dbInfo, err := postgresqlRepo.Get(commonRepo.WithByName(req.DetailName), postgresqlRepo.WithByPostgresqlName(req.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
|
||||
if err := cli.Backup(client.BackupInfo{
|
||||
Name: req.DetailName,
|
||||
TargetDir: path.Dir(rollbackFile),
|
||||
FileName: path.Base(rollbackFile),
|
||||
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("backup postgresql db %s for rollback before recover failed, err: %v", req.DetailName, err)
|
||||
}
|
||||
defer func() {
|
||||
if !isOk {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := cli.Recover(client.RecoverInfo{
|
||||
Name: req.DetailName,
|
||||
SourceFile: rollbackFile,
|
||||
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("rollback postgresql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
|
||||
}
|
||||
global.LOG.Infof("rollback postgresql db %s from %s successful", req.DetailName, rollbackFile)
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
} else {
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
}
|
||||
}()
|
||||
}
|
||||
if err := cli.Recover(client.RecoverInfo{
|
||||
Name: req.DetailName,
|
||||
SourceFile: req.File,
|
||||
Username: dbInfo.Username,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
isOk = true
|
||||
return nil
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
@@ -35,7 +34,7 @@ func (u *BackupService) RedisBackup() error {
|
||||
}
|
||||
global.LOG.Infof("appendonly in redis conf is %s", appendonly)
|
||||
|
||||
timeNow := time.Now().Format("20060102150405") + common.RandStrAndNum(5)
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
fileName := fmt.Sprintf("%s.rdb", timeNow)
|
||||
if appendonly == "yes" {
|
||||
if strings.HasPrefix(redisInfo.Version, "6.") {
|
||||
@@ -44,8 +43,7 @@ func (u *BackupService) RedisBackup() error {
|
||||
fileName = fmt.Sprintf("%s.tar.gz", timeNow)
|
||||
}
|
||||
}
|
||||
itemDir := fmt.Sprintf("database/redis/%s", redisInfo.Name)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/redis/%s", redisInfo.Name))
|
||||
if err := handleRedisBackup(redisInfo, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -53,7 +51,7 @@ func (u *BackupService) RedisBackup() error {
|
||||
Type: "redis",
|
||||
Source: "LOCAL",
|
||||
BackupType: "LOCAL",
|
||||
FileDir: itemDir,
|
||||
FileDir: backupDir,
|
||||
FileName: fileName,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
@@ -113,7 +111,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string) err
|
||||
func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback bool) error {
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(recoverFile) {
|
||||
return buserr.WithName("ErrFileNotFound", recoverFile)
|
||||
return fmt.Errorf("%s file is not exist", recoverFile)
|
||||
}
|
||||
|
||||
appendonly, err := configGetStr(redisInfo.ContainerName, redisInfo.Password, "appendonly")
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
@@ -26,15 +25,14 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(req.DetailName))
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(req.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("website/%s", req.Name)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow+common.RandStrAndNum(5))
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("website/%s", req.Name))
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow)
|
||||
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -42,10 +40,10 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
record := &model.BackupRecord{
|
||||
Type: "website",
|
||||
Name: website.PrimaryDomain,
|
||||
DetailName: req.DetailName,
|
||||
DetailName: "",
|
||||
Source: "LOCAL",
|
||||
BackupType: "LOCAL",
|
||||
FileDir: itemDir,
|
||||
FileDir: backupDir,
|
||||
FileName: fileName,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
@@ -56,14 +54,14 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
}
|
||||
|
||||
func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error {
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(req.File) {
|
||||
return buserr.WithName("ErrFileNotFound", req.File)
|
||||
}
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(req.DetailName))
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(req.Name))
|
||||
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 website %s from backup file %s", req.Name, req.File)
|
||||
if err := handleWebsiteRecover(&website, req.File, false); err != nil {
|
||||
return err
|
||||
@@ -81,6 +79,15 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
_ = os.RemoveAll(tmpPath)
|
||||
}()
|
||||
|
||||
temPathWithName := tmpPath + "/" + website.Alias
|
||||
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)
|
||||
}
|
||||
if website.Type == constant.Deployment {
|
||||
if !fileOp.Stat(temPathWithName + ".app.tar.gz") {
|
||||
return buserr.WithDetail(constant.ErrBackupExist, ".app.tar.gz", nil)
|
||||
}
|
||||
}
|
||||
var oldWebsite model.Website
|
||||
websiteJson, err := os.ReadFile(tmpPath + "/website.json")
|
||||
if err != nil {
|
||||
@@ -94,16 +101,6 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
|
||||
temPathWithName := tmpPath + "/" + website.Alias
|
||||
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)
|
||||
}
|
||||
if website.Type == constant.Deployment {
|
||||
if !fileOp.Stat(temPathWithName + ".app.tar.gz") {
|
||||
return buserr.WithDetail(constant.ErrBackupExist, ".app.tar.gz", nil)
|
||||
}
|
||||
}
|
||||
|
||||
isOk := false
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
|
||||
|
||||
@@ -23,7 +23,7 @@ func NewICommandService() ICommandService {
|
||||
}
|
||||
|
||||
func (u *CommandService) List() ([]dto.CommandInfo, error) {
|
||||
commands, err := commandRepo.GetList(commonRepo.WithOrderBy("name"))
|
||||
commands, err := commandRepo.GetList()
|
||||
if err != nil {
|
||||
return nil, constant.ErrRecordNotFound
|
||||
}
|
||||
@@ -39,7 +39,7 @@ func (u *CommandService) List() ([]dto.CommandInfo, error) {
|
||||
}
|
||||
|
||||
func (u *CommandService) SearchForTree() ([]dto.CommandTree, error) {
|
||||
cmdList, err := commandRepo.GetList(commonRepo.WithOrderBy("name"))
|
||||
cmdList, err := commandRepo.GetList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,11 +65,11 @@ func (u *CommandService) SearchForTree() ([]dto.CommandTree, error) {
|
||||
}
|
||||
|
||||
func (u *CommandService) SearchWithPage(search dto.SearchCommandWithPage) (int64, interface{}, error) {
|
||||
total, commands, err := commandRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithByGroupID(search.GroupID), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
|
||||
total, commands, err := commandRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithByGroupID(search.GroupID))
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
groups, _ := groupRepo.GetList(commonRepo.WithByType("command"), commonRepo.WithOrderBy("name"))
|
||||
groups, _ := groupRepo.GetList(commonRepo.WithByType("command"))
|
||||
var dtoCommands []dto.CommandInfo
|
||||
for _, command := range commands {
|
||||
var item dto.CommandInfo
|
||||
|
||||
@@ -2,12 +2,12 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -15,9 +15,6 @@ import (
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
@@ -30,7 +27,6 @@ import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -92,21 +88,10 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
options.Filters = filters.NewArgs()
|
||||
options.Filters.Add("label", req.Filters)
|
||||
}
|
||||
containers, err := client.ContainerList(context.Background(), options)
|
||||
list, err = client.ContainerList(context.Background(), options)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if req.ExcludeAppStore {
|
||||
for _, item := range containers {
|
||||
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" {
|
||||
continue
|
||||
}
|
||||
list = append(list, item)
|
||||
}
|
||||
} else {
|
||||
list = containers
|
||||
}
|
||||
|
||||
if len(req.Name) != 0 {
|
||||
length, count := len(list), 0
|
||||
for count < length {
|
||||
@@ -175,8 +160,8 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
IsFromApp = true
|
||||
}
|
||||
|
||||
ports := loadContainerPort(item.Ports)
|
||||
info := dto.ContainerInfo{
|
||||
ports := simplifyPort(item.Ports)
|
||||
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:],
|
||||
@@ -188,16 +173,6 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
IsFromApp: IsFromApp,
|
||||
IsFromCompose: IsFromCompose,
|
||||
}
|
||||
install, _ := appInstallRepo.GetFirst(appInstallRepo.WithContainerName(info.Name))
|
||||
if install.ID > 0 {
|
||||
info.AppInstallName = install.Name
|
||||
info.AppName = install.App.Name
|
||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(install.ID))
|
||||
for _, website := range websites {
|
||||
info.Websites = append(info.Websites, website.PrimaryDomain)
|
||||
}
|
||||
}
|
||||
backDatas[i] = info
|
||||
if item.NetworkSettings != nil && len(item.NetworkSettings.Networks) > 0 {
|
||||
networks := make([]string, 0, len(item.NetworkSettings.Networks))
|
||||
for key := range item.NetworkSettings.Networks {
|
||||
@@ -337,7 +312,7 @@ func (u *ContainerService) LoadResourceLimit() (*dto.ResourceLimit, error) {
|
||||
|
||||
data := dto.ResourceLimit{
|
||||
CPU: cpuCounts,
|
||||
Memory: memoryInfo.Total,
|
||||
Memory: int(memoryInfo.Total),
|
||||
}
|
||||
return &data, nil
|
||||
}
|
||||
@@ -433,9 +408,8 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
|
||||
}
|
||||
}
|
||||
data.AutoRemove = oldContainer.HostConfig.AutoRemove
|
||||
data.Privileged = oldContainer.HostConfig.Privileged
|
||||
data.PublishAllPorts = oldContainer.HostConfig.PublishAllPorts
|
||||
data.RestartPolicy = string(oldContainer.HostConfig.RestartPolicy.Name)
|
||||
data.RestartPolicy = oldContainer.HostConfig.RestartPolicy.Name
|
||||
if oldContainer.HostConfig.NanoCPUs != 0 {
|
||||
data.NanoCPUs = float64(oldContainer.HostConfig.NanoCPUs) / 1000000000
|
||||
}
|
||||
@@ -467,7 +441,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
||||
if !req.ForcePull {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("pull image %s failed, err: %v", req.Image, err)
|
||||
global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,7 +484,7 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
|
||||
if !req.ForcePull {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("pull image %s failed, err: %v", req.Image, err)
|
||||
global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err)
|
||||
}
|
||||
}
|
||||
config := oldContainer.Config
|
||||
@@ -640,9 +614,6 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
|
||||
cmd := exec.Command("bash", "-c", command)
|
||||
if !follow {
|
||||
stdout, _ := cmd.CombinedOutput()
|
||||
if !utf8.Valid(stdout) {
|
||||
return errors.New("invalid utf8")
|
||||
}
|
||||
if err := wsConn.WriteMessage(websocket.TextMessage, stdout); err != nil {
|
||||
global.LOG.Errorf("send message with log to ws failed, err: %v", err)
|
||||
}
|
||||
@@ -684,9 +655,6 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
|
||||
global.LOG.Errorf("read bytes from log failed, err: %v", err)
|
||||
continue
|
||||
}
|
||||
if !utf8.Valid(buffer[:n]) {
|
||||
continue
|
||||
}
|
||||
if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil {
|
||||
global.LOG.Errorf("send message with log to ws failed, err: %v", err)
|
||||
return err
|
||||
@@ -723,6 +691,7 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
|
||||
if cache, ok := stats.MemoryStats.Stats["cache"]; ok {
|
||||
data.Cache = float64(cache) / 1024 / 1024
|
||||
}
|
||||
data.Memory = data.Memory - data.Cache
|
||||
data.NetworkRX, data.NetworkTX = calculateNetwork(stats.Networks)
|
||||
data.ShotTime = stats.Read
|
||||
return &data, nil
|
||||
@@ -730,15 +699,18 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
|
||||
|
||||
func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) string {
|
||||
filePath := ""
|
||||
if req.Type == "compose-detail" {
|
||||
cli, err := docker.NewDockerClient()
|
||||
switch req.Type {
|
||||
case "image-pull", "image-push", "image-build", "compose-create":
|
||||
filePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
||||
case "compose-detail":
|
||||
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 := cli.ContainerList(context.Background(), options)
|
||||
containers, err := client.ContainerList(context.Background(), options)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
@@ -753,6 +725,9 @@ func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) s
|
||||
break
|
||||
}
|
||||
}
|
||||
if req.Type == "compose-create" {
|
||||
filePath = path.Join(path.Dir(filePath), "compose.log")
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(filePath); err != nil {
|
||||
return ""
|
||||
@@ -790,7 +765,7 @@ func calculateCPUPercentUnix(stats *types.StatsJSON) float64 {
|
||||
}
|
||||
func calculateMemPercentUnix(memStats types.MemoryStats) float64 {
|
||||
memPercent := 0.0
|
||||
memUsage := float64(memStats.Usage)
|
||||
memUsage := float64(memStats.Usage - memStats.Stats["cache"])
|
||||
memLimit := float64(memStats.Limit)
|
||||
if memUsage > 0.0 && memLimit > 0.0 {
|
||||
memPercent = (memUsage / memLimit) * 100.0
|
||||
@@ -836,25 +811,7 @@ func checkImageExist(client *client.Client, image string) bool {
|
||||
}
|
||||
|
||||
func pullImages(ctx context.Context, client *client.Client, image string) error {
|
||||
options := types.ImagePullOptions{}
|
||||
repos, _ := imageRepoRepo.List()
|
||||
if len(repos) != 0 {
|
||||
for _, repo := range repos {
|
||||
if strings.HasPrefix(image, repo.DownloadUrl) && repo.Auth {
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
Password: repo.Password,
|
||||
}
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
}
|
||||
}
|
||||
out, err := client.ImagePull(ctx, image, options)
|
||||
out, err := client.ImagePull(ctx, image, types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -894,7 +851,6 @@ func loadCpuAndMem(client *client.Client, container string) dto.ContainerListSta
|
||||
data.MemoryCache = stats.MemoryStats.Stats["cache"]
|
||||
data.MemoryUsage = stats.MemoryStats.Usage
|
||||
data.MemoryLimit = stats.MemoryStats.Limit
|
||||
|
||||
data.MemoryPercent = calculateMemPercentUnix(stats.MemoryStats)
|
||||
return data
|
||||
}
|
||||
@@ -981,11 +937,10 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
|
||||
networkConf = network.NetworkingConfig{}
|
||||
}
|
||||
|
||||
hostConf.Privileged = req.Privileged
|
||||
hostConf.AutoRemove = req.AutoRemove
|
||||
hostConf.CPUShares = req.CPUShares
|
||||
hostConf.PublishAllPorts = req.PublishAllPorts
|
||||
hostConf.RestartPolicy = container.RestartPolicy{Name: container.RestartPolicyMode(req.RestartPolicy)}
|
||||
hostConf.RestartPolicy = container.RestartPolicy{Name: req.RestartPolicy}
|
||||
if req.RestartPolicy == "on-failure" {
|
||||
hostConf.RestartPolicy.MaximumRetryCount = 5
|
||||
}
|
||||
@@ -1063,22 +1018,6 @@ func loadVolumeBinds(binds []string) []dto.VolumeHelper {
|
||||
return datas
|
||||
}
|
||||
|
||||
func loadContainerPort(ports []types.Port) []string {
|
||||
var (
|
||||
ipv4Ports []types.Port
|
||||
ipv6Ports []types.Port
|
||||
)
|
||||
for _, port := range ports {
|
||||
if strings.Contains(port.IP, ":") {
|
||||
ipv6Ports = append(ipv6Ports, port)
|
||||
} else {
|
||||
ipv4Ports = append(ipv4Ports, port)
|
||||
}
|
||||
}
|
||||
list1 := simplifyPort(ipv4Ports)
|
||||
list2 := simplifyPort(ipv6Ports)
|
||||
return append(list1, list2...)
|
||||
}
|
||||
func simplifyPort(ports []types.Port) []string {
|
||||
var datas []string
|
||||
if len(ports) == 0 {
|
||||
@@ -1109,19 +1048,13 @@ func simplifyPort(ports []types.Port) []string {
|
||||
if start.PublicPort != 0 {
|
||||
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", start.IP, start.PublicPort, start.PrivatePort, start.Type)
|
||||
}
|
||||
if len(start.IP) == 0 {
|
||||
itemPortStr = strings.TrimPrefix(itemPortStr, ":")
|
||||
}
|
||||
datas = append(datas, itemPortStr)
|
||||
datas = append(datas, strings.TrimPrefix(itemPortStr, ":"))
|
||||
} else {
|
||||
itemPortStr := fmt.Sprintf("%s:%v-%v/%s", start.IP, start.PrivatePort, ports[i-1].PrivatePort, start.Type)
|
||||
if start.PublicPort != 0 {
|
||||
itemPortStr = fmt.Sprintf("%s:%v-%v->%v-%v/%s", start.IP, start.PublicPort, ports[i-1].PublicPort, start.PrivatePort, ports[i-1].PrivatePort, start.Type)
|
||||
}
|
||||
if len(start.IP) == 0 {
|
||||
itemPortStr = strings.TrimPrefix(itemPortStr, ":")
|
||||
}
|
||||
datas = append(datas, itemPortStr)
|
||||
datas = append(datas, strings.TrimPrefix(itemPortStr, ":"))
|
||||
}
|
||||
start = ports[i]
|
||||
}
|
||||
@@ -1131,19 +1064,13 @@ func simplifyPort(ports []types.Port) []string {
|
||||
if start.PublicPort != 0 {
|
||||
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", start.IP, start.PublicPort, start.PrivatePort, start.Type)
|
||||
}
|
||||
if len(start.IP) == 0 {
|
||||
itemPortStr = strings.TrimPrefix(itemPortStr, ":")
|
||||
}
|
||||
datas = append(datas, itemPortStr)
|
||||
datas = append(datas, strings.TrimPrefix(itemPortStr, ":"))
|
||||
} else {
|
||||
itemPortStr := fmt.Sprintf("%s:%v-%v/%s", start.IP, start.PrivatePort, ports[i].PrivatePort, start.Type)
|
||||
if start.PublicPort != 0 {
|
||||
itemPortStr = fmt.Sprintf("%s:%v-%v->%v-%v/%s", start.IP, start.PublicPort, ports[i].PublicPort, start.PrivatePort, ports[i].PrivatePort, start.Type)
|
||||
}
|
||||
if len(start.IP) == 0 {
|
||||
itemPortStr = strings.TrimPrefix(itemPortStr, ":")
|
||||
}
|
||||
datas = append(datas, itemPortStr)
|
||||
datas = append(datas, strings.TrimPrefix(itemPortStr, ":"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,8 +216,7 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
||||
if cmd.CheckIllegal(req.Name, req.Path) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
oldFile, err := os.ReadFile(req.Path)
|
||||
if err != nil {
|
||||
if _, err := os.Stat(req.Path); err != nil {
|
||||
return fmt.Errorf("load file with path %s failed, %v", req.Path, err)
|
||||
}
|
||||
file, err := os.OpenFile(req.Path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
@@ -231,16 +230,10 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
||||
|
||||
global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.Path)
|
||||
if stdout, err := compose.Down(req.Path); err != nil {
|
||||
if err := recreateCompose(string(oldFile), req.Path); err != nil {
|
||||
return fmt.Errorf("update failed when handle compose down, err: %s, recreate failed: %v", string(stdout), err)
|
||||
}
|
||||
return fmt.Errorf("update failed when handle compose down, err: %s", string(stdout))
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
if stdout, err := compose.Up(req.Path); err != nil {
|
||||
if err := recreateCompose(string(oldFile), req.Path); err != nil {
|
||||
return fmt.Errorf("update failed when handle compose up, err: %s, recreate failed: %v", string(stdout), err)
|
||||
}
|
||||
return fmt.Errorf("update failed when handle compose up, err: %s", string(stdout))
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -268,19 +261,3 @@ func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func recreateCompose(content, path string) error {
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(content)
|
||||
write.Flush()
|
||||
|
||||
if stdout, err := compose.Up(path); err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -116,57 +116,29 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
ipams []network.IPAMConfig
|
||||
enableV6 bool
|
||||
ipam network.IPAMConfig
|
||||
hasConf bool
|
||||
)
|
||||
if req.Ipv4 {
|
||||
var itemIpam network.IPAMConfig
|
||||
if len(req.AuxAddress) != 0 {
|
||||
itemIpam.AuxAddress = make(map[string]string)
|
||||
}
|
||||
if len(req.Subnet) != 0 {
|
||||
itemIpam.Subnet = req.Subnet
|
||||
}
|
||||
if len(req.Gateway) != 0 {
|
||||
itemIpam.Gateway = req.Gateway
|
||||
}
|
||||
if len(req.IPRange) != 0 {
|
||||
itemIpam.IPRange = req.IPRange
|
||||
}
|
||||
for _, addr := range req.AuxAddress {
|
||||
itemIpam.AuxAddress[addr.Key] = addr.Value
|
||||
}
|
||||
ipams = append(ipams, itemIpam)
|
||||
if len(req.Subnet) != 0 {
|
||||
ipam.Subnet = req.Subnet
|
||||
hasConf = true
|
||||
}
|
||||
if req.Ipv6 {
|
||||
enableV6 = true
|
||||
var itemIpam network.IPAMConfig
|
||||
if len(req.AuxAddress) != 0 {
|
||||
itemIpam.AuxAddress = make(map[string]string)
|
||||
}
|
||||
if len(req.SubnetV6) != 0 {
|
||||
itemIpam.Subnet = req.SubnetV6
|
||||
}
|
||||
if len(req.GatewayV6) != 0 {
|
||||
itemIpam.Gateway = req.GatewayV6
|
||||
}
|
||||
if len(req.IPRangeV6) != 0 {
|
||||
itemIpam.IPRange = req.IPRangeV6
|
||||
}
|
||||
for _, addr := range req.AuxAddressV6 {
|
||||
itemIpam.AuxAddress[addr.Key] = addr.Value
|
||||
}
|
||||
ipams = append(ipams, itemIpam)
|
||||
if len(req.Gateway) != 0 {
|
||||
ipam.Gateway = req.Gateway
|
||||
hasConf = true
|
||||
}
|
||||
if len(req.IPRange) != 0 {
|
||||
ipam.IPRange = req.IPRange
|
||||
hasConf = true
|
||||
}
|
||||
|
||||
options := types.NetworkCreate{
|
||||
EnableIPv6: enableV6,
|
||||
Driver: req.Driver,
|
||||
Options: stringsToMap(req.Options),
|
||||
Labels: stringsToMap(req.Labels),
|
||||
Driver: req.Driver,
|
||||
Options: stringsToMap(req.Options),
|
||||
Labels: stringsToMap(req.Labels),
|
||||
}
|
||||
if len(ipams) != 0 {
|
||||
options.IPAM = &network.IPAM{Config: ipams}
|
||||
if hasConf {
|
||||
options.IPAM = &network.IPAM{Config: []network.IPAMConfig{ipam}}
|
||||
}
|
||||
if _, err := client.NetworkCreate(context.TODO(), req.Name, options); err != nil {
|
||||
return err
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
@@ -52,20 +51,15 @@ func (u *ContainerService) PageVolume(req dto.SearchWithPage) (int64, interface{
|
||||
records = list.Volumes[start:end]
|
||||
}
|
||||
|
||||
nyc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
for _, item := range records {
|
||||
tag := make([]string, 0)
|
||||
for _, val := range item.Labels {
|
||||
tag = append(tag, val)
|
||||
}
|
||||
var createTime time.Time
|
||||
if strings.Contains(item.CreatedAt, "Z") {
|
||||
createTime, _ = time.ParseInLocation("2006-01-02T15:04:05Z", item.CreatedAt, nyc)
|
||||
} else if strings.Contains(item.CreatedAt, "+") {
|
||||
createTime, _ = time.ParseInLocation("2006-01-02T15:04:05+08:00", item.CreatedAt, nyc)
|
||||
} else {
|
||||
createTime, _ = time.ParseInLocation("2006-01-02T15:04:05", item.CreatedAt, nyc)
|
||||
if len(item.CreatedAt) > 19 {
|
||||
item.CreatedAt = item.CreatedAt[0:19]
|
||||
}
|
||||
createTime, _ := time.Parse("2006-01-02T15:04:05", item.CreatedAt)
|
||||
data = append(data, dto.Volume{
|
||||
CreatedAt: createTime,
|
||||
Name: item.Name,
|
||||
|
||||
@@ -5,12 +5,11 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/jinzhu/copier"
|
||||
@@ -29,10 +28,10 @@ type ICronjobService interface {
|
||||
UpdateStatus(id uint, status string) error
|
||||
Delete(req dto.CronjobBatchDelete) error
|
||||
Download(down dto.CronjobDownload) (string, error)
|
||||
StartJob(cronjob *model.Cronjob) (string, error)
|
||||
StartJob(cronjob *model.Cronjob) (int, error)
|
||||
CleanRecord(req dto.CronjobClean) error
|
||||
|
||||
LoadRecordLog(req dto.OperateByID) string
|
||||
LoadRecordLog(req dto.OperateByID) (string, error)
|
||||
}
|
||||
|
||||
func NewICronjobService() ICronjobService {
|
||||
@@ -47,6 +46,14 @@ func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, inter
|
||||
if err := copier.Copy(&item, &cronjob); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
if hasBackup(item.Type) {
|
||||
backup, _ := backupRepo.Get(commonRepo.WithByID(uint(item.TargetDirID)))
|
||||
if len(backup.Type) != 0 {
|
||||
item.TargetDir = backup.Type
|
||||
}
|
||||
} else {
|
||||
item.TargetDir = "-"
|
||||
}
|
||||
record, _ := cronjobRepo.RecordFirst(cronjob.ID)
|
||||
if record.ID != 0 {
|
||||
item.LastRecordTime = record.StartTime.Format("2006-01-02 15:04:05")
|
||||
@@ -76,19 +83,19 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
|
||||
return total, dtoCronjobs, err
|
||||
}
|
||||
|
||||
func (u *CronjobService) LoadRecordLog(req dto.OperateByID) string {
|
||||
func (u *CronjobService) LoadRecordLog(req dto.OperateByID) (string, error) {
|
||||
record, err := cronjobRepo.GetRecord(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return ""
|
||||
return "", err
|
||||
}
|
||||
if _, err := os.Stat(record.Records); err != nil {
|
||||
return ""
|
||||
return "", buserr.New("ErrHttpReqNotFound")
|
||||
}
|
||||
content, err := os.ReadFile(record.Records)
|
||||
if err != nil {
|
||||
return ""
|
||||
return "", err
|
||||
}
|
||||
return string(content)
|
||||
return string(content), nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
||||
@@ -96,23 +103,24 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if req.CleanData {
|
||||
if hasBackup(cronjob.Type) {
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if req.CleanData && hasBackup(cronjob.Type) {
|
||||
cronjob.RetainCopies = 0
|
||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if backup.Type != "LOCAL" {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cronjob.RetainCopies = 0
|
||||
u.removeExpiredBackup(cronjob, accountMap, model.BackupRecord{})
|
||||
client, err := NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client)
|
||||
} else {
|
||||
u.removeExpiredLog(cronjob)
|
||||
}
|
||||
}
|
||||
if req.IsDelete {
|
||||
records, _ := backupRepo.ListRecord(backupRepo.WithByCronID(cronjob.ID))
|
||||
for _, records := range records {
|
||||
records.CronjobID = 0
|
||||
_ = backupRepo.UpdateRecord(&records)
|
||||
u.HandleRmExpired(backup.Type, backup.BackupPath, "", &cronjob, nil)
|
||||
}
|
||||
}
|
||||
delRecords, err := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(req.CronjobID)))
|
||||
@@ -176,40 +184,29 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
cronjob.Status = constant.StatusEnable
|
||||
cronjob.Spec = loadSpec(cronjob)
|
||||
|
||||
global.LOG.Infof("create cronjob %s successful, spec: %s", cronjob.Name, cronjob.Spec)
|
||||
spec := cronjob.Spec
|
||||
entryIDs, err := u.StartJob(&cronjob)
|
||||
entryID, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cronjob.Spec = spec
|
||||
cronjob.EntryIDs = entryIDs
|
||||
cronjob.EntryID = uint64(entryID)
|
||||
if err := cronjobRepo.Create(&cronjob); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob) (string, error) {
|
||||
if len(cronjob.EntryIDs) != 0 {
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob) (int, error) {
|
||||
if cronjob.EntryID != 0 {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
}
|
||||
specs := strings.Split(cronjob.Spec, ",")
|
||||
var ids []string
|
||||
for _, spec := range specs {
|
||||
cronjob.Spec = spec
|
||||
entryID, err := u.AddCronJob(cronjob)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ids = append(ids, fmt.Sprintf("%v", entryID))
|
||||
entryID, err := u.AddCronJob(cronjob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strings.Join(ids, ","), nil
|
||||
return entryID, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||
@@ -218,13 +215,9 @@ func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||
if cronjob.ID == 0 {
|
||||
return errors.New("find cronjob in db failed")
|
||||
}
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
global.LOG.Infof("stop cronjob entryID: %s", cronjob.EntryIDs)
|
||||
if err := u.CleanRecord(dto.CronjobClean{CronjobID: id, CleanData: req.CleanData, IsDelete: true}); err != nil {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||
if err := u.CleanRecord(dto.CronjobClean{CronjobID: id, CleanData: req.CleanData}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cronjobRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
||||
@@ -245,37 +238,37 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
upMap := make(map[string]interface{})
|
||||
cronjob.EntryIDs = cronModel.EntryIDs
|
||||
cronjob.EntryID = cronModel.EntryID
|
||||
cronjob.Type = cronModel.Type
|
||||
spec := cronjob.Spec
|
||||
cronjob.Spec = loadSpec(cronjob)
|
||||
if cronModel.Status == constant.StatusEnable {
|
||||
newEntryIDs, err := u.StartJob(&cronjob)
|
||||
newEntryID, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upMap["entry_ids"] = newEntryIDs
|
||||
upMap["entry_id"] = newEntryID
|
||||
} else {
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
}
|
||||
|
||||
upMap["name"] = req.Name
|
||||
upMap["spec"] = spec
|
||||
upMap["spec"] = cronjob.Spec
|
||||
upMap["script"] = req.Script
|
||||
upMap["container_name"] = req.ContainerName
|
||||
upMap["spec_type"] = req.SpecType
|
||||
upMap["week"] = req.Week
|
||||
upMap["day"] = req.Day
|
||||
upMap["hour"] = req.Hour
|
||||
upMap["minute"] = req.Minute
|
||||
upMap["second"] = req.Second
|
||||
upMap["app_id"] = req.AppID
|
||||
upMap["website"] = req.Website
|
||||
upMap["exclusion_rules"] = req.ExclusionRules
|
||||
upMap["db_type"] = req.DBType
|
||||
upMap["db_name"] = req.DBName
|
||||
upMap["url"] = req.URL
|
||||
upMap["source_dir"] = req.SourceDir
|
||||
|
||||
upMap["backup_accounts"] = req.BackupAccounts
|
||||
upMap["default_download"] = req.DefaultDownload
|
||||
upMap["keep_local"] = req.KeepLocal
|
||||
upMap["target_dir_id"] = req.TargetDirID
|
||||
upMap["retain_copies"] = req.RetainCopies
|
||||
return cronjobRepo.Update(id, upMap)
|
||||
}
|
||||
@@ -286,23 +279,19 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
|
||||
return errors.WithMessage(constant.ErrRecordNotFound, "record not found")
|
||||
}
|
||||
var (
|
||||
entryIDs string
|
||||
err error
|
||||
entryID int
|
||||
err error
|
||||
)
|
||||
if status == constant.StatusEnable {
|
||||
entryIDs, err = u.StartJob(&cronjob)
|
||||
entryID, err = u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
global.LOG.Infof("stop cronjob entryID: %s", cronjob.EntryIDs)
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||
}
|
||||
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status, "entry_ids": entryIDs})
|
||||
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status, "entry_id": entryID})
|
||||
}
|
||||
|
||||
func (u *CronjobService) AddCronJob(cronjob *model.Cronjob) (int, error) {
|
||||
@@ -338,3 +327,26 @@ func mkdirAndWriteFile(cronjob *model.Cronjob, startTime time.Time, msg []byte)
|
||||
write.Flush()
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func loadSpec(cronjob model.Cronjob) string {
|
||||
switch cronjob.SpecType {
|
||||
case "perMonth":
|
||||
return fmt.Sprintf("%v %v %v * *", cronjob.Minute, cronjob.Hour, cronjob.Day)
|
||||
case "perWeek":
|
||||
return fmt.Sprintf("%v %v * * %v", cronjob.Minute, cronjob.Hour, cronjob.Week)
|
||||
case "perNDay":
|
||||
return fmt.Sprintf("%v %v */%v * *", cronjob.Minute, cronjob.Hour, cronjob.Day)
|
||||
case "perDay":
|
||||
return fmt.Sprintf("%v %v * * *", cronjob.Minute, cronjob.Hour)
|
||||
case "perNHour":
|
||||
return fmt.Sprintf("%v */%v * * *", cronjob.Minute, cronjob.Hour)
|
||||
case "perHour":
|
||||
return fmt.Sprintf("%v * * * *", cronjob.Minute)
|
||||
case "perNMinute":
|
||||
return fmt.Sprintf("@every %vm", cronjob.Minute)
|
||||
case "perNSecond":
|
||||
return fmt.Sprintf("@every %vs", cronjob.Second)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
)
|
||||
|
||||
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) error {
|
||||
var apps []model.AppInstall
|
||||
if cronjob.AppID == "all" {
|
||||
apps, _ = appInstallRepo.ListBy()
|
||||
} else {
|
||||
itemID, _ := (strconv.Atoi(cronjob.AppID))
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apps = append(apps, app)
|
||||
}
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, app := range apps {
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
record.Type = "app"
|
||||
record.CronjobID = cronjob.ID
|
||||
record.Name = app.App.Key
|
||||
record.DetailName = app.Name
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
||||
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err := handleAppBackup(&app, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
u.removeExpiredBackup(cronjob, accountMap, record)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Time) error {
|
||||
webs := loadWebsForJob(cronjob)
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, web := range webs {
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
record.Type = "website"
|
||||
record.CronjobID = cronjob.ID
|
||||
record.Name = web.PrimaryDomain
|
||||
record.DetailName = web.Alias
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain))
|
||||
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err := handleWebsiteBackup(&web, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
u.removeExpiredBackup(cronjob, accountMap, record)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Time) error {
|
||||
dbs := loadDbsForJob(cronjob)
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, dbInfo := range dbs {
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
record.Type = dbInfo.DBType
|
||||
record.CronjobID = cronjob.ID
|
||||
record.Name = dbInfo.Database
|
||||
record.DetailName = dbInfo.Name
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name))
|
||||
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
if err := handleMysqlBackup(dbInfo.Database, dbInfo.DBType, dbInfo.Name, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := handlePostgresqlBackup(dbInfo.Database, dbInfo.Name, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
u.removeExpiredBackup(cronjob, accountMap, record)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.Time) error {
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileName := fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name))
|
||||
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil {
|
||||
return err
|
||||
}
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
record.Type = "directory"
|
||||
record.CronjobID = cronjob.ID
|
||||
record.Name = cronjob.Name
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, fileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
record.FileName = fileName
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
u.removeExpiredBackup(cronjob, accountMap, record)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.Time) error {
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nameItem := startTime.Format("20060102150405") + common.RandStrAndNum(5)
|
||||
fileName := fmt.Sprintf("system_log_%s.tar.gz", nameItem)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, "log", nameItem)
|
||||
if err := handleBackupLogs(backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
record.Type = "log"
|
||||
record.CronjobID = cronjob.ID
|
||||
record.Name = cronjob.Name
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(path.Dir(backupDir), fileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
record.FileName = fileName
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
u.removeExpiredBackup(cronjob, accountMap, record)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Time, logPath string) error {
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
record.Type = "directory"
|
||||
record.CronjobID = cronjob.ID
|
||||
record.Name = cronjob.Name
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
record.FileDir = "system_snapshot"
|
||||
|
||||
req := dto.SnapshotCreate{
|
||||
From: record.BackupType,
|
||||
DefaultDownload: cronjob.DefaultDownload,
|
||||
}
|
||||
name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record.FileName = name + ".tar.gz"
|
||||
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
u.removeExpiredBackup(cronjob, accountMap, record)
|
||||
return nil
|
||||
}
|
||||
|
||||
type databaseHelper struct {
|
||||
DBType string
|
||||
Database string
|
||||
Name string
|
||||
}
|
||||
|
||||
func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
|
||||
var dbs []databaseHelper
|
||||
if cronjob.DBName == "all" {
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
mysqlItems, _ := mysqlRepo.List()
|
||||
for _, mysql := range mysqlItems {
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysql.MysqlName,
|
||||
Name: mysql.Name,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
pgItems, _ := postgresqlRepo.List()
|
||||
for _, pg := range pgItems {
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: pg.PostgresqlName,
|
||||
Name: pg.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
return dbs
|
||||
}
|
||||
itemID, _ := (strconv.Atoi(cronjob.DBName))
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID)))
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysqlItem.MysqlName,
|
||||
Name: mysqlItem.Name,
|
||||
})
|
||||
} else {
|
||||
pgItem, _ := postgresqlRepo.Get(commonRepo.WithByID(uint(itemID)))
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: pgItem.PostgresqlName,
|
||||
Name: pgItem.Name,
|
||||
})
|
||||
}
|
||||
return dbs
|
||||
}
|
||||
|
||||
func loadWebsForJob(cronjob model.Cronjob) []model.Website {
|
||||
var weblist []model.Website
|
||||
if cronjob.Website == "all" {
|
||||
weblist, _ = websiteRepo.List()
|
||||
return weblist
|
||||
}
|
||||
itemID, _ := (strconv.Atoi(cronjob.Website))
|
||||
webItem, _ := websiteRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
|
||||
if webItem.ID != 0 {
|
||||
weblist = append(weblist, webItem)
|
||||
}
|
||||
return weblist
|
||||
}
|
||||
|
||||
func loadRecordPath(cronjob model.Cronjob, accountMap map[string]cronjobUploadHelper) (string, string) {
|
||||
source := accountMap[fmt.Sprintf("%v", cronjob.DefaultDownload)].backType
|
||||
targets := strings.Split(cronjob.BackupAccounts, ",")
|
||||
var itemAccounts []string
|
||||
for _, target := range targets {
|
||||
if len(target) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(accountMap[target].backType) != 0 {
|
||||
itemAccounts = append(itemAccounts, accountMap[target].backType)
|
||||
}
|
||||
}
|
||||
backupType := strings.Join(itemAccounts, ",")
|
||||
return source, backupType
|
||||
}
|
||||
|
||||
func handleBackupLogs(targetDir, fileName string) error {
|
||||
websites, err := websiteRepo.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(websites) != 0 {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
webItem := path.Join(nginxInstall.GetPath(), "www/sites")
|
||||
for _, website := range websites {
|
||||
dirItem := path.Join(targetDir, "website", website.Alias)
|
||||
if _, err := os.Stat(dirItem); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dirItem, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
itemDir := path.Join(webItem, website.Alias, "log")
|
||||
logFiles, _ := os.ReadDir(itemDir)
|
||||
if len(logFiles) != 0 {
|
||||
for i := 0; i < len(logFiles); i++ {
|
||||
if !logFiles[i].IsDir() {
|
||||
_ = cpBinary([]string{path.Join(itemDir, logFiles[i].Name())}, dirItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
itemDir2 := path.Join(global.CONF.System.Backup, "log/website", website.Alias)
|
||||
logFiles2, _ := os.ReadDir(itemDir2)
|
||||
if len(logFiles2) != 0 {
|
||||
for i := 0; i < len(logFiles2); i++ {
|
||||
if !logFiles2[i].IsDir() {
|
||||
_ = cpBinary([]string{path.Join(itemDir2, logFiles2[i].Name())}, dirItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Debug("backup website log successful!")
|
||||
}
|
||||
|
||||
systemLogDir := path.Join(global.CONF.System.BaseDir, "1panel/log")
|
||||
systemDir := path.Join(targetDir, "system")
|
||||
if _, err := os.Stat(systemDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(systemDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
systemLogFiles, _ := os.ReadDir(systemLogDir)
|
||||
if len(systemLogFiles) != 0 {
|
||||
for i := 0; i < len(systemLogFiles); i++ {
|
||||
if !systemLogFiles[i].IsDir() {
|
||||
_ = cpBinary([]string{path.Join(systemLogDir, systemLogFiles[i].Name())}, systemDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Debug("backup system log successful!")
|
||||
|
||||
loginLogFiles, _ := os.ReadDir("/var/log")
|
||||
loginDir := path.Join(targetDir, "login")
|
||||
if _, err := os.Stat(loginDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(loginDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(loginLogFiles) != 0 {
|
||||
for i := 0; i < len(loginLogFiles); i++ {
|
||||
if !loginLogFiles[i].IsDir() && (strings.HasPrefix(loginLogFiles[i].Name(), "secure") || strings.HasPrefix(loginLogFiles[i].Name(), "auth.log")) {
|
||||
_ = cpBinary([]string{path.Join("/var/log", loginLogFiles[i].Name())}, loginDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Debug("backup ssh log successful!")
|
||||
|
||||
if err := handleTar(targetDir, path.Dir(targetDir), fileName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(targetDir)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
@@ -5,14 +5,13 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"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/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||
@@ -34,58 +33,48 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
if len(cronjob.Script) == 0 {
|
||||
return
|
||||
}
|
||||
record.Records = u.generateLogsPath(*cronjob, record.StartTime)
|
||||
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
|
||||
script := cronjob.Script
|
||||
if len(cronjob.ContainerName) != 0 {
|
||||
script = fmt.Sprintf("docker exec %s %s", cronjob.ContainerName, cronjob.Script)
|
||||
message, err = u.handleShell(cronjob.Type, cronjob.Name, fmt.Sprintf("docker exec %s %s", cronjob.ContainerName, cronjob.Script))
|
||||
} else {
|
||||
message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script)
|
||||
}
|
||||
err = u.handleShell(cronjob.Type, cronjob.Name, script, record.Records)
|
||||
u.removeExpiredLog(*cronjob)
|
||||
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
||||
case "snapshot":
|
||||
messageItem := ""
|
||||
messageItem, record.File, err = u.handleSnapshot(cronjob, record.StartTime)
|
||||
message = []byte(messageItem)
|
||||
case "curl":
|
||||
if len(cronjob.URL) == 0 {
|
||||
return
|
||||
}
|
||||
record.Records = u.generateLogsPath(*cronjob, record.StartTime)
|
||||
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
|
||||
err = u.handleShell(cronjob.Type, cronjob.Name, fmt.Sprintf("curl '%s'", cronjob.URL), record.Records)
|
||||
u.removeExpiredLog(*cronjob)
|
||||
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.removeExpiredLog(*cronjob)
|
||||
case "cutWebsiteLog":
|
||||
var messageItem []string
|
||||
messageItem, record.File, err = u.handleCutWebsiteLog(cronjob, record.StartTime)
|
||||
message = []byte(strings.Join(messageItem, "\n"))
|
||||
case "clean":
|
||||
messageItem := ""
|
||||
messageItem, err = u.handleSystemClean()
|
||||
message = []byte(messageItem)
|
||||
u.removeExpiredLog(*cronjob)
|
||||
case "website":
|
||||
err = u.handleWebsite(*cronjob, record.StartTime)
|
||||
case "app":
|
||||
err = u.handleApp(*cronjob, record.StartTime)
|
||||
case "database":
|
||||
err = u.handleDatabase(*cronjob, record.StartTime)
|
||||
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
||||
case "website", "database", "app":
|
||||
record.File, err = u.handleBackup(cronjob, record.StartTime)
|
||||
case "directory":
|
||||
if len(cronjob.SourceDir) == 0 {
|
||||
return
|
||||
}
|
||||
err = u.handleDirectory(*cronjob, record.StartTime)
|
||||
record.File, err = u.handleBackup(cronjob, record.StartTime)
|
||||
case "cutWebsiteLog":
|
||||
record.File, err = u.handleCutWebsiteLog(cronjob, record.StartTime)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("cut website log file failed, err: %v", err)
|
||||
}
|
||||
case "clean":
|
||||
messageItem := ""
|
||||
messageItem, err = u.handleSystemClean()
|
||||
message = []byte(messageItem)
|
||||
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
||||
case "log":
|
||||
err = u.handleSystemLog(*cronjob, record.StartTime)
|
||||
case "snapshot":
|
||||
record.Records = u.generateLogsPath(*cronjob, record.StartTime)
|
||||
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
|
||||
err = u.handleSnapshot(*cronjob, record.StartTime, record.Records)
|
||||
record.File, err = u.handleSystemLog(*cronjob, record.StartTime)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if len(message) != 0 {
|
||||
record.Records, _ = mkdirAndWriteFile(cronjob, record.StartTime, message)
|
||||
}
|
||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), record.Records)
|
||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
||||
return
|
||||
}
|
||||
if len(message) != 0 {
|
||||
@@ -98,17 +87,18 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
}()
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleShell(cronType, cornName, script, logPath string) error {
|
||||
func (u *CronjobService) handleShell(cronType, cornName, script string) ([]byte, 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 err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := cmd.ExecCronjobWithTimeOut(script, handleDir, logPath, 24*time.Hour); err != nil {
|
||||
return err
|
||||
stdout, err := cmd.ExecCronjobWithTimeOut(script, handleDir, 24*time.Hour)
|
||||
if err != nil {
|
||||
return []byte(stdout), err
|
||||
}
|
||||
return nil
|
||||
return []byte(stdout), nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleNtpSync() error {
|
||||
@@ -126,6 +116,102 @@ func (u *CronjobService) handleNtpSync() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
|
||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
global.LOG.Infof("start to backup %s %s to %s", cronjob.Type, cronjob.Name, backup.Type)
|
||||
|
||||
switch cronjob.Type {
|
||||
case "database":
|
||||
paths, err := u.handleDatabase(*cronjob, backup, startTime)
|
||||
return strings.Join(paths, ","), err
|
||||
case "app":
|
||||
paths, err := u.handleApp(*cronjob, backup, startTime)
|
||||
return strings.Join(paths, ","), err
|
||||
case "website":
|
||||
paths, err := u.handleWebsite(*cronjob, backup, startTime)
|
||||
return strings.Join(paths, ","), err
|
||||
default:
|
||||
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))
|
||||
itemFileDir := fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name)
|
||||
global.LOG.Infof("handle tar %s to %s", backupDir, fileName)
|
||||
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil {
|
||||
return "", err
|
||||
}
|
||||
var client cloud_storage.CloudStorageClient
|
||||
if backup.Type != "LOCAL" {
|
||||
if !cronjob.KeepLocal {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, fileName))
|
||||
}()
|
||||
}
|
||||
client, err = NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
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 {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, cronjob, client)
|
||||
if backup.Type == "LOCAL" || cronjob.KeepLocal {
|
||||
return fmt.Sprintf("%s/%s", backupDir, fileName), nil
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", itemFileDir, fileName), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (u *CronjobService) HandleRmExpired(backType, backupPath, localDir string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) {
|
||||
global.LOG.Infof("start to handle remove expired, retain copies: %d", cronjob.RetainCopies)
|
||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), commonRepo.WithOrderBy("created_at desc"))
|
||||
if len(records) <= int(cronjob.RetainCopies) {
|
||||
return
|
||||
}
|
||||
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
||||
if len(records[i].File) != 0 {
|
||||
files := strings.Split(records[i].File, ",")
|
||||
for _, file := range files {
|
||||
_ = os.Remove(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+"/")
|
||||
}
|
||||
}
|
||||
|
||||
if cronjob.Type == "snapshot" {
|
||||
_ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(path.Base(fileItem), ".tar.gz")))
|
||||
}
|
||||
_, _ = backClient.Delete(fileItem)
|
||||
}
|
||||
}
|
||||
_ = cronjobRepo.DeleteRecord(commonRepo.WithByID(uint(records[i].ID)))
|
||||
_ = os.Remove(records[i].Records)
|
||||
}
|
||||
}
|
||||
|
||||
func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
|
||||
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
|
||||
@@ -183,190 +269,439 @@ func handleUnTar(sourceFile, targetDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time) ([]string, string, error) {
|
||||
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
|
||||
var paths []string
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
|
||||
var dbs []model.DatabaseMysql
|
||||
if cronjob.DBName == "all" {
|
||||
dbs, err = mysqlRepo.List()
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
} else {
|
||||
itemID, _ := (strconv.Atoi(cronjob.DBName))
|
||||
dbs, err = mysqlRepo.List(commonRepo.WithByID(uint(itemID)))
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
}
|
||||
|
||||
var client cloud_storage.CloudStorageClient
|
||||
if backup.Type != "LOCAL" {
|
||||
client, err = NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dbInfo := range dbs {
|
||||
var record model.BackupRecord
|
||||
|
||||
database, _ := databaseRepo.Get(commonRepo.WithByName(dbInfo.MysqlName))
|
||||
record.Type = database.Type
|
||||
record.Source = "LOCAL"
|
||||
record.BackupType = backup.Type
|
||||
|
||||
record.Name = dbInfo.MysqlName
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", database.Type, record.Name, dbInfo.Name))
|
||||
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405"))
|
||||
if err = handleMysqlBackup(dbInfo.MysqlName, dbInfo.Name, backupDir, record.FileName); err != nil {
|
||||
return paths, err
|
||||
}
|
||||
|
||||
record.DetailName = dbInfo.Name
|
||||
record.FileDir = backupDir
|
||||
itemFileDir := strings.TrimPrefix(backupDir, localDir+"/")
|
||||
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||
record.Source = backup.Type
|
||||
record.FileDir = itemFileDir
|
||||
}
|
||||
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return paths, err
|
||||
}
|
||||
if backup.Type != "LOCAL" {
|
||||
if !cronjob.KeepLocal {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
|
||||
}()
|
||||
}
|
||||
if 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 {
|
||||
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)
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time) (string, error) {
|
||||
var (
|
||||
websites []string
|
||||
err error
|
||||
filePaths []string
|
||||
msgs []string
|
||||
)
|
||||
websites := loadWebsForJob(*cronjob)
|
||||
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 msgs, "", nil
|
||||
return "", nil
|
||||
}
|
||||
baseDir := path.Join(nginx.GetPath(), "www", "sites")
|
||||
fileOp := files.NewFileOp()
|
||||
for _, website := range websites {
|
||||
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)
|
||||
}
|
||||
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"))
|
||||
dstFilePath := path.Join(dstLogDir, dstName)
|
||||
filePaths = append(filePaths, dstFilePath)
|
||||
|
||||
if err = backupLogFile(dstFilePath, websiteLogDir, fileOp); err != nil {
|
||||
websiteErr := buserr.WithNameAndErr("ErrCutWebsiteLog", website.PrimaryDomain, err)
|
||||
err = websiteErr
|
||||
msgs = append(msgs, websiteErr.Error())
|
||||
global.LOG.Error(websiteErr.Error())
|
||||
continue
|
||||
} else {
|
||||
_ = fileOp.WriteFile(srcAccessLogPath, strings.NewReader(""), 0755)
|
||||
_ = fileOp.WriteFile(srcErrorLogPath, strings.NewReader(""), 0755)
|
||||
}
|
||||
msg := i18n.GetMsgWithMap("CutWebsiteLogSuccess", map[string]interface{}{"name": website.PrimaryDomain, "path": dstFilePath})
|
||||
global.LOG.Infof(msg)
|
||||
msgs = append(msgs, msg)
|
||||
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()
|
||||
}()
|
||||
}
|
||||
u.removeExpiredLog(*cronjob)
|
||||
return msgs, strings.Join(filePaths, ","), err
|
||||
wg.Wait()
|
||||
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
||||
return strings.Join(filePaths, ","), nil
|
||||
}
|
||||
|
||||
func backupLogFile(dstFilePath, websiteLogDir string, fileOp files.FileOp) error {
|
||||
if err := cmd.ExecCmd(fmt.Sprintf("tar -czf %s -C %s %s", dstFilePath, websiteLogDir, strings.Join([]string{"access.log", "error.log"}, " "))); err != nil {
|
||||
dstDir := path.Dir(dstFilePath)
|
||||
if err = fileOp.Copy(path.Join(websiteLogDir, "access.log"), dstDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = fileOp.Copy(path.Join(websiteLogDir, "error.log"), dstDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = cmd.ExecCmd(fmt.Sprintf("tar -czf %s -C %s %s", dstFilePath, dstDir, strings.Join([]string{"access.log", "error.log"}, " "))); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = fileOp.DeleteFile(path.Join(dstDir, "access.log"))
|
||||
_ = fileOp.DeleteFile(path.Join(dstDir, "error.log"))
|
||||
return nil
|
||||
func (u *CronjobService) handleApp(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
|
||||
var paths []string
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
return nil
|
||||
|
||||
var applist []model.AppInstall
|
||||
if cronjob.AppID == "all" {
|
||||
applist, err = appInstallRepo.ListBy()
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
} else {
|
||||
itemID, _ := (strconv.Atoi(cronjob.AppID))
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
applist = append(applist, app)
|
||||
}
|
||||
|
||||
var client cloud_storage.CloudStorageClient
|
||||
if backup.Type != "LOCAL" {
|
||||
client, err = NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, app := range applist {
|
||||
var record model.BackupRecord
|
||||
record.Type = "app"
|
||||
record.Name = app.App.Key
|
||||
record.DetailName = app.Name
|
||||
record.Source = "LOCAL"
|
||||
record.BackupType = backup.Type
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
||||
record.FileDir = backupDir
|
||||
itemFileDir := strings.TrimPrefix(backupDir, localDir+"/")
|
||||
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||
record.Source = backup.Type
|
||||
record.FileDir = strings.TrimPrefix(backupDir, localDir+"/")
|
||||
}
|
||||
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405"))
|
||||
if err := handleAppBackup(&app, backupDir, record.FileName); err != nil {
|
||||
return paths, err
|
||||
}
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return paths, err
|
||||
}
|
||||
if backup.Type != "LOCAL" {
|
||||
if !cronjob.KeepLocal {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
|
||||
}()
|
||||
}
|
||||
if 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 {
|
||||
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)
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
|
||||
var paths []string
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
|
||||
var weblist []string
|
||||
if cronjob.Website == "all" {
|
||||
weblist, err = NewIWebsiteService().GetWebsiteOptions()
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
} else {
|
||||
weblist = append(weblist, cronjob.Website)
|
||||
}
|
||||
|
||||
var client cloud_storage.CloudStorageClient
|
||||
if backup.Type != "LOCAL" {
|
||||
client, err = NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, websiteItem := range weblist {
|
||||
var record model.BackupRecord
|
||||
record.Type = "website"
|
||||
record.Name = cronjob.Website
|
||||
record.Source = "LOCAL"
|
||||
record.BackupType = backup.Type
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(websiteItem))
|
||||
if err != nil {
|
||||
return paths, err
|
||||
}
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("website/%s", website.PrimaryDomain))
|
||||
record.FileDir = backupDir
|
||||
itemFileDir := strings.TrimPrefix(backupDir, localDir+"/")
|
||||
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||
record.Source = backup.Type
|
||||
record.FileDir = strings.TrimPrefix(backupDir, localDir+"/")
|
||||
}
|
||||
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", website.PrimaryDomain, startTime.Format("20060102150405"))
|
||||
if err := handleWebsiteBackup(&website, backupDir, record.FileName); err != nil {
|
||||
return paths, err
|
||||
}
|
||||
record.Name = website.PrimaryDomain
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return paths, err
|
||||
}
|
||||
if backup.Type != "LOCAL" {
|
||||
if !cronjob.KeepLocal {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
|
||||
}()
|
||||
}
|
||||
if 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 {
|
||||
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)
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleSnapshot(cronjob *model.Cronjob, startTime time.Time) (string, string, error) {
|
||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
client, err := NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
req := dto.SnapshotCreate{
|
||||
From: backup.Type,
|
||||
}
|
||||
message, name, err := NewISnapshotService().HandleSnapshot(true, req, startTime.Format("20060102150405"))
|
||||
if err != nil {
|
||||
return message, "", err
|
||||
}
|
||||
|
||||
path := path.Join(strings.TrimPrefix(backup.BackupPath, "/"), "system_snapshot", name+".tar.gz")
|
||||
|
||||
u.HandleRmExpired(backup.Type, backup.BackupPath, "", cronjob, client)
|
||||
return message, path, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleSystemClean() (string, error) {
|
||||
return NewIDeviceService().CleanForCronjob()
|
||||
return NewISettingService().SystemCleanForCronjob()
|
||||
}
|
||||
|
||||
func loadClientMap(backupAccounts string) (map[string]cronjobUploadHelper, error) {
|
||||
clients := make(map[string]cronjobUploadHelper)
|
||||
accounts, err := backupRepo.List()
|
||||
func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.Time) (string, error) {
|
||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
targets := strings.Split(backupAccounts, ",")
|
||||
for _, target := range targets {
|
||||
if len(target) == 0 {
|
||||
continue
|
||||
|
||||
pathItem := path.Join(global.CONF.System.BaseDir, "1panel/tmp/log", startTime.Format("20060102150405"))
|
||||
websites, err := websiteRepo.List()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(websites) != 0 {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, account := range accounts {
|
||||
if target == account.Type {
|
||||
client, err := NewIBackupService().NewClient(&account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
webItem := path.Join(nginxInstall.GetPath(), "www/sites")
|
||||
for _, website := range websites {
|
||||
dirItem := path.Join(pathItem, "website", website.Alias)
|
||||
if _, err := os.Stat(dirItem); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dirItem, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
pathItem := account.BackupPath
|
||||
if account.BackupPath != "/" {
|
||||
pathItem = strings.TrimPrefix(account.BackupPath, "/")
|
||||
}
|
||||
itemDir := path.Join(webItem, website.Alias, "log")
|
||||
logFiles, _ := os.ReadDir(itemDir)
|
||||
if len(logFiles) != 0 {
|
||||
for i := 0; i < len(logFiles); i++ {
|
||||
if !logFiles[i].IsDir() {
|
||||
_ = cpBinary([]string{path.Join(itemDir, logFiles[i].Name())}, dirItem)
|
||||
}
|
||||
}
|
||||
clients[target] = cronjobUploadHelper{
|
||||
client: client,
|
||||
backupPath: pathItem,
|
||||
backType: account.Type,
|
||||
}
|
||||
itemDir2 := path.Join(global.CONF.System.Backup, "log/website", website.Alias)
|
||||
logFiles2, _ := os.ReadDir(itemDir2)
|
||||
if len(logFiles2) != 0 {
|
||||
for i := 0; i < len(logFiles2); i++ {
|
||||
if !logFiles2[i].IsDir() {
|
||||
_ = cpBinary([]string{path.Join(itemDir2, logFiles2[i].Name())}, dirItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Debug("backup website log successful!")
|
||||
}
|
||||
return clients, nil
|
||||
}
|
||||
|
||||
type cronjobUploadHelper struct {
|
||||
backupPath string
|
||||
backType string
|
||||
client cloud_storage.CloudStorageClient
|
||||
}
|
||||
systemLogDir := path.Join(global.CONF.System.BaseDir, "1panel/log")
|
||||
systemDir := path.Join(pathItem, "system")
|
||||
if _, err := os.Stat(systemDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(systemDir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
systemLogFiles, _ := os.ReadDir(systemLogDir)
|
||||
if len(systemLogFiles) != 0 {
|
||||
for i := 0; i < len(systemLogFiles); i++ {
|
||||
if !systemLogFiles[i].IsDir() {
|
||||
_ = cpBinary([]string{path.Join(systemLogDir, systemLogFiles[i].Name())}, systemDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Debug("backup system log successful!")
|
||||
|
||||
func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, accountMap map[string]cronjobUploadHelper, file string) (string, error) {
|
||||
loginLogFiles, _ := os.ReadDir("/var/log")
|
||||
loginDir := path.Join(pathItem, "login")
|
||||
if _, err := os.Stat(loginDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(loginDir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if len(loginLogFiles) != 0 {
|
||||
for i := 0; i < len(loginLogFiles); i++ {
|
||||
if !loginLogFiles[i].IsDir() && (strings.HasPrefix(loginLogFiles[i].Name(), "secure") || strings.HasPrefix(loginLogFiles[i].Name(), "auth.log")) {
|
||||
_ = cpBinary([]string{path.Join("/var/log", loginLogFiles[i].Name())}, loginDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Debug("backup ssh log successful!")
|
||||
|
||||
fileName := fmt.Sprintf("system_log_%s.tar.gz", startTime.Format("20060102150405"))
|
||||
targetDir := path.Dir(pathItem)
|
||||
if err := handleTar(pathItem, targetDir, fileName, ""); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() {
|
||||
_ = os.Remove(file)
|
||||
os.RemoveAll(pathItem)
|
||||
os.RemoveAll(path.Join(targetDir, fileName))
|
||||
}()
|
||||
accounts := strings.Split(cronjob.BackupAccounts, ",")
|
||||
cloudSrc := strings.TrimPrefix(file, global.CONF.System.TmpDir+"/")
|
||||
for _, account := range accounts {
|
||||
if len(account) != 0 {
|
||||
global.LOG.Debugf("start upload file to %s, dir: %s", account, path.Join(accountMap[account].backupPath, cloudSrc))
|
||||
if _, err := accountMap[account].client.Upload(file, path.Join(accountMap[account].backupPath, cloudSrc)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
global.LOG.Debugf("upload successful!")
|
||||
}
|
||||
}
|
||||
return cloudSrc, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap map[string]cronjobUploadHelper, record model.BackupRecord) {
|
||||
global.LOG.Infof("start to handle remove expired, retain copies: %d", cronjob.RetainCopies)
|
||||
var opts []repo.DBOption
|
||||
opts = append(opts, commonRepo.WithByFrom("cronjob"))
|
||||
opts = append(opts, backupRepo.WithByCronID(cronjob.ID))
|
||||
opts = append(opts, commonRepo.WithOrderBy("created_at desc"))
|
||||
if record.ID != 0 {
|
||||
opts = append(opts, backupRepo.WithByType(record.Type))
|
||||
opts = append(opts, commonRepo.WithByName(record.Name))
|
||||
opts = append(opts, backupRepo.WithByDetailName(record.DetailName))
|
||||
}
|
||||
records, _ := backupRepo.ListRecord(opts...)
|
||||
if len(records) <= int(cronjob.RetainCopies) {
|
||||
return
|
||||
}
|
||||
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
||||
accounts := strings.Split(cronjob.BackupAccounts, ",")
|
||||
if cronjob.Type == "snapshot" {
|
||||
for _, account := range accounts {
|
||||
if len(account) != 0 {
|
||||
_, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, "system_snapshot", records[i].FileName))
|
||||
}
|
||||
}
|
||||
_ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(records[i].FileName, ".tar.gz")))
|
||||
} else {
|
||||
for _, account := range accounts {
|
||||
if len(account) != 0 {
|
||||
_, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, records[i].FileDir, records[i].FileName))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = backupRepo.DeleteRecord(context.Background(), commonRepo.WithByID(records[i].ID))
|
||||
}
|
||||
}
|
||||
|
||||
func (u *CronjobService) removeExpiredLog(cronjob model.Cronjob) {
|
||||
global.LOG.Infof("start to handle remove expired, retain copies: %d", cronjob.RetainCopies)
|
||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), commonRepo.WithOrderBy("created_at desc"))
|
||||
if len(records) <= int(cronjob.RetainCopies) {
|
||||
return
|
||||
}
|
||||
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
||||
if len(records[i].File) != 0 {
|
||||
files := strings.Split(records[i].File, ",")
|
||||
for _, file := range files {
|
||||
_ = os.Remove(file)
|
||||
}
|
||||
}
|
||||
_ = cronjobRepo.DeleteRecord(commonRepo.WithByID(uint(records[i].ID)))
|
||||
_ = os.Remove(records[i].Records)
|
||||
}
|
||||
}
|
||||
|
||||
func (u *CronjobService) generateLogsPath(cronjob model.Cronjob, startTime time.Time) string {
|
||||
dir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronjob.Type, cronjob.Name)
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
_ = os.MkdirAll(dir, os.ModePerm)
|
||||
client, err := NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format("20060102150405"))
|
||||
return path
|
||||
targetPath := "log/" + fileName
|
||||
if len(backup.BackupPath) != 0 {
|
||||
targetPath = strings.TrimPrefix(backup.BackupPath, "/") + "/log/" + fileName
|
||||
}
|
||||
|
||||
if _, err = client.Upload(path.Join(targetDir, fileName), targetPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
u.HandleRmExpired(backup.Type, backup.BackupPath, "", &cronjob, client)
|
||||
return targetPath, nil
|
||||
}
|
||||
|
||||
func hasBackup(cronjobType string) bool {
|
||||
|
||||
@@ -3,9 +3,7 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -22,7 +20,6 @@ import (
|
||||
type DashboardService struct{}
|
||||
|
||||
type IDashboardService interface {
|
||||
LoadOsInfo() (*dto.OsInfo, error)
|
||||
LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error)
|
||||
LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent
|
||||
|
||||
@@ -50,27 +47,6 @@ func (u *DashboardService) Restart(operation string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
|
||||
var baseInfo dto.OsInfo
|
||||
hostInfo, err := host.Info()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
baseInfo.OS = hostInfo.OS
|
||||
baseInfo.Platform = hostInfo.Platform
|
||||
baseInfo.PlatformFamily = hostInfo.PlatformFamily
|
||||
baseInfo.KernelArch = hostInfo.KernelArch
|
||||
baseInfo.KernelVersion = hostInfo.KernelVersion
|
||||
|
||||
if baseInfo.KernelArch == "armv7l" {
|
||||
baseInfo.KernelArch = "armv7"
|
||||
}
|
||||
if baseInfo.KernelArch == "x86_64" {
|
||||
baseInfo.KernelArch = "amd64"
|
||||
}
|
||||
return &baseInfo, nil
|
||||
}
|
||||
|
||||
func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error) {
|
||||
var baseInfo dto.DashboardBase
|
||||
hostInfo, err := host.Info()
|
||||
@@ -147,12 +123,6 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
currentInfo.MemoryUsed = memoryInfo.Used
|
||||
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
||||
|
||||
swapInfo, _ := mem.SwapMemory()
|
||||
currentInfo.SwapMemoryTotal = swapInfo.Total
|
||||
currentInfo.SwapMemoryAvailable = swapInfo.Free
|
||||
currentInfo.SwapMemoryUsed = swapInfo.Used
|
||||
currentInfo.SwapMemoryUsedPercent = swapInfo.UsedPercent
|
||||
|
||||
currentInfo.DiskData = loadDiskInfo()
|
||||
|
||||
if ioOption == "all" {
|
||||
@@ -203,12 +173,9 @@ type diskInfo struct {
|
||||
|
||||
func loadDiskInfo() []dto.DiskInfo {
|
||||
var datas []dto.DiskInfo
|
||||
stdout, err := cmd.ExecWithTimeOut("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev", 2*time.Second)
|
||||
stdout, err := cmd.Exec("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")
|
||||
if err != nil {
|
||||
stdout, err = cmd.ExecWithTimeOut("df -lhT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev", 1*time.Second)
|
||||
if err != nil {
|
||||
return datas
|
||||
}
|
||||
return datas
|
||||
}
|
||||
lines := strings.Split(stdout, "\n")
|
||||
|
||||
@@ -240,52 +207,24 @@ func loadDiskInfo() []dto.DiskInfo {
|
||||
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: fields[6]})
|
||||
}
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
mu sync.Mutex
|
||||
)
|
||||
wg.Add(len(mounts))
|
||||
for i := 0; i < len(mounts); i++ {
|
||||
go func(timeoutCh <-chan time.Time, mount diskInfo) {
|
||||
defer wg.Done()
|
||||
|
||||
var itemData dto.DiskInfo
|
||||
itemData.Path = mount.Mount
|
||||
itemData.Type = mount.Type
|
||||
itemData.Device = mount.Device
|
||||
select {
|
||||
case <-timeoutCh:
|
||||
mu.Lock()
|
||||
datas = append(datas, itemData)
|
||||
mu.Unlock()
|
||||
global.LOG.Errorf("load disk info from %s failed, err: timeout", mount.Mount)
|
||||
default:
|
||||
state, err := disk.Usage(mount.Mount)
|
||||
if err != nil {
|
||||
mu.Lock()
|
||||
datas = append(datas, itemData)
|
||||
mu.Unlock()
|
||||
global.LOG.Errorf("load disk info from %s failed, err: %v", mount.Mount, err)
|
||||
return
|
||||
}
|
||||
itemData.Total = state.Total
|
||||
itemData.Free = state.Free
|
||||
itemData.Used = state.Used
|
||||
itemData.UsedPercent = state.UsedPercent
|
||||
itemData.InodesTotal = state.InodesTotal
|
||||
itemData.InodesUsed = state.InodesUsed
|
||||
itemData.InodesFree = state.InodesFree
|
||||
itemData.InodesUsedPercent = state.InodesUsedPercent
|
||||
mu.Lock()
|
||||
datas = append(datas, itemData)
|
||||
mu.Unlock()
|
||||
}
|
||||
}(time.After(5*time.Second), mounts[i])
|
||||
state, err := disk.Usage(mounts[i].Mount)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var itemData dto.DiskInfo
|
||||
itemData.Path = mounts[i].Mount
|
||||
itemData.Type = mounts[i].Type
|
||||
itemData.Device = mounts[i].Device
|
||||
itemData.Total = state.Total
|
||||
itemData.Free = state.Free
|
||||
itemData.Used = state.Used
|
||||
itemData.UsedPercent = state.UsedPercent
|
||||
itemData.InodesTotal = state.InodesTotal
|
||||
itemData.InodesUsed = state.InodesUsed
|
||||
itemData.InodesFree = state.InodesFree
|
||||
itemData.InodesUsedPercent = state.InodesUsedPercent
|
||||
datas = append(datas, itemData)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
sort.Slice(datas, func(i, j int) bool {
|
||||
return datas[i].Path < datas[j].Path
|
||||
})
|
||||
return datas
|
||||
}
|
||||
|
||||
+30
-138
@@ -6,9 +6,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql"
|
||||
client2 "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -31,7 +28,6 @@ type IDatabaseService interface {
|
||||
DeleteCheck(id uint) ([]string, error)
|
||||
Delete(req dto.DatabaseDelete) error
|
||||
List(dbType string) ([]dto.DatabaseOption, error)
|
||||
LoadItems(dbType string) ([]dto.DatabaseItem, error)
|
||||
}
|
||||
|
||||
func NewIDatabaseService() IDatabaseService {
|
||||
@@ -81,66 +77,18 @@ func (u *DatabaseService) List(dbType string) ([]dto.DatabaseOption, error) {
|
||||
return datas, err
|
||||
}
|
||||
|
||||
func (u *DatabaseService) LoadItems(dbType string) ([]dto.DatabaseItem, error) {
|
||||
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
|
||||
var datas []dto.DatabaseItem
|
||||
for _, db := range dbs {
|
||||
if dbType == "postgresql" {
|
||||
items, _ := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(db.Name))
|
||||
for _, item := range items {
|
||||
var dItem dto.DatabaseItem
|
||||
if err := copier.Copy(&dItem, &item); err != nil {
|
||||
continue
|
||||
}
|
||||
dItem.Database = db.Name
|
||||
datas = append(datas, dItem)
|
||||
}
|
||||
} else {
|
||||
items, _ := mysqlRepo.List(mysqlRepo.WithByMysqlName(db.Name))
|
||||
for _, item := range items {
|
||||
var dItem dto.DatabaseItem
|
||||
if err := copier.Copy(&dItem, &item); err != nil {
|
||||
continue
|
||||
}
|
||||
dItem.Database = db.Name
|
||||
datas = append(datas, dItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
return datas, err
|
||||
}
|
||||
|
||||
func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
||||
switch req.Type {
|
||||
case constant.AppPostgresql:
|
||||
_, err := postgresql.NewPostgresqlClient(client2.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Timeout: 6,
|
||||
})
|
||||
return err == nil
|
||||
case "mysql", "mariadb":
|
||||
_, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
|
||||
SSL: req.SSL,
|
||||
RootCert: req.RootCert,
|
||||
ClientKey: req.ClientKey,
|
||||
ClientCert: req.ClientCert,
|
||||
SkipVerify: req.SkipVerify,
|
||||
Timeout: 6,
|
||||
})
|
||||
return err == nil
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Timeout: 6,
|
||||
}); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
||||
@@ -151,39 +99,16 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
||||
}
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
switch req.Type {
|
||||
case constant.AppPostgresql:
|
||||
if _, err := postgresql.NewPostgresqlClient(client2.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Timeout: 6,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
case "mysql", "mariadb":
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
|
||||
SSL: req.SSL,
|
||||
RootCert: req.RootCert,
|
||||
ClientKey: req.ClientKey,
|
||||
ClientCert: req.ClientCert,
|
||||
SkipVerify: req.SkipVerify,
|
||||
Timeout: 6,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("database type not supported")
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Timeout: 6,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := copier.Copy(&db, &req); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
@@ -233,51 +158,23 @@ func (u *DatabaseService) Delete(req dto.DatabaseDelete) error {
|
||||
return err
|
||||
}
|
||||
if db.From != "local" {
|
||||
if db.Type == "mysql" || db.Type == "mariadb" {
|
||||
if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByMysqlName(db.Name)); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := postgresqlRepo.Delete(context.Background(), postgresqlRepo.WithByPostgresqlName(db.Name)); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByMysqlName(db.Name)); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
||||
switch req.Type {
|
||||
case constant.AppPostgresql:
|
||||
if _, err := postgresql.NewPostgresqlClient(client2.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
case "mysql", "mariadb":
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
|
||||
SSL: req.SSL,
|
||||
RootCert: req.RootCert,
|
||||
ClientKey: req.ClientKey,
|
||||
ClientCert: req.ClientCert,
|
||||
SkipVerify: req.SkipVerify,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("database type not supported")
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pass, err := encrypt.StringEncrypt(req.Password)
|
||||
@@ -293,10 +190,5 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
||||
upMap["username"] = req.Username
|
||||
upMap["password"] = pass
|
||||
upMap["description"] = req.Description
|
||||
upMap["ssl"] = req.SSL
|
||||
upMap["client_key"] = req.ClientKey
|
||||
upMap["client_cert"] = req.ClientCert
|
||||
upMap["root_cert"] = req.RootCert
|
||||
upMap["skip_verify"] = req.SkipVerify
|
||||
return databaseRepo.Update(req.ID, upMap)
|
||||
}
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
)
|
||||
|
||||
type DBCommonService struct{}
|
||||
|
||||
type IDBCommonService interface {
|
||||
LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error)
|
||||
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
|
||||
|
||||
UpdateConfByFile(req dto.DBConfUpdateByFile) error
|
||||
}
|
||||
|
||||
func NewIDBCommonService() IDBCommonService {
|
||||
return &DBCommonService{}
|
||||
}
|
||||
|
||||
func (u *DBCommonService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
|
||||
var data dto.DBBaseInfo
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data.ContainerName = app.ContainerName
|
||||
data.Name = app.Name
|
||||
data.Port = int64(app.Port)
|
||||
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (u *DBCommonService) 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 "mariadb-conf":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/conf/my.cnf", req.Name))
|
||||
case "postgresql-conf":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
|
||||
case "redis-conf":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
|
||||
case "mysql-slow-logs":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
||||
case "mariadb-slow-logs":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/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 (u *DBCommonService) UpdateConfByFile(req dto.DBConfUpdateByFile) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := ""
|
||||
switch req.Type {
|
||||
case constant.AppMariaDB, constant.AppMysql:
|
||||
path = fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
|
||||
case constant.AppPostgresql:
|
||||
path = fmt.Sprintf("%s/%s/%s/data/postgresql.conf", constant.AppInstallDir, req.Type, app.Name)
|
||||
case constant.AppRedis:
|
||||
path = fmt.Sprintf("%s/%s/%s/conf/redis.conf", constant.AppInstallDir, req.Type, app.Name)
|
||||
}
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -34,18 +35,21 @@ type IMysqlService interface {
|
||||
SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error)
|
||||
ListDBOption() ([]dto.MysqlOption, error)
|
||||
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
|
||||
BindUser(req dto.BindUser) error
|
||||
LoadFromRemote(req dto.MysqlLoadDB) error
|
||||
ChangeAccess(info dto.ChangeDBInfo) error
|
||||
ChangePassword(info dto.ChangeDBInfo) error
|
||||
UpdateVariables(req dto.MysqlVariablesUpdate) error
|
||||
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
|
||||
UpdateDescription(req dto.UpdateDescription) error
|
||||
DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error)
|
||||
Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
||||
|
||||
LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error)
|
||||
LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error)
|
||||
LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error)
|
||||
LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error)
|
||||
|
||||
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
|
||||
}
|
||||
|
||||
func NewIMysqlService() IMysqlService {
|
||||
@@ -140,42 +144,6 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
|
||||
return &createItem, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) BindUser(req dto.BindUser) error {
|
||||
dbItem, err := mysqlRepo.Get(mysqlRepo.WithByMysqlName(req.Database), commonRepo.WithByName(req.DB))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
if err := cli.CreateUser(client.CreateInfo{
|
||||
Name: dbItem.Name,
|
||||
Format: dbItem.Format,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Permission: req.Permission,
|
||||
Version: version,
|
||||
Timeout: 300,
|
||||
}, false); err != nil {
|
||||
return err
|
||||
}
|
||||
pass, err := encrypt.StringEncrypt(req.Password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decrypt database db password failed, err: %v", err)
|
||||
}
|
||||
if err := mysqlRepo.Update(dbItem.ID, map[string]interface{}{
|
||||
"username": req.Username,
|
||||
"password": pass,
|
||||
"permission": req.Permission,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
|
||||
client, version, err := LoadMysqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
@@ -342,7 +310,7 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
}
|
||||
|
||||
global.LOG.Infof("start to update mysql password used by app %s-%s", appModel.Key, appInstall.Name)
|
||||
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", req.Value); err != nil {
|
||||
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -355,7 +323,7 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := updateInstallInfoInDB(req.Type, req.Database, "password", req.Value); err != nil {
|
||||
if err := updateInstallInfoInDB(req.Type, req.Database, "password", false, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -401,6 +369,26 @@ func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) UpdateConfByFile(req dto.MysqlConfUpdateByFile) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
@@ -446,6 +434,19 @@ func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
|
||||
var data dto.DBBaseInfo
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data.ContainerName = app.ContainerName
|
||||
data.Name = app.Name
|
||||
data.Port = int64(app.Port)
|
||||
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
@@ -527,6 +528,30 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
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 "mariadb-conf":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%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 "mysql-slow-logs":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
||||
case "mariadb-slow-logs":
|
||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/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 executeSqlForMaps(containerName, password, command string) (map[string]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
@@ -616,11 +641,6 @@ func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
|
||||
dbInfo.Port = databaseItem.Port
|
||||
dbInfo.Username = databaseItem.Username
|
||||
dbInfo.Password = databaseItem.Password
|
||||
dbInfo.SSL = databaseItem.SSL
|
||||
dbInfo.ClientKey = databaseItem.ClientKey
|
||||
dbInfo.ClientCert = databaseItem.ClientCert
|
||||
dbInfo.RootCert = databaseItem.RootCert
|
||||
dbInfo.SkipVerify = databaseItem.SkipVerify
|
||||
version = databaseItem.Version
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1,413 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
_ "github.com/jackc/pgx/v5/stdlib"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type PostgresqlService struct{}
|
||||
|
||||
type IPostgresqlService interface {
|
||||
SearchWithPage(search dto.PostgresqlDBSearch) (int64, interface{}, error)
|
||||
ListDBOption() ([]dto.PostgresqlOption, error)
|
||||
BindUser(req dto.PostgresqlBindUser) error
|
||||
Create(ctx context.Context, req dto.PostgresqlDBCreate) (*model.DatabasePostgresql, error)
|
||||
LoadFromRemote(database string) error
|
||||
ChangePrivileges(req dto.PostgresqlPrivileges) error
|
||||
ChangePassword(info dto.ChangeDBInfo) error
|
||||
UpdateDescription(req dto.UpdateDescription) error
|
||||
DeleteCheck(req dto.PostgresqlDBDeleteCheck) ([]string, error)
|
||||
Delete(ctx context.Context, req dto.PostgresqlDBDelete) error
|
||||
}
|
||||
|
||||
func NewIPostgresqlService() IPostgresqlService {
|
||||
return &PostgresqlService{}
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) SearchWithPage(search dto.PostgresqlDBSearch) (int64, interface{}, error) {
|
||||
total, postgresqls, err := postgresqlRepo.Page(search.Page, search.PageSize,
|
||||
postgresqlRepo.WithByPostgresqlName(search.Database),
|
||||
commonRepo.WithLikeName(search.Info),
|
||||
commonRepo.WithOrderRuleBy(search.OrderBy, search.Order),
|
||||
)
|
||||
var dtoPostgresqls []dto.PostgresqlDBInfo
|
||||
for _, pg := range postgresqls {
|
||||
var item dto.PostgresqlDBInfo
|
||||
if err := copier.Copy(&item, &pg); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
dtoPostgresqls = append(dtoPostgresqls, item)
|
||||
}
|
||||
return total, dtoPostgresqls, err
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) ListDBOption() ([]dto.PostgresqlOption, error) {
|
||||
postgresqls, err := postgresqlRepo.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
databases, err := databaseRepo.GetList(databaseRepo.WithTypeList("postgresql,mariadb"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var dbs []dto.PostgresqlOption
|
||||
for _, pg := range postgresqls {
|
||||
var item dto.PostgresqlOption
|
||||
if err := copier.Copy(&item, &pg); err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
item.Database = pg.PostgresqlName
|
||||
for _, database := range databases {
|
||||
if database.Name == item.Database {
|
||||
item.Type = database.Type
|
||||
}
|
||||
}
|
||||
dbs = append(dbs, item)
|
||||
}
|
||||
return dbs, err
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) BindUser(req dto.PostgresqlBindUser) error {
|
||||
if cmd.CheckIllegal(req.Name, req.Username, req.Password) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
dbItem, err := postgresqlRepo.Get(postgresqlRepo.WithByPostgresqlName(req.Database), commonRepo.WithByName(req.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pgClient, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pgClient.CreateUser(client.CreateInfo{
|
||||
Name: req.Name,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
SuperUser: req.SuperUser,
|
||||
Timeout: 300,
|
||||
}, false); err != nil {
|
||||
return err
|
||||
}
|
||||
pass, err := encrypt.StringEncrypt(req.Password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decrypt database db password failed, err: %v", err)
|
||||
}
|
||||
if err := postgresqlRepo.Update(dbItem.ID, map[string]interface{}{
|
||||
"username": req.Username,
|
||||
"password": pass,
|
||||
"super_user": req.SuperUser,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) Create(ctx context.Context, req dto.PostgresqlDBCreate) (*model.DatabasePostgresql, error) {
|
||||
if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format) {
|
||||
return nil, buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
|
||||
pgsql, _ := postgresqlRepo.Get(commonRepo.WithByName(req.Name), postgresqlRepo.WithByPostgresqlName(req.Database), databaseRepo.WithByFrom(req.From))
|
||||
if pgsql.ID != 0 {
|
||||
return nil, constant.ErrRecordExist
|
||||
}
|
||||
|
||||
var createItem model.DatabasePostgresql
|
||||
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")
|
||||
}
|
||||
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
createItem.PostgresqlName = req.Database
|
||||
defer cli.Close()
|
||||
if err := cli.Create(client.CreateInfo{
|
||||
Name: req.Name,
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
SuperUser: req.SuperUser,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
global.LOG.Infof("create database %s successful!", req.Name)
|
||||
if err := postgresqlRepo.Create(ctx, &createItem); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &createItem, nil
|
||||
}
|
||||
|
||||
func LoadPostgresqlClientByFrom(database string) (postgresql.PostgresqlClient, error) {
|
||||
var (
|
||||
dbInfo client.DBInfo
|
||||
err error
|
||||
)
|
||||
|
||||
dbInfo.Timeout = 300
|
||||
databaseItem, err := databaseRepo.Get(commonRepo.WithByName(database))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbInfo.From = databaseItem.From
|
||||
dbInfo.Database = database
|
||||
if dbInfo.From != "local" {
|
||||
dbInfo.Address = databaseItem.Address
|
||||
dbInfo.Port = databaseItem.Port
|
||||
dbInfo.Username = databaseItem.Username
|
||||
dbInfo.Password = databaseItem.Password
|
||||
} else {
|
||||
app, err := appInstallRepo.LoadBaseInfo(databaseItem.Type, database)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbInfo.From = "local"
|
||||
dbInfo.Address = app.ContainerName
|
||||
dbInfo.Username = app.UserName
|
||||
dbInfo.Password = app.Password
|
||||
dbInfo.Port = uint(app.Port)
|
||||
}
|
||||
|
||||
cli, err := postgresql.NewPostgresqlClient(dbInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) LoadFromRemote(database string) error {
|
||||
client, err := LoadPostgresqlClientByFrom(database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
databases, err := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
datas, err := client.SyncDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, data := range datas {
|
||||
hasOld := false
|
||||
for _, oldData := range databases {
|
||||
if strings.EqualFold(oldData.Name, data.Name) && strings.EqualFold(oldData.PostgresqlName, data.PostgresqlName) {
|
||||
hasOld = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasOld {
|
||||
var createItem model.DatabasePostgresql
|
||||
if err := copier.Copy(&createItem, &data); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
if err := postgresqlRepo.Create(context.Background(), &createItem); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) UpdateDescription(req dto.UpdateDescription) error {
|
||||
return postgresqlRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) DeleteCheck(req dto.PostgresqlDBDeleteCheck) ([]string, error) {
|
||||
var appInUsed []string
|
||||
db, err := postgresqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return appInUsed, err
|
||||
}
|
||||
|
||||
if db.From == "local" {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return appInUsed, err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) Delete(ctx context.Context, req dto.PostgresqlDBDelete) error {
|
||||
db, err := postgresqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
if err := cli.Delete(client.DeleteInfo{
|
||||
Name: db.Name,
|
||||
Username: db.Username,
|
||||
ForceDelete: req.ForceDelete,
|
||||
Timeout: 300,
|
||||
}); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
|
||||
if req.DeleteBackup {
|
||||
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/%s/%s/%s", req.Type, req.Database, db.Name))
|
||||
if _, err := os.Stat(uploadDir); err == nil {
|
||||
_ = os.RemoveAll(uploadDir)
|
||||
}
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, db.PostgresqlName, db.Name))
|
||||
if _, err := os.Stat(backupDir); err == nil {
|
||||
_ = os.RemoveAll(backupDir)
|
||||
}
|
||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(req.Type), commonRepo.WithByName(req.Database), backupRepo.WithByDetailName(db.Name))
|
||||
global.LOG.Infof("delete database %s-%s backups successful", req.Database, db.Name)
|
||||
}
|
||||
|
||||
_ = postgresqlRepo.Delete(ctx, commonRepo.WithByID(db.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) ChangePrivileges(req dto.PostgresqlPrivileges) error {
|
||||
if cmd.CheckIllegal(req.Database, req.Username) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
dbItem, err := postgresqlRepo.Get(postgresqlRepo.WithByPostgresqlName(req.Database), commonRepo.WithByName(req.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
if err := cli.ChangePrivileges(client.Privileges{Username: req.Username, SuperUser: req.SuperUser, Timeout: 300}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := postgresqlRepo.Update(dbItem.ID, map[string]interface{}{
|
||||
"super_user": req.SuperUser,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
if cmd.CheckIllegal(req.Value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
cli, err := LoadPostgresqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
var (
|
||||
postgresqlData model.DatabasePostgresql
|
||||
passwordInfo client.PasswordChangeInfo
|
||||
)
|
||||
passwordInfo.Password = req.Value
|
||||
passwordInfo.Timeout = 300
|
||||
|
||||
if req.ID != 0 {
|
||||
postgresqlData, err = postgresqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
passwordInfo.Username = postgresqlData.Username
|
||||
} else {
|
||||
dbItem, err := databaseRepo.Get(commonRepo.WithByType(req.Type), commonRepo.WithByFrom(req.From))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
passwordInfo.Username = dbItem.Username
|
||||
}
|
||||
if err := cli.ChangePassword(passwordInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if req.ID != 0 {
|
||||
var appRess []model.AppInstallResource
|
||||
if req.From == "local" {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appRess, _ = appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(postgresqlData.ID))
|
||||
} else {
|
||||
appRess, _ = appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(postgresqlData.ID))
|
||||
}
|
||||
for _, appRes := range appRess {
|
||||
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(appRes.AppInstallId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appModel, err := appRepo.GetFirst(commonRepo.WithByID(appInstall.AppId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
global.LOG.Infof("start to update postgresql password used by app %s-%s", appModel.Key, appInstall.Name)
|
||||
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
global.LOG.Info("execute password change sql successful")
|
||||
pass, err := encrypt.StringEncrypt(req.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decrypt database db password failed, err: %v", err)
|
||||
}
|
||||
_ = postgresqlRepo.Update(postgresqlData.ID, map[string]interface{}{"password": pass})
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := updateInstallInfoInDB(req.Type, req.Database, "password", req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||
confs = append(confs, redisConfig{key: "timeout", value: req.Timeout})
|
||||
confs = append(confs, redisConfig{key: "maxclients", value: req.Maxclients})
|
||||
confs = append(confs, redisConfig{key: "maxmemory", value: req.Maxmemory})
|
||||
if err := confSet(redisInfo.Name, "", confs); err != nil {
|
||||
if err := confSet(redisInfo.Name, confs); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/redis/%s/docker-compose.yml", constant.AppInstallDir, redisInfo.Name)); err != nil {
|
||||
@@ -55,10 +55,10 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||
}
|
||||
|
||||
func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
|
||||
if err := updateInstallInfoInDB("redis", "", "password", req.Value); err != nil {
|
||||
if err := updateInstallInfoInDB("redis", "", "password", true, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := updateInstallInfoInDB("redis-commander", "", "password", req.Value); err != nil {
|
||||
if err := updateInstallInfoInDB("redis-commander", "", "password", true, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate)
|
||||
confs = append(confs, redisConfig{key: "appendonly", value: req.Appendonly})
|
||||
confs = append(confs, redisConfig{key: "appendfsync", value: req.Appendfsync})
|
||||
}
|
||||
if err := confSet(redisInfo.Name, req.Type, confs); err != nil {
|
||||
if err := confSet(redisInfo.Name, confs); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/redis/%s/docker-compose.yml", constant.AppInstallDir, redisInfo.Name)); err != nil {
|
||||
@@ -213,7 +213,7 @@ type redisConfig struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func confSet(redisName string, updateType string, changeConf []redisConfig) error {
|
||||
func confSet(redisName string, changeConf []redisConfig) error {
|
||||
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", constant.AppInstallDir, redisName)
|
||||
lineBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -221,38 +221,19 @@ func confSet(redisName string, updateType string, changeConf []redisConfig) erro
|
||||
}
|
||||
files := strings.Split(string(lineBytes), "\n")
|
||||
|
||||
startIndex, endIndex, emptyLine := 0, 0, 0
|
||||
startIndex, endIndex := 0, 0
|
||||
var newFiles []string
|
||||
for i := 0; i < len(files); i++ {
|
||||
if files[i] == "# Redis configuration rewrite by 1Panel" {
|
||||
startIndex = i
|
||||
newFiles = append(newFiles, files[i])
|
||||
continue
|
||||
}
|
||||
if files[i] == "# End Redis configuration rewrite by 1Panel" {
|
||||
endIndex = i
|
||||
break
|
||||
}
|
||||
if startIndex == 0 && strings.HasPrefix(files[i], "save ") {
|
||||
newFiles = append(newFiles, "# "+files[i])
|
||||
continue
|
||||
}
|
||||
if startIndex != 0 && endIndex == 0 && (len(files[i]) == 0 || (updateType == "rbd" && strings.HasPrefix(files[i], "save "))) {
|
||||
emptyLine++
|
||||
continue
|
||||
}
|
||||
newFiles = append(newFiles, files[i])
|
||||
}
|
||||
endIndex = endIndex - emptyLine
|
||||
for _, item := range changeConf {
|
||||
if item.key == "save" {
|
||||
saveVal := strings.Split(item.value, ",")
|
||||
for i := 0; i < len(saveVal); i++ {
|
||||
newFiles = append(newFiles, "save "+saveVal[i])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
isExist := false
|
||||
for i := startIndex; i < endIndex; i++ {
|
||||
if strings.HasPrefix(newFiles[i], item.key) || strings.HasPrefix(newFiles[i], "# "+item.key) {
|
||||
|
||||
@@ -1,431 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
)
|
||||
|
||||
const defaultDNSPath = "/etc/resolv.conf"
|
||||
const defaultHostPath = "/etc/hosts"
|
||||
const defaultFstab = "/etc/fstab"
|
||||
|
||||
type DeviceService struct{}
|
||||
|
||||
type IDeviceService interface {
|
||||
LoadBaseInfo() (dto.DeviceBaseInfo, error)
|
||||
Update(key, value string) error
|
||||
UpdateHosts(req []dto.HostHelper) error
|
||||
UpdatePasswd(req dto.ChangePasswd) error
|
||||
UpdateSwap(req dto.SwapHelper) error
|
||||
UpdateByConf(req dto.UpdateByNameAndFile) error
|
||||
LoadTimeZone() ([]string, error)
|
||||
CheckDNS(key, value string) (bool, error)
|
||||
LoadConf(name string) (string, error)
|
||||
|
||||
Scan() dto.CleanData
|
||||
Clean(req []dto.Clean)
|
||||
CleanForCronjob() (string, error)
|
||||
}
|
||||
|
||||
func NewIDeviceService() IDeviceService {
|
||||
return &DeviceService{}
|
||||
}
|
||||
|
||||
func (u *DeviceService) LoadBaseInfo() (dto.DeviceBaseInfo, error) {
|
||||
var baseInfo dto.DeviceBaseInfo
|
||||
baseInfo.LocalTime = time.Now().Format("2006-01-02 15:04:05 MST -0700")
|
||||
baseInfo.TimeZone = common.LoadTimeZoneByCmd()
|
||||
baseInfo.DNS = loadDNS()
|
||||
baseInfo.Hosts = loadHosts()
|
||||
baseInfo.Hostname = loadHostname()
|
||||
baseInfo.User = loadUser()
|
||||
ntp, err := settingRepo.Get(settingRepo.WithByKey("NtpSite"))
|
||||
if err == nil {
|
||||
baseInfo.Ntp = ntp.Value
|
||||
}
|
||||
|
||||
swapInfo, err := mem.SwapMemory()
|
||||
if err != nil {
|
||||
return baseInfo, err
|
||||
}
|
||||
baseInfo.SwapMemoryTotal = swapInfo.Total
|
||||
baseInfo.SwapMemoryAvailable = swapInfo.Free
|
||||
baseInfo.SwapMemoryUsed = swapInfo.Used
|
||||
if baseInfo.SwapMemoryTotal != 0 {
|
||||
baseInfo.SwapDetails = loadSwap()
|
||||
}
|
||||
disks := loadDiskInfo()
|
||||
for _, item := range disks {
|
||||
baseInfo.MaxSize += item.Free
|
||||
}
|
||||
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) LoadTimeZone() ([]string, error) {
|
||||
std, err := cmd.Exec("timedatectl list-timezones")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return strings.Split(std, "\n"), nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) CheckDNS(key, value string) (bool, error) {
|
||||
content, err := os.ReadFile(defaultDNSPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer func() { _ = u.UpdateByConf(dto.UpdateByNameAndFile{Name: "DNS", File: string(content)}) }()
|
||||
if key == "form" {
|
||||
if err := u.Update("DNS", value); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
if err := u.UpdateByConf(dto.UpdateByNameAndFile{Name: "DNS", File: value}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("ip4:icmp", "www.baidu.com", time.Second*2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) Update(key, value string) error {
|
||||
switch key {
|
||||
case "TimeZone":
|
||||
if cmd.CheckIllegal(value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
if err := ntp.UpdateSystemTimeZone(value); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
||||
if err != nil {
|
||||
global.LOG.Errorf("restart system for new time zone failed, err: %v", err)
|
||||
}
|
||||
}()
|
||||
case "DNS":
|
||||
if err := updateDNS(strings.Split(value, ",")); err != nil {
|
||||
return err
|
||||
}
|
||||
case "Hostname":
|
||||
if cmd.CheckIllegal(value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
std, err := cmd.Execf("%s hostnamectl set-hostname %s", cmd.SudoHandleCmd(), value)
|
||||
if err != nil {
|
||||
return errors.New(std)
|
||||
}
|
||||
case "Ntp", "LocalTime":
|
||||
if cmd.CheckIllegal(value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
ntpValue := value
|
||||
if key == "LocalTime" {
|
||||
ntpItem, err := settingRepo.Get(settingRepo.WithByKey("NtpSite"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ntpValue = ntpItem.Value
|
||||
} else {
|
||||
if err := settingRepo.Update("NtpSite", ntpValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ntime, err := ntp.GetRemoteTime(ntpValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts := ntime.Format("2006-01-02 15:04:05")
|
||||
if err := ntp.UpdateSystemTime(ts); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("not support such key %s", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdateHosts(req []dto.HostHelper) error {
|
||||
conf, err := os.ReadFile(defaultHostPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read namesever conf of %s failed, err: %v", defaultHostPath, err)
|
||||
}
|
||||
lines := strings.Split(string(conf), "\n")
|
||||
newFile := ""
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
newFile += line + "\n"
|
||||
continue
|
||||
}
|
||||
for index, item := range req {
|
||||
if item.IP == parts[0] && item.Host == strings.Join(parts[1:], " ") {
|
||||
newFile += line + "\n"
|
||||
req = append(req[:index], req[index+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, item := range req {
|
||||
newFile += fmt.Sprintf("%s %s \n", item.IP, item.Host)
|
||||
}
|
||||
file, err := os.OpenFile(defaultHostPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(newFile)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdatePasswd(req dto.ChangePasswd) error {
|
||||
if cmd.CheckIllegal(req.User, req.Passwd) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
std, err := cmd.Execf("%s echo '%s:%s' | %s chpasswd", cmd.SudoHandleCmd(), req.User, req.Passwd, cmd.SudoHandleCmd())
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "does not exist") {
|
||||
return buserr.New(constant.ErrNotExistUser)
|
||||
}
|
||||
return errors.New(std)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdateSwap(req dto.SwapHelper) error {
|
||||
if cmd.CheckIllegal(req.Path) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
if !req.IsNew {
|
||||
std, err := cmd.Execf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle swapoff %s failed, err: %s", req.Path, std)
|
||||
}
|
||||
}
|
||||
if req.Size == 0 {
|
||||
if req.Path == path.Join(global.CONF.System.BaseDir, ".1panel_swap") {
|
||||
_ = os.Remove(path.Join(global.CONF.System.BaseDir, ".1panel_swap"))
|
||||
}
|
||||
return operateSwapWithFile(true, req)
|
||||
}
|
||||
std1, err := cmd.Execf("%s dd if=/dev/zero of=%s bs=1024 count=%d", cmd.SudoHandleCmd(), req.Path, req.Size)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle dd path %s failed, err: %s", req.Path, std1)
|
||||
}
|
||||
std2, err := cmd.Execf("%s mkswap -f %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle dd path %s failed, err: %s", req.Path, std2)
|
||||
}
|
||||
std3, err := cmd.Execf("%s swapon %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
_, _ = cmd.Execf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path)
|
||||
return fmt.Errorf("handle dd path %s failed, err: %s", req.Path, std3)
|
||||
}
|
||||
return operateSwapWithFile(false, req)
|
||||
}
|
||||
|
||||
func (u *DeviceService) LoadConf(name string) (string, error) {
|
||||
pathItem := ""
|
||||
switch name {
|
||||
case "DNS":
|
||||
pathItem = defaultDNSPath
|
||||
case "Hosts":
|
||||
pathItem = defaultHostPath
|
||||
default:
|
||||
return "", fmt.Errorf("not support such name %s", name)
|
||||
}
|
||||
if _, err := os.Stat(pathItem); err != nil {
|
||||
return "", err
|
||||
}
|
||||
content, err := os.ReadFile(pathItem)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(content), nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdateByConf(req dto.UpdateByNameAndFile) error {
|
||||
if req.Name != "DNS" && req.Name != "Hosts" {
|
||||
return fmt.Errorf("not support such name %s", req.Name)
|
||||
}
|
||||
path := defaultDNSPath
|
||||
if req.Name == "Hosts" {
|
||||
path = defaultHostPath
|
||||
}
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadDNS() []string {
|
||||
var list []string
|
||||
dnsConf, err := os.ReadFile(defaultDNSPath)
|
||||
if err == nil {
|
||||
lines := strings.Split(string(dnsConf), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "nameserver ") {
|
||||
list = append(list, strings.TrimPrefix(line, "nameserver "))
|
||||
}
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func updateDNS(list []string) error {
|
||||
conf, err := os.ReadFile(defaultDNSPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read nameserver conf of %s failed, err: %v", defaultDNSPath, err)
|
||||
}
|
||||
lines := strings.Split(string(conf), "\n")
|
||||
newFile := ""
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 || parts[0] != "nameserver" {
|
||||
newFile += line + "\n"
|
||||
continue
|
||||
}
|
||||
itemNs := strings.Join(parts[1:], " ")
|
||||
for index, item := range list {
|
||||
if item == itemNs {
|
||||
newFile += line + "\n"
|
||||
list = append(list[:index], list[index+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, item := range list {
|
||||
if len(item) != 0 {
|
||||
newFile += fmt.Sprintf("nameserver %s \n", item)
|
||||
}
|
||||
}
|
||||
file, err := os.OpenFile(defaultDNSPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(newFile)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadHosts() []dto.HostHelper {
|
||||
var list []dto.HostHelper
|
||||
hostConf, err := os.ReadFile(defaultHostPath)
|
||||
if err == nil {
|
||||
lines := strings.Split(string(hostConf), "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 || strings.HasPrefix(strings.TrimPrefix(line, " "), "#") {
|
||||
continue
|
||||
}
|
||||
list = append(list, dto.HostHelper{IP: parts[0], Host: strings.Join(parts[1:], " ")})
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func loadHostname() string {
|
||||
std, err := cmd.Exec("hostname")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.ReplaceAll(std, "\n", "")
|
||||
}
|
||||
|
||||
func loadUser() string {
|
||||
std, err := cmd.Exec("whoami")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.ReplaceAll(std, "\n", "")
|
||||
}
|
||||
|
||||
func loadSwap() []dto.SwapHelper {
|
||||
var data []dto.SwapHelper
|
||||
std, err := cmd.Execf("%s swapon --summary", cmd.SudoHandleCmd())
|
||||
if err != nil {
|
||||
return data
|
||||
}
|
||||
lines := strings.Split(std, "\n")
|
||||
for index, line := range lines {
|
||||
if index == 0 {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 5 {
|
||||
continue
|
||||
}
|
||||
sizeItem, _ := strconv.Atoi(parts[2])
|
||||
data = append(data, dto.SwapHelper{Path: parts[0], Size: uint64(sizeItem), Used: parts[3]})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func operateSwapWithFile(delete bool, req dto.SwapHelper) error {
|
||||
conf, err := os.ReadFile(defaultFstab)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read file %s failed, err: %v", defaultFstab, err)
|
||||
}
|
||||
lines := strings.Split(string(conf), "\n")
|
||||
newFile := ""
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) == 6 && parts[0] == req.Path {
|
||||
continue
|
||||
}
|
||||
newFile += line + "\n"
|
||||
}
|
||||
if !delete {
|
||||
newFile += fmt.Sprintf("%s swap swap defaults 0 0\n", req.Path)
|
||||
}
|
||||
file, err := os.OpenFile(defaultFstab, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(newFile)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user