mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 08:00:27 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c826525e3 | ||
|
|
3f0fd48cf3 | ||
|
|
211dbfdead | ||
|
|
aafec142cc | ||
|
|
384ff57df7 | ||
|
|
01ddd203ea | ||
|
|
29aed616ac | ||
|
|
83f0df9d84 | ||
|
|
7aa16c8142 | ||
|
|
3bd505954f | ||
|
|
275c0522a3 | ||
|
|
85dec6815b | ||
|
|
5e4e9f762e | ||
|
|
7ae3722997 |
@@ -13,11 +13,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.2'
|
||||
node-version: '18.14'
|
||||
- name: Build Web
|
||||
id: build_frontend
|
||||
run: |
|
||||
@@ -25,10 +25,10 @@ jobs:
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.22'
|
||||
go-version: '1.20.x'
|
||||
- name: Build Server
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
args: release --snapshot --clean
|
||||
@@ -11,9 +11,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.2'
|
||||
- name: Build Web
|
||||
@@ -22,15 +22,15 @@ jobs:
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.22'
|
||||
go-version: '1.21.x'
|
||||
- name: Build Release
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --skip=publish --clean
|
||||
args: release --skip-publish --clean
|
||||
- name: Upload Assets
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@
|
||||
## Create pull request
|
||||
PR are always welcome, even if they only contain small fixes like typos or a few lines of code. If there will be a significant effort, please document it as an issue and get a discussion going before starting to work on it.
|
||||
|
||||
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot of features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
|
||||
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
|
||||
|
||||
This [development guideline](https://1panel.cn/docs/dev_manual/dev_manual/) contains information about repository structure, how to set up development environment, how to run it, and more.
|
||||
This [development guideline](https://1panel.cn/docs/dev_manual/dev_manual/) contains information about repository structure, how to setup development environment, how to run it, and more.
|
||||
|
||||
Note: If you split your pull request to small changes, please make sure any of the changes goes to master will not break anything. Otherwise, it can not be merged until this feature complete.
|
||||
|
||||
|
||||
@@ -21,8 +21,18 @@
|
||||
|
||||
1Panel 三分钟速览:https://www.bilibili.com/video/BV1Mt421n7LZ/
|
||||
|
||||
## UI 展示
|
||||
|
||||

|
||||
|
||||
## 快速开始
|
||||
|
||||
**在线体验**
|
||||
|
||||
- 环境地址:<https://demo.1panel.cn/>
|
||||
- 用户名:demo
|
||||
- 密码:1panel
|
||||
|
||||
**一键安装**
|
||||
|
||||
执行如下命令一键安装 1Panel:
|
||||
@@ -31,29 +41,33 @@
|
||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
|
||||
```
|
||||
|
||||
如果是用于离线环境,推荐使用 [安装包方式](https://1panel.cn/docs/installation/package_installation/) 进行安装部署。
|
||||
|
||||
**学习资料**
|
||||
|
||||
- [在线文档](https://1panel.cn/docs/)
|
||||
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
|
||||
- [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)
|
||||
|
||||
## UI 展示
|
||||
## 安全说明
|
||||
|
||||

|
||||
如果您在使用过程中发现任何安全问题,请通过以下方式直接联系我们:
|
||||
|
||||
- 邮箱:wanghe@fit2cloud.com
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||
|
||||
## 我们的其他明星项目
|
||||
|
||||
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统
|
||||
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
|
||||
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
|
||||
- [DataEase](https://github.com/dataease/dataease/) - 人人可用的开源数据可视化分析工具
|
||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - 开源自动化测试平台
|
||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - 一站式开源自动化测试平台
|
||||
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
|
||||
|
||||
|
||||
## FOSSA Status
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_large)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -205,13 +205,14 @@ func (b *BaseApi) GetServices(c *gin.Context) {
|
||||
// @Param appInstallId path integer true "request"
|
||||
// @Success 200 {array} dto.AppVersion
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed/update/versions [post]
|
||||
// @Router /apps/installed/:appInstallId/versions [get]
|
||||
func (b *BaseApi) GetUpdateVersions(c *gin.Context) {
|
||||
var req request.AppUpdateVersion
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
versions, err := appInstallService.GetUpdateVersions(req)
|
||||
versions, err := appInstallService.GetUpdateVersions(appInstallId)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"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/middleware"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/captcha"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/qqwry"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -119,19 +118,7 @@ func (b *BaseApi) CheckIsSafety(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
if status == "disable" && len(code) != 0 {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrNotFound, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
if status == "unpass" {
|
||||
if middleware.LoadErrCode("err-entrance") != 200 {
|
||||
helper.ErrResponse(c, middleware.LoadErrCode("err-entrance"))
|
||||
return
|
||||
}
|
||||
helper.ErrorWithDetail(c, constant.CodeErrEntrance, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
helper.SuccessWithData(c, status)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetResponsePage(c *gin.Context) {
|
||||
|
||||
@@ -118,11 +118,11 @@ func (b *BaseApi) LoadOneDriveInfo(c *gin.Context) {
|
||||
// @Summary Delete backup account
|
||||
// @Description 删除备份账号
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Param request body dto.BatchDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/backup/del [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"backup_accounts","output_column":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":true,"db":"backup_accounts","output_column":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
|
||||
func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
@@ -323,7 +323,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
|
||||
switch req.Type {
|
||||
case "app":
|
||||
if _, err := backupService.AppBackup(req); err != nil {
|
||||
if err := backupService.AppBackup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
@@ -343,7 +343,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
case "redis":
|
||||
if err := backupService.RedisBackup(req); err != nil {
|
||||
if err := backupService.RedisBackup(); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -29,28 +29,6 @@ func (b *BaseApi) CreateCommand(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Redis Command
|
||||
// @Summary Save redis command
|
||||
// @Description 保存 Redis 快速命令
|
||||
// @Accept json
|
||||
// @Param request body dto.RedisCommand true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /hosts/command/redis [post]
|
||||
// @x-panel-log {"bodyKeys":["name","command"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"保存 redis 快捷命令 [name][command]","formatEN":"save quick command for redis [name][command]"}
|
||||
func (b *BaseApi) SaveRedisCommand(c *gin.Context) {
|
||||
var req dto.RedisCommand
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := commandService.SaveRedisCommand(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Command
|
||||
// @Summary Page commands
|
||||
// @Description 获取快速命令列表分页
|
||||
@@ -77,32 +55,6 @@ func (b *BaseApi) SearchCommand(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Redis Command
|
||||
// @Summary Page redis commands
|
||||
// @Description 获取 redis 快速命令列表分页
|
||||
// @Accept json
|
||||
// @Param request body dto.SearchWithPage true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /hosts/command/redis/search [post]
|
||||
func (b *BaseApi) SearchRedisCommand(c *gin.Context) {
|
||||
var req dto.SearchWithPage
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := commandService.SearchRedisCommandWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Command
|
||||
// @Summary Tree commands
|
||||
// @Description 获取快速命令树
|
||||
@@ -120,22 +72,6 @@ func (b *BaseApi) SearchCommandTree(c *gin.Context) {
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Redis Command
|
||||
// @Summary List redis commands
|
||||
// @Description 获取 redis 快速命令列表
|
||||
// @Success 200 {Array} dto.RedisCommand
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /hosts/command/redis [get]
|
||||
func (b *BaseApi) ListRedisCommand(c *gin.Context) {
|
||||
list, err := commandService.ListRedisCommand()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Command
|
||||
// @Summary List commands
|
||||
// @Description 获取快速命令列表
|
||||
@@ -174,28 +110,6 @@ func (b *BaseApi) DeleteCommand(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Redis Command
|
||||
// @Summary Delete redis command
|
||||
// @Description 删除 redis 快速命令
|
||||
// @Accept json
|
||||
// @Param request body dto.BatchDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /hosts/command/redis/del [post]
|
||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"redis_commands","output_column":"name","output_value":"names"}],"formatZH":"删除 redis 快捷命令 [names]","formatEN":"delete quick command of redis [names]"}
|
||||
func (b *BaseApi) DeleteRedisCommand(c *gin.Context) {
|
||||
var req dto.BatchDeleteReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := commandService.DeleteRedisCommand(req.Ids); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Command
|
||||
// @Summary Update command
|
||||
// @Description 更新快速命令
|
||||
|
||||
@@ -12,17 +12,11 @@ import (
|
||||
// @Tags Database Redis
|
||||
// @Summary Load redis status info
|
||||
// @Description 获取 redis 状态信息
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Success 200 {object} dto.RedisStatus
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/redis/status [post]
|
||||
// @Router /databases/redis/status [get]
|
||||
func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
data, err := redisService.LoadStatus(req)
|
||||
data, err := redisService.LoadStatus()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -34,17 +28,11 @@ func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
||||
// @Tags Database Redis
|
||||
// @Summary Load redis conf
|
||||
// @Description 获取 redis 配置信息
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Success 200 {object} dto.RedisConf
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/redis/conf [post]
|
||||
// @Router /databases/redis/conf [get]
|
||||
func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
data, err := redisService.LoadConf(req)
|
||||
data, err := redisService.LoadConf()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -56,17 +44,11 @@ func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
||||
// @Tags Database Redis
|
||||
// @Summary Load redis persistence conf
|
||||
// @Description 获取 redis 持久化配置
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Success 200 {object} dto.RedisPersistence
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/redis/persistence/conf [post]
|
||||
// @Router /databases/redis/persistence/conf [get]
|
||||
func (b *BaseApi) LoadPersistenceConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
data, err := redisService.LoadPersistenceConf(req)
|
||||
data, err := redisService.LoadPersistenceConf()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -75,25 +57,6 @@ func (b *BaseApi) LoadPersistenceConf(c *gin.Context) {
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
func (b *BaseApi) CheckHasCli(c *gin.Context) {
|
||||
helper.SuccessWithData(c, redisService.CheckHasCli())
|
||||
}
|
||||
|
||||
// @Tags Database Redis
|
||||
// @Summary Install redis-cli
|
||||
// @Description 安装 redis cli
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/redis/install/cli [post]
|
||||
func (b *BaseApi) InstallCli(c *gin.Context) {
|
||||
if err := redisService.InstallCli(); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Database Redis
|
||||
// @Summary Update redis conf
|
||||
// @Description 更新 redis 配置信息
|
||||
@@ -168,3 +131,29 @@ func (b *BaseApi) UpdateRedisPersistenceConf(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Database Redis
|
||||
// @Summary Page redis backups
|
||||
// @Description 获取 redis 备份记录分页
|
||||
// @Accept json
|
||||
// @Param request body dto.PageInfo true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/redis/backup/search [post]
|
||||
func (b *BaseApi) RedisBackupList(c *gin.Context) {
|
||||
var req dto.PageInfo
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := redisService.SearchBackupListWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ var (
|
||||
|
||||
deviceService = service.NewIDeviceService()
|
||||
fail2banService = service.NewIFail2BanService()
|
||||
ftpService = service.NewIFtpService()
|
||||
|
||||
settingService = service.NewISettingService()
|
||||
backupService = service.NewIBackupService()
|
||||
|
||||
@@ -318,7 +318,7 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
}
|
||||
dir := path.Dir(paths[0])
|
||||
|
||||
_, err = os.Stat(dir)
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
mode, err := files.GetParentMode(dir)
|
||||
if err != nil {
|
||||
@@ -330,7 +330,7 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
info, err := os.Stat(dir)
|
||||
info, err = os.Stat(dir)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -486,7 +486,6 @@ func (b *BaseApi) Download(c *gin.Context) {
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
}
|
||||
defer file.Close()
|
||||
info, _ := file.Stat()
|
||||
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
|
||||
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
|
||||
@@ -592,11 +591,7 @@ func (b *BaseApi) Size(c *gin.Context) {
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int, overwrite bool) error {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(fileDir)
|
||||
}()
|
||||
|
||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
|
||||
op := files.NewFileOp()
|
||||
dstDir = strings.TrimSpace(dstDir)
|
||||
mode, _ := files.GetParentMode(dstDir)
|
||||
@@ -608,21 +603,12 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
|
||||
return err
|
||||
}
|
||||
}
|
||||
dstFileName := filepath.Join(dstDir, fileName)
|
||||
dstInfo, statErr := os.Stat(dstFileName)
|
||||
if statErr == nil {
|
||||
mode = dstInfo.Mode()
|
||||
} else {
|
||||
mode = 0644
|
||||
}
|
||||
if overwrite {
|
||||
_ = os.Remove(dstFileName)
|
||||
}
|
||||
targetFile, err := os.OpenFile(dstFileName, os.O_RDWR|os.O_CREATE, mode)
|
||||
|
||||
targetFile, err := os.OpenFile(filepath.Join(dstDir, fileName), os.O_RDWR|os.O_CREATE, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer targetFile.Close()
|
||||
|
||||
for i := 0; i < chunkCount; i++ {
|
||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
||||
chunkData, err := os.ReadFile(chunkPath)
|
||||
@@ -633,10 +619,9 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(chunkPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
return files.NewFileOp().DeleteDir(fileDir)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
@@ -658,7 +643,6 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
defer uploadFile.Close()
|
||||
chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
@@ -718,11 +702,7 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
}
|
||||
|
||||
if chunkIndex+1 == chunkCount {
|
||||
overwrite := true
|
||||
if ow := c.PostForm("overwrite"); ow != "" {
|
||||
overwrite, _ = strconv.ParseBool(ow)
|
||||
}
|
||||
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount, overwrite)
|
||||
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, buserr.WithMap(constant.ErrFileUpload, map[string]interface{}{"name": filename, "detail": err.Error()}, err))
|
||||
return
|
||||
|
||||
@@ -1,199 +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 FTP
|
||||
// @Summary Load FTP base info
|
||||
// @Description 获取 FTP 基础信息
|
||||
// @Success 200 {object} dto.FtpBaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp/base [get]
|
||||
func (b *BaseApi) LoadFtpBaseInfo(c *gin.Context) {
|
||||
data, err := ftpService.LoadBaseInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags FTP
|
||||
// @Summary Load FTP operation log
|
||||
// @Description 获取 FTP 操作日志
|
||||
// @Accept json
|
||||
// @Param request body dto.FtpLogSearch true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp/log/search [post]
|
||||
func (b *BaseApi) LoadFtpLogInfo(c *gin.Context) {
|
||||
var req dto.FtpLogSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := ftpService.LoadLog(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags FTP
|
||||
// @Summary Operate FTP
|
||||
// @Description 修改 FTP 状态
|
||||
// @Accept json
|
||||
// @Param request body dto.Operate true "request"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp/operate [post]
|
||||
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] FTP","formatEN":"[operation] FTP"}
|
||||
func (b *BaseApi) OperateFtp(c *gin.Context) {
|
||||
var req dto.Operate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := ftpService.Operate(req.Operation); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags FTP
|
||||
// @Summary Page FTP user
|
||||
// @Description 获取 FTP 账户列表分页
|
||||
// @Accept json
|
||||
// @Param request body dto.SearchWithPage true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp/search [post]
|
||||
func (b *BaseApi) SearchFtp(c *gin.Context) {
|
||||
var req dto.SearchWithPage
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := ftpService.SearchWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags FTP
|
||||
// @Summary Create FTP user
|
||||
// @Description 创建 FTP 账户
|
||||
// @Accept json
|
||||
// @Param request body dto.FtpCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp [post]
|
||||
// @x-panel-log {"bodyKeys":["user", "path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 FTP 账户 [user][path]","formatEN":"create FTP [user][path]"}
|
||||
func (b *BaseApi) CreateFtp(c *gin.Context) {
|
||||
var req dto.FtpCreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Password) != 0 {
|
||||
pass, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(pass)
|
||||
}
|
||||
if _, err := ftpService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags FTP
|
||||
// @Summary Delete FTP user
|
||||
// @Description 删除 FTP 账户
|
||||
// @Accept json
|
||||
// @Param request body dto.BatchDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp/del [post]
|
||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"ftps","output_column":"user","output_value":"users"}],"formatZH":"删除 FTP 账户 [users]","formatEN":"delete FTP users [users]"}
|
||||
func (b *BaseApi) DeleteFtp(c *gin.Context) {
|
||||
var req dto.BatchDeleteReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := ftpService.Delete(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags FTP
|
||||
// @Summary Sync FTP user
|
||||
// @Description 同步 FTP 账户
|
||||
// @Accept json
|
||||
// @Param request body dto.BatchDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp/sync [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"同步 FTP 账户","formatEN":"sync FTP users"}
|
||||
func (b *BaseApi) SyncFtp(c *gin.Context) {
|
||||
if err := ftpService.Sync(); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags FTP
|
||||
// @Summary Update FTP user
|
||||
// @Description 修改 FTP 账户
|
||||
// @Accept json
|
||||
// @Param request body dto.FtpUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/ftp/update [post]
|
||||
// @x-panel-log {"bodyKeys":["user", "path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 FTP 账户 [user][path]","formatEN":"update FTP [user][path]"}
|
||||
func (b *BaseApi) UpdateFtp(c *gin.Context) {
|
||||
var req dto.FtpUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Password) != 0 {
|
||||
pass, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(pass)
|
||||
}
|
||||
if err := ftpService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
@@ -133,8 +133,3 @@ func CheckBind(req interface{}, c *gin.Context) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ErrResponse(ctx *gin.Context, code int) {
|
||||
ctx.JSON(code, nil)
|
||||
ctx.Abort()
|
||||
}
|
||||
|
||||
@@ -76,20 +76,6 @@ func (b *BaseApi) DeleteRuntime(c *gin.Context) {
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteRuntimeCheck(c *gin.Context) {
|
||||
runTimeId, err := helper.GetIntParamByKey(c, "runTimeId")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
checkData, err := runtimeService.DeleteCheck(runTimeId)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, checkData)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Update runtime
|
||||
// @Description 更新运行环境
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
@@ -61,37 +60,6 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Update proxy setting
|
||||
// @Description 服务器代理配置
|
||||
// @Accept json
|
||||
// @Param request body dto.ProxyUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/proxy/update [post]
|
||||
// @x-panel-log {"bodyKeys":["proxyUrl","proxyPort"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"服务器代理配置 [proxyPort]:[proxyPort]","formatEN":"set proxy [proxyPort]:[proxyPort]."}
|
||||
func (b *BaseApi) UpdateProxy(c *gin.Context) {
|
||||
var req dto.ProxyUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.ProxyPasswd) != 0 && len(req.ProxyType) != 0 {
|
||||
pass, err := base64.StdEncoding.DecodeString(req.ProxyPasswd)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.ProxyPasswd = string(pass)
|
||||
}
|
||||
|
||||
if err := settingService.UpdateProxy(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Update system setting
|
||||
// @Description 隐藏高级功能菜单
|
||||
|
||||
@@ -168,13 +168,13 @@ func (b *BaseApi) RollbackSnapshot(c *gin.Context) {
|
||||
// @Summary Delete system backup
|
||||
// @Description 删除系统快照
|
||||
// @Accept json
|
||||
// @Param request body dto.SnapshotBatchDelete true "request"
|
||||
// @Param request body dto.BatchDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/snapshot/del [post]
|
||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"删除系统快照 [name]","formatEN":"Delete system backup [name]"}
|
||||
func (b *BaseApi) DeleteSnapshot(c *gin.Context) {
|
||||
var req dto.SnapshotBatchDelete
|
||||
var req dto.BatchDeleteReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
||||
@@ -79,13 +78,6 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
||||
global.LOG.Errorf("gin context http handler failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
defer wsConn.Close()
|
||||
|
||||
if global.CONF.System.IsDemo {
|
||||
if wshandleError(wsConn, errors.New(" demo server, prohibit this operation!")) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
|
||||
if wshandleError(wsConn, errors.WithMessage(err, "invalid param cols in request")) {
|
||||
@@ -95,38 +87,22 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
||||
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
|
||||
return
|
||||
}
|
||||
name := c.Query("name")
|
||||
from := c.Query("from")
|
||||
commands := []string{"redis-cli"}
|
||||
database, err := databaseService.Get(name)
|
||||
if wshandleError(wsConn, errors.WithMessage(err, "no such database in db")) {
|
||||
redisConf, err := redisService.LoadConf()
|
||||
if wshandleError(wsConn, errors.WithMessage(err, "load redis container failed")) {
|
||||
return
|
||||
}
|
||||
if from == "local" {
|
||||
redisInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: name, Type: "redis"})
|
||||
if wshandleError(wsConn, errors.WithMessage(err, "no such database in db")) {
|
||||
return
|
||||
}
|
||||
name = redisInfo.ContainerName
|
||||
if len(database.Password) != 0 {
|
||||
commands = []string{"redis-cli", "-a", database.Password, "--no-auth-warning"}
|
||||
}
|
||||
} else {
|
||||
itemPort := fmt.Sprintf("%v", database.Port)
|
||||
commands = []string{"redis-cli", "-h", database.Address, "-p", itemPort}
|
||||
if len(database.Password) != 0 {
|
||||
commands = []string{"redis-cli", "-h", database.Address, "-p", itemPort, "-a", database.Password, "--no-auth-warning"}
|
||||
}
|
||||
name = "1Panel-redis-cli-tools"
|
||||
}
|
||||
|
||||
pidMap := loadMapFromDockerTop(name)
|
||||
itemCmds := append([]string{"exec", "-it", name}, commands...)
|
||||
slave, err := terminal.NewCommand(itemCmds)
|
||||
defer wsConn.Close()
|
||||
commands := "redis-cli"
|
||||
if len(redisConf.Requirepass) != 0 {
|
||||
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass)
|
||||
}
|
||||
pidMap := loadMapFromDockerTop(redisConf.ContainerName)
|
||||
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(name, strings.Join(commands, " "), pidMap)
|
||||
defer killBash(redisConf.ContainerName, pidMap)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
|
||||
@@ -154,12 +130,6 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
||||
}
|
||||
defer wsConn.Close()
|
||||
|
||||
if global.CONF.System.IsDemo {
|
||||
if wshandleError(wsConn, errors.New(" demo server, prohibit this operation!")) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
containerID := c.Query("containerid")
|
||||
command := c.Query("command")
|
||||
user := c.Query("user")
|
||||
@@ -191,16 +161,16 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
commands := []string{"exec", "-it", containerID, command}
|
||||
commands := fmt.Sprintf("docker exec -it %s %s", containerID, command)
|
||||
if len(user) != 0 {
|
||||
commands = []string{"exec", "-it", "-u", user, containerID, command}
|
||||
commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command)
|
||||
}
|
||||
pidMap := loadMapFromDockerTop(containerID)
|
||||
slave, err := terminal.NewCommand(commands)
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(containerID, command, pidMap)
|
||||
defer killBash(containerID, pidMap)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, true)
|
||||
@@ -251,26 +221,26 @@ func loadMapFromDockerTop(containerID string) map[string]string {
|
||||
lines := strings.Split(stdout, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
if len(parts) == 0 {
|
||||
continue
|
||||
}
|
||||
pidMap[parts[0]] = strings.Join(parts[1:], " ")
|
||||
pidMap[parts[0]] = strings.Join(parts, " ")
|
||||
}
|
||||
return pidMap
|
||||
}
|
||||
|
||||
func killBash(containerID, comm string, pidMap map[string]string) {
|
||||
func killBash(containerID string, pidMap map[string]string) {
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
newPidMap := loadMapFromDockerTop(containerID)
|
||||
for pid, command := range newPidMap {
|
||||
for pid, newCmd := range newPidMap {
|
||||
isOld := false
|
||||
for pid2 := range pidMap {
|
||||
if pid == pid2 {
|
||||
for pid2, oldCmd := range pidMap {
|
||||
if pid == pid2 && oldCmd == newCmd {
|
||||
isOld = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isOld && command == comm {
|
||||
if !isOld {
|
||||
_, _ = cmd.Execf("%s kill -9 %s", sudo, pid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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/app/dto/request"
|
||||
@@ -78,14 +76,6 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if len(req.FtpPassword) != 0 {
|
||||
pass, err := base64.StdEncoding.DecodeString(req.FtpPassword)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.FtpPassword = string(pass)
|
||||
}
|
||||
err := websiteService.CreateWebsite(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
|
||||
@@ -37,9 +37,8 @@ type AppOssConfig struct {
|
||||
}
|
||||
|
||||
type AppVersion struct {
|
||||
Version string `json:"version"`
|
||||
DetailId uint `json:"detailId"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
Version string `json:"version"`
|
||||
DetailId uint `json:"detailId"`
|
||||
}
|
||||
|
||||
type AppList struct {
|
||||
|
||||
@@ -35,7 +35,6 @@ type CommonBackup struct {
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
type CommonRecover struct {
|
||||
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive WebDAV"`
|
||||
@@ -43,7 +42,6 @@ type CommonRecover struct {
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
File string `json:"file"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type RecordSearch struct {
|
||||
|
||||
@@ -30,9 +30,3 @@ type CommandTree struct {
|
||||
Label string `json:"label"`
|
||||
Children []CommandInfo `json:"children"`
|
||||
}
|
||||
|
||||
type RedisCommand struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Command string `json:"command"`
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ type ContainerRename struct {
|
||||
}
|
||||
|
||||
type ContainerPrune struct {
|
||||
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network buildcache"`
|
||||
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network"`
|
||||
WithTagAll bool `json:"withTagAll"`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
import "time"
|
||||
|
||||
type CronjobCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
@@ -23,7 +21,6 @@ type CronjobCreate struct {
|
||||
BackupAccounts string `json:"backupAccounts"`
|
||||
DefaultDownload string `json:"defaultDownload"`
|
||||
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type CronjobUpdate struct {
|
||||
@@ -45,7 +42,6 @@ type CronjobUpdate struct {
|
||||
BackupAccounts string `json:"backupAccounts"`
|
||||
DefaultDownload string `json:"defaultDownload"`
|
||||
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type CronjobUpdateStatus struct {
|
||||
@@ -91,7 +87,6 @@ type CronjobInfo struct {
|
||||
|
||||
LastRecordTime string `json:"lastRecordTime"`
|
||||
Status string `json:"status"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type SearchRecord struct {
|
||||
@@ -103,12 +98,12 @@ type SearchRecord struct {
|
||||
}
|
||||
|
||||
type Record struct {
|
||||
ID uint `json:"id"`
|
||||
StartTime string `json:"startTime"`
|
||||
Records string `json:"records"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
TargetPath string `json:"targetPath"`
|
||||
Interval int `json:"interval"`
|
||||
File string `json:"file"`
|
||||
ID uint `json:"id"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
Records string `json:"records"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
TargetPath string `json:"targetPath"`
|
||||
Interval int `json:"interval"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ type MysqlStatus struct {
|
||||
}
|
||||
|
||||
type MysqlVariables struct {
|
||||
BinlogCacheSize string `json:"binlog_cache_size"`
|
||||
BinlogCacheSize string `json:"binlog_cache_size"`
|
||||
InnodbBufferPoolSize string `json:"innodb_buffer_pool_size"`
|
||||
InnodbLogBufferSize string `json:"innodb_log_buffer_size"`
|
||||
JoinBufferSize string `json:"join_buffer_size"`
|
||||
@@ -165,26 +165,26 @@ type MysqlVariablesUpdateHelper struct {
|
||||
|
||||
// redis
|
||||
type ChangeRedisPass struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
Value string `json:"value"`
|
||||
Value string `json:"value" validate:"required"`
|
||||
}
|
||||
|
||||
type RedisConfUpdate struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
Timeout string `json:"timeout"`
|
||||
Maxclients string `json:"maxclients"`
|
||||
Maxmemory string `json:"maxmemory"`
|
||||
}
|
||||
type RedisConfPersistenceUpdate struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=aof rbd"`
|
||||
Appendonly string `json:"appendonly"`
|
||||
Appendfsync string `json:"appendfsync"`
|
||||
Save string `json:"save"`
|
||||
}
|
||||
type RedisConfUpdateByFile struct {
|
||||
File string `json:"file" validate:"required"`
|
||||
RestartNow bool `json:"restartNow"`
|
||||
}
|
||||
|
||||
type RedisConf struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
Name string `json:"name"`
|
||||
Port int64 `json:"port"`
|
||||
ContainerName string `json:"containerName"`
|
||||
@@ -195,14 +195,12 @@ type RedisConf struct {
|
||||
}
|
||||
|
||||
type RedisPersistence struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
Appendonly string `json:"appendonly"`
|
||||
Appendfsync string `json:"appendfsync"`
|
||||
Save string `json:"save"`
|
||||
}
|
||||
|
||||
type RedisStatus struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
TcpPort string `json:"tcp_port"`
|
||||
UptimeInDays string `json:"uptime_in_days"`
|
||||
ConnectedClients string `json:"connected_clients"`
|
||||
@@ -219,14 +217,12 @@ type RedisStatus struct {
|
||||
}
|
||||
|
||||
type DatabaseFileRecords struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
FileName string `json:"fileName"`
|
||||
FileDir string `json:"fileDir"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
type RedisBackupRecover struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
FileName string `json:"fileName"`
|
||||
FileDir string `json:"fileDir"`
|
||||
}
|
||||
@@ -285,7 +281,7 @@ type DatabaseCreate struct {
|
||||
Address string `json:"address"`
|
||||
Port uint `json:"port"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
|
||||
SSL bool `json:"ssl"`
|
||||
RootCert string `json:"rootCert"`
|
||||
@@ -303,7 +299,7 @@ type DatabaseUpdate struct {
|
||||
Address string `json:"address"`
|
||||
Port uint `json:"port"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
|
||||
SSL bool `json:"ssl"`
|
||||
RootCert string `json:"rootCert"`
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type FtpInfo struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Path string `json:"path"`
|
||||
Status string `json:"status"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type FtpBaseInfo struct {
|
||||
IsActive bool `json:"isActive"`
|
||||
IsExist bool `json:"isExist"`
|
||||
}
|
||||
|
||||
type FtpLogSearch struct {
|
||||
PageInfo
|
||||
User string `json:"user"`
|
||||
Operation string `json:"operation"`
|
||||
}
|
||||
|
||||
type FtpCreate struct {
|
||||
User string `json:"user" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type FtpUpdate struct {
|
||||
ID uint `json:"id"`
|
||||
|
||||
Password string `json:"password" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
Status string `json:"status"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
@@ -43,7 +43,6 @@ type AppInstalledSearch struct {
|
||||
Update bool `json:"update"`
|
||||
Unused bool `json:"unused"`
|
||||
All bool `json:"all"`
|
||||
Sync bool `json:"sync"`
|
||||
}
|
||||
|
||||
type AppInstalledInfo struct {
|
||||
@@ -61,24 +60,15 @@ type AppBackupDelete struct {
|
||||
}
|
||||
|
||||
type AppInstalledOperate struct {
|
||||
InstallId uint `json:"installId" validate:"required"`
|
||||
BackupId uint `json:"backupId"`
|
||||
DetailId uint `json:"detailId"`
|
||||
Operate constant.AppOperate `json:"operate" validate:"required"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
DeleteDB bool `json:"deleteDB"`
|
||||
Backup bool `json:"backup"`
|
||||
PullImage bool `json:"pullImage"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
}
|
||||
|
||||
type AppInstallUpgrade struct {
|
||||
InstallID uint `json:"installId"`
|
||||
DetailID uint `json:"detailId"`
|
||||
Backup bool `json:"backup"`
|
||||
PullImage bool `json:"pullImage"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
InstallId uint `json:"installId" validate:"required"`
|
||||
BackupId uint `json:"backupId"`
|
||||
DetailId uint `json:"detailId"`
|
||||
Operate constant.AppOperate `json:"operate" validate:"required"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
DeleteDB bool `json:"deleteDB"`
|
||||
Backup bool `json:"backup"`
|
||||
PullImage bool `json:"pullImage"`
|
||||
}
|
||||
|
||||
type AppInstalledUpdate struct {
|
||||
@@ -97,8 +87,3 @@ type PortUpdate struct {
|
||||
Name string `json:"name"`
|
||||
Port int64 `json:"port"`
|
||||
}
|
||||
|
||||
type AppUpdateVersion struct {
|
||||
AppInstallID uint `json:"appInstallID" validate:"required"`
|
||||
UpdateVersion string `json:"updateVersion"`
|
||||
}
|
||||
|
||||
@@ -54,14 +54,12 @@ type FileCompress struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Replace bool `json:"replace"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type FileDeCompress struct {
|
||||
Dst string `json:"dst" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
Secret string `json:"secret"`
|
||||
Dst string `json:"dst" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
}
|
||||
|
||||
type FileEdit struct {
|
||||
|
||||
@@ -27,7 +27,7 @@ type NginxRewriteReq struct {
|
||||
type NginxRewriteUpdate struct {
|
||||
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Content string `json:"content"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
}
|
||||
|
||||
type NginxProxyUpdate struct {
|
||||
|
||||
@@ -27,9 +27,6 @@ type WebsiteCreate struct {
|
||||
AppID uint `json:"appID"`
|
||||
AppInstallID uint `json:"appInstallID"`
|
||||
|
||||
FtpUser string `json:"ftpUser"`
|
||||
FtpPassword string `json:"ftpPassword"`
|
||||
|
||||
RuntimeID uint `json:"runtimeID"`
|
||||
RuntimeConfig
|
||||
}
|
||||
|
||||
@@ -20,10 +20,6 @@ type WebsiteSSLCreate struct {
|
||||
Dir string `json:"dir"`
|
||||
ID uint `json:"id"`
|
||||
Description string `json:"description"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
}
|
||||
|
||||
type WebsiteDNSReq struct {
|
||||
@@ -36,9 +32,8 @@ type WebsiteSSLRenew struct {
|
||||
}
|
||||
|
||||
type WebsiteSSLApply struct {
|
||||
ID uint `json:"ID" validate:"required"`
|
||||
SkipDNSCheck bool `json:"skipDNSCheck"`
|
||||
Nameservers []string `json:"nameservers"`
|
||||
ID uint `json:"ID" validate:"required"`
|
||||
SkipDNSCheck bool `json:"SkipDNSCheck"`
|
||||
}
|
||||
|
||||
type WebsiteAcmeAccountCreate struct {
|
||||
@@ -71,22 +66,9 @@ type WebsiteBatchDelReq struct {
|
||||
}
|
||||
|
||||
type WebsiteSSLUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
Description string `json:"description"`
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
OtherDomains string `json:"otherDomains"`
|
||||
Provider string `json:"provider" validate:"required"`
|
||||
AcmeAccountID uint `json:"acmeAccountId"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
KeyType string `json:"keyType"`
|
||||
Apply bool `json:"apply"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type WebsiteSSLUpload struct {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
type AppRes struct {
|
||||
Items []*AppDto `json:"items"`
|
||||
Items []*AppDTO `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
@@ -28,22 +28,6 @@ type AppDTO struct {
|
||||
Tags []model.Tag `json:"tags"`
|
||||
}
|
||||
|
||||
type AppDto struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
ID uint `json:"id"`
|
||||
ShortDescZh string `json:"shortDescZh"`
|
||||
ShortDescEn string `json:"shortDescEn"`
|
||||
Icon string `json:"icon"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Resource string `json:"resource"`
|
||||
Installed bool `json:"installed"`
|
||||
Versions []string `json:"versions"`
|
||||
Limit int `json:"limit"`
|
||||
Tags []model.Tag `json:"tags"`
|
||||
}
|
||||
|
||||
type TagDTO struct {
|
||||
model.Tag
|
||||
}
|
||||
@@ -88,38 +72,7 @@ type AppInstalledDTO struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type AppDetail struct {
|
||||
Website string `json:"website"`
|
||||
Document string `json:"document"`
|
||||
Github string `json:"github"`
|
||||
}
|
||||
|
||||
type AppInstallDTO struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
AppID uint `json:"appID"`
|
||||
AppDetailID uint `json:"appDetailID"`
|
||||
Version string `json:"version"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
HttpPort int `json:"httpPort"`
|
||||
HttpsPort int `json:"httpsPort"`
|
||||
Path string `json:"path"`
|
||||
CanUpdate bool `json:"canUpdate"`
|
||||
Icon string `json:"icon"`
|
||||
AppName string `json:"appName"`
|
||||
Ready int `json:"ready"`
|
||||
Total int `json:"total"`
|
||||
AppKey string `json:"appKey"`
|
||||
AppType string `json:"appType"`
|
||||
AppStatus string `json:"appStatus"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
App AppDetail `json:"app"`
|
||||
}
|
||||
|
||||
type DatabaseConn struct {
|
||||
Status string `json:"status"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
ContainerName string `json:"containerName"`
|
||||
|
||||
@@ -8,7 +8,6 @@ type SettingInfo struct {
|
||||
SystemIP string `json:"systemIP"`
|
||||
SystemVersion string `json:"systemVersion"`
|
||||
DockerSockPath string `json:"dockerSockPath"`
|
||||
DeveloperMode string `json:"developerMode"`
|
||||
|
||||
SessionTimeout string `json:"sessionTimeout"`
|
||||
LocalTime string `json:"localTime"`
|
||||
@@ -58,13 +57,6 @@ type SettingInfo struct {
|
||||
SnapshotIgnore string `json:"snapshotIgnore"`
|
||||
XpackHideMenu string `json:"xpackHideMenu"`
|
||||
NoAuthSetting string `json:"noAuthSetting"`
|
||||
|
||||
ProxyUrl string `json:"proxyUrl"`
|
||||
ProxyType string `json:"proxyType"`
|
||||
ProxyPort string `json:"proxyPort"`
|
||||
ProxyUser string `json:"proxyUser"`
|
||||
ProxyPasswd string `json:"proxyPasswd"`
|
||||
ProxyPasswdKeep string `json:"proxyPasswdKeep"`
|
||||
}
|
||||
|
||||
type SettingUpdate struct {
|
||||
@@ -116,17 +108,11 @@ type SnapshotCreate struct {
|
||||
From string `json:"from" validate:"required"`
|
||||
DefaultDownload string `json:"defaultDownload" validate:"required"`
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
type SnapshotRecover struct {
|
||||
IsNew bool `json:"isNew"`
|
||||
ReDownload bool `json:"reDownload"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
type SnapshotBatchDelete struct {
|
||||
DeleteWithFile bool `json:"deleteWithFile"`
|
||||
Ids []uint `json:"ids" validate:"required"`
|
||||
IsNew bool `json:"isNew"`
|
||||
ReDownload bool `json:"reDownload"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
type SnapshotImport struct {
|
||||
From string `json:"from"`
|
||||
@@ -154,7 +140,6 @@ type SnapshotInfo struct {
|
||||
}
|
||||
|
||||
type UpgradeInfo struct {
|
||||
TestVersion string `json:"testVersion"`
|
||||
NewVersion string `json:"newVersion"`
|
||||
LatestVersion string `json:"latestVersion"`
|
||||
ReleaseNote string `json:"releaseNote"`
|
||||
@@ -173,21 +158,11 @@ type Upgrade struct {
|
||||
Version string `json:"version" validate:"required"`
|
||||
}
|
||||
|
||||
type ProxyUpdate struct {
|
||||
ProxyUrl string `json:"proxyUrl"`
|
||||
ProxyType string `json:"proxyType"`
|
||||
ProxyPort string `json:"proxyPort"`
|
||||
ProxyUser string `json:"proxyUser"`
|
||||
ProxyPasswd string `json:"proxyPasswd"`
|
||||
ProxyPasswdKeep string `json:"proxyPasswdKeep"`
|
||||
}
|
||||
|
||||
type CleanData struct {
|
||||
SystemClean []CleanTree `json:"systemClean"`
|
||||
UploadClean []CleanTree `json:"uploadClean"`
|
||||
DownloadClean []CleanTree `json:"downloadClean"`
|
||||
SystemLogClean []CleanTree `json:"systemLogClean"`
|
||||
ContainerClean []CleanTree `json:"containerClean"`
|
||||
}
|
||||
|
||||
type CleanTree struct {
|
||||
@@ -208,12 +183,3 @@ type Clean struct {
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"`
|
||||
}
|
||||
|
||||
type XpackHideMenu struct {
|
||||
ID string `json:"id"`
|
||||
Label string `json:"label"`
|
||||
IsCheck bool `json:"isCheck"`
|
||||
Title string `json:"title"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Children []XpackHideMenu `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type App struct {
|
||||
Type string `json:"type" gorm:"type:varchar(64);not null"`
|
||||
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
||||
Required string `json:"required" gorm:"type:varchar(64);"`
|
||||
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
|
||||
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
||||
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
||||
Website string `json:"website" gorm:"type:varchar(64);not null"`
|
||||
Github string `json:"github" gorm:"type:varchar(64);not null"`
|
||||
|
||||
@@ -6,9 +6,3 @@ type Command struct {
|
||||
GroupID uint `gorm:"type:decimal" json:"groupID"`
|
||||
Command string `gorm:"type:varchar(256);not null" json:"command"`
|
||||
}
|
||||
|
||||
type RedisCommand struct {
|
||||
BaseModel
|
||||
Name string `gorm:"type:varchar(64);unique;not null" json:"name"`
|
||||
Command string `gorm:"type:varchar(256);not null" json:"command"`
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
import "time"
|
||||
|
||||
type Cronjob struct {
|
||||
BaseModel
|
||||
@@ -33,7 +31,6 @@ type Cronjob struct {
|
||||
Status string `gorm:"type:varchar(64)" json:"status"`
|
||||
EntryIDs string `gorm:"type:varchar(64)" json:"entryIDs"`
|
||||
Records []JobRecords `json:"records"`
|
||||
Secret string `gorm:"type:varchar(64)" json:"secret"`
|
||||
}
|
||||
|
||||
type JobRecords struct {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package model
|
||||
|
||||
type Ftp struct {
|
||||
BaseModel
|
||||
|
||||
User string `gorm:"type:varchar(64);not null" json:"user"`
|
||||
Password string `gorm:"type:varchar(64);not null" json:"password"`
|
||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
||||
Path string `gorm:"type:varchar(64);not null" json:"path"`
|
||||
Description string `gorm:"type:varchar(64);not null" json:"description"`
|
||||
}
|
||||
@@ -26,7 +26,6 @@ type Website struct {
|
||||
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
||||
RuntimeID uint `gorm:"type:integer" json:"runtimeID"`
|
||||
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
||||
FtpID uint `gorm:"type:integer" json:"ftpId"`
|
||||
|
||||
User string `gorm:"type:varchar;" json:"user"`
|
||||
Group string `gorm:"type:varchar;" json:"group"`
|
||||
|
||||
@@ -9,30 +9,26 @@ import (
|
||||
|
||||
type WebsiteSSL struct {
|
||||
BaseModel
|
||||
PrimaryDomain string `json:"primaryDomain"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Pem string `json:"pem"`
|
||||
Domains string `json:"domains"`
|
||||
CertURL string `json:"certURL"`
|
||||
Type string `json:"type"`
|
||||
Provider string `json:"provider"`
|
||||
Organization string `json:"organization"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"column:acme_account_id" json:"acmeAccountId" `
|
||||
CaID uint `json:"caId"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
|
||||
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
||||
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
||||
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
|
||||
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
|
||||
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
|
||||
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
|
||||
CaID uint `gorm:"type:integer;not null;default:0" json:"caId"`
|
||||
AutoRenew bool `gorm:"type:varchar(64);not null" json:"autoRenew"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
StartDate time.Time `json:"startDate"`
|
||||
Status string `json:"status"`
|
||||
Status string `gorm:"not null;default:ready" json:"status"`
|
||||
Message string `json:"message"`
|
||||
KeyType string `json:"keyType"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
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"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
|
||||
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
|
||||
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
|
||||
|
||||
@@ -3,7 +3,6 @@ package repo
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
@@ -161,7 +160,6 @@ func (a *AppInstallRepo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOp
|
||||
type RootInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Port int64 `json:"port"`
|
||||
HttpsPort int64 `json:"httpsPort"`
|
||||
UserName string `json:"userName"`
|
||||
@@ -236,6 +234,5 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
||||
info.Key = app.Key
|
||||
appInstall.App = app
|
||||
info.AppPath = appInstall.GetAppPath()
|
||||
info.Status = appInstall.Status
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
@@ -17,12 +17,6 @@ type ICommandRepo interface {
|
||||
Delete(opts ...DBOption) error
|
||||
Get(opts ...DBOption) (model.Command, error)
|
||||
WithLikeName(name string) DBOption
|
||||
|
||||
PageRedis(limit, offset int, opts ...DBOption) (int64, []model.RedisCommand, error)
|
||||
GetRedis(opts ...DBOption) (model.RedisCommand, error)
|
||||
GetRedisList(opts ...DBOption) ([]model.RedisCommand, error)
|
||||
SaveRedis(command *model.RedisCommand) error
|
||||
DeleteRedis(opts ...DBOption) error
|
||||
}
|
||||
|
||||
func NewICommandRepo() ICommandRepo {
|
||||
@@ -39,16 +33,6 @@ func (u *CommandRepo) Get(opts ...DBOption) (model.Command, error) {
|
||||
return command, err
|
||||
}
|
||||
|
||||
func (u *CommandRepo) GetRedis(opts ...DBOption) (model.RedisCommand, error) {
|
||||
var command model.RedisCommand
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.First(&command).Error
|
||||
return command, err
|
||||
}
|
||||
|
||||
func (u *CommandRepo) Page(page, size int, opts ...DBOption) (int64, []model.Command, error) {
|
||||
var users []model.Command
|
||||
db := global.DB.Model(&model.Command{})
|
||||
@@ -61,18 +45,6 @@ func (u *CommandRepo) Page(page, size int, opts ...DBOption) (int64, []model.Com
|
||||
return count, users, err
|
||||
}
|
||||
|
||||
func (u *CommandRepo) PageRedis(page, size int, opts ...DBOption) (int64, []model.RedisCommand, error) {
|
||||
var users []model.RedisCommand
|
||||
db := global.DB.Model(&model.RedisCommand{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
|
||||
return count, users, err
|
||||
}
|
||||
|
||||
func (u *CommandRepo) GetList(opts ...DBOption) ([]model.Command, error) {
|
||||
var commands []model.Command
|
||||
db := global.DB.Model(&model.Command{})
|
||||
@@ -83,16 +55,6 @@ func (u *CommandRepo) GetList(opts ...DBOption) ([]model.Command, error) {
|
||||
return commands, err
|
||||
}
|
||||
|
||||
func (u *CommandRepo) GetRedisList(opts ...DBOption) ([]model.RedisCommand, error) {
|
||||
var commands []model.RedisCommand
|
||||
db := global.DB.Model(&model.RedisCommand{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.Find(&commands).Error
|
||||
return commands, err
|
||||
}
|
||||
|
||||
func (c *CommandRepo) WithByInfo(info string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if len(info) == 0 {
|
||||
@@ -107,10 +69,6 @@ func (u *CommandRepo) Create(command *model.Command) error {
|
||||
return global.DB.Create(command).Error
|
||||
}
|
||||
|
||||
func (u *CommandRepo) SaveRedis(command *model.RedisCommand) error {
|
||||
return global.DB.Save(command).Error
|
||||
}
|
||||
|
||||
func (u *CommandRepo) Update(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.Command{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
@@ -123,14 +81,6 @@ func (u *CommandRepo) Delete(opts ...DBOption) error {
|
||||
return db.Delete(&model.Command{}).Error
|
||||
}
|
||||
|
||||
func (u *CommandRepo) DeleteRedis(opts ...DBOption) error {
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
return db.Delete(&model.RedisCommand{}).Error
|
||||
}
|
||||
|
||||
func (a CommandRepo) WithLikeName(name string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if len(name) == 0 {
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type FtpRepo struct{}
|
||||
|
||||
type IFtpRepo interface {
|
||||
Get(opts ...DBOption) (model.Ftp, error)
|
||||
GetList(opts ...DBOption) ([]model.Ftp, error)
|
||||
Page(limit, offset int, opts ...DBOption) (int64, []model.Ftp, error)
|
||||
Create(ftp *model.Ftp) error
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
Delete(opts ...DBOption) error
|
||||
WithByUser(user string) DBOption
|
||||
}
|
||||
|
||||
func NewIFtpRepo() IFtpRepo {
|
||||
return &FtpRepo{}
|
||||
}
|
||||
|
||||
func (u *FtpRepo) Get(opts ...DBOption) (model.Ftp, error) {
|
||||
var ftp model.Ftp
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.First(&ftp).Error
|
||||
return ftp, err
|
||||
}
|
||||
|
||||
func (h *FtpRepo) WithByUser(user string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if len(user) == 0 {
|
||||
return g
|
||||
}
|
||||
return g.Where("user like ?", "%"+user+"%")
|
||||
}
|
||||
}
|
||||
|
||||
func (u *FtpRepo) GetList(opts ...DBOption) ([]model.Ftp, error) {
|
||||
var ftps []model.Ftp
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.Find(&ftps).Error
|
||||
return ftps, err
|
||||
}
|
||||
|
||||
func (h *FtpRepo) Page(page, size int, opts ...DBOption) (int64, []model.Ftp, error) {
|
||||
var users []model.Ftp
|
||||
db := global.DB.Model(&model.Ftp{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
|
||||
return count, users, err
|
||||
}
|
||||
|
||||
func (h *FtpRepo) Create(ftp *model.Ftp) error {
|
||||
return global.DB.Create(ftp).Error
|
||||
}
|
||||
|
||||
func (h *FtpRepo) Update(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.Ftp{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
|
||||
func (h *FtpRepo) Delete(opts ...DBOption) error {
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
return db.Delete(&model.Ftp{}).Error
|
||||
}
|
||||
@@ -21,7 +21,6 @@ type ISSLRepo interface {
|
||||
Create(ctx context.Context, ssl *model.WebsiteSSL) error
|
||||
Save(ssl *model.WebsiteSSL) error
|
||||
DeleteBy(opts ...DBOption) error
|
||||
SaveByMap(ssl *model.WebsiteSSL, params map[string]interface{}) error
|
||||
}
|
||||
|
||||
type WebsiteSSLRepo struct {
|
||||
@@ -83,15 +82,7 @@ func (w WebsiteSSLRepo) Create(ctx context.Context, ssl *model.WebsiteSSL) error
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) Save(ssl *model.WebsiteSSL) error {
|
||||
return getDb().Model(&model.WebsiteSSL{BaseModel: model.BaseModel{
|
||||
ID: ssl.ID,
|
||||
}}).Save(&ssl).Error
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) SaveByMap(ssl *model.WebsiteSSL, params map[string]interface{}) error {
|
||||
return getDb().Model(&model.WebsiteSSL{BaseModel: model.BaseModel{
|
||||
ID: ssl.ID,
|
||||
}}).Updates(params).Error
|
||||
return getDb().Save(&ssl).Error
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) DeleteBy(opts ...DBOption) error {
|
||||
|
||||
+35
-48
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -25,8 +26,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
http2 "github.com/1Panel-dev/1Panel/backend/utils/http"
|
||||
httpUtil "github.com/1Panel-dev/1Panel/backend/utils/http"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@@ -89,22 +88,14 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var appDTOs []*response.AppDto
|
||||
var appDTOs []*response.AppDTO
|
||||
for _, ap := range apps {
|
||||
ap.ReadMe = ""
|
||||
ap.Website = ""
|
||||
ap.Document = ""
|
||||
ap.Github = ""
|
||||
appDTO := &response.AppDto{
|
||||
ID: ap.ID,
|
||||
Name: ap.Name,
|
||||
Key: ap.Key,
|
||||
Type: ap.Type,
|
||||
Icon: ap.Icon,
|
||||
ShortDescZh: ap.ShortDescZh,
|
||||
ShortDescEn: ap.ShortDescEn,
|
||||
Resource: ap.Resource,
|
||||
Limit: ap.Limit,
|
||||
appDTO := &response.AppDTO{
|
||||
App: ap,
|
||||
}
|
||||
appDTOs = append(appDTOs, appDTO)
|
||||
appTags, err := appTagRepo.GetByAppId(ap.ID)
|
||||
@@ -235,16 +226,20 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
|
||||
if appDetailDTO.DockerCompose == "" {
|
||||
filename := filepath.Base(appDetailDTO.DownloadUrl)
|
||||
dockerComposeUrl := fmt.Sprintf("%s%s", strings.TrimSuffix(appDetailDTO.DownloadUrl, filename), "docker-compose.yml")
|
||||
statusCode, composeRes, err := httpUtil.HandleGet(dockerComposeUrl, http.MethodGet, constant.TimeOut20s)
|
||||
composeRes, err := http.Get(dockerComposeUrl)
|
||||
if err != nil {
|
||||
return appDetailDTO, buserr.WithDetail("ErrGetCompose", err.Error(), err)
|
||||
}
|
||||
if statusCode > 200 {
|
||||
return appDetailDTO, buserr.WithDetail("ErrGetCompose", string(composeRes), err)
|
||||
bodyContent, err := io.ReadAll(composeRes.Body)
|
||||
if err != nil {
|
||||
return appDetailDTO, buserr.WithDetail("ErrGetCompose", err.Error(), err)
|
||||
}
|
||||
detail.DockerCompose = string(composeRes)
|
||||
if composeRes.StatusCode > 200 {
|
||||
return appDetailDTO, buserr.WithDetail("ErrGetCompose", string(bodyContent), err)
|
||||
}
|
||||
detail.DockerCompose = string(bodyContent)
|
||||
_ = appDetailRepo.Update(context.Background(), detail)
|
||||
appDetailDTO.DockerCompose = string(composeRes)
|
||||
appDetailDTO.DockerCompose = string(bodyContent)
|
||||
}
|
||||
|
||||
appDetailDTO.HostMode = isHostModel(appDetailDTO.DockerCompose)
|
||||
@@ -367,7 +362,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
}
|
||||
|
||||
value, ok := composeMap["services"]
|
||||
if !ok || value == nil {
|
||||
if !ok {
|
||||
err = buserr.New(constant.ErrFileParse)
|
||||
return
|
||||
}
|
||||
@@ -444,14 +439,6 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
return
|
||||
}
|
||||
appInstall.Env = string(paramByte)
|
||||
|
||||
containerNames, err := getContainerNames(*appInstall)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(containerNames) > 0 {
|
||||
appInstall.ContainerName = strings.Join(containerNames, ",")
|
||||
}
|
||||
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -461,7 +448,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
go func() {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
appInstall.Status = constant.UpErr
|
||||
appInstall.Status = constant.Error
|
||||
appInstall.Message = err.Error()
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
}
|
||||
@@ -711,11 +698,16 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||
}
|
||||
|
||||
versionUrl := fmt.Sprintf("%s/%s/1panel.json.version.txt", global.CONF.System.AppRepo, global.CONF.System.Mode)
|
||||
_, versionRes, err := http2.HandleGet(versionUrl, http.MethodGet, constant.TimeOut20s)
|
||||
versionRes, err := http2.GetHttpRes(versionUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lastModifiedStr := string(versionRes)
|
||||
defer versionRes.Body.Close()
|
||||
body, err := io.ReadAll(versionRes.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lastModifiedStr := string(body)
|
||||
lastModified, err := strconv.Atoi(lastModifiedStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -735,14 +727,6 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||
res.CanUpdate = true
|
||||
return res, err
|
||||
}
|
||||
apps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
|
||||
for _, app := range apps {
|
||||
if app.Icon == "" {
|
||||
res.CanUpdate = true
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
list, err := getAppList()
|
||||
if err != nil {
|
||||
return res, err
|
||||
@@ -760,10 +744,10 @@ func getAppFromRepo(downloadPath string) error {
|
||||
global.LOG.Infof("[AppStore] download file from %s", downloadUrl)
|
||||
fileOp := files.NewFileOp()
|
||||
packagePath := filepath.Join(constant.ResourceDir, filepath.Base(downloadUrl))
|
||||
if err := fileOp.DownloadFileWithProxy(downloadUrl, packagePath); err != nil {
|
||||
if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.SdkZip, ""); err != nil {
|
||||
if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.SdkZip); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
@@ -841,22 +825,21 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
||||
oldAppIds = append(oldAppIds, old.ID)
|
||||
}
|
||||
|
||||
transport := xpack.LoadRequestTransport()
|
||||
baseRemoteUrl := fmt.Sprintf("%s/%s/1panel", global.CONF.System.AppRepo, global.CONF.System.Mode)
|
||||
appsMap := getApps(oldApps, list.Apps)
|
||||
|
||||
global.LOG.Infof("Starting synchronization of application details...")
|
||||
for _, l := range list.Apps {
|
||||
app := appsMap[l.AppProperty.Key]
|
||||
_, iconRes, err := httpUtil.HandleGetWithTransport(l.Icon, http.MethodGet, transport, constant.TimeOut20s)
|
||||
iconRes, err := http.Get(l.Icon)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
iconStr := ""
|
||||
if !strings.Contains(string(iconRes), "<xml>") {
|
||||
iconStr = base64.StdEncoding.EncodeToString(iconRes)
|
||||
body, err := io.ReadAll(iconRes.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iconStr := base64.StdEncoding.EncodeToString(body)
|
||||
app.Icon = iconStr
|
||||
app.TagsKey = l.AppProperty.Tags
|
||||
if l.AppProperty.Recommend > 0 {
|
||||
@@ -875,11 +858,15 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
||||
|
||||
if _, ok := InitTypes[app.Type]; ok {
|
||||
dockerComposeUrl := fmt.Sprintf("%s/%s", versionUrl, "docker-compose.yml")
|
||||
_, composeRes, err := httpUtil.HandleGetWithTransport(dockerComposeUrl, http.MethodGet, transport, constant.TimeOut20s)
|
||||
composeRes, err := http.Get(dockerComposeUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
detail.DockerCompose = string(composeRes)
|
||||
bodyContent, err := io.ReadAll(composeRes.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
detail.DockerCompose = string(bodyContent)
|
||||
} else {
|
||||
detail.DockerCompose = ""
|
||||
}
|
||||
|
||||
@@ -5,18 +5,14 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
httpUtil "github.com/1Panel-dev/1Panel/backend/utils/http"
|
||||
"github.com/docker/docker/api/types"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/env"
|
||||
@@ -43,17 +39,17 @@ type AppInstallService struct {
|
||||
}
|
||||
|
||||
type IAppInstallService interface {
|
||||
Page(req request.AppInstalledSearch) (int64, []response.AppInstallDTO, error)
|
||||
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
|
||||
CheckExist(req request.AppInstalledInfo) (*response.AppInstalledCheck, error)
|
||||
LoadPort(req dto.OperationWithNameAndType) (int64, error)
|
||||
LoadConnInfo(req dto.OperationWithNameAndType) (response.DatabaseConn, error)
|
||||
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstallDTO, error)
|
||||
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
|
||||
Operate(req request.AppInstalledOperate) error
|
||||
Update(req request.AppInstalledUpdate) error
|
||||
IgnoreUpgrade(req request.AppInstalledIgnoreUpgrade) error
|
||||
SyncAll(systemInit bool) error
|
||||
GetServices(key string) ([]response.AppService, error)
|
||||
GetUpdateVersions(req request.AppUpdateVersion) ([]dto.AppVersion, error)
|
||||
GetUpdateVersions(installId uint) ([]dto.AppVersion, error)
|
||||
GetParams(id uint) (*response.AppConfig, error)
|
||||
ChangeAppPort(req request.PortUpdate) error
|
||||
GetDefaultConfigByKey(key, name string) (string, error)
|
||||
@@ -78,7 +74,7 @@ func (a *AppInstallService) GetInstallList() ([]dto.AppInstallInfo, error) {
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstallDTO, error) {
|
||||
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
total int64
|
||||
@@ -122,7 +118,7 @@ func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []respo
|
||||
}
|
||||
}
|
||||
|
||||
installDTOs, err := handleInstalled(installs, req.Update, req.Sync)
|
||||
installDTOs, err := handleInstalled(installs, req.Update)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
@@ -154,7 +150,7 @@ func (a *AppInstallService) CheckExist(req request.AppInstalledInfo) (*response.
|
||||
if reflect.DeepEqual(appInstall, model.AppInstall{}) {
|
||||
return res, nil
|
||||
}
|
||||
if err = syncAppInstallStatus(&appInstall, false); err != nil {
|
||||
if err = syncAppInstallStatus(&appInstall); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -186,7 +182,6 @@ func (a *AppInstallService) LoadConnInfo(req dto.OperationWithNameAndType) (resp
|
||||
if err != nil {
|
||||
return data, nil
|
||||
}
|
||||
data.Status = app.Status
|
||||
data.Username = app.UserName
|
||||
data.Password = app.Password
|
||||
data.ServiceName = app.ServiceName
|
||||
@@ -195,7 +190,7 @@ func (a *AppInstallService) LoadConnInfo(req dto.OperationWithNameAndType) (resp
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstallDTO, error) {
|
||||
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
||||
var (
|
||||
installs []model.AppInstall
|
||||
err error
|
||||
@@ -225,7 +220,7 @@ func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]
|
||||
}
|
||||
}
|
||||
|
||||
return handleInstalled(installs, false, true)
|
||||
return handleInstalled(installs, false)
|
||||
}
|
||||
|
||||
func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
@@ -245,35 +240,28 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
if err != nil {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
return syncAppInstallStatus(&install, false)
|
||||
return syncAppInstallStatus(&install)
|
||||
case constant.Stop:
|
||||
out, err := compose.Stop(dockerComposePath)
|
||||
if err != nil {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
return syncAppInstallStatus(&install, false)
|
||||
return syncAppInstallStatus(&install)
|
||||
case constant.Restart:
|
||||
out, err := compose.Restart(dockerComposePath)
|
||||
if err != nil {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
return syncAppInstallStatus(&install, false)
|
||||
return syncAppInstallStatus(&install)
|
||||
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, true)
|
||||
return syncAppInstallStatus(&install)
|
||||
case constant.Upgrade:
|
||||
upgradeReq := request.AppInstallUpgrade{
|
||||
InstallID: install.ID,
|
||||
DetailID: req.DetailId,
|
||||
Backup: req.Backup,
|
||||
PullImage: req.PullImage,
|
||||
DockerCompose: req.DockerCompose,
|
||||
}
|
||||
return upgradeInstall(upgradeReq)
|
||||
return upgradeInstall(install.ID, req.DetailId, req.Backup, req.PullImage)
|
||||
case constant.Reload:
|
||||
return opNginx(install.ContainerName, constant.NginxReload)
|
||||
default:
|
||||
@@ -432,7 +420,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
||||
continue
|
||||
}
|
||||
if !systemInit {
|
||||
if err = syncAppInstallStatus(&i, false); err != nil {
|
||||
if err = syncAppInstallStatus(&i); err != nil {
|
||||
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -495,8 +483,8 @@ func (a *AppInstallService) GetServices(key string) ([]response.AppService, erro
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) GetUpdateVersions(req request.AppUpdateVersion) ([]dto.AppVersion, error) {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.AppInstallID))
|
||||
func (a *AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion, error) {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||
var versions []dto.AppVersion
|
||||
if err != nil {
|
||||
return versions, err
|
||||
@@ -517,28 +505,9 @@ func (a *AppInstallService) GetUpdateVersions(req request.AppUpdateVersion) ([]d
|
||||
continue
|
||||
}
|
||||
if common.CompareVersion(detail.Version, install.Version) {
|
||||
var newCompose string
|
||||
if req.UpdateVersion != "" && req.UpdateVersion == detail.Version && detail.DockerCompose == "" && !app.IsLocalApp() {
|
||||
filename := filepath.Base(detail.DownloadUrl)
|
||||
dockerComposeUrl := fmt.Sprintf("%s%s", strings.TrimSuffix(detail.DownloadUrl, filename), "docker-compose.yml")
|
||||
statusCode, composeRes, err := httpUtil.HandleGet(dockerComposeUrl, http.MethodGet, constant.TimeOut20s)
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
if statusCode > 200 {
|
||||
return versions, err
|
||||
}
|
||||
detail.DockerCompose = string(composeRes)
|
||||
_ = appDetailRepo.Update(context.Background(), detail)
|
||||
}
|
||||
newCompose, err = getUpgradeCompose(install, detail)
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
versions = append(versions, dto.AppVersion{
|
||||
Version: detail.Version,
|
||||
DetailId: detail.ID,
|
||||
DockerCompose: newCompose,
|
||||
Version: detail.Version,
|
||||
DetailId: detail.ID,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -731,30 +700,81 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func syncAppInstallStatus(appInstall *model.AppInstall, force bool) error {
|
||||
func syncAppInstallStatus(appInstall *model.AppInstall) error {
|
||||
if appInstall.Status == constant.Installing || appInstall.Status == constant.Rebuilding || appInstall.Status == constant.Upgrading {
|
||||
return nil
|
||||
}
|
||||
containerNames, err := getContainerNames(*appInstall)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, err := docker.NewClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
var (
|
||||
containers []types.Container
|
||||
containersMap map[string]types.Container
|
||||
containerNames = strings.Split(appInstall.ContainerName, ",")
|
||||
)
|
||||
containers, err = cli.ListContainersByName(containerNames)
|
||||
containers, err := cli.ListContainersByName(containerNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containersMap = make(map[string]types.Container)
|
||||
|
||||
var (
|
||||
runningCount int
|
||||
exitedCount int
|
||||
pausedCount int
|
||||
exitedContainerNames []string
|
||||
total = len(containerNames)
|
||||
count = len(containers)
|
||||
)
|
||||
|
||||
foundNames := make(map[string]bool)
|
||||
for _, con := range containers {
|
||||
containersMap[con.Names[0]] = con
|
||||
foundNames[con.Names[0]] = true
|
||||
switch con.State {
|
||||
case "exited":
|
||||
exitedContainerNames = append(exitedContainerNames, strings.TrimPrefix(con.Names[0], "/"))
|
||||
exitedCount++
|
||||
case "running":
|
||||
runningCount++
|
||||
case "paused":
|
||||
pausedCount++
|
||||
}
|
||||
}
|
||||
synAppInstall(containersMap, appInstall, force)
|
||||
|
||||
var notFoundNames []string
|
||||
for _, name := range containerNames {
|
||||
if !foundNames["/"+name] {
|
||||
notFoundNames = append(notFoundNames, name)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case count == 0:
|
||||
if appInstall.Status != constant.Error {
|
||||
appInstall.Status = constant.SyncErr
|
||||
appInstall.Message = buserr.WithName("ErrContainerNotFound", strings.Join(containerNames, ",")).Error()
|
||||
}
|
||||
case exitedCount == total:
|
||||
appInstall.Status = constant.Stopped
|
||||
case runningCount == total:
|
||||
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
|
||||
appInstall.Status = constant.UnHealthy
|
||||
}
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+103
-272
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -14,13 +16,6 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
|
||||
httpUtil "github.com/1Panel-dev/1Panel/backend/utils/http"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
|
||||
@@ -42,7 +37,6 @@ import (
|
||||
"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/docker"
|
||||
composeV2 "github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
@@ -441,65 +435,12 @@ func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, f
|
||||
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
}
|
||||
|
||||
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
||||
if detail.DockerCompose == "" {
|
||||
return "", nil
|
||||
}
|
||||
composeMap := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
value, ok := composeMap["services"]
|
||||
if !ok || value == nil {
|
||||
return "", buserr.New(constant.ErrFileParse)
|
||||
}
|
||||
servicesMap := value.(map[string]interface{})
|
||||
if len(servicesMap) == 1 {
|
||||
index := 0
|
||||
oldServiceName := ""
|
||||
for k := range servicesMap {
|
||||
oldServiceName = k
|
||||
index++
|
||||
if index > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
servicesMap[install.ServiceName] = servicesMap[oldServiceName]
|
||||
if install.ServiceName != oldServiceName {
|
||||
delete(servicesMap, oldServiceName)
|
||||
}
|
||||
}
|
||||
envs := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(install.Env), &envs); err != nil {
|
||||
return "", err
|
||||
}
|
||||
config := getAppCommonConfig(envs)
|
||||
if config.ContainerName == "" {
|
||||
config.ContainerName = install.ContainerName
|
||||
envs[constant.ContainerName] = install.ContainerName
|
||||
}
|
||||
config.Advanced = true
|
||||
if err := addDockerComposeCommonParam(composeMap, install.ServiceName, config, envs); err != nil {
|
||||
return "", err
|
||||
}
|
||||
paramByte, err := json.Marshal(envs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
install.Env = string(paramByte)
|
||||
composeByte, err := yaml.Marshal(composeMap)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(composeByte), nil
|
||||
}
|
||||
|
||||
func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallID))
|
||||
func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
detail, err := appDetailRepo.GetFirst(commonRepo.WithByID(req.DetailID))
|
||||
detail, err := appDetailRepo.GetFirst(commonRepo.WithByID(detailID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -509,70 +450,43 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
install.Status = constant.Upgrading
|
||||
|
||||
go func() {
|
||||
var (
|
||||
upErr error
|
||||
backupFile string
|
||||
preErr error
|
||||
)
|
||||
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppStart", install.Name, nil))
|
||||
if req.Backup {
|
||||
backupRecord, err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name})
|
||||
if err == nil {
|
||||
localDir, err := loadLocalDir()
|
||||
if err == nil {
|
||||
backupFile = path.Join(localDir, backupRecord.FileDir, backupRecord.FileName)
|
||||
} else {
|
||||
global.LOG.Errorf(i18n.GetMsgWithName("ErrAppBackup", install.Name, err))
|
||||
}
|
||||
} else {
|
||||
global.LOG.Errorf(i18n.GetMsgWithName("ErrAppBackup", install.Name, err))
|
||||
if backup {
|
||||
if err = NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
|
||||
global.LOG.Errorf(i18n.GetMsgWithMap("ErrAppBackup", map[string]interface{}{"name": install.Name, "err": err.Error()}))
|
||||
}
|
||||
}
|
||||
var upErr error
|
||||
|
||||
defer func() {
|
||||
if upErr != nil {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("ErrAppUpgrade", install.Name, upErr))
|
||||
if req.Backup {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("AppRecover", install.Name, nil))
|
||||
if err := NewIBackupService().AppRecover(dto.CommonRecover{Name: install.App.Key, DetailName: install.Name, Type: "app", Source: constant.ResourceLocal, File: backupFile}); err != nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
existInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallID))
|
||||
if existInstall.ID > 0 {
|
||||
existInstall.Status = constant.UpgradeErr
|
||||
existInstall.Message = upErr.Error()
|
||||
_ = appInstallRepo.Save(context.Background(), &existInstall)
|
||||
}
|
||||
}
|
||||
if preErr != nil {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("ErrAppUpgrade", install.Name, preErr))
|
||||
existInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallID))
|
||||
if existInstall.ID > 0 {
|
||||
existInstall.Status = constant.UpgradeErr
|
||||
existInstall.Message = preErr.Error()
|
||||
_ = appInstallRepo.Save(context.Background(), &existInstall)
|
||||
}
|
||||
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 preErr = downloadApp(install.App, detail, &install); preErr != nil {
|
||||
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 {
|
||||
preErr = err
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
detail.DockerCompose = string(composeDetail)
|
||||
_ = appDetailRepo.Update(context.Background(), detail)
|
||||
}
|
||||
go func() {
|
||||
_, _, _ = httpUtil.HandleGet(detail.DownloadCallBackUrl, http.MethodGet, constant.TimeOut5s)
|
||||
_, _ = http.Get(detail.DownloadCallBackUrl)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -580,32 +494,6 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version)
|
||||
}
|
||||
|
||||
content, err := fileOp.GetContent(install.GetEnvPath())
|
||||
if err != nil {
|
||||
preErr = err
|
||||
return
|
||||
}
|
||||
if req.PullImage {
|
||||
projectName := strings.ToLower(install.Name)
|
||||
images, err := composeV2.GetDockerComposeImages(projectName, content, []byte(detail.DockerCompose))
|
||||
if err != nil {
|
||||
preErr = err
|
||||
return
|
||||
}
|
||||
for _, image := range images {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("PullImageStart", image, nil))
|
||||
if out, err := cmd.ExecWithTimeOut("docker pull "+image, 20*time.Minute); err != nil {
|
||||
if out != "" {
|
||||
err = errors.New(out)
|
||||
}
|
||||
preErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
|
||||
return
|
||||
} else {
|
||||
global.LOG.Infof(i18n.GetMsgByKey("PullImageSuccess"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
|
||||
stdout, _ := command.CombinedOutput()
|
||||
if stdout != nil {
|
||||
@@ -620,42 +508,100 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
_, _ = scriptCmd.CombinedOutput()
|
||||
}
|
||||
|
||||
var newCompose string
|
||||
if req.DockerCompose == "" {
|
||||
newCompose, upErr = getUpgradeCompose(install, detail)
|
||||
if upErr != nil {
|
||||
return
|
||||
composeMap := make(map[string]interface{})
|
||||
if upErr = yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); upErr != nil {
|
||||
return
|
||||
}
|
||||
value, ok := composeMap["services"]
|
||||
if !ok {
|
||||
upErr = buserr.New(constant.ErrFileParse)
|
||||
return
|
||||
}
|
||||
servicesMap := value.(map[string]interface{})
|
||||
if len(servicesMap) == 1 {
|
||||
index := 0
|
||||
oldServiceName := ""
|
||||
for k := range servicesMap {
|
||||
oldServiceName = k
|
||||
index++
|
||||
if index > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newCompose = req.DockerCompose
|
||||
servicesMap[install.ServiceName] = servicesMap[oldServiceName]
|
||||
if install.ServiceName != oldServiceName {
|
||||
delete(servicesMap, oldServiceName)
|
||||
}
|
||||
}
|
||||
envs := make(map[string]interface{})
|
||||
if upErr = json.Unmarshal([]byte(install.Env), &envs); upErr != nil {
|
||||
return
|
||||
}
|
||||
config := getAppCommonConfig(envs)
|
||||
if config.ContainerName == "" {
|
||||
config.ContainerName = install.ContainerName
|
||||
envs[constant.ContainerName] = install.ContainerName
|
||||
}
|
||||
config.Advanced = true
|
||||
if upErr = addDockerComposeCommonParam(composeMap, install.ServiceName, config, envs); upErr != nil {
|
||||
return
|
||||
}
|
||||
paramByte, upErr := json.Marshal(envs)
|
||||
if upErr != nil {
|
||||
return
|
||||
}
|
||||
install.Env = string(paramByte)
|
||||
composeByte, upErr := yaml.Marshal(composeMap)
|
||||
if upErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
install.DockerCompose = newCompose
|
||||
install.DockerCompose = string(composeByte)
|
||||
install.Version = detail.Version
|
||||
install.AppDetailId = req.DetailID
|
||||
install.AppDetailId = detailID
|
||||
|
||||
if out, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
if out != "" {
|
||||
upErr = errors.New(out)
|
||||
return
|
||||
}
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
envs := make(map[string]interface{})
|
||||
if upErr = json.Unmarshal([]byte(install.Env), &envs); upErr != nil {
|
||||
return
|
||||
}
|
||||
envParams := make(map[string]string, len(envs))
|
||||
handleMap(envs, envParams)
|
||||
if upErr = env.Write(envParams, install.GetEnvPath()); upErr != nil {
|
||||
if err = env.Write(envParams, install.GetEnvPath()); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if upErr = runScript(&install, "upgrade"); upErr != nil {
|
||||
if err = runScript(&install, "upgrade"); err != nil {
|
||||
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
|
||||
}
|
||||
@@ -669,7 +615,6 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
}
|
||||
install.Status = constant.Running
|
||||
_ = appInstallRepo.Save(context.Background(), &install)
|
||||
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppSuccess", install.Name, nil))
|
||||
}()
|
||||
|
||||
return appInstallRepo.Save(context.Background(), &install)
|
||||
@@ -786,11 +731,11 @@ func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.App
|
||||
}
|
||||
}()
|
||||
|
||||
if err = fileOp.DownloadFileWithProxy(appDetail.DownloadUrl, filePath); err != nil {
|
||||
if err = fileOp.DownloadFile(appDetail.DownloadUrl, filePath); err != nil {
|
||||
global.LOG.Errorf("download app[%s] error %v", app.Name, err)
|
||||
return
|
||||
}
|
||||
if err = fileOp.Decompress(filePath, appResourceDir, files.SdkTarGz, ""); err != nil {
|
||||
if err = fileOp.Decompress(filePath, appResourceDir, files.SdkTarGz); err != nil {
|
||||
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
|
||||
return
|
||||
}
|
||||
@@ -810,7 +755,7 @@ func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppIns
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
_, _, _ = httpUtil.HandleGet(appDetail.DownloadCallBackUrl, http.MethodGet, constant.TimeOut5s)
|
||||
_, _ = http.Get(appDetail.DownloadCallBackUrl)
|
||||
}()
|
||||
}
|
||||
appKey := app.Key
|
||||
@@ -884,7 +829,6 @@ func checkContainerNameIsExist(containerName, appDir string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer client.Close()
|
||||
var options container.ListOptions
|
||||
list, err := client.ContainerList(context.Background(), options)
|
||||
if err != nil {
|
||||
@@ -937,7 +881,7 @@ func upApp(appInstall *model.AppInstall, pullImages bool) {
|
||||
return
|
||||
}
|
||||
if err := upProject(appInstall); err != nil {
|
||||
appInstall.Status = constant.UpErr
|
||||
appInstall.Status = constant.Error
|
||||
} else {
|
||||
appInstall.Status = constant.Running
|
||||
}
|
||||
@@ -962,12 +906,6 @@ func rebuildApp(appInstall model.AppInstall) error {
|
||||
_ = handleErr(appInstall, err, out)
|
||||
return
|
||||
}
|
||||
containerNames, err := getContainerNames(appInstall)
|
||||
if err != nil {
|
||||
_ = handleErr(appInstall, err, out)
|
||||
return
|
||||
}
|
||||
appInstall.ContainerName = strings.Join(containerNames, ",")
|
||||
|
||||
appInstall.Status = constant.Running
|
||||
_ = appInstallRepo.Save(context.Background(), &appInstall)
|
||||
@@ -1145,131 +1083,24 @@ func handleErr(install model.AppInstall, err error, out string) error {
|
||||
install.Message = out
|
||||
reErr = errors.New(out)
|
||||
}
|
||||
install.Status = constant.UpErr
|
||||
install.Status = constant.Error
|
||||
_ = appInstallRepo.Save(context.Background(), &install)
|
||||
return reErr
|
||||
}
|
||||
|
||||
func doNotNeedSync(installed model.AppInstall) bool {
|
||||
return installed.Status == constant.Installing || installed.Status == constant.Rebuilding || installed.Status == constant.Upgrading ||
|
||||
installed.Status == constant.Syncing
|
||||
}
|
||||
|
||||
func synAppInstall(containers map[string]types.Container, appInstall *model.AppInstall, force bool) {
|
||||
containerNames := strings.Split(appInstall.ContainerName, ",")
|
||||
if len(containers) == 0 {
|
||||
if appInstall.Status == constant.UpErr && !force {
|
||||
return
|
||||
}
|
||||
appInstall.Status = constant.Error
|
||||
appInstall.Message = buserr.WithName("ErrContainerNotFound", strings.Join(containerNames, ",")).Error()
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
return
|
||||
}
|
||||
notFoundNames := make([]string, 0)
|
||||
exitNames := make([]string, 0)
|
||||
exitedCount := 0
|
||||
pausedCount := 0
|
||||
runningCount := 0
|
||||
total := len(containerNames)
|
||||
for _, name := range containerNames {
|
||||
if con, ok := containers["/"+name]; ok {
|
||||
switch con.State {
|
||||
case "exited":
|
||||
exitedCount++
|
||||
exitNames = append(exitNames, name)
|
||||
case "running":
|
||||
runningCount++
|
||||
case "paused":
|
||||
pausedCount++
|
||||
}
|
||||
} else {
|
||||
notFoundNames = append(notFoundNames, name)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case exitedCount == total:
|
||||
appInstall.Status = constant.Stopped
|
||||
case runningCount == total:
|
||||
appInstall.Status = constant.Running
|
||||
case pausedCount == total:
|
||||
appInstall.Status = constant.Paused
|
||||
case len(notFoundNames) == total:
|
||||
if appInstall.Status == constant.UpErr && !force {
|
||||
return
|
||||
}
|
||||
appInstall.Status = constant.Error
|
||||
appInstall.Message = buserr.WithName("ErrContainerNotFound", strings.Join(notFoundNames, ",")).Error()
|
||||
default:
|
||||
var msg string
|
||||
if exitedCount > 0 {
|
||||
msg = buserr.WithName("ErrContainerMsg", strings.Join(exitNames, ",")).Error()
|
||||
}
|
||||
if len(notFoundNames) > 0 {
|
||||
msg += buserr.WithName("ErrContainerNotFound", strings.Join(notFoundNames, ",")).Error()
|
||||
}
|
||||
if msg == "" {
|
||||
msg = buserr.New("ErrAppWarn").Error()
|
||||
}
|
||||
appInstall.Message = msg
|
||||
appInstall.Status = constant.UnHealthy
|
||||
}
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
}
|
||||
|
||||
func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool) ([]response.AppInstallDTO, error) {
|
||||
var (
|
||||
res []response.AppInstallDTO
|
||||
containersMap map[string]types.Container
|
||||
)
|
||||
if sync {
|
||||
cli, err := docker.NewClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err := cli.ListAllContainers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containersMap = make(map[string]types.Container, len(containers))
|
||||
for _, contain := range containers {
|
||||
containersMap[contain.Names[0]] = contain
|
||||
}
|
||||
}
|
||||
|
||||
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
|
||||
var res []response.AppInstalledDTO
|
||||
for _, installed := range appInstallList {
|
||||
if updated && (installed.App.Type == "php" || installed.Status == constant.Installing || (installed.App.Key == constant.AppMysql && installed.Version == "5.6.51")) {
|
||||
continue
|
||||
}
|
||||
if sync && !doNotNeedSync(installed) {
|
||||
synAppInstall(containersMap, &installed, false)
|
||||
if err := syncAppInstallStatus(&installed); err != nil {
|
||||
global.LOG.Error("sync app install status error : ", err)
|
||||
}
|
||||
|
||||
installDTO := response.AppInstallDTO{
|
||||
ID: installed.ID,
|
||||
Name: installed.Name,
|
||||
AppID: installed.AppId,
|
||||
AppDetailID: installed.AppDetailId,
|
||||
Version: installed.Version,
|
||||
Status: installed.Status,
|
||||
Message: installed.Message,
|
||||
HttpPort: installed.HttpPort,
|
||||
HttpsPort: installed.HttpsPort,
|
||||
Icon: installed.App.Icon,
|
||||
AppName: installed.App.Name,
|
||||
AppKey: installed.App.Key,
|
||||
AppType: installed.App.Type,
|
||||
Path: installed.GetPath(),
|
||||
CreatedAt: installed.CreatedAt,
|
||||
App: response.AppDetail{
|
||||
Github: installed.App.Github,
|
||||
Website: installed.App.Website,
|
||||
Document: installed.App.Document,
|
||||
},
|
||||
}
|
||||
if updated {
|
||||
installDTO.DockerCompose = installed.DockerCompose
|
||||
installDTO := response.AppInstalledDTO{
|
||||
AppInstall: installed,
|
||||
Path: installed.GetPath(),
|
||||
}
|
||||
app, err := appRepo.GetFirst(commonRepo.WithByID(installed.AppId))
|
||||
if err != nil {
|
||||
|
||||
@@ -37,7 +37,6 @@ type IBackupService interface {
|
||||
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
||||
Update(ireq dto.BackupOperate) error
|
||||
Delete(id uint) error
|
||||
DeleteRecordByName(backupType, name, detailName string, withDeleteFile bool) error
|
||||
BatchDeleteRecord(ids []uint) error
|
||||
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
|
||||
|
||||
@@ -50,13 +49,13 @@ type IBackupService interface {
|
||||
MysqlRecoverByUpload(req dto.CommonRecover) error
|
||||
PostgresqlRecoverByUpload(req dto.CommonRecover) error
|
||||
|
||||
RedisBackup(db dto.CommonBackup) error
|
||||
RedisBackup() error
|
||||
RedisRecover(db dto.CommonRecover) error
|
||||
|
||||
WebsiteBackup(db dto.CommonBackup) error
|
||||
WebsiteRecover(req dto.CommonRecover) error
|
||||
|
||||
AppBackup(db dto.CommonBackup) (*model.BackupRecord, error)
|
||||
AppBackup(db dto.CommonBackup) error
|
||||
AppRecover(req dto.CommonRecover) error
|
||||
|
||||
Run()
|
||||
@@ -261,35 +260,6 @@ func (u *BackupService) Delete(id uint) error {
|
||||
return backupRepo.Delete(commonRepo.WithByID(id))
|
||||
}
|
||||
|
||||
func (u *BackupService) DeleteRecordByName(backupType, name, detailName string, withDeleteFile bool) error {
|
||||
if !withDeleteFile {
|
||||
return backupRepo.DeleteRecord(context.Background(), commonRepo.WithByType(backupType), commonRepo.WithByName(name), backupRepo.WithByDetailName(detailName))
|
||||
}
|
||||
|
||||
records, err := backupRepo.ListRecord(commonRepo.WithByType(backupType), commonRepo.WithByName(name), backupRepo.WithByDetailName(detailName))
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
_ = backupRepo.DeleteRecord(context.Background(), commonRepo.WithByID(record.ID))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) BatchDeleteRecord(ids []uint) error {
|
||||
records, err := backupRepo.ListRecord(commonRepo.WithIdsIn(ids))
|
||||
if err != nil {
|
||||
|
||||
@@ -22,26 +22,26 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, error) {
|
||||
func (u *BackupService) AppBackup(req dto.CommonBackup) error {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(req.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByName(req.DetailName), appInstallRepo.WithAppId(app.ID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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))
|
||||
if err := handleAppBackup(&install, backupDir, fileName, "", req.Secret); err != nil {
|
||||
return nil, err
|
||||
if err := handleAppBackup(&install, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record := &model.BackupRecord{
|
||||
@@ -56,9 +56,9 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er
|
||||
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
return record, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
@@ -78,13 +78,13 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
if _, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleAppRecover(&install, req.File, false, req.Secret); err != nil {
|
||||
if err := handleAppRecover(&install, req.File, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excludes string, secret string) error {
|
||||
func handleAppBackup(install *model.AppInstall, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
@@ -103,7 +103,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excl
|
||||
}
|
||||
|
||||
appPath := install.GetPath()
|
||||
if err := handleTar(appPath, tmpDir, "app.tar.gz", excludes, ""); err != nil {
|
||||
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -129,16 +129,16 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excl
|
||||
}
|
||||
}
|
||||
|
||||
if err := handleTar(tmpDir, backupDir, fileName, "", secret); err != nil {
|
||||
if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback bool, secret string) error {
|
||||
func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback bool) error {
|
||||
isOk := false
|
||||
fileOp := files.NewFileOp()
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile), secret); err != nil {
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
@@ -164,13 +164,13 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format("20060102150405")))
|
||||
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil {
|
||||
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
return fmt.Errorf("backup app %s for rollback before recover failed, err: %v", install.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
if !isOk {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := handleAppRecover(install, rollbackFile, true, secret); err != nil {
|
||||
if err := handleAppRecover(install, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback app %s from %s failed, err: %v", install.Name, rollbackFile, err)
|
||||
return
|
||||
}
|
||||
@@ -251,7 +251,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
_ = fileOp.Rename(appDir, backPath)
|
||||
_ = fileOp.CreateDir(appDir, 0755)
|
||||
|
||||
if err := handleUnTar(tmpPath+"/app.tar.gz", install.GetAppPath(), ""); err != nil {
|
||||
if err := handleUnTar(tmpPath+"/app.tar.gz", install.GetAppPath()); err != nil {
|
||||
global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
|
||||
_ = fileOp.DeleteDir(appDir)
|
||||
_ = fileOp.Rename(backPath, appDir)
|
||||
|
||||
@@ -66,7 +66,7 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err)
|
||||
}
|
||||
}
|
||||
if err := handleUnTar(req.File, dstDir, ""); err != nil {
|
||||
if err := handleUnTar(req.File, dstDir); err != nil {
|
||||
_ = os.RemoveAll(dstDir)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err)
|
||||
}
|
||||
}
|
||||
if err := handleUnTar(req.File, dstDir, ""); err != nil {
|
||||
if err := handleUnTar(req.File, dstDir); err != nil {
|
||||
_ = os.RemoveAll(dstDir)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (u *BackupService) RedisBackup(db dto.CommonBackup) error {
|
||||
func (u *BackupService) RedisBackup() error {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", db.Name)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -46,12 +46,11 @@ func (u *BackupService) RedisBackup(db dto.CommonBackup) error {
|
||||
}
|
||||
itemDir := fmt.Sprintf("database/redis/%s", redisInfo.Name)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
if err := handleRedisBackup(redisInfo, backupDir, fileName, db.Secret); err != nil {
|
||||
if err := handleRedisBackup(redisInfo, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
record := &model.BackupRecord{
|
||||
Type: "redis",
|
||||
Name: db.Name,
|
||||
Source: "LOCAL",
|
||||
BackupType: "LOCAL",
|
||||
FileDir: itemDir,
|
||||
@@ -65,18 +64,18 @@ func (u *BackupService) RedisBackup(db dto.CommonBackup) error {
|
||||
}
|
||||
|
||||
func (u *BackupService) RedisRecover(req dto.CommonRecover) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Infof("recover redis from backup file %s", req.File)
|
||||
if err := handleRedisRecover(redisInfo, req.File, false, req.Secret); err != nil {
|
||||
if err := handleRedisRecover(redisInfo, req.File, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string, secret string) error {
|
||||
func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(backupDir) {
|
||||
if err := os.MkdirAll(backupDir, os.ModePerm); err != nil {
|
||||
@@ -91,7 +90,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string, sec
|
||||
|
||||
if strings.HasSuffix(fileName, ".tar.gz") {
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data/appendonlydir", constant.AppInstallDir, "redis", redisInfo.Name)
|
||||
if err := handleTar(redisDataDir, backupDir, fileName, "", secret); err != nil {
|
||||
if err := handleTar(redisDataDir, backupDir, fileName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -111,7 +110,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string, sec
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback bool, secret string) error {
|
||||
func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback bool) error {
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(recoverFile) {
|
||||
return buserr.WithName("ErrFileNotFound", recoverFile)
|
||||
@@ -147,13 +146,13 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
||||
}
|
||||
}
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format("20060102150405"), suffix))
|
||||
if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile), secret); err != nil {
|
||||
if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
return fmt.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
if !isOk {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := handleRedisRecover(redisInfo, rollbackFile, true, secret); err != nil {
|
||||
if err := handleRedisRecover(redisInfo, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback redis from %s failed, err: %v", rollbackFile, err)
|
||||
return
|
||||
}
|
||||
@@ -170,7 +169,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
||||
}
|
||||
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "7.") {
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data", constant.AppInstallDir, "redis", redisInfo.Name)
|
||||
if err := handleUnTar(recoverFile, redisDataDir, secret); err != nil {
|
||||
if err := handleUnTar(recoverFile, redisDataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -4,19 +4,18 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, excludes string, secret string) error {
|
||||
func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
@@ -35,19 +34,19 @@ func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, exc
|
||||
}
|
||||
|
||||
appPath := runtime.GetPath()
|
||||
if err := handleTar(appPath, tmpDir, "runtime.tar.gz", excludes, secret); err != nil {
|
||||
if err := handleTar(appPath, tmpDir, "runtime.tar.gz", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleTar(tmpDir, backupDir, fileName, "", secret); err != nil {
|
||||
if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback bool, secret string) error {
|
||||
func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback bool) error {
|
||||
isOk := false
|
||||
fileOp := files.NewFileOp()
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile), secret); err != nil {
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
@@ -73,13 +72,13 @@ func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("runtime/%s_%s.tar.gz", runtime.Name, time.Now().Format("20060102150405")))
|
||||
if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile), "", secret); err != nil {
|
||||
if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
return fmt.Errorf("backup runtime %s for rollback before recover failed, err: %v", runtime.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
if !isOk {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := handleRuntimeRecover(runtime, rollbackFile, true, secret); err != nil {
|
||||
if err := handleRuntimeRecover(runtime, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback runtime %s from %s failed, err: %v", runtime.Name, rollbackFile, err)
|
||||
return
|
||||
}
|
||||
@@ -100,7 +99,7 @@ func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback
|
||||
_ = fileOp.Rename(runtimeDir, backPath)
|
||||
_ = fileOp.CreateDir(runtimeDir, 0755)
|
||||
|
||||
if err := handleUnTar(tmpPath+"/runtime.tar.gz", fmt.Sprintf("%s/%s", constant.RuntimeDir, runtime.Type), secret); err != nil {
|
||||
if err := handleUnTar(tmpPath+"/runtime.tar.gz", fmt.Sprintf("%s/%s", constant.RuntimeDir, runtime.Type)); err != nil {
|
||||
global.LOG.Errorf("handle recover from runtime.tar.gz failed, err: %v", err)
|
||||
_ = fileOp.DeleteDir(runtimeDir)
|
||||
_ = fileOp.Rename(backPath, runtimeDir)
|
||||
|
||||
@@ -35,7 +35,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
itemDir := fmt.Sprintf("website/%s", req.Name)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow+common.RandStrAndNum(5))
|
||||
if err := handleWebsiteBackup(&website, backupDir, fileName, "", req.Secret); err != nil {
|
||||
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -65,16 +65,16 @@ func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error {
|
||||
return err
|
||||
}
|
||||
global.LOG.Infof("recover website %s from backup file %s", req.Name, req.File)
|
||||
if err := handleWebsiteRecover(&website, req.File, false, req.Secret); err != nil {
|
||||
if err := handleWebsiteRecover(&website, req.File, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback bool, secret string) error {
|
||||
func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback bool) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile), secret); err != nil {
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
@@ -107,13 +107,13 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
isOk := false
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
|
||||
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil {
|
||||
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
|
||||
}
|
||||
defer func() {
|
||||
if !isOk {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := handleWebsiteRecover(website, rollbackFile, true, ""); err != nil {
|
||||
if err := handleWebsiteRecover(website, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback website %s from %s failed, err: %v", website.Alias, rollbackFile, err)
|
||||
return
|
||||
}
|
||||
@@ -141,7 +141,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true, ""); err != nil {
|
||||
if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true); err != nil {
|
||||
global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
@@ -155,7 +155,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
if runtime.Type == constant.RuntimeNode {
|
||||
if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true, ""); err != nil {
|
||||
if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put runtime.tar.gz into tmp dir successful")
|
||||
@@ -163,7 +163,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
}
|
||||
|
||||
siteDir := fmt.Sprintf("%s/openresty/%s/www/sites", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir, ""); err != nil {
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir); err != nil {
|
||||
global.LOG.Errorf("handle recover from web.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
@@ -182,7 +182,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleWebsiteBackup(website *model.Website, backupDir, fileName string, excludes string, secret string) error {
|
||||
func handleWebsiteBackup(website *model.Website, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
@@ -216,7 +216,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes, ""); err != nil {
|
||||
if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias)); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put app.tar.gz into tmp dir successful")
|
||||
@@ -226,7 +226,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
|
||||
return err
|
||||
}
|
||||
if runtime.Type == constant.RuntimeNode {
|
||||
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes, ""); err != nil {
|
||||
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias)); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put runtime.tar.gz into tmp dir successful")
|
||||
@@ -234,11 +234,11 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
|
||||
}
|
||||
|
||||
websiteDir := fmt.Sprintf("%s/openresty/%s/www/sites/%s", constant.AppInstallDir, nginxInfo.Name, website.Alias)
|
||||
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), excludes, ""); err != nil {
|
||||
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put web.tar.gz into tmp dir successful, now start to tar tmp dir")
|
||||
if err := handleTar(tmpDir, backupDir, fileName, "", secret); err != nil {
|
||||
if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -250,18 +250,18 @@ func checkValidOfWebsite(oldWebsite, website *model.Website) error {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, fmt.Sprintf("oldName: %s, oldType: %v", oldWebsite.Alias, oldWebsite.Type), nil)
|
||||
}
|
||||
if oldWebsite.AppInstallID != 0 {
|
||||
_, err := appInstallRepo.GetFirst(commonRepo.WithByID(oldWebsite.AppInstallID))
|
||||
_, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, "app", nil)
|
||||
}
|
||||
}
|
||||
if oldWebsite.RuntimeID != 0 {
|
||||
if _, err := runtimeRepo.GetFirst(commonRepo.WithByID(oldWebsite.RuntimeID)); err != nil {
|
||||
if _, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID)); err != nil {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, "runtime", nil)
|
||||
}
|
||||
}
|
||||
if oldWebsite.WebsiteSSLID != 0 {
|
||||
if _, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(oldWebsite.WebsiteSSLID)); err != nil {
|
||||
if _, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID)); err != nil {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, "ssl", nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
@@ -17,11 +16,6 @@ type ICommandService interface {
|
||||
Create(commandDto dto.CommandOperate) error
|
||||
Update(id uint, upMap map[string]interface{}) error
|
||||
Delete(ids []uint) error
|
||||
|
||||
SearchRedisCommandWithPage(search dto.SearchWithPage) (int64, interface{}, error)
|
||||
ListRedisCommand() ([]dto.RedisCommand, error)
|
||||
SaveRedisCommand(commandDto dto.RedisCommand) error
|
||||
DeleteRedisCommand(ids []uint) error
|
||||
}
|
||||
|
||||
func NewICommandService() ICommandService {
|
||||
@@ -121,63 +115,3 @@ func (u *CommandService) Delete(ids []uint) error {
|
||||
func (u *CommandService) Update(id uint, upMap map[string]interface{}) error {
|
||||
return commandRepo.Update(id, upMap)
|
||||
}
|
||||
|
||||
func (u *CommandService) SearchRedisCommandWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
|
||||
total, commands, err := commandRepo.PageRedis(search.Page, search.PageSize, commandRepo.WithLikeName(search.Info))
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
var dtoCommands []dto.RedisCommand
|
||||
for _, command := range commands {
|
||||
var item dto.RedisCommand
|
||||
if err := copier.Copy(&item, &command); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
dtoCommands = append(dtoCommands, item)
|
||||
}
|
||||
return total, dtoCommands, err
|
||||
}
|
||||
|
||||
func (u *CommandService) ListRedisCommand() ([]dto.RedisCommand, error) {
|
||||
commands, err := commandRepo.GetRedisList()
|
||||
if err != nil {
|
||||
return nil, constant.ErrRecordNotFound
|
||||
}
|
||||
var dtoCommands []dto.RedisCommand
|
||||
for _, command := range commands {
|
||||
var item dto.RedisCommand
|
||||
if err := copier.Copy(&item, &command); err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
dtoCommands = append(dtoCommands, item)
|
||||
}
|
||||
return dtoCommands, err
|
||||
}
|
||||
|
||||
func (u *CommandService) SaveRedisCommand(req dto.RedisCommand) error {
|
||||
if req.ID == 0 {
|
||||
command, _ := commandRepo.GetRedis(commonRepo.WithByName(req.Name))
|
||||
if command.ID != 0 {
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
}
|
||||
var command model.RedisCommand
|
||||
if err := copier.Copy(&command, &req); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
if err := commandRepo.SaveRedis(&command); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CommandService) DeleteRedisCommand(ids []uint) error {
|
||||
if len(ids) == 1 {
|
||||
command, _ := commandRepo.GetRedis(commonRepo.WithByID(ids[0]))
|
||||
if command.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
return commandRepo.DeleteRedis(commonRepo.WithByID(ids[0]))
|
||||
}
|
||||
return commandRepo.DeleteRedis(commonRepo.WithIdsIn(ids))
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
@@ -89,7 +88,6 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
options := container.ListOptions{
|
||||
All: true,
|
||||
}
|
||||
@@ -221,7 +219,6 @@ func (u *ContainerService) List() ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
containers, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -243,7 +240,6 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -266,7 +262,6 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
var inspectInfo interface{}
|
||||
switch req.Type {
|
||||
case "container":
|
||||
@@ -294,7 +289,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
defer client.Close()
|
||||
pruneFilters := filters.NewArgs()
|
||||
if req.WithTagAll {
|
||||
pruneFilters.Add("dangling", "false")
|
||||
@@ -324,28 +318,12 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
|
||||
}
|
||||
report.DeletedNumber = len(rep.NetworksDeleted)
|
||||
case "volume":
|
||||
versions, err := client.ServerVersion(context.Background())
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
if common.ComparePanelVersion(versions.APIVersion, "1.42") {
|
||||
pruneFilters.Add("all", "true")
|
||||
}
|
||||
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
report.DeletedNumber = len(rep.VolumesDeleted)
|
||||
report.SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
case "buildcache":
|
||||
opts := types.BuildCachePruneOptions{}
|
||||
opts.All = true
|
||||
rep, err := client.BuildCachePrune(context.Background(), opts)
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
report.DeletedNumber = len(rep.CachesDeleted)
|
||||
report.SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
}
|
||||
return report, nil
|
||||
}
|
||||
@@ -372,7 +350,6 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
newContainer, _ := client.ContainerInspect(ctx, req.Name)
|
||||
if newContainer.ContainerJSONBase != nil {
|
||||
@@ -420,7 +397,6 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
oldContainer, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
@@ -491,7 +467,6 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
newContainer, _ := client.ContainerInspect(ctx, req.Name)
|
||||
if newContainer.ContainerJSONBase != nil && newContainer.ID != req.ContainerID {
|
||||
@@ -540,7 +515,6 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
oldContainer, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
@@ -588,7 +562,6 @@ func (u *ContainerService) ContainerRename(req dto.ContainerRename) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
newContainer, _ := client.ContainerInspect(ctx, req.NewName)
|
||||
if newContainer.ContainerJSONBase != nil {
|
||||
@@ -604,7 +577,6 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, item := range req.Names {
|
||||
global.LOG.Infof("start container %s operation %s", item, req.Operation)
|
||||
switch req.Operation {
|
||||
@@ -632,7 +604,6 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
containerItem, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
@@ -751,7 +722,6 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
res, err := client.ContainerStats(context.TODO(), id, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -787,7 +757,6 @@ func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) s
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer cli.Close()
|
||||
options := container.ListOptions{All: true}
|
||||
options.Filters = filters.NewArgs()
|
||||
options.Filters.Add("label", fmt.Sprintf("%s=%s", composeProjectLabel, req.Name))
|
||||
@@ -871,15 +840,16 @@ func calculateNetwork(network map[string]types.NetworkStats) (float64, float64)
|
||||
return rx, tx
|
||||
}
|
||||
|
||||
func checkImageExist(client *client.Client, imageItem string) bool {
|
||||
images, err := client.ImageList(context.Background(), image.ListOptions{})
|
||||
func checkImageExist(client *client.Client, image string) bool {
|
||||
images, err := client.ImageList(context.Background(), types.ImageListOptions{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, img := range images {
|
||||
for _, tag := range img.RepoTags {
|
||||
if tag == imageItem || tag == imageItem+":latest" {
|
||||
if tag == image || tag == image+":latest" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -927,11 +897,12 @@ func loadCpuAndMem(client *client.Client, container string) dto.ContainerListSta
|
||||
return data
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
res.Body.Close()
|
||||
return data
|
||||
}
|
||||
res.Body.Close()
|
||||
var stats *types.StatsJSON
|
||||
if err := json.Unmarshal(body, &stats); err != nil {
|
||||
return data
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -12,8 +13,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
@@ -40,7 +39,6 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
options := container.ListOptions{All: true}
|
||||
options.Filters = filters.NewArgs()
|
||||
|
||||
@@ -19,7 +19,6 @@ func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
@@ -82,7 +81,6 @@ func (u *ContainerService) ListNetwork() ([]dto.Options, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -102,7 +100,6 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, id := range req.Names {
|
||||
if err := client.NetworkRemove(context.TODO(), id); err != nil {
|
||||
if strings.Contains(err.Error(), "has active endpoints") {
|
||||
@@ -118,7 +115,6 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
var (
|
||||
ipams []network.IPAMConfig
|
||||
enableV6 bool
|
||||
|
||||
@@ -82,7 +82,6 @@ func (u *ContainerService) ListVolume() ([]dto.Options, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.VolumeList(context.TODO(), volume.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -103,7 +102,6 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, id := range req.Names {
|
||||
if err := client.VolumeRemove(context.TODO(), id, true); err != nil {
|
||||
if strings.Contains(err.Error(), "volume is in use") {
|
||||
@@ -119,7 +117,6 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
arg := filters.NewArgs()
|
||||
arg.Add("name", req.Name)
|
||||
vos, _ := client.VolumeList(context.TODO(), volume.ListOptions{Filters: arg})
|
||||
|
||||
@@ -29,7 +29,7 @@ type ICronjobService interface {
|
||||
UpdateStatus(id uint, status string) error
|
||||
Delete(req dto.CronjobBatchDelete) error
|
||||
Download(down dto.CronjobDownload) (string, error)
|
||||
StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error)
|
||||
StartJob(cronjob *model.Cronjob) (string, error)
|
||||
CleanRecord(req dto.CronjobClean) error
|
||||
|
||||
LoadRecordLog(req dto.OperateByID) string
|
||||
@@ -71,7 +71,6 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
|
||||
if err := copier.Copy(&item, &record); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
item.StartTime = record.StartTime.Format("2006-01-02 15:04:05")
|
||||
dtoCronjobs = append(dtoCronjobs, item)
|
||||
}
|
||||
return total, dtoCronjobs, err
|
||||
@@ -173,7 +172,6 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
|
||||
if cronjob.ID != 0 {
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
cronjob.Secret = cronjobDto.Secret
|
||||
if err := copier.Copy(&cronjob, &cronjobDto); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
@@ -181,7 +179,7 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
|
||||
|
||||
global.LOG.Infof("create cronjob %s successful, spec: %s", cronjob.Name, cronjob.Spec)
|
||||
spec := cronjob.Spec
|
||||
entryIDs, err := u.StartJob(&cronjob, false)
|
||||
entryIDs, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -193,8 +191,8 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error) {
|
||||
if len(cronjob.EntryIDs) != 0 && isUpdate {
|
||||
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)
|
||||
@@ -251,7 +249,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||
cronjob.Type = cronModel.Type
|
||||
spec := cronjob.Spec
|
||||
if cronModel.Status == constant.StatusEnable {
|
||||
newEntryIDs, err := u.StartJob(&cronjob, true)
|
||||
newEntryIDs, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -280,7 +278,6 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||
upMap["backup_accounts"] = req.BackupAccounts
|
||||
upMap["default_download"] = req.DefaultDownload
|
||||
upMap["retain_copies"] = req.RetainCopies
|
||||
upMap["secret"] = req.Secret
|
||||
return cronjobRepo.Update(id, upMap)
|
||||
}
|
||||
|
||||
@@ -294,7 +291,7 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
|
||||
err error
|
||||
)
|
||||
if status == constant.StatusEnable {
|
||||
entryIDs, err = u.StartJob(&cronjob, false)
|
||||
entryIDs, err = u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
||||
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err := handleAppBackup(&app, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||
if err := handleAppBackup(&app, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
@@ -74,7 +74,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain))
|
||||
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||
if err := handleWebsiteBackup(&web, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
@@ -138,7 +138,7 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
|
||||
}
|
||||
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, cronjob.Secret); err != nil {
|
||||
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil {
|
||||
return err
|
||||
}
|
||||
var record model.BackupRecord
|
||||
@@ -169,7 +169,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
|
||||
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, cronjob.Secret); err != nil {
|
||||
if err := handleBackupLogs(backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
var record model.BackupRecord
|
||||
@@ -210,7 +210,7 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Ti
|
||||
From: record.BackupType,
|
||||
DefaultDownload: cronjob.DefaultDownload,
|
||||
}
|
||||
name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format("20060102150405")+common.RandStrAndNum(5), cronjob.Secret)
|
||||
name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -303,7 +303,7 @@ func loadRecordPath(cronjob model.Cronjob, accountMap map[string]cronjobUploadHe
|
||||
return source, backupType
|
||||
}
|
||||
|
||||
func handleBackupLogs(targetDir, fileName string, secret string) error {
|
||||
func handleBackupLogs(targetDir, fileName string) error {
|
||||
websites, err := websiteRepo.List()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -376,7 +376,7 @@ func handleBackupLogs(targetDir, fileName string, secret string) error {
|
||||
}
|
||||
global.LOG.Debug("backup ssh log successful!")
|
||||
|
||||
if err := handleTar(targetDir, path.Dir(targetDir), fileName, "", secret); err != nil {
|
||||
if err := handleTar(targetDir, path.Dir(targetDir), fileName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
|
||||
@@ -130,7 +130,7 @@ func (u *CronjobService) handleNtpSync() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleTar(sourceDir, targetDir, name, exclusionRules string, secret string) error {
|
||||
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 {
|
||||
return err
|
||||
@@ -158,16 +158,8 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string, secret string)
|
||||
path = sourceDir
|
||||
}
|
||||
|
||||
commands := ""
|
||||
|
||||
if len(secret) != 0 {
|
||||
extraCmd := "| openssl enc -aes-256-cbc -salt -k " + secret + " -out"
|
||||
commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s %s", " -"+excludeRules, path, extraCmd, targetDir+"/"+name)
|
||||
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
|
||||
} else {
|
||||
commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
||||
global.LOG.Debug(commands)
|
||||
}
|
||||
commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
||||
global.LOG.Debug(commands)
|
||||
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
|
||||
if err != nil {
|
||||
if len(stdout) != 0 {
|
||||
@@ -178,22 +170,15 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string, secret string)
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleUnTar(sourceFile, targetDir string, secret string) error {
|
||||
func handleUnTar(sourceFile, targetDir string) error {
|
||||
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
commands := ""
|
||||
if len(secret) != 0 {
|
||||
extraCmd := "openssl enc -d -aes-256-cbc -k " + secret + " -in " + sourceFile + " | "
|
||||
commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, targetDir+" > /dev/null 2>&1")
|
||||
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
|
||||
} else {
|
||||
commands = fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir)
|
||||
global.LOG.Debug(commands)
|
||||
}
|
||||
|
||||
commands := fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir)
|
||||
global.LOG.Debug(commands)
|
||||
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
||||
|
||||
@@ -222,13 +222,10 @@ func loadDiskInfo() []dto.DiskInfo {
|
||||
if len(fields) < 7 {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(fields[6], "/snap") || len(strings.Split(fields[6], "/")) > 10 {
|
||||
if fields[1] == "tmpfs" {
|
||||
continue
|
||||
}
|
||||
if strings.TrimSpace(fields[1]) == "tmpfs" {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(fields[2], "K") {
|
||||
if strings.Contains(fields[2], "M") || strings.Contains(fields[2], "K") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(fields[6], "docker") {
|
||||
|
||||
@@ -7,8 +7,7 @@ import (
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql"
|
||||
pg_client "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
redis_client "github.com/1Panel-dev/1Panel/backend/utils/redis"
|
||||
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"
|
||||
@@ -43,7 +42,6 @@ func (u *DatabaseService) SearchWithPage(search dto.DatabaseSearch) (int64, inte
|
||||
total, dbs, err := databaseRepo.Page(search.Page, search.PageSize,
|
||||
databaseRepo.WithTypeList(search.Type),
|
||||
commonRepo.WithLikeName(search.Info),
|
||||
commonRepo.WithOrderRuleBy(search.OrderBy, search.Order),
|
||||
databaseRepo.WithoutByFrom("local"),
|
||||
)
|
||||
var datas []dto.DatabaseInfo
|
||||
@@ -71,9 +69,6 @@ func (u *DatabaseService) Get(name string) (dto.DatabaseInfo, error) {
|
||||
|
||||
func (u *DatabaseService) List(dbType string) ([]dto.DatabaseOption, error) {
|
||||
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var datas []dto.DatabaseOption
|
||||
for _, db := range dbs {
|
||||
var item dto.DatabaseOption
|
||||
@@ -118,7 +113,7 @@ func (u *DatabaseService) LoadItems(dbType string) ([]dto.DatabaseItem, error) {
|
||||
func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
||||
switch req.Type {
|
||||
case constant.AppPostgresql:
|
||||
_, err := postgresql.NewPostgresqlClient(pg_client.DBInfo{
|
||||
_, err := postgresql.NewPostgresqlClient(client2.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
@@ -127,13 +122,6 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
||||
Timeout: 6,
|
||||
})
|
||||
return err == nil
|
||||
case constant.AppRedis:
|
||||
_, err := redis_client.NewRedisClient(redis_client.DBInfo{
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Password: req.Password,
|
||||
})
|
||||
return err == nil
|
||||
case "mysql", "mariadb":
|
||||
_, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
@@ -165,7 +153,7 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
||||
}
|
||||
switch req.Type {
|
||||
case constant.AppPostgresql:
|
||||
if _, err := postgresql.NewPostgresqlClient(pg_client.DBInfo{
|
||||
if _, err := postgresql.NewPostgresqlClient(client2.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
@@ -175,14 +163,6 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
case constant.AppRedis:
|
||||
if _, err := redis_client.NewRedisClient(redis_client.DBInfo{
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Password: req.Password,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
case "mysql", "mariadb":
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
@@ -269,7 +249,7 @@ func (u *DatabaseService) Delete(req dto.DatabaseDelete) error {
|
||||
func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
||||
switch req.Type {
|
||||
case constant.AppPostgresql:
|
||||
if _, err := postgresql.NewPostgresqlClient(pg_client.DBInfo{
|
||||
if _, err := postgresql.NewPostgresqlClient(client2.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
@@ -279,14 +259,6 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
case constant.AppRedis:
|
||||
if _, err := redis_client.NewRedisClient(redis_client.DBInfo{
|
||||
Address: req.Address,
|
||||
Port: req.Port,
|
||||
Password: req.Password,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
case "mysql", "mariadb":
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
|
||||
@@ -240,7 +240,7 @@ func (u *MysqlService) DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(db.ID), appRepo.WithKey(req.Type))
|
||||
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(db.ID))
|
||||
for _, app := range apps {
|
||||
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
|
||||
if appInstall.ID != 0 {
|
||||
@@ -363,17 +363,6 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
if err := updateInstallInfoInDB(req.Type, req.Database, "password", req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.From == "local" {
|
||||
remote, err := databaseRepo.Get(commonRepo.WithByName(req.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pass, err := encrypt.StringEncrypt(req.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decrypt database password failed, err: %v", err)
|
||||
}
|
||||
_ = databaseRepo.Update(remote.ID, map[string]interface{}{"password": pass})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -467,7 +456,7 @@ func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool,
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
hosts, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "select host from mysql.user where user='root';")
|
||||
hosts, err := executeSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -485,7 +474,7 @@ func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.Mys
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
variableMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global variables;")
|
||||
variableMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global variables;")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -504,7 +493,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statusMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global status;")
|
||||
statusMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global status;")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -528,7 +517,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
|
||||
info.File = "OFF"
|
||||
info.Position = "OFF"
|
||||
rows, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "show master status;")
|
||||
rows, err := executeSqlForRows(app.ContainerName, app.Password, "show master status;")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -543,8 +532,8 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func executeSqlForMaps(containerName, dbType, password, command string) (map[string]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||
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()
|
||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||
@@ -562,8 +551,8 @@ func executeSqlForMaps(containerName, dbType, password, command string) (map[str
|
||||
return rowMap, nil
|
||||
}
|
||||
|
||||
func executeSqlForRows(containerName, dbType, password, command string) ([]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||
func executeSqlForRows(containerName, password, command string) ([]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||
@@ -625,7 +614,6 @@ func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
dbInfo.Type = databaseItem.Type
|
||||
dbInfo.From = databaseItem.From
|
||||
dbInfo.Database = database
|
||||
if dbInfo.From != "local" {
|
||||
|
||||
@@ -266,7 +266,7 @@ func (u *PostgresqlService) DeleteCheck(req dto.PostgresqlDBDeleteCheck) ([]stri
|
||||
}
|
||||
}
|
||||
} else {
|
||||
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(db.ID), appRepo.WithKey(req.Type))
|
||||
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(db.ID))
|
||||
for _, app := range apps {
|
||||
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
|
||||
if appInstall.ID != 0 {
|
||||
@@ -414,16 +414,5 @@ func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
if err := updateInstallInfoInDB(req.Type, req.Database, "password", req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.From == "local" {
|
||||
remote, err := databaseRepo.Get(commonRepo.WithByName(req.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pass, err := encrypt.StringEncrypt(req.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decrypt database password failed, err: %v", err)
|
||||
}
|
||||
_ = databaseRepo.Update(remote.ID, map[string]interface{}{"password": pass})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"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/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
@@ -25,12 +23,11 @@ type IRedisService interface {
|
||||
UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error
|
||||
ChangePassword(info dto.ChangeRedisPass) error
|
||||
|
||||
LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error)
|
||||
LoadConf(req dto.OperationWithName) (*dto.RedisConf, error)
|
||||
LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error)
|
||||
LoadStatus() (*dto.RedisStatus, error)
|
||||
LoadConf() (*dto.RedisConf, error)
|
||||
LoadPersistenceConf() (*dto.RedisPersistence, error)
|
||||
|
||||
CheckHasCli() bool
|
||||
InstallCli() error
|
||||
SearchBackupListWithPage(req dto.PageInfo) (int64, interface{}, error)
|
||||
}
|
||||
|
||||
func NewIRedisService() IRedisService {
|
||||
@@ -38,7 +35,7 @@ func NewIRedisService() IRedisService {
|
||||
}
|
||||
|
||||
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Database)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -57,54 +54,19 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *RedisService) CheckHasCli() bool {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer client.Close()
|
||||
containerLists, err := client.ContainerList(context.Background(), container.ListOptions{})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, item := range containerLists {
|
||||
if strings.ReplaceAll(item.Names[0], "/", "") == "1Panel-redis-cli-tools" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (u *RedisService) InstallCli() error {
|
||||
item := dto.ContainerOperate{
|
||||
Name: "1Panel-redis-cli-tools",
|
||||
Image: "redis:7.2.4",
|
||||
Network: "1panel-network",
|
||||
}
|
||||
return NewIContainerService().ContainerCreate(item)
|
||||
}
|
||||
|
||||
func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
|
||||
if err := updateInstallInfoInDB("redis", req.Database, "password", req.Value); err != nil {
|
||||
if err := updateInstallInfoInDB("redis", "", "password", req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
remote, err := databaseRepo.Get(commonRepo.WithByName(req.Database))
|
||||
if err != nil {
|
||||
if err := updateInstallInfoInDB("redis-commander", "", "password", req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if remote.From == "local" {
|
||||
pass, err := encrypt.StringEncrypt(req.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decrypt database password failed, err: %v", err)
|
||||
}
|
||||
_ = databaseRepo.Update(remote.ID, map[string]interface{}{"password": pass})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Database)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -126,8 +88,8 @@ func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadStatus() (*dto.RedisStatus, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -154,8 +116,8 @@ func (u *RedisService) LoadStatus(req dto.OperationWithName) (*dto.RedisStatus,
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadConf() (*dto.RedisConf, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -171,8 +133,8 @@ func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, erro
|
||||
return &item, nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadPersistenceConf() (*dto.RedisPersistence, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -189,6 +151,46 @@ func (u *RedisService) LoadPersistenceConf(req dto.OperationWithName) (*dto.Redi
|
||||
return &item, nil
|
||||
}
|
||||
|
||||
func (u *RedisService) SearchBackupListWithPage(req dto.PageInfo) (int64, interface{}, error) {
|
||||
var (
|
||||
list []dto.DatabaseFileRecords
|
||||
backDatas []dto.DatabaseFileRecords
|
||||
)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", "")
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/redis/%s", redisInfo.Name))
|
||||
_ = filepath.Walk(backupDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if !info.IsDir() {
|
||||
list = append(list, dto.DatabaseFileRecords{
|
||||
CreatedAt: info.ModTime().Format("2006-01-02 15:04:05"),
|
||||
Size: int(info.Size()),
|
||||
FileDir: backupDir,
|
||||
FileName: info.Name(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
if start > total {
|
||||
backDatas = make([]dto.DatabaseFileRecords, 0)
|
||||
} else {
|
||||
if end >= total {
|
||||
end = total
|
||||
}
|
||||
backDatas = list[start:end]
|
||||
}
|
||||
return int64(total), backDatas, nil
|
||||
}
|
||||
|
||||
func configGetStr(containerName, password, param string) (string, error) {
|
||||
commands := append(redisExec(containerName, password), []string{"config", "get", param}...)
|
||||
cmd := exec.Command("docker", commands...)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
@@ -9,10 +8,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
@@ -135,9 +130,6 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
logTree := loadLogTree(fileOp)
|
||||
SystemClean.SystemLogClean = append(SystemClean.SystemLogClean, logTree...)
|
||||
|
||||
containerTree := loadContainerTree()
|
||||
SystemClean.ContainerClean = append(SystemClean.ContainerClean, containerTree...)
|
||||
|
||||
return SystemClean
|
||||
}
|
||||
|
||||
@@ -267,14 +259,6 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
} else {
|
||||
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByRecordFile(pathItem))
|
||||
}
|
||||
case "images":
|
||||
dropImages()
|
||||
case "containers":
|
||||
dropContainers()
|
||||
case "volumes":
|
||||
dropVolumes()
|
||||
case "build_cache":
|
||||
dropBuildCache()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,50 +496,6 @@ func loadLogTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadContainerTree() []dto.CleanTree {
|
||||
var treeData []dto.CleanTree
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return treeData
|
||||
}
|
||||
diskUsage, err := client.DiskUsage(context.Background(), types.DiskUsageOptions{})
|
||||
if err != nil {
|
||||
return treeData
|
||||
}
|
||||
imageSize := uint64(0)
|
||||
for _, file := range diskUsage.Images {
|
||||
if file.Containers == 0 {
|
||||
imageSize += uint64(file.Size)
|
||||
}
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "container_images", Size: imageSize, Children: nil, Type: "images", IsRecommend: true})
|
||||
|
||||
containerSize := uint64(0)
|
||||
for _, file := range diskUsage.Containers {
|
||||
if file.State != "running" {
|
||||
containerSize += uint64(file.SizeRw)
|
||||
}
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "container_containers", Size: containerSize, Children: nil, Type: "containers", IsRecommend: true})
|
||||
|
||||
volumeSize := uint64(0)
|
||||
for _, file := range diskUsage.Volumes {
|
||||
if file.UsageData.RefCount <= 0 {
|
||||
volumeSize += uint64(file.UsageData.Size)
|
||||
}
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "container_volumes", Size: volumeSize, Children: nil, Type: "volumes", IsRecommend: true})
|
||||
|
||||
var buildCacheTotalSize int64
|
||||
for _, cache := range diskUsage.BuildCache {
|
||||
if cache.Type == "source.local" {
|
||||
buildCacheTotalSize += cache.Size
|
||||
}
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "build_cache", Size: uint64(buildCacheTotalSize), Type: "build_cache", IsRecommend: true})
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadTreeWithDir(isCheck bool, treeType, pathItem string, fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
var lists []dto.CleanTree
|
||||
files, err := os.ReadDir(pathItem)
|
||||
@@ -646,63 +586,6 @@ func dropFileOrDir(itemPath string) {
|
||||
}
|
||||
}
|
||||
|
||||
func dropBuildCache() {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("do not get docker client")
|
||||
}
|
||||
opts := types.BuildCachePruneOptions{}
|
||||
opts.All = true
|
||||
_, err = client.BuildCachePrune(context.Background(), opts)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("drop build cache failed, err %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropImages() {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("do not get docker client")
|
||||
}
|
||||
pruneFilters := filters.NewArgs()
|
||||
pruneFilters.Add("dangling", "false")
|
||||
_, err = client.ImagesPrune(context.Background(), pruneFilters)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("drop images failed, err %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropContainers() {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("do not get docker client")
|
||||
}
|
||||
pruneFilters := filters.NewArgs()
|
||||
_, err = client.ContainersPrune(context.Background(), pruneFilters)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("drop containers failed, err %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropVolumes() {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("do not get docker client")
|
||||
}
|
||||
pruneFilters := filters.NewArgs()
|
||||
versions, err := client.ServerVersion(context.Background())
|
||||
if err != nil {
|
||||
global.LOG.Errorf("do not get docker api versions")
|
||||
}
|
||||
if common.ComparePanelVersion(versions.APIVersion, "1.42") {
|
||||
pruneFilters.Add("all", "true")
|
||||
}
|
||||
_, err = client.VolumesPrune(context.Background(), pruneFilters)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("drop volumes failed, err %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropFileOrDirWithLog(itemPath string, log *string, size *int64, count *int) {
|
||||
itemSize := int64(0)
|
||||
itemCount := 0
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -54,7 +55,6 @@ func (u *DockerService) LoadDockerStatus() string {
|
||||
if err != nil {
|
||||
return constant.Stopped
|
||||
}
|
||||
defer client.Close()
|
||||
if _, err := client.Ping(context.Background()); err != nil {
|
||||
return constant.Stopped
|
||||
}
|
||||
@@ -72,7 +72,6 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
||||
if err != nil {
|
||||
data.Status = constant.Stopped
|
||||
} else {
|
||||
defer client.Close()
|
||||
if _, err := client.Ping(ctx); err != nil {
|
||||
data.Status = constant.Stopped
|
||||
}
|
||||
@@ -103,6 +102,7 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
||||
return &data
|
||||
}
|
||||
if err := json.Unmarshal(arr, &conf); err != nil {
|
||||
fmt.Println(err)
|
||||
return &data
|
||||
}
|
||||
if _, ok := daemonMap["iptables"]; !ok {
|
||||
|
||||
@@ -24,7 +24,6 @@ var (
|
||||
hostRepo = repo.NewIHostRepo()
|
||||
groupRepo = repo.NewIGroupRepo()
|
||||
commandRepo = repo.NewICommandRepo()
|
||||
ftpRepo = repo.NewIFtpRepo()
|
||||
|
||||
settingRepo = repo.NewISettingRepo()
|
||||
backupRepo = repo.NewIBackupRepo()
|
||||
|
||||
@@ -2,23 +2,17 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"golang.org/x/net/html/charset"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
@@ -219,12 +213,12 @@ func (f *FileService) Compress(c request.FileCompress) error {
|
||||
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
||||
return buserr.New(constant.ErrFileIsExit)
|
||||
}
|
||||
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type), c.Secret)
|
||||
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type))
|
||||
}
|
||||
|
||||
func (f *FileService) DeCompress(c request.FileDeCompress) error {
|
||||
fo := files.NewFileOp()
|
||||
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type), c.Secret)
|
||||
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type))
|
||||
}
|
||||
|
||||
func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo, error) {
|
||||
@@ -235,23 +229,6 @@ func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo,
|
||||
if err != nil {
|
||||
return response.FileInfo{}, err
|
||||
}
|
||||
|
||||
content := []byte(info.Content)
|
||||
if len(content) > 1024 {
|
||||
content = content[:1024]
|
||||
}
|
||||
if !utf8.Valid(content) {
|
||||
_, decodeName, _ := charset.DetermineEncoding(content, "")
|
||||
if decodeName == "windows-1252" {
|
||||
reader := strings.NewReader(info.Content)
|
||||
item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder())
|
||||
contents, err := io.ReadAll(item)
|
||||
if err != nil {
|
||||
return response.FileInfo{}, err
|
||||
}
|
||||
info.Content = string(contents)
|
||||
}
|
||||
}
|
||||
return response.FileInfo{FileInfo: *info}, nil
|
||||
}
|
||||
|
||||
@@ -326,7 +303,7 @@ func (f *FileService) FileDownload(d request.FileDownload) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
fo := files.NewFileOp()
|
||||
if err := fo.Compress(d.Paths, tempPath, d.Name, files.CompressType(d.Type), ""); err != nil {
|
||||
if err := fo.Compress(d.Paths, tempPath, d.Name, files.CompressType(d.Type)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
filePath = filepath.Join(tempPath, d.Name)
|
||||
@@ -335,32 +312,12 @@ func (f *FileService) FileDownload(d request.FileDownload) (string, error) {
|
||||
}
|
||||
|
||||
func (f *FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) {
|
||||
var (
|
||||
res response.DirSizeRes
|
||||
)
|
||||
if req.Path == "/proc" {
|
||||
return res, nil
|
||||
}
|
||||
cmd := exec.Command("du", "-s", req.Path)
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
fields := strings.Fields(string(output))
|
||||
if len(fields) == 2 {
|
||||
var cmdSize int64
|
||||
_, err = fmt.Sscanf(fields[0], "%d", &cmdSize)
|
||||
if err == nil {
|
||||
res.Size = float64(cmdSize * 1024)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
fo := files.NewFileOp()
|
||||
size, err := fo.GetDirSize(req.Path)
|
||||
if err != nil {
|
||||
return res, err
|
||||
return response.DirSizeRes{}, err
|
||||
}
|
||||
res.Size = size
|
||||
return res, nil
|
||||
return response.DirSizeRes{Size: size}, nil
|
||||
}
|
||||
|
||||
func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) {
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/toolbox"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type FtpService struct{}
|
||||
|
||||
type IFtpService interface {
|
||||
LoadBaseInfo() (dto.FtpBaseInfo, error)
|
||||
SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
|
||||
Operate(operation string) error
|
||||
Create(req dto.FtpCreate) (uint, error)
|
||||
Delete(req dto.BatchDeleteReq) error
|
||||
Update(req dto.FtpUpdate) error
|
||||
Sync() error
|
||||
LoadLog(req dto.FtpLogSearch) (int64, interface{}, error)
|
||||
}
|
||||
|
||||
func NewIFtpService() IFtpService {
|
||||
return &FtpService{}
|
||||
}
|
||||
|
||||
func (f *FtpService) LoadBaseInfo() (dto.FtpBaseInfo, error) {
|
||||
var baseInfo dto.FtpBaseInfo
|
||||
client, err := toolbox.NewFtpClient()
|
||||
if err != nil {
|
||||
return baseInfo, err
|
||||
}
|
||||
baseInfo.IsActive, baseInfo.IsExist = client.Status()
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
func (f *FtpService) LoadLog(req dto.FtpLogSearch) (int64, interface{}, error) {
|
||||
client, err := toolbox.NewFtpClient()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
logItem, err := client.LoadLogs(req.User, req.Operation)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
sort.Slice(logItem, func(i, j int) bool {
|
||||
return logItem[i].Time > logItem[j].Time
|
||||
})
|
||||
var logs []toolbox.FtpLog
|
||||
total, start, end := len(logItem), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
if start > total {
|
||||
logs = make([]toolbox.FtpLog, 0)
|
||||
} else {
|
||||
if end >= total {
|
||||
end = total
|
||||
}
|
||||
logs = logItem[start:end]
|
||||
}
|
||||
return int64(total), logs, nil
|
||||
}
|
||||
|
||||
func (u *FtpService) Operate(operation string) error {
|
||||
client, err := toolbox.NewFtpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.Operate(operation)
|
||||
}
|
||||
|
||||
func (f *FtpService) SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error) {
|
||||
total, lists, err := ftpRepo.Page(req.Page, req.PageSize, ftpRepo.WithByUser(req.Info), commonRepo.WithOrderBy("created_at desc"))
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
var users []dto.FtpInfo
|
||||
for _, user := range lists {
|
||||
var item dto.FtpInfo
|
||||
if err := copier.Copy(&item, &user); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
item.Password, _ = encrypt.StringDecrypt(item.Password)
|
||||
users = append(users, item)
|
||||
}
|
||||
return total, users, err
|
||||
}
|
||||
|
||||
func (f *FtpService) Sync() error {
|
||||
client, err := toolbox.NewFtpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lists, err := client.LoadList()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
listsInDB, err := ftpRepo.GetList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sameData := make(map[string]struct{})
|
||||
for _, item := range lists {
|
||||
for _, itemInDB := range listsInDB {
|
||||
if item.User == itemInDB.User {
|
||||
sameData[item.User] = struct{}{}
|
||||
if item.Path != itemInDB.Path || item.Status != itemInDB.Status {
|
||||
_ = ftpRepo.Update(itemInDB.ID, map[string]interface{}{"path": item.Path, "status": item.Status})
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, item := range lists {
|
||||
if _, ok := sameData[item.User]; !ok {
|
||||
_ = ftpRepo.Create(&model.Ftp{User: item.User, Path: item.Path, Status: item.Status})
|
||||
}
|
||||
}
|
||||
for _, item := range listsInDB {
|
||||
if _, ok := sameData[item.User]; !ok {
|
||||
_ = ftpRepo.Update(item.ID, map[string]interface{}{"status": "deleted"})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FtpService) Create(req dto.FtpCreate) (uint, error) {
|
||||
if _, err := os.Stat(req.Path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(req.Path, os.ModePerm); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
pass, err := encrypt.StringEncrypt(req.Password)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
userInDB, _ := ftpRepo.Get(hostRepo.WithByUser(req.User))
|
||||
if userInDB.ID != 0 {
|
||||
return 0, constant.ErrRecordExist
|
||||
}
|
||||
client, err := toolbox.NewFtpClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := client.UserAdd(req.User, req.Password, req.Path); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var ftp model.Ftp
|
||||
if err := copier.Copy(&ftp, &req); err != nil {
|
||||
return 0, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
ftp.Status = constant.StatusEnable
|
||||
ftp.Password = pass
|
||||
if err := ftpRepo.Create(&ftp); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return ftp.ID, nil
|
||||
}
|
||||
|
||||
func (f *FtpService) Delete(req dto.BatchDeleteReq) error {
|
||||
client, err := toolbox.NewFtpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, id := range req.Ids {
|
||||
ftpItem, err := ftpRepo.Get(commonRepo.WithByID(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = client.UserDel(ftpItem.User)
|
||||
_ = ftpRepo.Delete(commonRepo.WithByID(id))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FtpService) Update(req dto.FtpUpdate) error {
|
||||
if _, err := os.Stat(req.Path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(req.Path, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pass, err := encrypt.StringEncrypt(req.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ftpItem, _ := ftpRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if ftpItem.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
passItem, err := encrypt.StringDecrypt(ftpItem.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := toolbox.NewFtpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needReload := false
|
||||
updates := make(map[string]interface{})
|
||||
if req.Password != passItem {
|
||||
if err := client.SetPasswd(ftpItem.User, req.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
updates["password"] = pass
|
||||
needReload = true
|
||||
}
|
||||
if req.Status != ftpItem.Status {
|
||||
if err := client.SetStatus(ftpItem.User, req.Status); err != nil {
|
||||
return err
|
||||
}
|
||||
updates["status"] = req.Status
|
||||
needReload = true
|
||||
}
|
||||
if req.Path != ftpItem.Path {
|
||||
if err := client.SetPath(ftpItem.User, req.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
updates["path"] = req.Path
|
||||
needReload = true
|
||||
}
|
||||
if req.Description != ftpItem.Description {
|
||||
updates["description"] = req.Description
|
||||
}
|
||||
if needReload {
|
||||
_ = client.Reload()
|
||||
}
|
||||
if len(updates) != 0 {
|
||||
return ftpRepo.Update(ftpItem.ID, updates)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -307,7 +307,7 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = section.NewKey("command", strings.TrimSpace(req.Command))
|
||||
_, _ = section.NewKey("command", req.Command)
|
||||
_, _ = section.NewKey("directory", req.Dir)
|
||||
_, _ = section.NewKey("autorestart", "true")
|
||||
_, _ = section.NewKey("startsecs", "3")
|
||||
@@ -338,7 +338,7 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
}
|
||||
|
||||
commandKey := section.Key("command")
|
||||
commandKey.SetValue(strings.TrimSpace(req.Command))
|
||||
commandKey.SetValue(req.Command)
|
||||
directoryKey := section.Key("directory")
|
||||
directoryKey.SetValue(req.Dir)
|
||||
userKey := section.Key("user")
|
||||
|
||||
@@ -7,15 +7,14 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -54,7 +53,6 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err = client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
@@ -108,7 +106,6 @@ func (u *ImageService) ListAll() ([]dto.ImageInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -136,7 +133,6 @@ func (u *ImageService) List() ([]dto.Options, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err = client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -156,7 +152,6 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
fileName := "Dockerfile"
|
||||
if req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
||||
@@ -240,7 +235,6 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
|
||||
if _, err := os.Stat(dockerLogDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dockerLogDir, os.ModePerm); err != nil {
|
||||
@@ -271,7 +265,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options := image.PullOptions{}
|
||||
options := types.ImagePullOptions{}
|
||||
if repo.Auth {
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
@@ -311,12 +305,10 @@ func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
res, err := client.ImageLoad(context.TODO(), file, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
content, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -332,7 +324,6 @@ func (u *ImageService) ImageSave(req dto.ImageSave) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
out, err := client.ImageSave(context.TODO(), []string{req.TagName})
|
||||
if err != nil {
|
||||
@@ -355,7 +346,6 @@ func (u *ImageService) ImageTag(req dto.ImageTag) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if err := client.ImageTag(context.TODO(), req.SourceID, req.TargetName); err != nil {
|
||||
return err
|
||||
@@ -368,22 +358,23 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options := image.PushOptions{All: true}
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
Password: repo.Password,
|
||||
options := types.ImagePushOptions{}
|
||||
if repo.Auth {
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
Password: repo.Password,
|
||||
}
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
options.RegistryAuth = authStr
|
||||
newName := fmt.Sprintf("%s/%s", repo.DownloadUrl, req.Name)
|
||||
if newName != req.TagName {
|
||||
if err := client.ImageTag(context.TODO(), req.TagName, newName); err != nil {
|
||||
@@ -425,7 +416,6 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, id := range req.Names {
|
||||
if _, err := client.ImageRemove(context.TODO(), id, types.ImageRemoveOptions{Force: req.Force, PruneChildren: true}); err != nil {
|
||||
if strings.Contains(err.Error(), "image is being used") || strings.Contains(err.Error(), "is using") {
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -9,8 +10,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
|
||||
@@ -77,7 +76,6 @@ func (n NginxService) GetStatus() (response.NginxStatus, error) {
|
||||
if err != nil {
|
||||
return response.NginxStatus{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
content, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return response.NginxStatus{}, err
|
||||
|
||||
@@ -4,14 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
@@ -27,6 +19,13 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/subosito/gotenv"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RuntimeService struct {
|
||||
@@ -44,7 +43,6 @@ type IRuntimeService interface {
|
||||
OperateNodeModules(req request.NodeModuleOperateReq) error
|
||||
SyncForRestart() error
|
||||
SyncRuntimeStatus() error
|
||||
DeleteCheck(installID uint) ([]dto.AppResource, error)
|
||||
}
|
||||
|
||||
func NewRuntimeService() IRuntimeService {
|
||||
@@ -178,18 +176,6 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt
|
||||
return total, res, nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) DeleteCheck(runTimeId uint) ([]dto.AppResource, error) {
|
||||
var res []dto.AppResource
|
||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithRuntimeID(runTimeId))
|
||||
for _, website := range websites {
|
||||
res = append(res, dto.AppResource{
|
||||
Type: "website",
|
||||
Name: website.PrimaryDomain,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(runtimeDelete.ID))
|
||||
if err != nil {
|
||||
@@ -207,7 +193,6 @@ func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
imageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -435,7 +420,6 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
imageID, err := client.GetImageIDByName(oldImage)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,6 +3,16 @@ package service
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/subosito/gotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -11,18 +21,6 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
httpUtil "github.com/1Panel-dev/1Panel/backend/utils/http"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/subosito/gotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
|
||||
@@ -55,10 +53,7 @@ func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp fil
|
||||
}
|
||||
|
||||
go func() {
|
||||
if _, _, err := httpUtil.HandleGet(nodeDetail.DownloadCallBackUrl, http.MethodGet, constant.TimeOut5s); err != nil {
|
||||
global.LOG.Errorf("http request failed(handleNode), err: %v", err)
|
||||
return
|
||||
}
|
||||
_, _ = http.Get(nodeDetail.DownloadCallBackUrl)
|
||||
}()
|
||||
go startRuntime(runtime)
|
||||
|
||||
@@ -149,7 +144,6 @@ func runComposeCmdWithLog(operate string, composePath string, logPath string) er
|
||||
global.LOG.Errorf("Failed to open log file: %v", err)
|
||||
return err
|
||||
}
|
||||
defer logFile.Close()
|
||||
multiWriterStdout := io.MultiWriter(os.Stdout, logFile)
|
||||
cmd.Stdout = multiWriterStdout
|
||||
var stderrBuf bytes.Buffer
|
||||
@@ -178,7 +172,6 @@ func SyncRuntimeContainerStatus(runtime *model.Runtime) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err := cli.ListContainersByName(containerNames)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -235,7 +228,6 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
|
||||
if oldImageID != "" {
|
||||
client, err := docker.NewClient()
|
||||
if err == nil {
|
||||
defer client.Close()
|
||||
newImageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err == nil && newImageID != oldImageID {
|
||||
global.LOG.Infof("delete imageID [%s] ", oldImageID)
|
||||
@@ -398,7 +390,6 @@ func checkContainerName(name string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dockerCli.Close()
|
||||
names, err := dockerCli.ListContainersByName([]string{name})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -33,7 +33,6 @@ type ISettingService interface {
|
||||
GetSettingInfo() (*dto.SettingInfo, error)
|
||||
LoadInterfaceAddr() ([]string, error)
|
||||
Update(key, value string) error
|
||||
UpdateProxy(req dto.ProxyUpdate) error
|
||||
UpdatePassword(c *gin.Context, old, new string) error
|
||||
UpdatePort(port uint) error
|
||||
UpdateBindInfo(req dto.BindInfo) error
|
||||
@@ -63,12 +62,6 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
|
||||
if err := json.Unmarshal(arr, &info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if info.ProxyPasswdKeep != constant.StatusEnable {
|
||||
info.ProxyPasswd = ""
|
||||
} else {
|
||||
info.ProxyPasswd, _ = encrypt.StringDecrypt(info.ProxyPasswd)
|
||||
}
|
||||
|
||||
info.LocalTime = time.Now().Format("2006-01-02 15:04:05 MST -0700")
|
||||
return &info, err
|
||||
}
|
||||
@@ -169,29 +162,6 @@ func (u *SettingService) UpdateBindInfo(req dto.BindInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SettingService) UpdateProxy(req dto.ProxyUpdate) error {
|
||||
if err := settingRepo.Update("ProxyUrl", req.ProxyUrl); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("ProxyType", req.ProxyType); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("ProxyPort", req.ProxyPort); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("ProxyUser", req.ProxyUser); err != nil {
|
||||
return err
|
||||
}
|
||||
pass, _ := encrypt.StringEncrypt(req.ProxyPasswd)
|
||||
if err := settingRepo.Update("ProxyPasswd", pass); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("ProxyPasswdKeep", req.ProxyPasswdKeep); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SettingService) UpdatePort(port uint) error {
|
||||
if common.ScanPort(int(port)) {
|
||||
return buserr.WithDetail(constant.ErrPortInUsed, port, nil)
|
||||
@@ -347,18 +317,12 @@ func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data dto.SSLInfo
|
||||
data, err := loadInfoFromCert()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch sslType.Value {
|
||||
case "self":
|
||||
data, err = loadInfoFromCert()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "import":
|
||||
data, err = loadInfoFromCert()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := os.Stat(path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt")); err != nil {
|
||||
return nil, fmt.Errorf("load server.crt file failed, err: %v", err)
|
||||
}
|
||||
@@ -376,15 +340,9 @@ func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
id, _ := strconv.Atoi(sslID.Value)
|
||||
ssl, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(uint(id)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data.Domain = ssl.Domains
|
||||
data.SSLID = uint(id)
|
||||
data.Timeout = ssl.ExpireDate.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
return &data, nil
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error {
|
||||
@@ -426,23 +384,23 @@ func (u *SettingService) UpdatePassword(c *gin.Context, old, new string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadInfoFromCert() (dto.SSLInfo, error) {
|
||||
func loadInfoFromCert() (*dto.SSLInfo, error) {
|
||||
var info dto.SSLInfo
|
||||
certFile := path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt")
|
||||
if _, err := os.Stat(certFile); err != nil {
|
||||
return info, err
|
||||
return &info, err
|
||||
}
|
||||
certData, err := os.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return info, err
|
||||
return &info, err
|
||||
}
|
||||
certBlock, _ := pem.Decode(certData)
|
||||
if certBlock == nil {
|
||||
return info, err
|
||||
return &info, err
|
||||
}
|
||||
certObj, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return info, err
|
||||
return &info, err
|
||||
}
|
||||
var domains []string
|
||||
if len(certObj.IPAddresses) != 0 {
|
||||
@@ -453,7 +411,7 @@ func loadInfoFromCert() (dto.SSLInfo, error) {
|
||||
if len(certObj.DNSNames) != 0 {
|
||||
domains = append(domains, certObj.DNSNames...)
|
||||
}
|
||||
return dto.SSLInfo{
|
||||
return &dto.SSLInfo{
|
||||
Domain: strings.Join(domains, ","),
|
||||
Timeout: certObj.NotAfter.Format("2006-01-02 15:04:05"),
|
||||
RootPath: path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt"),
|
||||
|
||||
@@ -32,14 +32,14 @@ type ISnapshotService interface {
|
||||
SnapshotRecover(req dto.SnapshotRecover) error
|
||||
SnapshotRollback(req dto.SnapshotRecover) error
|
||||
SnapshotImport(req dto.SnapshotImport) error
|
||||
Delete(req dto.SnapshotBatchDelete) error
|
||||
Delete(req dto.BatchDeleteReq) error
|
||||
|
||||
LoadSnapShotStatus(id uint) (*dto.SnapshotStatus, error)
|
||||
|
||||
UpdateDescription(req dto.UpdateDescription) error
|
||||
readFromJson(path string) (SnapshotJson, error)
|
||||
|
||||
HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string, secret string) (string, error)
|
||||
HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string) (string, error)
|
||||
}
|
||||
|
||||
func NewISnapshotService() ISnapshotService {
|
||||
@@ -123,7 +123,7 @@ type SnapshotJson struct {
|
||||
}
|
||||
|
||||
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
||||
if _, err := u.HandleSnapshot(false, "", req, time.Now().Format("20060102150405"), req.Secret); err != nil {
|
||||
if _, err := u.HandleSnapshot(false, "", req, time.Now().Format("20060102150405")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -180,7 +180,7 @@ func (u *SnapshotService) readFromJson(path string) (SnapshotJson, error) {
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string, secret string) (string, error) {
|
||||
func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string) (string, error) {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -274,7 +274,7 @@ func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto
|
||||
return
|
||||
}
|
||||
if snapStatus.Compress != constant.StatusDone {
|
||||
snapCompress(itemHelper, rootDir, secret)
|
||||
snapCompress(itemHelper, rootDir)
|
||||
}
|
||||
if snapStatus.Compress != constant.StatusDone {
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||
@@ -305,7 +305,7 @@ func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto
|
||||
return snap.Name, fmt.Errorf("snapshot %s 1panel data failed", snap.Name)
|
||||
}
|
||||
loadLogByStatus(snapStatus, logPath)
|
||||
snapCompress(itemHelper, rootDir, secret)
|
||||
snapCompress(itemHelper, rootDir)
|
||||
if snapStatus.Compress != constant.StatusDone {
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||
loadLogByStatus(snapStatus, logPath)
|
||||
@@ -323,25 +323,25 @@ func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto
|
||||
return snap.Name, nil
|
||||
}
|
||||
|
||||
func (u *SnapshotService) Delete(req dto.SnapshotBatchDelete) error {
|
||||
snaps, _ := snapshotRepo.GetList(commonRepo.WithIdsIn(req.Ids))
|
||||
for _, snap := range snaps {
|
||||
if req.DeleteWithFile {
|
||||
targetAccounts, err := loadClientMap(snap.From)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range targetAccounts {
|
||||
global.LOG.Debugf("remove snapshot file %s.tar.gz from %s", snap.Name, item.backType)
|
||||
_, _ = item.client.Delete(path.Join(item.backupPath, "system_snapshot", snap.Name+".tar.gz"))
|
||||
}
|
||||
}
|
||||
func (u *SnapshotService) Delete(req dto.BatchDeleteReq) error {
|
||||
backups, _ := snapshotRepo.GetList(commonRepo.WithIdsIn(req.Ids))
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, snap := range backups {
|
||||
itemFile := path.Join(localDir, "system", snap.Name)
|
||||
_ = os.RemoveAll(itemFile)
|
||||
|
||||
itemTarFile := path.Join(global.CONF.System.TmpDir, "system", snap.Name+".tar.gz")
|
||||
_ = os.Remove(itemTarFile)
|
||||
|
||||
_ = snapshotRepo.DeleteStatus(snap.ID)
|
||||
if err := snapshotRepo.Delete(commonRepo.WithByID(snap.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := snapshotRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -385,21 +385,15 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
|
||||
}
|
||||
}
|
||||
|
||||
func (u *SnapshotService) handleUnTar(sourceDir, targetDir string, secret string) error {
|
||||
func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
|
||||
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
commands := ""
|
||||
if len(secret) != 0 {
|
||||
extraCmd := "openssl enc -d -aes-256-cbc -k " + secret + " -in " + sourceDir + " | "
|
||||
commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, targetDir+" > /dev/null 2>&1")
|
||||
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
|
||||
} else {
|
||||
commands = fmt.Sprintf("tar zxvfC %s %s", sourceDir, targetDir)
|
||||
global.LOG.Debug(commands)
|
||||
}
|
||||
|
||||
commands := fmt.Sprintf("tar -zxf %s -C %s .", sourceDir, targetDir)
|
||||
global.LOG.Debug(commands)
|
||||
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
||||
if err != nil {
|
||||
if len(stdout) != 0 {
|
||||
|
||||
@@ -131,7 +131,7 @@ func snapBackup(snap snapHelper, localDir, targetDir string) {
|
||||
defer snap.Wg.Done()
|
||||
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"backup_data": constant.Running})
|
||||
status := constant.StatusDone
|
||||
if err := handleSnapTar(localDir, targetDir, "1panel_backup.tar.gz", "./system;./system_snapshot;", ""); err != nil {
|
||||
if err := handleSnapTar(localDir, targetDir, "1panel_backup.tar.gz", "./system;./system_snapshot;"); err != nil {
|
||||
status = err.Error()
|
||||
}
|
||||
snap.Status.BackupData = status
|
||||
@@ -158,7 +158,7 @@ func snapPanelData(snap snapHelper, localDir, targetDir string) {
|
||||
sysIP, _ := settingRepo.Get(settingRepo.WithByKey("SystemIP"))
|
||||
_ = settingRepo.Update("SystemIP", "")
|
||||
checkPointOfWal()
|
||||
if err := handleSnapTar(dataDir, targetDir, "1panel_data.tar.gz", exclusionRules, ""); err != nil {
|
||||
if err := handleSnapTar(dataDir, targetDir, "1panel_data.tar.gz", exclusionRules); err != nil {
|
||||
status = err.Error()
|
||||
}
|
||||
_ = snapshotRepo.Update(snap.SnapID, map[string]interface{}{"status": constant.StatusWaiting})
|
||||
@@ -168,11 +168,11 @@ func snapPanelData(snap snapHelper, localDir, targetDir string) {
|
||||
_ = settingRepo.Update("SystemIP", sysIP.Value)
|
||||
}
|
||||
|
||||
func snapCompress(snap snapHelper, rootDir string, secret string) {
|
||||
func snapCompress(snap snapHelper, rootDir string) {
|
||||
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": constant.StatusRunning})
|
||||
tmpDir := path.Join(global.CONF.System.TmpDir, "system")
|
||||
fileName := fmt.Sprintf("%s.tar.gz", path.Base(rootDir))
|
||||
if err := handleSnapTar(rootDir, tmpDir, fileName, "", secret); err != nil {
|
||||
if err := snap.FileOp.Compress([]string{rootDir}, tmpDir, fileName, files.TarGz); err != nil {
|
||||
snap.Status.Compress = err.Error()
|
||||
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": err.Error()})
|
||||
return
|
||||
@@ -221,7 +221,7 @@ func snapUpload(snap snapHelper, accounts string, file string) {
|
||||
_ = os.Remove(source)
|
||||
}
|
||||
|
||||
func handleSnapTar(sourceDir, targetDir, name, exclusionRules string, secret string) error {
|
||||
func handleSnapTar(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 {
|
||||
return err
|
||||
@@ -243,26 +243,9 @@ func handleSnapTar(sourceDir, targetDir, name, exclusionRules string, secret str
|
||||
exStr += exclude
|
||||
exMap[exclude] = struct{}{}
|
||||
}
|
||||
path := ""
|
||||
if strings.Contains(sourceDir, "/") {
|
||||
itemDir := strings.ReplaceAll(sourceDir[strings.LastIndex(sourceDir, "/"):], "/", "")
|
||||
aheadDir := sourceDir[:strings.LastIndex(sourceDir, "/")]
|
||||
if len(aheadDir) == 0 {
|
||||
aheadDir = "/"
|
||||
}
|
||||
path += fmt.Sprintf("-C %s %s", aheadDir, itemDir)
|
||||
} else {
|
||||
path = sourceDir
|
||||
}
|
||||
commands := ""
|
||||
if len(secret) != 0 {
|
||||
extraCmd := "| openssl enc -aes-256-cbc -salt -k " + secret + " -out"
|
||||
commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s %s", " -"+exStr, path, extraCmd, targetDir+"/"+name)
|
||||
global.LOG.Debug(strings.ReplaceAll(commands, fmt.Sprintf(" %s ", secret), "******"))
|
||||
} else {
|
||||
commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
||||
global.LOG.Debug(commands)
|
||||
}
|
||||
|
||||
commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
||||
global.LOG.Debug(commands)
|
||||
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
||||
if err != nil {
|
||||
if len(stdout) != 0 {
|
||||
|
||||
@@ -30,6 +30,14 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
|
||||
if _, err := os.Stat(baseDir); err != nil && os.IsNotExist(err) {
|
||||
_ = os.MkdirAll(baseDir, os.ModePerm)
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "Backup" {
|
||||
if err := backupBeforeRecover(snap); err != nil {
|
||||
updateRecoverStatus(snap.ID, isRecover, "Backup", constant.StatusFailed, fmt.Sprintf("handle backup before recover failed, err: %v", err))
|
||||
return
|
||||
}
|
||||
global.LOG.Debug("handle backup before recover successful!")
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "Download" || req.ReDownload {
|
||||
if err := handleDownloadSnapshot(snap, baseDir); err != nil {
|
||||
updateRecoverStatus(snap.ID, isRecover, "Backup", constant.StatusFailed, err.Error())
|
||||
@@ -39,25 +47,14 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "Decompress" {
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.tar.gz", baseDir, snap.Name), baseDir, req.Secret); err != nil {
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.tar.gz", baseDir, snap.Name), baseDir); err != nil {
|
||||
updateRecoverStatus(snap.ID, isRecover, "Decompress", constant.StatusFailed, fmt.Sprintf("decompress file failed, err: %v", err))
|
||||
return
|
||||
}
|
||||
global.LOG.Debug("decompress snapshot file successful!", baseDir)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "Backup" {
|
||||
if err := backupBeforeRecover(snap, ""); err != nil {
|
||||
updateRecoverStatus(snap.ID, isRecover, "Backup", constant.StatusFailed, fmt.Sprintf("handle backup before recover failed, err: %v", err))
|
||||
return
|
||||
}
|
||||
global.LOG.Debug("handle backup before recover successful!")
|
||||
req.IsNew = true
|
||||
}
|
||||
snapFileDir = fmt.Sprintf("%s/%s", baseDir, snap.Name)
|
||||
if _, err := os.Stat(snapFileDir); err != nil {
|
||||
snapFileDir = baseDir
|
||||
}
|
||||
} else {
|
||||
snapFileDir = fmt.Sprintf("%s/1panel_original/original_%s", global.CONF.System.BaseDir, snap.Name)
|
||||
if _, err := os.Stat(snapFileDir); err != nil {
|
||||
@@ -117,7 +114,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
|
||||
}
|
||||
|
||||
if req.IsNew || snap.InterruptStep == "1PanelBackups" {
|
||||
if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_backup.tar.gz"), snapJson.BackupDataDir, ""); err != nil {
|
||||
if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_backup.tar.gz"), snapJson.BackupDataDir); err != nil {
|
||||
updateRecoverStatus(snap.ID, isRecover, "1PanelBackups", constant.StatusFailed, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -127,7 +124,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
|
||||
|
||||
if req.IsNew || snap.InterruptStep == "1PanelData" {
|
||||
checkPointOfWal()
|
||||
if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_data.tar.gz"), path.Join(snapJson.BaseDir, "1panel"), ""); err != nil {
|
||||
if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_data.tar.gz"), path.Join(snapJson.BaseDir, "1panel")); err != nil {
|
||||
updateRecoverStatus(snap.ID, isRecover, "1PanelData", constant.StatusFailed, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -149,7 +146,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
|
||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
||||
}
|
||||
|
||||
func backupBeforeRecover(snap model.Snapshot, secret string) error {
|
||||
func backupBeforeRecover(snap model.Snapshot) error {
|
||||
baseDir := fmt.Sprintf("%s/1panel_original/original_%s", global.CONF.System.BaseDir, snap.Name)
|
||||
var wg sync.WaitGroup
|
||||
var status model.SnapshotStatus
|
||||
|
||||
@@ -479,12 +479,9 @@ func loadFailedAuthDatas(line string) dto.SSHHistory {
|
||||
return data
|
||||
}
|
||||
data.DateStr = dataStr
|
||||
switch index {
|
||||
case 1:
|
||||
data.User = parts[9]
|
||||
case 2:
|
||||
if index == 2 {
|
||||
data.User = parts[10]
|
||||
default:
|
||||
} else {
|
||||
data.User = parts[7]
|
||||
}
|
||||
data.AuthMode = parts[6+index]
|
||||
@@ -546,22 +543,14 @@ func loadDate(currentYear int, DateStr string, nyc *time.Location) time.Time {
|
||||
|
||||
func analyzeDateStr(parts []string) (int, string) {
|
||||
t, err := time.Parse("2006-01-02T15:04:05.999999-07:00", parts[0])
|
||||
if err == nil {
|
||||
if len(parts) < 12 {
|
||||
return 0, ""
|
||||
}
|
||||
return 0, t.Format("2006 Jan 2 15:04:05")
|
||||
}
|
||||
t, err = time.Parse("2006-01-02 15:04:05", fmt.Sprintf("%s %s", parts[0], parts[1]))
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
if len(parts) < 14 {
|
||||
return 0, ""
|
||||
}
|
||||
return 1, t.Format("2006 Jan 2 15:04:05")
|
||||
return 2, fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2])
|
||||
}
|
||||
|
||||
if len(parts) < 14 {
|
||||
if len(parts) < 12 {
|
||||
return 0, ""
|
||||
}
|
||||
return 2, fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2])
|
||||
return 0, t.Format("2006 Jan 2 15:04:05")
|
||||
}
|
||||
|
||||
+58
-138
@@ -3,20 +3,20 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
httpUtil "github.com/1Panel-dev/1Panel/backend/utils/http"
|
||||
)
|
||||
|
||||
type UpgradeService struct{}
|
||||
@@ -37,43 +37,45 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
DeveloperMode, err := settingRepo.Get(settingRepo.WithByKey("DeveloperMode"))
|
||||
|
||||
latestVersion, err := u.loadVersion(true, currentVersion.Value)
|
||||
if err != nil {
|
||||
global.LOG.Infof("load latest version failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
upgrade.TestVersion, upgrade.NewVersion, upgrade.LatestVersion = u.loadVersionByMode(DeveloperMode.Value, currentVersion.Value)
|
||||
var itemVersion string
|
||||
if len(upgrade.LatestVersion) != 0 {
|
||||
itemVersion = upgrade.LatestVersion
|
||||
if !common.ComparePanelVersion(string(latestVersion), currentVersion.Value) {
|
||||
return nil, err
|
||||
}
|
||||
if len(upgrade.NewVersion) != 0 {
|
||||
upgrade.LatestVersion = latestVersion
|
||||
if latestVersion[0:4] == currentVersion.Value[0:4] {
|
||||
upgrade.NewVersion = ""
|
||||
} else {
|
||||
newerVersion, err := u.loadVersion(false, currentVersion.Value)
|
||||
if err != nil {
|
||||
global.LOG.Infof("load newer version failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if newerVersion == currentVersion.Value {
|
||||
upgrade.NewVersion = ""
|
||||
} else {
|
||||
upgrade.NewVersion = newerVersion
|
||||
}
|
||||
}
|
||||
itemVersion := upgrade.LatestVersion
|
||||
if upgrade.NewVersion != "" {
|
||||
itemVersion = upgrade.NewVersion
|
||||
}
|
||||
if (global.CONF.System.Mode == "dev" || DeveloperMode.Value == "enable") && len(upgrade.TestVersion) != 0 {
|
||||
itemVersion = upgrade.TestVersion
|
||||
}
|
||||
if len(itemVersion) == 0 {
|
||||
return &upgrade, nil
|
||||
}
|
||||
mode := global.CONF.System.Mode
|
||||
if strings.Contains(itemVersion, "beta") {
|
||||
mode = "beta"
|
||||
}
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, mode, itemVersion, itemVersion))
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, itemVersion, itemVersion))
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", itemVersion, err)
|
||||
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", latestVersion, err)
|
||||
}
|
||||
upgrade.ReleaseNote = notes
|
||||
return &upgrade, nil
|
||||
}
|
||||
|
||||
func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
|
||||
mode := global.CONF.System.Mode
|
||||
if strings.Contains(req.Version, "beta") {
|
||||
mode = "beta"
|
||||
}
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, mode, req.Version, req.Version))
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version, req.Version))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load releases-notes of version %s failed, err: %v", req.Version, err)
|
||||
}
|
||||
@@ -97,11 +99,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
return err
|
||||
}
|
||||
|
||||
mode := global.CONF.System.Mode
|
||||
if strings.Contains(req.Version, "beta") {
|
||||
mode = "beta"
|
||||
}
|
||||
downloadPath := fmt.Sprintf("%s/%s/%s/release", global.CONF.System.RepoUrl, mode, req.Version)
|
||||
downloadPath := fmt.Sprintf("%s/%s/%s/release", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version)
|
||||
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", itemArch)
|
||||
_ = settingRepo.Update("SystemStatus", "Upgrading")
|
||||
go func() {
|
||||
@@ -109,7 +107,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
defer func() {
|
||||
global.Cron.Start()
|
||||
}()
|
||||
if err := fileOp.DownloadFileWithProxy(downloadPath+"/"+fileName, rootDir+"/"+fileName); err != nil {
|
||||
if err := fileOp.DownloadFile(downloadPath+"/"+fileName, rootDir+"/"+fileName); err != nil {
|
||||
global.LOG.Errorf("download service file failed, err: %v", err)
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
return
|
||||
@@ -118,7 +116,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
defer func() {
|
||||
_ = os.Remove(rootDir)
|
||||
}()
|
||||
if err := handleUnTar(rootDir+"/"+fileName, rootDir, ""); err != nil {
|
||||
if err := handleUnTar(rootDir+"/"+fileName, rootDir); err != nil {
|
||||
global.LOG.Errorf("decompress file failed, err: %v", err)
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
return
|
||||
@@ -175,8 +173,8 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
|
||||
if err := fileOp.Copy("/etc/systemd/system/1panel.service", originalDir); err != nil {
|
||||
return err
|
||||
}
|
||||
checkPointOfWal()
|
||||
if err := handleTar(path.Join(global.CONF.System.BaseDir, "1panel/db"), originalDir, "db.tar.gz", "db/1Panel.db-*", ""); err != nil {
|
||||
dbPath := global.CONF.System.DbPath + "/" + global.CONF.System.DbFile
|
||||
if err := fileOp.Copy(dbPath, originalDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -184,17 +182,8 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
|
||||
|
||||
func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
|
||||
checkPointOfWal()
|
||||
if _, err := os.Stat(path.Join(originalDir, "1Panel.db")); err == nil {
|
||||
if err := common.CopyFile(path.Join(originalDir, "1Panel.db"), global.CONF.System.DbPath); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel db failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path.Join(originalDir, "db.tar.gz")); err == nil {
|
||||
if err := handleUnTar(path.Join(originalDir, "db.tar.gz"), global.CONF.System.DbPath, ""); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel db failed, err: %v", err)
|
||||
}
|
||||
if err := common.CopyFile(path.Join(originalDir, "1Panel.db"), global.CONF.System.DbPath); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||
}
|
||||
if err := common.CopyFile(path.Join(originalDir, "1panel"), "/usr/local/bin"); err != nil {
|
||||
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
|
||||
@@ -213,118 +202,49 @@ func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UpgradeService) loadVersionByMode(developer, currentVersion string) (string, string, string) {
|
||||
var current, latest string
|
||||
if global.CONF.System.Mode == "dev" {
|
||||
betaVersionLatest := u.loadVersion(true, currentVersion, "beta")
|
||||
devVersionLatest := u.loadVersion(true, currentVersion, "dev")
|
||||
if common.ComparePanelVersion(betaVersionLatest, devVersionLatest) {
|
||||
return betaVersionLatest, "", ""
|
||||
}
|
||||
return devVersionLatest, "", ""
|
||||
}
|
||||
|
||||
betaVersionLatest := ""
|
||||
latest = u.loadVersion(true, currentVersion, "stable")
|
||||
current = u.loadVersion(false, currentVersion, "stable")
|
||||
if developer == "enable" {
|
||||
betaVersionLatest = u.loadVersion(true, currentVersion, "beta")
|
||||
}
|
||||
if current != latest {
|
||||
return betaVersionLatest, current, latest
|
||||
}
|
||||
|
||||
versionPart := strings.Split(current, ".")
|
||||
if len(versionPart) < 3 {
|
||||
return betaVersionLatest, current, latest
|
||||
}
|
||||
num, _ := strconv.Atoi(versionPart[1])
|
||||
if num == 0 {
|
||||
return betaVersionLatest, current, latest
|
||||
}
|
||||
if num >= 10 {
|
||||
if current[:6] == currentVersion[:6] {
|
||||
return betaVersionLatest, current, ""
|
||||
}
|
||||
return betaVersionLatest, "", latest
|
||||
}
|
||||
if current[:5] == currentVersion[:5] {
|
||||
return betaVersionLatest, current, ""
|
||||
}
|
||||
return betaVersionLatest, "", latest
|
||||
}
|
||||
|
||||
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion, mode string) string {
|
||||
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, mode)
|
||||
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (string, error) {
|
||||
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode)
|
||||
if !isLatest {
|
||||
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, mode)
|
||||
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, global.CONF.System.Mode)
|
||||
}
|
||||
_, latestVersionRes, err := httpUtil.HandleGet(path, http.MethodGet, constant.TimeOut20s)
|
||||
latestVersionRes, err := http.Get(path)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load latest version from oss failed, err: %v", err)
|
||||
return ""
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
version := string(latestVersionRes)
|
||||
if strings.Contains(version, "<") {
|
||||
global.LOG.Errorf("load latest version from oss failed, err: %v", version)
|
||||
return ""
|
||||
defer latestVersionRes.Body.Close()
|
||||
version, err := io.ReadAll(latestVersionRes.Body)
|
||||
if err != nil {
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
if isLatest {
|
||||
return u.checkVersion(version, currentVersion)
|
||||
return string(version), nil
|
||||
}
|
||||
|
||||
versionMap := make(map[string]string)
|
||||
if err := json.Unmarshal(latestVersionRes, &versionMap); err != nil {
|
||||
global.LOG.Errorf("load latest version from oss failed (error unmarshal), err: %v", err)
|
||||
return ""
|
||||
if err := json.Unmarshal(version, &versionMap); err != nil {
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
|
||||
versionPart := strings.Split(currentVersion, ".")
|
||||
if len(versionPart) < 3 {
|
||||
global.LOG.Errorf("current version is error format: %s", currentVersion)
|
||||
return ""
|
||||
}
|
||||
num, _ := strconv.Atoi(versionPart[1])
|
||||
if num == 0 {
|
||||
global.LOG.Errorf("current version is error format: %s", currentVersion)
|
||||
return ""
|
||||
}
|
||||
if num >= 10 {
|
||||
if version, ok := versionMap[currentVersion[0:5]]; ok {
|
||||
return u.checkVersion(version, currentVersion)
|
||||
}
|
||||
return ""
|
||||
if len(currentVersion) < 4 {
|
||||
return "", fmt.Errorf("current version is error format: %s", currentVersion)
|
||||
}
|
||||
if version, ok := versionMap[currentVersion[0:4]]; ok {
|
||||
return u.checkVersion(version, currentVersion)
|
||||
return version, nil
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (u *UpgradeService) checkVersion(v2, v1 string) string {
|
||||
addSuffix := false
|
||||
if !strings.Contains(v1, "-") {
|
||||
v1 = v1 + "-lts"
|
||||
}
|
||||
if !strings.Contains(v2, "-") {
|
||||
addSuffix = true
|
||||
v2 = v2 + "-lts"
|
||||
}
|
||||
if common.ComparePanelVersion(v2, v1) {
|
||||
if addSuffix {
|
||||
return strings.TrimSuffix(v2, "-lts")
|
||||
}
|
||||
return v2
|
||||
}
|
||||
return ""
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
|
||||
func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
|
||||
_, releaseNotes, err := httpUtil.HandleGet(path, http.MethodGet, constant.TimeOut20s)
|
||||
releaseNotes, err := http.Get(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(releaseNotes), nil
|
||||
defer releaseNotes.Body.Close()
|
||||
release, err := io.ReadAll(releaseNotes.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(release), nil
|
||||
}
|
||||
|
||||
func loadArch() (string, error) {
|
||||
|
||||
@@ -180,9 +180,6 @@ func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
|
||||
|
||||
func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error) {
|
||||
alias := create.Alias
|
||||
if alias == "default" {
|
||||
return buserr.New("ErrDefaultAlias")
|
||||
}
|
||||
if common.ContainsChinese(alias) {
|
||||
alias, err = common.PunycodeEncode(alias)
|
||||
if err != nil {
|
||||
@@ -296,7 +293,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
install *model.AppInstall
|
||||
)
|
||||
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
|
||||
req.Name = reg.ReplaceAllString(strings.ToLower(alias), "")
|
||||
req.Name = reg.ReplaceAllString(strings.ToLower(create.PrimaryDomain), "")
|
||||
req.AppDetailId = create.AppInstall.AppDetailId
|
||||
req.Params = create.AppInstall.Params
|
||||
req.Params["IMAGE_NAME"] = runtime.Image
|
||||
@@ -331,14 +328,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(create.FtpUser) != 0 && len(create.FtpPassword) != 0 {
|
||||
itemID, err := NewIFtpService().Create(dto.FtpCreate{User: create.FtpUser, Password: create.FtpPassword, Path: path.Join(global.CONF.System.BaseDir, "1panel/apps/openresty/openresty/www/sites", website.Alias, "index")})
|
||||
if err != nil {
|
||||
global.LOG.Errorf("create ftp for website failed, err: %v", err)
|
||||
}
|
||||
website.FtpID = itemID
|
||||
}
|
||||
|
||||
if err = createWafConfig(website, domains); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -454,8 +443,7 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
|
||||
|
||||
tx, ctx := helper.GetTxAndContext()
|
||||
defer tx.Rollback()
|
||||
|
||||
go NewIBackupService().DeleteRecordByName("website", website.PrimaryDomain, website.Alias, req.DeleteBackup)
|
||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("website"), commonRepo.WithByName(website.Alias))
|
||||
if err := websiteRepo.DeleteBy(ctx, commonRepo.WithByID(req.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -464,6 +452,14 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
|
||||
}
|
||||
tx.Commit()
|
||||
|
||||
if req.DeleteBackup {
|
||||
localDir, _ := loadLocalDir()
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("website/%s", website.Alias))
|
||||
if _, err := os.Stat(backupDir); err == nil {
|
||||
_ = os.RemoveAll(backupDir)
|
||||
}
|
||||
global.LOG.Infof("delete website %s backups successful", website.Alias)
|
||||
}
|
||||
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/website/%s", website.Alias))
|
||||
if _, err := os.Stat(uploadDir); err == nil {
|
||||
_ = os.RemoveAll(uploadDir)
|
||||
@@ -526,7 +522,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
for _, domain := range domainModels {
|
||||
wafSite.Domains = append(wafSite.Domains, domain.Domain)
|
||||
if domain.Port != 80 && domain.Port != 443 {
|
||||
wafSite.Host = append(wafSite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
|
||||
wafSite.Host = append(wafSite.Host, domain.Domain+":"+string(rune(domain.Port)))
|
||||
}
|
||||
}
|
||||
if len(wafSite.Host) == 0 {
|
||||
@@ -619,7 +615,7 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
|
||||
oldHostArray := wafSite.Host
|
||||
var newHostArray []string
|
||||
for _, host := range oldHostArray {
|
||||
if host == webSiteDomain.Domain+":"+strconv.Itoa(webSiteDomain.Port) {
|
||||
if host == webSiteDomain.Domain+":"+string(rune(webSiteDomain.Port)) {
|
||||
continue
|
||||
}
|
||||
newHostArray = append(newHostArray, host)
|
||||
@@ -941,7 +937,7 @@ func (w WebsiteService) PreInstallCheck(req request.WebsiteInstallCheckReq) ([]r
|
||||
if len(checkIds) > 0 {
|
||||
installList, _ := appInstallRepo.ListBy(commonRepo.WithIdsIn(checkIds))
|
||||
for _, install := range installList {
|
||||
if err = syncAppInstallStatus(&install, false); err != nil {
|
||||
if err = syncAppInstallStatus(&install); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, response.WebsitePreInstallCheck{
|
||||
@@ -1037,16 +1033,14 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
|
||||
case constant.EnableLog:
|
||||
key := "access_log"
|
||||
logPath := path.Join("/www", "sites", website.Alias, "log", req.LogType)
|
||||
params := []string{logPath}
|
||||
switch req.LogType {
|
||||
case constant.AccessLog:
|
||||
params = append(params, "main")
|
||||
website.AccessLog = true
|
||||
case constant.ErrorLog:
|
||||
key = "error_log"
|
||||
website.ErrorLog = true
|
||||
}
|
||||
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: key, Params: params}}, &website); err != nil {
|
||||
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: key, Params: []string{logPath}}}, &website); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := websiteRepo.Save(context.Background(), &website); err != nil {
|
||||
|
||||
@@ -82,7 +82,7 @@ func (w WebsiteCAService) Create(create request.WebsiteCACreate) (*request.Websi
|
||||
}
|
||||
|
||||
rootCA := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(time.Now().Unix() + 1),
|
||||
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||
Subject: pkixName,
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
@@ -279,7 +279,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
notAfter = notAfter.AddDate(0, 0, req.Time)
|
||||
}
|
||||
interCsr := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(time.Now().Unix() + 2),
|
||||
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||
Subject: rootCsr.Subject,
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: notAfter,
|
||||
@@ -315,7 +315,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
subject := rootCsr.Subject
|
||||
subject.CommonName = commonName
|
||||
csr := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(time.Now().Unix() + 3),
|
||||
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||
Subject: subject,
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: notAfter,
|
||||
@@ -346,7 +346,6 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
websiteSSL.StartDate = cert.NotBefore
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.Organization = rootCsr.Subject.Organization[0]
|
||||
websiteSSL.Status = constant.SSLReady
|
||||
|
||||
if req.Renew {
|
||||
if err := websiteSSLRepo.Save(websiteSSL); err != nil {
|
||||
|
||||
@@ -102,12 +102,6 @@ func (w WebsiteSSLService) Search(search request.WebsiteSSLSearch) ([]response.W
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error) {
|
||||
if create.Nameserver1 != "" && !common.IsValidIP(create.Nameserver1) {
|
||||
return create, buserr.New("ErrParseIP")
|
||||
}
|
||||
if create.Nameserver2 != "" && !common.IsValidIP(create.Nameserver2) {
|
||||
return create, buserr.New("ErrParseIP")
|
||||
}
|
||||
var res request.WebsiteSSLCreate
|
||||
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(create.AcmeAccountID))
|
||||
if err != nil {
|
||||
@@ -122,10 +116,6 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
||||
KeyType: create.KeyType,
|
||||
PushDir: create.PushDir,
|
||||
Description: create.Description,
|
||||
Nameserver1: create.Nameserver1,
|
||||
Nameserver2: create.Nameserver2,
|
||||
SkipDNS: create.SkipDNS,
|
||||
DisableCNAME: create.DisableCNAME,
|
||||
}
|
||||
if create.PushDir {
|
||||
if !files.NewFileOp().Stat(create.Dir) {
|
||||
@@ -201,7 +191,7 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, *websiteSSL); err != nil {
|
||||
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, apply.SkipDNSCheck); err != nil {
|
||||
return err
|
||||
}
|
||||
case constant.Http:
|
||||
@@ -378,62 +368,15 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams := make(map[string]interface{})
|
||||
updateParams["primary_domain"] = update.PrimaryDomain
|
||||
updateParams["description"] = update.Description
|
||||
updateParams["provider"] = update.Provider
|
||||
updateParams["key_type"] = update.KeyType
|
||||
updateParams["push_dir"] = update.PushDir
|
||||
updateParams["disable_cname"] = update.DisableCNAME
|
||||
updateParams["skip_dns"] = update.SkipDNS
|
||||
updateParams["nameserver1"] = update.Nameserver1
|
||||
updateParams["nameserver2"] = update.Nameserver2
|
||||
|
||||
if websiteSSL.Provider != constant.SelfSigned {
|
||||
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(update.AcmeAccountID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams["acme_account_id"] = acmeAccount.ID
|
||||
}
|
||||
|
||||
if update.PushDir {
|
||||
if !files.NewFileOp().Stat(update.Dir) {
|
||||
return buserr.New(constant.ErrLinkPathNotFound)
|
||||
}
|
||||
updateParams["dir"] = update.Dir
|
||||
}
|
||||
var domains []string
|
||||
if update.OtherDomains != "" {
|
||||
otherDomainArray := strings.Split(update.OtherDomains, "\n")
|
||||
for _, domain := range otherDomainArray {
|
||||
if !common.IsValidDomain(domain) {
|
||||
return buserr.WithName("ErrDomainFormat", domain)
|
||||
}
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
}
|
||||
updateParams["domains"] = strings.Join(domains, ",")
|
||||
if update.Provider == constant.DNSAccount || update.Provider == constant.Http || update.Provider == constant.SelfSigned {
|
||||
updateParams["auto_renew"] = update.AutoRenew
|
||||
} else {
|
||||
updateParams["auto_renew"] = false
|
||||
}
|
||||
if update.Provider == constant.DNSAccount {
|
||||
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(update.DnsAccountID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams["dns_account_id"] = dnsAccount.ID
|
||||
}
|
||||
return websiteSSLRepo.SaveByMap(websiteSSL, updateParams)
|
||||
websiteSSL.AutoRenew = update.AutoRenew
|
||||
websiteSSL.Description = update.Description
|
||||
return websiteSSLRepo.Save(websiteSSL)
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) Upload(req request.WebsiteSSLUpload) error {
|
||||
websiteSSL := &model.WebsiteSSL{
|
||||
Provider: constant.Manual,
|
||||
Description: req.Description,
|
||||
Status: constant.SSLReady,
|
||||
}
|
||||
var err error
|
||||
if req.SSLID > 0 {
|
||||
@@ -552,7 +495,7 @@ func (w WebsiteSSLService) DownloadFile(id uint) (*os.File, error) {
|
||||
return nil, err
|
||||
}
|
||||
fileName := websiteSSL.PrimaryDomain + ".zip"
|
||||
if err = fileOp.Compress([]string{path.Join(dir, "fullchain.pem"), path.Join(dir, "privkey.pem")}, dir, fileName, files.SdkZip, ""); err != nil {
|
||||
if err = fileOp.Compress([]string{path.Join(dir, "fullchain.pem"), path.Join(dir, "privkey.pem")}, dir, fileName, files.SdkZip); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.Open(path.Join(dir, fileName))
|
||||
|
||||
@@ -235,7 +235,7 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
server.UpdateServerName(serverNames)
|
||||
|
||||
siteFolder := path.Join("/www", "sites", website.Alias)
|
||||
server.UpdateDirective("access_log", []string{path.Join(siteFolder, "log", "access.log"), "main"})
|
||||
server.UpdateDirective("access_log", []string{path.Join(siteFolder, "log", "access.log")})
|
||||
server.UpdateDirective("error_log", []string{path.Join(siteFolder, "log", "error.log")})
|
||||
|
||||
rootIndex := path.Join("/www/sites", website.Alias, "index")
|
||||
@@ -316,7 +316,9 @@ func createWafConfig(website *model.Website, domains []model.WebsiteDomain) erro
|
||||
|
||||
for _, domain := range domains {
|
||||
wafWebsite.Domains = append(wafWebsite.Domains, domain.Domain)
|
||||
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
|
||||
if domain.Port != 80 && domain.Port != 443 {
|
||||
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+string(rune(domain.Port)))
|
||||
}
|
||||
}
|
||||
websitesArray = append(websitesArray, wafWebsite)
|
||||
websitesContent, err := json.Marshal(websitesArray)
|
||||
@@ -360,11 +362,11 @@ func createWafConfig(website *model.Website, domains []model.WebsiteDomain) erro
|
||||
return err
|
||||
}
|
||||
}
|
||||
defaultRulesName := []string{"acl", "args", "cookie", "defaultUaBlack", "defaultUrlBlack", "fileExt", "header", "methodWhite", "cdn"}
|
||||
defaultRulesName := []string{"acl", "args", "cookie", "defaultUaBlack", "defaultUrlBlack", "fileExt", "header", "methodWhite"}
|
||||
for _, ruleName := range defaultRulesName {
|
||||
srcPath := path.Join(defaultRuleDir, ruleName+".json")
|
||||
if fileOp.Stat(srcPath) {
|
||||
_ = fileOp.Copy(srcPath, websiteRuleDir)
|
||||
if err = fileOp.Copy(srcPath, websiteRuleDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,10 +431,6 @@ func delWafConfig(website model.Website, force bool) error {
|
||||
if !fileOp.Stat(wafDataPath) {
|
||||
return nil
|
||||
}
|
||||
monitorDir := path.Join(wafDataPath, "db", "sites", website.Alias)
|
||||
if fileOp.Stat(monitorDir) {
|
||||
_ = fileOp.DeleteDir(monitorDir)
|
||||
}
|
||||
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
|
||||
content, err := fileOp.GetContent(websitesConfigPath)
|
||||
if err != nil {
|
||||
@@ -561,16 +559,6 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
domains, err := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(website.ID))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
noDefaultPort := true
|
||||
for _, domain := range domains {
|
||||
if domain.Port == 80 {
|
||||
noDefaultPort = false
|
||||
}
|
||||
}
|
||||
config := nginxFull.SiteConfig.Config
|
||||
server := config.FindServers()[0]
|
||||
|
||||
@@ -590,17 +578,13 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
|
||||
server.RemoveListenByBind(httpPortIPV6)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
case constant.HTTPToHTTPS:
|
||||
if !noDefaultPort {
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
}
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
}
|
||||
server.AddHTTP2HTTPS()
|
||||
case constant.HTTPAlso:
|
||||
if !noDefaultPort {
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
}
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
@@ -738,15 +722,15 @@ func opWebsite(website *model.Website, operate string) error {
|
||||
website.Status = constant.WebStopped
|
||||
}
|
||||
if operate == constant.StartWeb {
|
||||
proxyInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||
absoluteIncludeDir := path.Join(nginxInstall.Install.GetPath(), fmt.Sprintf("/www/sites/%s/proxy", website.Alias))
|
||||
fileOp := files.NewFileOp()
|
||||
if fileOp.Stat(absoluteIncludeDir) && !files.IsEmptyDir(absoluteIncludeDir) {
|
||||
proxyInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||
if files.NewFileOp().Stat(absoluteIncludeDir) {
|
||||
server.UpdateDirective("include", []string{proxyInclude})
|
||||
}
|
||||
server.UpdateDirective("include", []string{proxyInclude})
|
||||
rewriteInclude := fmt.Sprintf("/www/sites/%s/rewrite/%s.conf", website.Alias, website.Alias)
|
||||
absoluteRewritePath := path.Join(nginxInstall.Install.GetPath(), rewriteInclude)
|
||||
if fileOp.Stat(absoluteRewritePath) {
|
||||
if files.NewFileOp().Stat(absoluteRewritePath) {
|
||||
server.UpdateDirective("include", []string{rewriteInclude})
|
||||
}
|
||||
rootIndex := path.Join("/www/sites", website.Alias, "index")
|
||||
@@ -775,7 +759,7 @@ func opWebsite(website *model.Website, operate string) error {
|
||||
return err
|
||||
}
|
||||
if runtime.Type == constant.RuntimePHP {
|
||||
if website.ProxyType == constant.RuntimeProxyUnix || website.ProxyType == constant.RuntimeProxyTcp {
|
||||
if website.ProxyType == constant.RuntimeProxyUnix {
|
||||
localPath = path.Join(nginxInstall.Install.GetPath(), rootIndex, "index.php")
|
||||
}
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||
@@ -861,7 +845,7 @@ func changeServiceName(newComposeContent, newServiceName string) (composeByte []
|
||||
return
|
||||
}
|
||||
value, ok := composeMap["services"]
|
||||
if !ok || value == nil {
|
||||
if !ok {
|
||||
err = buserr.New(constant.ErrFileParse)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ const (
|
||||
Syncing = "Syncing"
|
||||
SyncSuccess = "SyncSuccess"
|
||||
Paused = "Paused"
|
||||
UpErr = "UpErr"
|
||||
SyncErr = "SyncErr"
|
||||
|
||||
ContainerPrefix = "1Panel-"
|
||||
|
||||
|
||||
@@ -12,9 +12,3 @@ const (
|
||||
TypeSSL = "ssl"
|
||||
TypeSystem = "system"
|
||||
)
|
||||
|
||||
const (
|
||||
TimeOut5s = 5
|
||||
TimeOut20s = 20
|
||||
TimeOut5m = 300
|
||||
)
|
||||
|
||||
@@ -8,15 +8,16 @@ const (
|
||||
CodeSuccess = 200
|
||||
CodeErrBadRequest = 400
|
||||
CodeErrUnauthorized = 401
|
||||
CodeErrUnSafety = 402
|
||||
CodeErrForbidden = 403
|
||||
CodeErrNotFound = 404
|
||||
CodePasswordExpired = 405
|
||||
CodeAuth = 406
|
||||
CodeGlobalLoading = 407
|
||||
CodeErrIP = 408
|
||||
CodeErrDomain = 409
|
||||
CodeErrInternalServer = 500
|
||||
|
||||
CodeErrIP = 310
|
||||
CodeErrDomain = 311
|
||||
CodeErrEntrance = 312
|
||||
CodePasswordExpired = 313
|
||||
CodeErrHeader = 406
|
||||
|
||||
CodeErrXpack = 410
|
||||
)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
mathRand "math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -43,12 +41,9 @@ func Run() {
|
||||
if _, err := global.Cron.AddJob("@daily", job.NewSSLJob()); err != nil {
|
||||
global.LOG.Errorf("can not add ssl corn job: %s", err.Error())
|
||||
}
|
||||
if _, err := global.Cron.AddJob(fmt.Sprintf("%v %v * * *", mathRand.Intn(60), mathRand.Intn(3)), job.NewAppStoreJob()); err != nil {
|
||||
if _, err := global.Cron.AddJob("@daily", job.NewAppStoreJob()); err != nil {
|
||||
global.LOG.Errorf("can not add appstore corn job: %s", err.Error())
|
||||
}
|
||||
if _, err := global.Cron.AddJob("@daily", job.NewCacheJob()); err != nil {
|
||||
global.LOG.Errorf("can not add cache corn job: %s", err.Error())
|
||||
}
|
||||
|
||||
var backup model.BackupAccount
|
||||
_ = global.DB.Where("type = ?", "OneDrive").Find(&backup).Error
|
||||
@@ -71,7 +66,7 @@ func Run() {
|
||||
global.LOG.Errorf("start my cronjob failed, err: %v", err)
|
||||
}
|
||||
for i := 0; i < len(cronJobs); i++ {
|
||||
entryIDs, err := service.NewICronjobService().StartJob(&cronJobs[i], false)
|
||||
entryIDs, err := service.NewICronjobService().StartJob(&cronJobs[i])
|
||||
if err != nil {
|
||||
global.LOG.Errorf("start %s job %s failed, err: %v", cronJobs[i].Type, cronJobs[i].Name, err)
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package job
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cache struct{}
|
||||
|
||||
func NewCacheJob() *Cache {
|
||||
return &Cache{}
|
||||
}
|
||||
|
||||
func (c *Cache) Run() {
|
||||
global.LOG.Info("run cache gc start ...")
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
again:
|
||||
err := global.CacheDb.RunValueLogGC(0.7)
|
||||
if err == nil {
|
||||
goto again
|
||||
}
|
||||
}
|
||||
global.LOG.Info("run cache gc end ...")
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/configs"
|
||||
"github.com/1Panel-dev/1Panel/backend/init/cache/badger_db"
|
||||
"github.com/1Panel-dev/1Panel/backend/init/session/psession"
|
||||
"github.com/dgraph-io/badger/v4"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/robfig/cron/v3"
|
||||
@@ -21,7 +20,6 @@ var (
|
||||
VALID *validator.Validate
|
||||
SESSION *psession.PSession
|
||||
CACHE *badger_db.Cache
|
||||
CacheDb *badger.DB
|
||||
Viper *viper.Viper
|
||||
|
||||
Cron *cron.Cron
|
||||
|
||||
@@ -31,27 +31,6 @@ func GetMsgWithMap(key string, maps map[string]interface{}) string {
|
||||
}
|
||||
}
|
||||
|
||||
func GetMsgWithName(key string, name string, err error) string {
|
||||
var (
|
||||
content string
|
||||
dataMap = make(map[string]interface{})
|
||||
)
|
||||
dataMap["name"] = name
|
||||
if err != nil {
|
||||
dataMap["err"] = err.Error()
|
||||
}
|
||||
content, _ = global.I18n.Localize(&i18n.LocalizeConfig{
|
||||
MessageID: key,
|
||||
TemplateData: dataMap,
|
||||
})
|
||||
content = strings.ReplaceAll(content, "<no value>", "")
|
||||
if content == "" {
|
||||
return key
|
||||
} else {
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
||||
func GetErrMsg(key string, maps map[string]interface{}) string {
|
||||
var content string
|
||||
if maps == nil {
|
||||
|
||||
@@ -61,12 +61,6 @@ AppStoreIsSyncing: 'The App Store is syncing, please try again later'
|
||||
ErrGetCompose: "Failed to obtain docker-compose.yml file! {{ .detail }}"
|
||||
ErrAppWarn: "Abnormal status, please check the log"
|
||||
ErrAppParamKey: "Parameter {{ .name }} field exception"
|
||||
ErrAppUpgrade: "Failed to upgrade application {{ .name }} {{ .err }}"
|
||||
AppRecover: "App {{ .name }} rolled back "
|
||||
PullImageStart: "Start pulling image {{ .name }}"
|
||||
PullImageSuccess: "Image pulled successfully"
|
||||
UpgradeAppStart: "Start upgrading application {{ .name }}"
|
||||
UpgradeAppSuccess: "App {{ .name }} upgraded successfully"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "File can not read"
|
||||
@@ -87,13 +81,12 @@ ErrDomainIsExist: "Domain is already exist"
|
||||
ErrAliasIsExist: "Alias is already exist"
|
||||
ErrAppDelete: 'Other Website use this App'
|
||||
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
|
||||
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}'
|
||||
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}'
|
||||
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}"'
|
||||
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}"'
|
||||
ErrPHPResource: 'The local runtime does not support switching!'
|
||||
ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the index directory, which may cause an Access denied error when accessing the website. Please click the save button above'
|
||||
ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the index directory, which may cause Access denied errors when accessing the website.'
|
||||
ErrDomainIsUsed: "Domain is already used by website {{ .name }}"
|
||||
ErrDomainFormat: "{{ .name }} domain format error"
|
||||
ErrDefaultAlias: "default is a reserved code name, please use another code name"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "The certificate {{ .name }} is being used by the website and cannot be removed"
|
||||
@@ -185,7 +178,6 @@ ErrDefaultIP: "default is a reserved name, please change it to another name"
|
||||
ErrGroupInUse: "The IP group is used by the black/white list and cannot be deleted"
|
||||
ErrGroupExist: "IP group name already exists"
|
||||
ErrIPRange: "Wrong IP range"
|
||||
ErrIPExist: "IP is exit"
|
||||
|
||||
#license
|
||||
ErrLicense: "License format error, please check and try again!"
|
||||
|
||||
@@ -62,12 +62,6 @@ AppStoreIsSyncing: '應用程式商店正在同步中,請稍後再試'
|
||||
ErrGetCompose: "docker-compose.yml 檔案取得失敗!{{ .detail }}"
|
||||
ErrAppWarn: "狀態異常,請查看日誌"
|
||||
ErrAppParamKey: "參數 {{ .name }} 欄位異常"
|
||||
ErrAppUpgrade: "應用程式 {{ .name }} 升級失敗 {{ .err }}"
|
||||
AppRecover: "應用程式 {{ .name }} 回滾 "
|
||||
PullImageStart: "開始拉取鏡像 {{ .name }}"
|
||||
PullImageSuccess: "鏡像拉取成功"
|
||||
UpgradeAppStart: "開始升級應用程式 {{ .name }}"
|
||||
UpgradeAppSuccess: "應用程式 {{ .name }} 升級成功"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持預覽"
|
||||
@@ -87,13 +81,12 @@ ErrDomainIsExist: "域名已存在"
|
||||
ErrAliasIsExist: "代號已存在"
|
||||
ErrAppDelete: '其他網站使用此應用,無法刪除'
|
||||
ErrGroupIsUsed: '分組正在使用中,無法刪除'
|
||||
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}'
|
||||
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}'
|
||||
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}"'
|
||||
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}"'
|
||||
ErrPHPResource: '本地運行環境不支持切換!'
|
||||
ErrPathPermission: 'index 目錄下偵測到非 1000:1000 權限資料夾,可能導致網站存取 Access denied 錯誤,請點擊上方儲存按鈕'
|
||||
ErrPathPermission: 'index 目錄下檢測到非 1000:1000 權限文件夾,可能導致網站訪問 Access denied 錯誤'
|
||||
ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正確"
|
||||
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
|
||||
@@ -179,15 +172,13 @@ ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後
|
||||
#waf
|
||||
ErrScope: "不支援修改此配置"
|
||||
ErrStateChange: "狀態修改失敗"
|
||||
ErrRuleExist: "規則已存在"
|
||||
ErrRuleExist: "規則名稱已存在"
|
||||
ErrRuleNotExist: "規則不存在"
|
||||
ErrParseIP: "IP 格式錯誤"
|
||||
ErrDefaultIP: "default 為保留名稱,請更換其他名稱"
|
||||
ErrGroupInUse: "IP 群組被黑/白名單使用,無法刪除"
|
||||
ErrGroupExist: "IP 群組名稱已存在"
|
||||
ErrIPRange: "IP 範圍錯誤"
|
||||
ErrIPExist: "IP 已存在"
|
||||
|
||||
|
||||
#license
|
||||
ErrLicense: "許可證格式錯誤,請檢查後重試!"
|
||||
|
||||
@@ -61,12 +61,6 @@ AppStoreIsSyncing: '应用商店正在同步中,请稍后再试'
|
||||
ErrGetCompose: "docker-compose.yml 文件获取失败!{{ .detail }}"
|
||||
ErrAppWarn: "状态异常,请查看日志"
|
||||
ErrAppParamKey: "参数 {{ .name }} 字段异常"
|
||||
ErrAppUpgrade: "应用 {{ .name }} 升级失败 {{ .err }}"
|
||||
AppRecover: "应用 {{ .name }} 回滚 "
|
||||
PullImageStart: "开始拉取镜像 {{ .name }}"
|
||||
PullImageSuccess: "镜像拉取成功"
|
||||
UpgradeAppStart: "开始升级应用 {{ .name }}"
|
||||
UpgradeAppSuccess: "应用 {{ .name }} 升级成功"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持预览"
|
||||
@@ -87,13 +81,12 @@ ErrDomainIsExist: "域名已存在"
|
||||
ErrAliasIsExist: "代号已存在"
|
||||
ErrAppDelete: '其他网站使用此应用,无法删除'
|
||||
ErrGroupIsUsed: '分组正在使用中,无法删除'
|
||||
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}'
|
||||
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}'
|
||||
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}"'
|
||||
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}"'
|
||||
ErrPHPResource: '本地运行环境不支持切换!'
|
||||
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误,请点击上方保存按钮'
|
||||
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误'
|
||||
ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正确"
|
||||
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
|
||||
@@ -178,14 +171,13 @@ ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后
|
||||
#waf
|
||||
ErrScope: "不支持修改此配置"
|
||||
ErrStateChange: "状态修改失败"
|
||||
ErrRuleExist: "规则已存在"
|
||||
ErrRuleExist: "规则名称已存在"
|
||||
ErrRuleNotExist: "规则不存在"
|
||||
ErrParseIP: "IP 格式错误"
|
||||
ErrDefaultIP: "default 为保留名称,请更换其他名称"
|
||||
ErrGroupInUse: "IP 组被黑/白名单使用,无法删除"
|
||||
ErrGroupExist: "IP 组名称已存在"
|
||||
ErrIPRange: "IP 范围错误"
|
||||
ErrIPExist: "IP 已存在"
|
||||
|
||||
#license
|
||||
ErrLicense: "许可证格式错误,请检查后重试!"
|
||||
|
||||
Vendored
+1
-2
@@ -49,8 +49,7 @@ func Init() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = cache.DropAll()
|
||||
global.CacheDb = cache
|
||||
|
||||
global.CACHE = badger_db.NewCacheDB(cache)
|
||||
global.LOG.Info("init cache successfully")
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -64,7 +63,6 @@ func Init() {
|
||||
handleCronjobStatus()
|
||||
handleSnapStatus()
|
||||
loadLocalDir()
|
||||
initDir()
|
||||
}
|
||||
|
||||
func handleSnapStatus() {
|
||||
@@ -200,13 +198,3 @@ func handleUserInfo(tags string, settingRepo repo.ISettingRepo) {
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=%v/d' /usr/local/bin/1pctl", sudo, global.CONF.System.ChangeUserInfo)
|
||||
}
|
||||
|
||||
func initDir() {
|
||||
composePath := path.Join(global.CONF.System.BaseDir, "1panel/docker/compose/")
|
||||
if _, err := os.Stat(composePath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(composePath, os.ModePerm); err != nil {
|
||||
global.LOG.Errorf("mkdir %s failed, err: %v", composePath, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,14 +81,6 @@ func Init() {
|
||||
migrations.AddNoAuthSetting,
|
||||
migrations.UpdateXpackHideMenu,
|
||||
migrations.AddMenuTabsSetting,
|
||||
migrations.AddDeveloperSetting,
|
||||
|
||||
migrations.AddWebsiteSSLColumn,
|
||||
migrations.AddRedisCommand,
|
||||
migrations.AddMonitorMenu,
|
||||
migrations.AddFtp,
|
||||
migrations.AddProxy,
|
||||
migrations.AddCronJobColumn,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -85,7 +85,7 @@ var AddTableSetting = &gormigrate.Migration{
|
||||
if err := tx.Create(&model.Setting{Key: "Language", Value: "zh"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "Theme", Value: "light"}).Error; err != nil {
|
||||
if err := tx.Create(&model.Setting{Key: "Theme", Value: "auto"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"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/go-gormigrate/gormigrate/v2"
|
||||
@@ -147,104 +144,3 @@ var AddMenuTabsSetting = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddDeveloperSetting = &gormigrate.Migration{
|
||||
ID: "20240423-add-developer-setting",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&model.Setting{Key: "DeveloperMode", Value: "disable"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddWebsiteSSLColumn = &gormigrate.Migration{
|
||||
ID: "20240508-update-website-ssl",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddRedisCommand = &gormigrate.Migration{
|
||||
ID: "20240515-add-redis-command",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.RedisCommand{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddMonitorMenu = &gormigrate.Migration{
|
||||
ID: "20240517-update-xpack-hide-menu",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var (
|
||||
setting model.Setting
|
||||
menu dto.XpackHideMenu
|
||||
)
|
||||
tx.Model(&model.Setting{}).Where("key", "XpackHideMenu").First(&setting)
|
||||
if err := json.Unmarshal([]byte(setting.Value), &menu); err != nil {
|
||||
return err
|
||||
}
|
||||
menu.Children = append(menu.Children, dto.XpackHideMenu{
|
||||
ID: "6",
|
||||
Title: "xpack.monitor.name",
|
||||
Path: "/xpack/monitor/dashboard",
|
||||
Label: "MonitorDashboard",
|
||||
IsCheck: true,
|
||||
})
|
||||
data, err := json.Marshal(menu)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Model(&model.Setting{}).Where("key", "XpackHideMenu").Updates(map[string]interface{}{"value": string(data)}).Error
|
||||
},
|
||||
}
|
||||
|
||||
var AddFtp = &gormigrate.Migration{
|
||||
ID: "20240521-add-ftp",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.Ftp{}, model.Website{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddProxy = &gormigrate.Migration{
|
||||
ID: "20240528-add-proxy",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&model.Setting{Key: "ProxyType", Value: ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "ProxyUrl", Value: ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "ProxyPort", Value: ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "ProxyUser", Value: ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "ProxyPasswd", Value: ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "ProxyPasswdKeep", Value: ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddCronJobColumn = &gormigrate.Migration{
|
||||
ID: "20240524-add-cronjob-command",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.Cronjob{}); err != nil {
|
||||
return err
|
||||
}
|
||||
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