mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 08:00:27 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b438a4483d | ||
|
|
fa00c9fadb | ||
|
|
77c73b6710 | ||
|
|
a73d13de00 | ||
|
|
5e0abeaf47 | ||
|
|
e22f1dc313 | ||
|
|
56ce7ddc88 | ||
|
|
2ec19fb7d4 | ||
|
|
b808038f37 | ||
|
|
c8154901d5 | ||
|
|
284aced52c |
@@ -0,0 +1 @@
|
||||
custom: ["https://afdian.net/a/1Panel"]
|
||||
@@ -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/')
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
# Contributing
|
||||
|
||||
As a contributor, you should agree that:
|
||||
|
||||
- The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
|
||||
- Your contributed code may be used for commercial purposes, including but not limited to its cloud business operations.
|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
@@ -1,32 +1,26 @@
|
||||
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
|
||||
<p align="center"><b>Web-based linux server management control panel</b></p>
|
||||
<p align="center"><b>现代化、开源的 Linux 服务器运维管理面板</b></p>
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
<a href="https://hellogithub.com/repository/71791baf930149ac9b84e1acf186573f" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=71791baf930149ac9b84e1acf186573f&claim_uid=p8vB3kP5CMrthiL&theme=dark&theme=neutral" alt="Featured|HelloGitHub" style="width: 250px; height: 55px;" width="250" height="55" /></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></a>
|
||||
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
|
||||
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
|
||||
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="GitHub Stars"></a>
|
||||
<a href="https://gitee.com/fit2cloud-feizhiyun/1Panel"><img src="https://gitee.com/fit2cloud-feizhiyun/1Panel/badge/star.svg?theme=gvp" alt="Gitee Stars"></a><br>
|
||||
[<a href="docs/README_EN.md">English</a>] | [<a href="docs/README_TW.md">中文(繁體)</a>] | [<a href="docs/README_JP.md">日本語</a>]
|
||||
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
|
||||
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=shield" alt="FOSSA Status"></a><br>
|
||||
[<a href="docs/README_TW.md">中文(繁體)</a>] | [<a href="docs/README_EN.md">English</a>] | [<a href="docs/README_JP.md">日本語</a>]
|
||||
</p>
|
||||
|
||||
[](https://www.bilibili.com/video/BV1Mt421n7LZ/)
|
||||
|
||||
------------------------------
|
||||
## 什么是 1Panel?
|
||||
|
||||
1Panel 是新一代的 Linux 服务器运维管理面板。
|
||||
|
||||
- **高效管理**:用户可以通过 Web 界面轻松管理 Linux 服务器,如主机监控、文件管理、数据库管理、容器管理等;
|
||||
- **高效管理**:用户可以通过 Web 图形界面轻松管理 Linux 服务器,实现主机监控、文件管理、数据库管理、容器管理等功能;
|
||||
- **快速建站**:深度集成开源建站软件 WordPress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等操作一键搞定;
|
||||
- **应用商店**:精选上架各类高质量的开源工具和应用软件,协助用户轻松安装并升级;
|
||||
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供病毒防护、防火墙和日志审计等功能;
|
||||
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供防火墙和日志审计等功能;
|
||||
- **一键备份**:支持一键备份和恢复,用户可以将数据备份到各类云端存储介质,永不丢失。
|
||||
|
||||
1Panel 三分钟速览:https://www.bilibili.com/video/BV1Mt421n7LZ/
|
||||
|
||||
## 快速开始
|
||||
|
||||
**一键安装**
|
||||
@@ -37,15 +31,21 @@
|
||||
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://bbs.fit2cloud.com/c/1p/7)
|
||||
- [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)
|
||||
|
||||
## 飞致云的其他明星项目
|
||||
## UI 展示
|
||||
|
||||

|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||
|
||||
## 我们的其他明星项目
|
||||
|
||||
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统
|
||||
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
|
||||
|
||||
@@ -155,7 +155,7 @@ func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
|
||||
// @Success 200 {object} model.AppInstall
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/install [post]
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"安装应用 [name]","formatEN":"Install app [name]"}
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[{"input_column":"name","input_value":"name","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"}
|
||||
func (b *BaseApi) InstallApp(c *gin.Context) {
|
||||
var req request.AppInstallCreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
|
||||
@@ -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 {
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,296 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Create clam
|
||||
// @Description 创建扫描规则
|
||||
// @Accept json
|
||||
// @Param request body dto.ClamCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam [post]
|
||||
// @x-panel-log {"bodyKeys":["name","path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建扫描规则 [name][path]","formatEN":"create clam [name][path]"}
|
||||
func (b *BaseApi) CreateClam(c *gin.Context) {
|
||||
var req dto.ClamCreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := clamService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Update clam
|
||||
// @Description 修改扫描规则
|
||||
// @Accept json
|
||||
// @Param request body dto.ClamUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/update [post]
|
||||
// @x-panel-log {"bodyKeys":["name","path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改扫描规则 [name][path]","formatEN":"update clam [name][path]"}
|
||||
func (b *BaseApi) UpdateClam(c *gin.Context) {
|
||||
var req dto.ClamUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := clamService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Update clam status
|
||||
// @Description 修改扫描规则状态
|
||||
// @Accept json
|
||||
// @Param request body dto.ClamUpdateStatus true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/status/update [post]
|
||||
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"clams","output_column":"name","output_value":"name"}],"formatZH":"修改扫描规则 [name] 状态为 [status]","formatEN":"change the status of clam [name] to [status]."}
|
||||
func (b *BaseApi) UpdateClamStatus(c *gin.Context) {
|
||||
var req dto.ClamUpdateStatus
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := clamService.UpdateStatus(req.ID, req.Status); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Page clam
|
||||
// @Description 获取扫描规则列表分页
|
||||
// @Accept json
|
||||
// @Param request body dto.SearchClamWithPage true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/search [post]
|
||||
func (b *BaseApi) SearchClam(c *gin.Context) {
|
||||
var req dto.SearchClamWithPage
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := clamService.SearchWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Load clam base info
|
||||
// @Description 获取 Clam 基础信息
|
||||
// @Accept json
|
||||
// @Success 200 {object} dto.ClamBaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/base [get]
|
||||
func (b *BaseApi) LoadClamBaseInfo(c *gin.Context) {
|
||||
info, err := clamService.LoadBaseInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, info)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Operate Clam
|
||||
// @Description 修改 Clam 状态
|
||||
// @Accept json
|
||||
// @Param request body dto.Operate true "request"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/operate [post]
|
||||
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] Clam","formatEN":"[operation] FTP"}
|
||||
func (b *BaseApi) OperateClam(c *gin.Context) {
|
||||
var req dto.Operate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := clamService.Operate(req.Operation); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Clean clam record
|
||||
// @Description 清空扫描报告
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/record/clean [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":true,"db":"clams","output_column":"name","output_value":"name"}],"formatZH":"清空扫描报告 [name]","formatEN":"clean clam record [name]"}
|
||||
func (b *BaseApi) CleanClamRecord(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := clamService.CleanRecord(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Page clam record
|
||||
// @Description 获取扫描结果列表分页
|
||||
// @Accept json
|
||||
// @Param request body dto.ClamLogSearch true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/record/search [post]
|
||||
func (b *BaseApi) SearchClamRecord(c *gin.Context) {
|
||||
var req dto.ClamLogSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := clamService.LoadRecords(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Load clam record detail
|
||||
// @Description 获取扫描结果详情
|
||||
// @Accept json
|
||||
// @Param request body dto.ClamLogReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/record/log [post]
|
||||
func (b *BaseApi) LoadClamRecordLog(c *gin.Context) {
|
||||
var req dto.ClamLogReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := clamService.LoadRecordLog(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, content)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Load clam file
|
||||
// @Description 获取扫描文件
|
||||
// @Accept json
|
||||
// @Param request body dto.ClamFileReq true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/file/search [post]
|
||||
func (b *BaseApi) SearchClamFile(c *gin.Context) {
|
||||
var req dto.ClamFileReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := clamService.LoadFile(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, content)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Update clam file
|
||||
// @Description 更新病毒扫描配置文件
|
||||
// @Accept json
|
||||
// @Param request body dto.UpdateByNameAndFile true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/file/update [post]
|
||||
func (b *BaseApi) UpdateFile(c *gin.Context) {
|
||||
var req dto.UpdateByNameAndFile
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := clamService.UpdateFile(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Delete clam
|
||||
// @Description 删除扫描规则
|
||||
// @Accept json
|
||||
// @Param request body dto.ClamDelete true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/del [post]
|
||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"clams","output_column":"name","output_value":"names"}],"formatZH":"删除扫描规则 [names]","formatEN":"delete clam [names]"}
|
||||
func (b *BaseApi) DeleteClam(c *gin.Context) {
|
||||
var req dto.ClamDelete
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := clamService.Delete(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Clam
|
||||
// @Summary Handle clam scan
|
||||
// @Description 执行病毒扫描
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/clam/handle [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":true,"db":"clams","output_column":"name","output_value":"name"}],"formatZH":"执行病毒扫描 [name]","formatEN":"handle clam scan [name]"}
|
||||
func (b *BaseApi) HandleClamScan(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := clamService.HandleOnce(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
@@ -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 更新快速命令
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// @Tags Container
|
||||
@@ -347,26 +346,6 @@ func (b *BaseApi) ContainerRename(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Container
|
||||
// @Summary Commit Container
|
||||
// @Description 容器提交生成新镜像
|
||||
// @Accept json
|
||||
// @Param request body dto.ContainerCommit true "request"
|
||||
// @Success 200
|
||||
// @Router /containers/commit [post]
|
||||
func (b *BaseApi) ContainerCommit(c *gin.Context) {
|
||||
var req dto.ContainerCommit
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := containerService.ContainerCommit(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Container
|
||||
// @Summary Operate Container
|
||||
// @Description 容器操作
|
||||
@@ -461,19 +440,6 @@ func (b *BaseApi) ContainerLogs(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// @Description 下载容器日志
|
||||
// @Router /containers/download/log [post]
|
||||
func (b *BaseApi) DownloadContainerLogs(c *gin.Context) {
|
||||
var req dto.ContainerLog
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := containerService.DownloadContainerLogs(req.ContainerType, req.Container, req.Since, strconv.Itoa(int(req.Tail)), c)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
}
|
||||
}
|
||||
|
||||
// @Tags Container Network
|
||||
// @Summary Page networks
|
||||
// @Description 获取容器网络列表分页
|
||||
|
||||
@@ -36,12 +36,12 @@ func (b *BaseApi) CreateCronjob(c *gin.Context) {
|
||||
// @Summary Page cronjobs
|
||||
// @Description 获取计划任务分页
|
||||
// @Accept json
|
||||
// @Param request body dto.PageCronjob true "request"
|
||||
// @Param request body dto.SearchWithPage true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /cronjobs/search [post]
|
||||
func (b *BaseApi) SearchCronjob(c *gin.Context) {
|
||||
var req dto.PageCronjob
|
||||
var req dto.SearchWithPage
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -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,8 +37,6 @@ var (
|
||||
|
||||
deviceService = service.NewIDeviceService()
|
||||
fail2banService = service.NewIFail2BanService()
|
||||
ftpService = service.NewIFtpService()
|
||||
clamService = service.NewIClamService()
|
||||
|
||||
settingService = service.NewISettingService()
|
||||
backupService = service.NewIBackupService()
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -337,12 +336,8 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
mode := info.Mode()
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||
uid, gid := -1, -1
|
||||
if ok {
|
||||
uid, gid = int(stat.Uid), int(stat.Gid)
|
||||
}
|
||||
|
||||
success := 0
|
||||
failures := make(buserr.MultiErr)
|
||||
@@ -356,7 +351,6 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
global.LOG.Error(e)
|
||||
continue
|
||||
}
|
||||
_ = os.Chown(dstDir, uid, gid)
|
||||
}
|
||||
tmpFilename := dstFilename + ".tmp"
|
||||
if err := c.SaveUploadedFile(file, tmpFilename); err != nil {
|
||||
@@ -384,9 +378,6 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
} else {
|
||||
_ = os.Chmod(dstFilename, mode)
|
||||
}
|
||||
if uid != -1 && gid != -1 {
|
||||
_ = os.Chown(dstFilename, uid, gid)
|
||||
}
|
||||
success++
|
||||
}
|
||||
if success == 0 {
|
||||
@@ -601,46 +592,24 @@ 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)
|
||||
if mode == 0 {
|
||||
mode = 0755
|
||||
}
|
||||
uid, gid := -1, -1
|
||||
if info, err := os.Stat(dstDir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err = op.CreateDir(dstDir, mode); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
|
||||
if err = op.CreateDir(dstDir, mode); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||
if ok {
|
||||
uid, gid = int(stat.Uid), int(stat.Gid)
|
||||
}
|
||||
}
|
||||
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)
|
||||
@@ -651,13 +620,9 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(chunkPath)
|
||||
}
|
||||
if uid != -1 && gid != -1 {
|
||||
_ = os.Chown(dstFileName, uid, gid)
|
||||
}
|
||||
|
||||
return nil
|
||||
return files.NewFileOp().DeleteDir(fileDir)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
@@ -739,11 +704,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
|
||||
|
||||
@@ -94,29 +94,6 @@ func (b *BaseApi) OperatePortRule(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// OperateForwardRule
|
||||
// @Tags Firewall
|
||||
// @Summary Create group
|
||||
// @Description 更新防火墙端口转发规则
|
||||
// @Accept json
|
||||
// @Param request body dto.ForwardRuleOperate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /hosts/firewall/forward [post]
|
||||
// @x-panel-log {"bodyKeys":["source_port"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新端口转发规则 [source_port]","formatEN":"update port forward rules [source_port]"}
|
||||
func (b *BaseApi) OperateForwardRule(c *gin.Context) {
|
||||
var req dto.ForwardRuleOperate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := firewallService.OperateForwardRule(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Firewall
|
||||
// @Summary Create group
|
||||
// @Description 创建防火墙 IP 规则
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@ package v1
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
||||
@@ -79,13 +77,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 +86,23 @@ 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...)
|
||||
defer wsConn.Close()
|
||||
commands := []string{"redis-cli"}
|
||||
if len(redisConf.Requirepass) != 0 {
|
||||
commands = []string{"redis-cli", "-a", redisConf.Requirepass, "--no-auth-warning"}
|
||||
}
|
||||
pidMap := loadMapFromDockerTop(redisConf.ContainerName)
|
||||
itemCmds := append([]string{"exec", "-it", redisConf.ContainerName}, commands...)
|
||||
slave, err := terminal.NewCommand(itemCmds)
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(name, strings.Join(commands, " "), pidMap)
|
||||
defer killBash(redisConf.ContainerName, strings.Join(commands, " "), 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")
|
||||
|
||||
@@ -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)
|
||||
@@ -778,45 +768,3 @@ func (b *BaseApi) GetDirConfig(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get default html
|
||||
// @Description 获取默认 html
|
||||
// @Accept json
|
||||
// @Success 200 {object} response.FileInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/default/html/:type [get]
|
||||
func (b *BaseApi) GetDefaultHtml(c *gin.Context) {
|
||||
resourceType, err := helper.GetStrParamByKey(c, "type")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
fileInfo, err := websiteService.GetDefaultHtml(resourceType)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, fileInfo)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Update default html
|
||||
// @Description 更新默认 html
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteHtmlUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/default/html/update [post]
|
||||
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新默认 html","formatEN":"Update default html"}
|
||||
func (b *BaseApi) UpdateDefaultHtml(c *gin.Context) {
|
||||
var req request.WebsiteHtmlUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteService.UpdateDefaultHtml(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// @Tags Website CA
|
||||
@@ -145,33 +142,3 @@ func (b *BaseApi) RenewWebsiteCA(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website CA
|
||||
// @Summary Download CA file
|
||||
// @Description 下载 CA 证书文件
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteResourceReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/ca/download [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_cas","output_column":"name","output_value":"name"}],"formatZH":"下载 CA 证书文件 [name]","formatEN":"download ca file [name]"}
|
||||
func (b *BaseApi) DownloadCAFile(c *gin.Context) {
|
||||
var req request.WebsiteResourceReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
file, err := websiteCAService.DownloadFile(req.ID)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
|
||||
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
|
||||
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
|
||||
}
|
||||
|
||||
@@ -236,7 +236,6 @@ func (b *BaseApi) DownloadWebsiteSSL(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
info, err := file.Stat()
|
||||
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 {
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type SearchClamWithPage struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=name status created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
}
|
||||
|
||||
type ClamBaseInfo struct {
|
||||
Version string `json:"version"`
|
||||
IsActive bool `json:"isActive"`
|
||||
IsExist bool `json:"isExist"`
|
||||
|
||||
FreshVersion string `json:"freshVersion"`
|
||||
FreshIsActive bool `json:"freshIsActive"`
|
||||
FreshIsExist bool `json:"freshIsExist"`
|
||||
}
|
||||
|
||||
type ClamInfo struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Path string `json:"path"`
|
||||
InfectedStrategy string `json:"infectedStrategy"`
|
||||
InfectedDir string `json:"infectedDir"`
|
||||
LastHandleDate string `json:"lastHandleDate"`
|
||||
Spec string `json:"spec"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ClamLogSearch struct {
|
||||
PageInfo
|
||||
|
||||
ClamID uint `json:"clamID"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
}
|
||||
|
||||
type ClamLogReq struct {
|
||||
Tail string `json:"tail"`
|
||||
ClamName string `json:"clamName"`
|
||||
RecordName string `json:"recordName"`
|
||||
}
|
||||
|
||||
type ClamFileReq struct {
|
||||
Tail string `json:"tail"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type ClamLog struct {
|
||||
Name string `json:"name"`
|
||||
ScanDate string `json:"scanDate"`
|
||||
ScanTime string `json:"scanTime"`
|
||||
InfectedFiles string `json:"infectedFiles"`
|
||||
TotalError string `json:"totalError"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type ClamCreate struct {
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Path string `json:"path"`
|
||||
InfectedStrategy string `json:"infectedStrategy"`
|
||||
InfectedDir string `json:"infectedDir"`
|
||||
Spec string `json:"spec"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ClamUpdate struct {
|
||||
ID uint `json:"id"`
|
||||
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
InfectedStrategy string `json:"infectedStrategy"`
|
||||
InfectedDir string `json:"infectedDir"`
|
||||
Spec string `json:"spec"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ClamUpdateStatus struct {
|
||||
ID uint `json:"id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type ClamDelete struct {
|
||||
RemoveRecord bool `json:"removeRecord"`
|
||||
RemoveInfected bool `json:"removeInfected"`
|
||||
Ids []uint `json:"ids" validate:"required"`
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package dto
|
||||
|
||||
type SearchCommandWithPage struct {
|
||||
PageInfo
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=name command created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
SearchWithPage
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
GroupID uint `json:"groupID"`
|
||||
Info string `json:"info"`
|
||||
Name string `json:"name"`
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package dto
|
||||
|
||||
type SearchWithPage struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
Info string `json:"info"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
}
|
||||
|
||||
type PageInfo struct {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
import "time"
|
||||
|
||||
type PageContainer struct {
|
||||
PageInfo
|
||||
Name string `json:"name"`
|
||||
State string `json:"state" validate:"required,oneof=all created running paused restarting removing exited dead"`
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=name state created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
Filters string `json:"filters"`
|
||||
ExcludeAppStore bool `json:"excludeAppStore"`
|
||||
}
|
||||
@@ -124,17 +122,8 @@ type ContainerRename struct {
|
||||
NewName string `json:"newName" validate:"required"`
|
||||
}
|
||||
|
||||
type ContainerCommit struct {
|
||||
ContainerId string `json:"containerID" validate:"required"`
|
||||
ContainerName string `json:"containerName"`
|
||||
NewImageName string `json:"newImageName"`
|
||||
Comment string `json:"comment"`
|
||||
Author string `json:"author"`
|
||||
Pause bool `json:"pause"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
@@ -225,10 +214,3 @@ type ComposeUpdate struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
}
|
||||
|
||||
type ContainerLog struct {
|
||||
Container string `json:"container" validate:"required"`
|
||||
Since string `json:"since"`
|
||||
Tail uint `json:"tail"`
|
||||
ContainerType string `json:"containerType"`
|
||||
}
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type PageCronjob struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=name status created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
}
|
||||
import "time"
|
||||
|
||||
type CronjobCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
@@ -30,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 {
|
||||
@@ -52,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 {
|
||||
@@ -98,7 +87,6 @@ type CronjobInfo struct {
|
||||
|
||||
LastRecordTime string `json:"lastRecordTime"`
|
||||
Status string `json:"status"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type SearchRecord struct {
|
||||
@@ -110,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"`
|
||||
}
|
||||
|
||||
@@ -30,8 +30,6 @@ type OsInfo struct {
|
||||
PlatformFamily string `json:"platformFamily"`
|
||||
KernelArch string `json:"kernelArch"`
|
||||
KernelVersion string `json:"kernelVersion"`
|
||||
|
||||
DiskSize int64 `json:"diskSize"`
|
||||
}
|
||||
|
||||
type DashboardCurrent struct {
|
||||
|
||||
+15
-19
@@ -27,8 +27,8 @@ type MysqlDBSearch struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=name created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
}
|
||||
|
||||
type MysqlDBInfo struct {
|
||||
@@ -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"`
|
||||
@@ -139,7 +139,7 @@ type MysqlVariables struct {
|
||||
MaxConnections string `json:"max_connections"`
|
||||
MaxHeapTableSize string `json:"max_heap_table_size"`
|
||||
QueryCacheSize string `json:"query_cache_size"`
|
||||
QueryCacheType string `json:"query_cache_type"`
|
||||
QueryCache_type string `json:"query_cache_type"`
|
||||
ReadBufferSize string `json:"read_buffer_size"`
|
||||
ReadRndBufferSize string `json:"read_rnd_buffer_size"`
|
||||
SortBufferSize string `json:"sort_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,20 +195,18 @@ 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"`
|
||||
UsedMemory string `json:"used_memory"`
|
||||
UsedMemoryRss string `json:"used_memory_rss"`
|
||||
UsedMemoryPeak string `json:"used_memory_peak"`
|
||||
UsedMemory_rss string `json:"used_memory_rss"`
|
||||
UsedMemory_peak string `json:"used_memory_peak"`
|
||||
MemFragmentationRatio string `json:"mem_fragmentation_ratio"`
|
||||
TotalConnectionsReceived string `json:"total_connections_received"`
|
||||
TotalCommandsProcessed string `json:"total_commands_processed"`
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -236,8 +232,8 @@ type DatabaseSearch struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
Type string `json:"type"`
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=name created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
}
|
||||
|
||||
type DatabaseInfo struct {
|
||||
@@ -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"`
|
||||
|
||||
@@ -6,8 +6,8 @@ type PostgresqlDBSearch struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=name created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
}
|
||||
|
||||
type PostgresqlDBInfo struct {
|
||||
|
||||
@@ -29,17 +29,6 @@ type PortRuleOperate struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ForwardRuleOperate struct {
|
||||
Rules []struct {
|
||||
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||
Num string `json:"num"`
|
||||
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
|
||||
Port string `json:"port" validate:"required"`
|
||||
TargetIP string `json:"targetIP"`
|
||||
TargetPort string `json:"targetPort" validate:"required"`
|
||||
} `json:"rules"`
|
||||
}
|
||||
|
||||
type UpdateFirewallDescription struct {
|
||||
Type string `json:"type"`
|
||||
Address string `json:"address"`
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ type FileOption struct {
|
||||
}
|
||||
|
||||
type FileContentReq struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
IsDetail bool `json:"isDetail"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
}
|
||||
|
||||
type SearchUploadWithPage struct {
|
||||
@@ -55,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 {
|
||||
@@ -127,7 +124,6 @@ type FileReadByLineReq struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Latest bool `json:"latest"`
|
||||
}
|
||||
|
||||
type FileExistReq 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 {
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
type WebsiteSearch struct {
|
||||
dto.PageInfo
|
||||
Name string `json:"name"`
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=primary_domain type status created_at expire_date"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
WebsiteGroupID uint `json:"websiteGroupId"`
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -55,7 +52,7 @@ type WebsiteUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
WebsiteGroupID uint `json:"webSiteGroupID"`
|
||||
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
|
||||
ExpireDate string `json:"expireDate"`
|
||||
IPV6 bool `json:"IPV6"`
|
||||
}
|
||||
@@ -123,7 +120,6 @@ type WebsiteHTTPSOp struct {
|
||||
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
|
||||
SSLProtocol []string `json:"SSLProtocol"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Hsts bool `json:"hsts"`
|
||||
}
|
||||
|
||||
type WebsiteNginxUpdate struct {
|
||||
@@ -189,7 +185,6 @@ type WebsiteProxyConfig struct {
|
||||
Content string `json:"content"`
|
||||
FilePath string `json:"filePath"`
|
||||
Replaces map[string]string `json:"replaces"`
|
||||
SNI bool `json:"sni"`
|
||||
}
|
||||
|
||||
type WebsiteProxyReq struct {
|
||||
@@ -209,12 +204,3 @@ type WafWebsite struct {
|
||||
Domains []string `json:"domains"`
|
||||
Host []string `json:"host"`
|
||||
}
|
||||
|
||||
type WebsiteHtmlReq struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteHtmlUpdate struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@ type WebsiteSSLCreate struct {
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
ExecShell bool `json:"execShell"`
|
||||
Shell string `json:"shell"`
|
||||
}
|
||||
|
||||
type WebsiteDNSReq struct {
|
||||
@@ -79,7 +77,7 @@ type WebsiteSSLUpdate struct {
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
OtherDomains string `json:"otherDomains"`
|
||||
Provider string `json:"provider" validate:"required"`
|
||||
AcmeAccountID uint `json:"acmeAccountId"`
|
||||
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
KeyType string `json:"keyType"`
|
||||
Apply bool `json:"apply"`
|
||||
@@ -89,8 +87,6 @@ type WebsiteSSLUpdate struct {
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
ExecShell bool `json:"execShell"`
|
||||
Shell string `json:"shell"`
|
||||
}
|
||||
|
||||
type WebsiteSSLUpload struct {
|
||||
@@ -130,8 +126,6 @@ type WebsiteCAObtain struct {
|
||||
Renew bool `json:"renew"`
|
||||
SSLID uint `json:"sslID"`
|
||||
Description string `json:"description"`
|
||||
ExecShell bool `json:"execShell"`
|
||||
Shell string `json:"shell"`
|
||||
}
|
||||
|
||||
type WebsiteCARenew 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"`
|
||||
|
||||
@@ -15,12 +15,10 @@ type UploadInfo struct {
|
||||
}
|
||||
|
||||
type FileTree struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
IsDir bool `json:"isDir"`
|
||||
Extension string `json:"extension"`
|
||||
Children []FileTree `json:"children"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Children []FileTree `json:"children"`
|
||||
}
|
||||
|
||||
type DirSizeRes struct {
|
||||
@@ -39,7 +37,6 @@ type FileLineContent struct {
|
||||
Content string `json:"content"`
|
||||
End bool `json:"end"`
|
||||
Path string `json:"path"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
type FileExist struct {
|
||||
|
||||
@@ -2,7 +2,6 @@ package response
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WebsiteDTO struct {
|
||||
@@ -12,24 +11,6 @@ type WebsiteDTO struct {
|
||||
SitePath string `json:"sitePath"`
|
||||
AppName string `json:"appName"`
|
||||
RuntimeName string `json:"runtimeName"`
|
||||
SiteDir string `gorm:"type:varchar;" json:"siteDir"`
|
||||
}
|
||||
|
||||
type WebsiteRes struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Protocol string `json:"protocol"`
|
||||
PrimaryDomain string `json:"primaryDomain"`
|
||||
Type string `json:"type"`
|
||||
Alias string `json:"alias"`
|
||||
Remark string `json:"remark"`
|
||||
Status string `json:"status"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
SitePath string `json:"sitePath"`
|
||||
AppName string `json:"appName"`
|
||||
RuntimeName string `json:"runtimeName"`
|
||||
SSLExpireDate time.Time `json:"sslExpireDate"`
|
||||
SSLStatus string `json:"sslStatus"`
|
||||
}
|
||||
|
||||
type WebsiteOption struct {
|
||||
@@ -56,7 +37,6 @@ type WebsiteHTTPS struct {
|
||||
SSL model.WebsiteSSL `json:"SSL"`
|
||||
SSLProtocol []string `json:"SSLProtocol"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Hsts bool `json:"hsts"`
|
||||
}
|
||||
|
||||
type WebsiteLog struct {
|
||||
@@ -82,7 +62,3 @@ type WebsiteDirConfig struct {
|
||||
UserGroup string `json:"userGroup"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
type WebsiteHtmlRes struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
@@ -58,13 +58,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 +109,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"`
|
||||
@@ -143,7 +130,6 @@ type SnapshotInfo struct {
|
||||
Message string `json:"message"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Version string `json:"version"`
|
||||
Size int64 `json:"size"`
|
||||
|
||||
InterruptStep string `json:"interruptStep"`
|
||||
RecoverStatus string `json:"recoverStatus"`
|
||||
@@ -174,21 +160,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 {
|
||||
@@ -209,12 +185,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"`
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package model
|
||||
|
||||
type Clam struct {
|
||||
BaseModel
|
||||
|
||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||
Status string `gorm:"type:varchar(64)" json:"status"`
|
||||
Path string `gorm:"type:varchar(64);not null" json:"path"`
|
||||
InfectedStrategy string `gorm:"type:varchar(64)" json:"infectedStrategy"`
|
||||
InfectedDir string `gorm:"type:varchar(64)" json:"infectedDir"`
|
||||
Spec string `gorm:"type:varchar(64)" json:"spec"`
|
||||
EntryID int `gorm:"type:varchar(64)" json:"entryID"`
|
||||
Description string `gorm:"type:varchar(64)" json:"description"`
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -10,12 +10,3 @@ type Firewall struct {
|
||||
Strategy string `gorm:"type:varchar(64);not null" json:"strategy"`
|
||||
Description string `gorm:"type:varchar(64);not null" json:"description"`
|
||||
}
|
||||
|
||||
type Forward struct {
|
||||
BaseModel
|
||||
|
||||
Protocol string `gorm:"type:varchar(64);not null" json:"protocol"`
|
||||
Port string `gorm:"type:varchar(64);not null" json:"port"`
|
||||
TargetIP string `gorm:"type:varchar(64);not null" json:"targetIP"`
|
||||
TargetPort string `gorm:"type:varchar(64);not null" json:"targetPort"`
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -33,8 +33,6 @@ type WebsiteSSL struct {
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
ExecShell bool `json:"execShell"`
|
||||
Shell string `json:"shell"`
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
)
|
||||
|
||||
type ClamRepo struct{}
|
||||
|
||||
type IClamRepo interface {
|
||||
Page(limit, offset int, opts ...DBOption) (int64, []model.Clam, error)
|
||||
Create(clam *model.Clam) error
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
Delete(opts ...DBOption) error
|
||||
Get(opts ...DBOption) (model.Clam, error)
|
||||
List(opts ...DBOption) ([]model.Clam, error)
|
||||
}
|
||||
|
||||
func NewIClamRepo() IClamRepo {
|
||||
return &ClamRepo{}
|
||||
}
|
||||
|
||||
func (u *ClamRepo) Get(opts ...DBOption) (model.Clam, error) {
|
||||
var clam model.Clam
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.First(&clam).Error
|
||||
return clam, err
|
||||
}
|
||||
|
||||
func (u *ClamRepo) List(opts ...DBOption) ([]model.Clam, error) {
|
||||
var clam []model.Clam
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.Find(&clam).Error
|
||||
return clam, err
|
||||
}
|
||||
|
||||
func (u *ClamRepo) Page(page, size int, opts ...DBOption) (int64, []model.Clam, error) {
|
||||
var users []model.Clam
|
||||
db := global.DB.Model(&model.Clam{})
|
||||
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 *ClamRepo) Create(clam *model.Clam) error {
|
||||
return global.DB.Create(clam).Error
|
||||
}
|
||||
|
||||
func (u *ClamRepo) Update(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.Clam{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
|
||||
func (u *ClamRepo) Delete(opts ...DBOption) error {
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
return db.Delete(&model.Clam{}).Error
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func (w *WebsiteRepo) Page(page, size int, opts ...DBOption) (int64, []model.Web
|
||||
db := getDb(opts...).Model(&model.Website{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Debug().Limit(size).Offset(size * (page - 1)).Preload("WebsiteSSL").Find(&websites).Error
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("WebsiteSSL").Find(&websites).Error
|
||||
return count, websites, err
|
||||
}
|
||||
|
||||
|
||||
+40
-34
@@ -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)
|
||||
@@ -145,9 +136,6 @@ func (a AppService) GetAppTags() ([]response.TagDTO, error) {
|
||||
|
||||
func (a AppService) GetApp(key string) (*response.AppDTO, error) {
|
||||
var appDTO response.AppDTO
|
||||
if key == "postgres" {
|
||||
key = "postgresql"
|
||||
}
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -238,16 +226,21 @@ 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)
|
||||
defer composeRes.Body.Close()
|
||||
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)
|
||||
@@ -370,7 +363,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
|
||||
}
|
||||
@@ -447,7 +440,6 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
return
|
||||
}
|
||||
appInstall.Env = string(paramByte)
|
||||
|
||||
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -457,7 +449,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)
|
||||
}
|
||||
@@ -707,11 +699,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
|
||||
@@ -756,10 +753,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() {
|
||||
@@ -837,21 +834,25 @@ 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
|
||||
}
|
||||
body, err := io.ReadAll(iconRes.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
iconStr := ""
|
||||
if !strings.Contains(string(iconRes), "<xml>") {
|
||||
iconStr = base64.StdEncoding.EncodeToString(iconRes)
|
||||
if !strings.Contains(string(body), "<xml>") {
|
||||
iconStr = base64.StdEncoding.EncodeToString(body)
|
||||
}
|
||||
_ = iconRes.Body.Close()
|
||||
|
||||
app.Icon = iconStr
|
||||
app.TagsKey = l.AppProperty.Tags
|
||||
@@ -871,11 +872,16 @@ 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)
|
||||
defer composeRes.Body.Close()
|
||||
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,82 @@ 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
|
||||
}
|
||||
|
||||
@@ -782,7 +803,7 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
|
||||
}
|
||||
case "port":
|
||||
envKey = "PANEL_APP_PORT_HTTP="
|
||||
default:
|
||||
case "user-password":
|
||||
envKey = "PANEL_DB_USER_PASSWORD="
|
||||
}
|
||||
files := strings.Split(string(lineBytes), "\n")
|
||||
|
||||
+100
-248
@@ -14,11 +14,7 @@ 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"
|
||||
|
||||
@@ -42,7 +38,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 +436,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
|
||||
}
|
||||
@@ -512,10 +454,9 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
var (
|
||||
upErr error
|
||||
backupFile string
|
||||
preErr error
|
||||
)
|
||||
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppStart", install.Name, nil))
|
||||
if req.Backup {
|
||||
if backup {
|
||||
backupRecord, err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name})
|
||||
if err == nil {
|
||||
localDir, err := loadLocalDir()
|
||||
@@ -532,47 +473,38 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
defer func() {
|
||||
if upErr != nil {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("ErrAppUpgrade", install.Name, upErr))
|
||||
if req.Backup {
|
||||
if 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 {
|
||||
global.LOG.Errorf("recover app [%s] [%s] failed %v", install.App.Key, install.Name, err)
|
||||
}
|
||||
}
|
||||
existInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallID))
|
||||
existInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(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)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
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 +512,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,19 +526,89 @@ 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, err := json.Marshal(envs)
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
install.Env = string(paramByte)
|
||||
composeByte, err := yaml.Marshal(composeMap)
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
|
||||
install.DockerCompose = newCompose
|
||||
install.DockerCompose = string(composeByte)
|
||||
install.Version = detail.Version
|
||||
install.AppDetailId = req.DetailID
|
||||
install.AppDetailId = detailID
|
||||
|
||||
content, err := fileOp.GetContent(install.GetEnvPath())
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
|
||||
if pullImage {
|
||||
projectName := strings.ToLower(install.Name)
|
||||
images, err := composeV2.GetDockerComposeImages(projectName, content, []byte(detail.DockerCompose))
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
dockerCli, err := composeV2.NewClient()
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
defer dockerCli.Close()
|
||||
for _, image := range images {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("PullImageStart", image, nil))
|
||||
if err = dockerCli.PullImage(image, true); err != nil {
|
||||
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
|
||||
return
|
||||
} else {
|
||||
global.LOG.Infof(i18n.GetMsgByKey("PullImageSuccess"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if out, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
if out != "" {
|
||||
@@ -642,10 +618,6 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
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 {
|
||||
@@ -786,11 +758,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 +782,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
|
||||
@@ -937,19 +909,12 @@ 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
|
||||
}
|
||||
exist, _ := appInstallRepo.GetFirst(commonRepo.WithByID(appInstall.ID))
|
||||
if exist.ID > 0 {
|
||||
containerNames, err := getContainerNames(*appInstall)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(containerNames) > 0 {
|
||||
appInstall.ContainerName = strings.Join(containerNames, ",")
|
||||
}
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
}
|
||||
}
|
||||
@@ -969,12 +934,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)
|
||||
@@ -1152,131 +1111,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,7 +49,7 @@ 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
|
||||
@@ -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 {
|
||||
@@ -364,7 +334,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
||||
}
|
||||
if err := copyDir(oldDir, dirStr); err != nil {
|
||||
_ = backupRepo.Update(req.ID, map[string]interface{}{"vars": oldVars})
|
||||
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
|
||||
return err
|
||||
}
|
||||
global.CONF.System.Backup = dirStr
|
||||
@@ -414,6 +384,8 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
|
||||
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||
varMap["accessKey"] = backup.AccessKey
|
||||
varMap["secretKey"] = backup.Credential
|
||||
case constant.OneDrive:
|
||||
varMap["accessToken"] = backup.Credential
|
||||
}
|
||||
|
||||
backClient, err := cloud_storage.NewCloudStorageClient(backup.Type, varMap)
|
||||
@@ -451,13 +423,14 @@ func (u *BackupService) loadAccessToken(backup *model.BackupAccount) error {
|
||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
||||
return fmt.Errorf("unmarshal backup vars failed, err: %v", err)
|
||||
}
|
||||
refreshToken, err := client.RefreshToken("authorization_code", "refreshToken", varMap)
|
||||
token, refreshToken, err := client.RefreshToken("authorization_code", varMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delete(varMap, "code")
|
||||
backup.Credential = token
|
||||
varMap["refresh_status"] = constant.StatusSuccess
|
||||
varMap["refresh_time"] = time.Now().Format(constant.DateTimeLayout)
|
||||
varMap["refresh_time"] = time.Now().Format("2006-01-02 15:04:05")
|
||||
varMap["refresh_token"] = refreshToken
|
||||
itemVars, err := json.Marshal(varMap)
|
||||
if err != nil {
|
||||
@@ -584,10 +557,10 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString("1Panel 备份账号测试文件。\n")
|
||||
_, _ = write.WriteString("1Panel 備份賬號測試文件。\n")
|
||||
_, _ = write.WriteString("1Panel Backs up account test files.\n")
|
||||
_, _ = write.WriteString("1Panelアカウントのテストファイルをバックアップします。\n")
|
||||
_, _ = write.WriteString(string("1Panel 备份账号测试文件。\n"))
|
||||
_, _ = write.WriteString(string("1Panel 備份賬號測試文件。\n"))
|
||||
_, _ = write.WriteString(string("1Panel Backs up account test files.\n"))
|
||||
_, _ = write.WriteString(string("1Panelアカウントのテストファイルをバックアップします。\n"))
|
||||
write.Flush()
|
||||
|
||||
targetPath := strings.TrimPrefix(path.Join(backup.BackupPath, "test/1panel"), "/")
|
||||
@@ -596,7 +569,7 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
|
||||
|
||||
func StartRefreshOneDriveToken() {
|
||||
service := NewIBackupService()
|
||||
oneDriveCronID, err := global.Cron.AddJob("0 3 */31 * *", service)
|
||||
oneDriveCronID, err := global.Cron.AddJob("0 * * * *", service)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("can not add OneDrive corn job: %s", err.Error())
|
||||
return
|
||||
@@ -610,15 +583,19 @@ func (u *BackupService) Run() {
|
||||
if backupItem.ID == 0 {
|
||||
return
|
||||
}
|
||||
if len(backupItem.Credential) == 0 {
|
||||
global.LOG.Error("OneDrive configuration lacks token information, please rebind.")
|
||||
return
|
||||
}
|
||||
global.LOG.Info("start to refresh token of OneDrive ...")
|
||||
varMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(backupItem.Vars), &varMap); err != nil {
|
||||
global.LOG.Errorf("Failed to refresh OneDrive token, please retry, err: %v", err)
|
||||
return
|
||||
}
|
||||
refreshToken, err := client.RefreshToken("refresh_token", "refreshToken", varMap)
|
||||
token, refreshToken, err := client.RefreshToken("refresh_token", varMap)
|
||||
varMap["refresh_status"] = constant.StatusSuccess
|
||||
varMap["refresh_time"] = time.Now().Format(constant.DateTimeLayout)
|
||||
varMap["refresh_time"] = time.Now().Format("2006-01-02 15:04:05")
|
||||
if err != nil {
|
||||
varMap["refresh_status"] = constant.StatusFailed
|
||||
varMap["refresh_msg"] = err.Error()
|
||||
@@ -631,7 +608,8 @@ func (u *BackupService) Run() {
|
||||
_ = global.DB.Model(&model.BackupAccount{}).
|
||||
Where("id = ?", backupItem.ID).
|
||||
Updates(map[string]interface{}{
|
||||
"vars": varsItem,
|
||||
"credential": token,
|
||||
"vars": varsItem,
|
||||
}).Error
|
||||
global.LOG.Info("Successfully refreshed OneDrive token.")
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
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 {
|
||||
if err := handleAppBackup(&install, backupDir, fileName, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -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, excludes 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", excludes); 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", "")
|
||||
@@ -163,14 +163,14 @@ 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(constant.DateTimeSlimLayout)))
|
||||
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil {
|
||||
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 {
|
||||
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)
|
||||
|
||||
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -25,7 +24,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
return err
|
||||
}
|
||||
|
||||
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName)
|
||||
targetDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
@@ -60,14 +59,14 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
file := req.File
|
||||
fileName := path.Base(req.File)
|
||||
if strings.HasSuffix(fileName, ".tar.gz") {
|
||||
fileNameItem := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
fileNameItem := time.Now().Format("20060102150405")
|
||||
dstDir := fmt.Sprintf("%s/%s", path.Dir(req.File), fileNameItem)
|
||||
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dstDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err)
|
||||
}
|
||||
}
|
||||
if err := handleUnTar(req.File, dstDir, ""); err != nil {
|
||||
if err := handleUnTar(req.File, dstDir); err != nil {
|
||||
_ = os.RemoveAll(dstDir)
|
||||
return err
|
||||
}
|
||||
@@ -143,7 +142,7 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
}
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format(constant.DateTimeSlimLayout)))
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
|
||||
if err := cli.Backup(client.BackupInfo{
|
||||
Name: req.DetailName,
|
||||
Type: req.Type,
|
||||
|
||||
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -26,7 +25,7 @@ func (u *BackupService) PostgresqlBackup(req dto.CommonBackup) error {
|
||||
return err
|
||||
}
|
||||
|
||||
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName)
|
||||
targetDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
@@ -60,14 +59,14 @@ func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
file := req.File
|
||||
fileName := path.Base(req.File)
|
||||
if strings.HasSuffix(fileName, ".tar.gz") {
|
||||
fileNameItem := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
fileNameItem := time.Now().Format("20060102150405")
|
||||
dstDir := fmt.Sprintf("%s/%s", path.Dir(req.File), fileNameItem)
|
||||
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dstDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err)
|
||||
}
|
||||
}
|
||||
if err := handleUnTar(req.File, dstDir, ""); err != nil {
|
||||
if err := handleUnTar(req.File, dstDir); err != nil {
|
||||
_ = os.RemoveAll(dstDir)
|
||||
return err
|
||||
}
|
||||
@@ -137,7 +136,7 @@ func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
|
||||
defer cli.Close()
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format(constant.DateTimeSlimLayout)))
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
|
||||
if err := cli.Backup(client.BackupInfo{
|
||||
Name: req.DetailName,
|
||||
TargetDir: path.Dir(rollbackFile),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func (u *BackupService) RedisBackup(db dto.CommonBackup) error {
|
||||
}
|
||||
global.LOG.Infof("appendonly in redis conf is %s", appendonly)
|
||||
|
||||
timeNow := time.Now().Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
|
||||
timeNow := time.Now().Format("20060102150405") + common.RandStrAndNum(5)
|
||||
fileName := fmt.Sprintf("%s.rdb", timeNow)
|
||||
if appendonly == "yes" {
|
||||
if strings.HasPrefix(redisInfo.Version, "6.") {
|
||||
@@ -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)
|
||||
@@ -146,14 +145,14 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
||||
suffix = "tar.gz"
|
||||
}
|
||||
}
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format(constant.DateTimeSlimLayout), suffix))
|
||||
if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile), secret); err != nil {
|
||||
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)); 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 {
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"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, excludes string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
@@ -35,19 +35,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", excludes); 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", "")
|
||||
@@ -72,14 +72,14 @@ 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(constant.DateTimeSlimLayout)))
|
||||
if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile), "", secret); err != nil {
|
||||
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), ""); 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 +100,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)
|
||||
|
||||
@@ -31,11 +31,11 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
return err
|
||||
}
|
||||
|
||||
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("website/%s", req.Name)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow+common.RandStrAndNum(5))
|
||||
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() {
|
||||
@@ -106,14 +106,14 @@ 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(constant.DateTimeSlimLayout)))
|
||||
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
@@ -154,8 +154,8 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if runtime.Type == constant.RuntimeNode || runtime.Type == constant.RuntimeJava || runtime.Type == constant.RuntimeGo {
|
||||
if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true, ""); err != nil {
|
||||
if runtime.Type == constant.RuntimeNode {
|
||||
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, excludes 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), excludes); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put app.tar.gz into tmp dir successful")
|
||||
@@ -225,8 +225,8 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if runtime.Type == constant.RuntimeNode || runtime.Type == constant.RuntimeJava || runtime.Type == constant.RuntimeGo {
|
||||
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes, ""); err != nil {
|
||||
if runtime.Type == constant.RuntimeNode {
|
||||
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes); 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), excludes); 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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,562 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
clamServiceNameCentOs = "clamd@scan.service"
|
||||
clamServiceNameUbuntu = "clamav-daemon.service"
|
||||
freshClamService = "clamav-freshclam.service"
|
||||
resultDir = "clamav"
|
||||
)
|
||||
|
||||
type ClamService struct {
|
||||
serviceName string
|
||||
}
|
||||
|
||||
type IClamService interface {
|
||||
LoadBaseInfo() (dto.ClamBaseInfo, error)
|
||||
Operate(operate string) error
|
||||
SearchWithPage(search dto.SearchClamWithPage) (int64, interface{}, error)
|
||||
Create(req dto.ClamCreate) error
|
||||
Update(req dto.ClamUpdate) error
|
||||
UpdateStatus(id uint, status string) error
|
||||
Delete(req dto.ClamDelete) error
|
||||
HandleOnce(req dto.OperateByID) error
|
||||
LoadFile(req dto.ClamFileReq) (string, error)
|
||||
UpdateFile(req dto.UpdateByNameAndFile) error
|
||||
LoadRecords(req dto.ClamLogSearch) (int64, interface{}, error)
|
||||
CleanRecord(req dto.OperateByID) error
|
||||
|
||||
LoadRecordLog(req dto.ClamLogReq) (string, error)
|
||||
}
|
||||
|
||||
func NewIClamService() IClamService {
|
||||
return &ClamService{}
|
||||
}
|
||||
|
||||
func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) {
|
||||
var baseInfo dto.ClamBaseInfo
|
||||
baseInfo.Version = "-"
|
||||
baseInfo.FreshVersion = "-"
|
||||
exist1, _ := systemctl.IsExist(clamServiceNameCentOs)
|
||||
if exist1 {
|
||||
c.serviceName = clamServiceNameCentOs
|
||||
baseInfo.IsExist = true
|
||||
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameCentOs)
|
||||
}
|
||||
exist2, _ := systemctl.IsExist(clamServiceNameUbuntu)
|
||||
if exist2 {
|
||||
c.serviceName = clamServiceNameUbuntu
|
||||
baseInfo.IsExist = true
|
||||
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameUbuntu)
|
||||
}
|
||||
freshExist, _ := systemctl.IsExist(freshClamService)
|
||||
if freshExist {
|
||||
baseInfo.FreshIsExist = true
|
||||
baseInfo.FreshIsActive, _ = systemctl.IsActive(freshClamService)
|
||||
}
|
||||
if !cmd.Which("clamdscan") {
|
||||
baseInfo.IsActive = false
|
||||
}
|
||||
|
||||
if baseInfo.IsActive {
|
||||
version, err := cmd.Exec("clamdscan --version")
|
||||
if err == nil {
|
||||
if strings.Contains(version, "/") {
|
||||
baseInfo.Version = strings.TrimPrefix(strings.Split(version, "/")[0], "ClamAV ")
|
||||
} else {
|
||||
baseInfo.Version = strings.TrimPrefix(version, "ClamAV ")
|
||||
}
|
||||
}
|
||||
}
|
||||
if baseInfo.FreshIsActive {
|
||||
version, err := cmd.Exec("freshclam --version")
|
||||
if err == nil {
|
||||
if strings.Contains(version, "/") {
|
||||
baseInfo.FreshVersion = strings.TrimPrefix(strings.Split(version, "/")[0], "ClamAV ")
|
||||
} else {
|
||||
baseInfo.FreshVersion = strings.TrimPrefix(version, "ClamAV ")
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
func (c *ClamService) Operate(operate string) error {
|
||||
switch operate {
|
||||
case "start", "restart", "stop":
|
||||
stdout, err := cmd.Execf("systemctl %s %s", operate, c.serviceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
|
||||
}
|
||||
return nil
|
||||
case "fresh-start", "fresh-restart", "fresh-stop":
|
||||
stdout, err := cmd.Execf("systemctl %s %s", strings.TrimPrefix(operate, "fresh-"), freshClamService)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("not support such operation: %v", operate)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interface{}, error) {
|
||||
total, commands, err := clamRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info), commonRepo.WithOrderRuleBy(req.OrderBy, req.Order))
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
var datas []dto.ClamInfo
|
||||
for _, command := range commands {
|
||||
var item dto.ClamInfo
|
||||
if err := copier.Copy(&item, &command); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
item.LastHandleDate = "-"
|
||||
datas = append(datas, item)
|
||||
}
|
||||
nyc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
for i := 0; i < len(datas); i++ {
|
||||
logPaths := loadFileByName(datas[i].Name)
|
||||
sort.Slice(logPaths, func(i, j int) bool {
|
||||
return logPaths[i] > logPaths[j]
|
||||
})
|
||||
if len(logPaths) != 0 {
|
||||
t1, err := time.ParseInLocation(constant.DateTimeSlimLayout, logPaths[0], nyc)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
datas[i].LastHandleDate = t1.Format(constant.DateTimeLayout)
|
||||
}
|
||||
}
|
||||
return total, datas, err
|
||||
}
|
||||
|
||||
func (c *ClamService) Create(req dto.ClamCreate) error {
|
||||
clam, _ := clamRepo.Get(commonRepo.WithByName(req.Name))
|
||||
if clam.ID != 0 {
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
if err := copier.Copy(&clam, &req); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
if clam.InfectedStrategy == "none" || clam.InfectedStrategy == "remove" {
|
||||
clam.InfectedDir = ""
|
||||
}
|
||||
if len(req.Spec) != 0 {
|
||||
entryID, err := xpack.StartClam(clam, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clam.EntryID = entryID
|
||||
clam.Status = constant.StatusEnable
|
||||
}
|
||||
if err := clamRepo.Create(&clam); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClamService) Update(req dto.ClamUpdate) error {
|
||||
clam, _ := clamRepo.Get(commonRepo.WithByName(req.Name))
|
||||
if clam.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
if req.InfectedStrategy == "none" || req.InfectedStrategy == "remove" {
|
||||
req.InfectedDir = ""
|
||||
}
|
||||
var clamItem model.Clam
|
||||
if err := copier.Copy(&clamItem, &req); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
clamItem.EntryID = clam.EntryID
|
||||
upMap := map[string]interface{}{}
|
||||
if len(clam.Spec) != 0 && clam.EntryID != 0 {
|
||||
global.Cron.Remove(cron.EntryID(clamItem.EntryID))
|
||||
upMap["entry_id"] = 0
|
||||
}
|
||||
if len(req.Spec) == 0 {
|
||||
upMap["status"] = ""
|
||||
upMap["entry_id"] = 0
|
||||
}
|
||||
if len(req.Spec) != 0 && clam.Status != constant.StatusDisable {
|
||||
newEntryID, err := xpack.StartClam(clamItem, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upMap["entry_id"] = newEntryID
|
||||
}
|
||||
if len(clam.Spec) == 0 && len(req.Spec) != 0 {
|
||||
upMap["status"] = constant.StatusEnable
|
||||
}
|
||||
|
||||
upMap["name"] = req.Name
|
||||
upMap["path"] = req.Path
|
||||
upMap["infected_dir"] = req.InfectedDir
|
||||
upMap["infected_strategy"] = req.InfectedStrategy
|
||||
upMap["spec"] = req.Spec
|
||||
upMap["description"] = req.Description
|
||||
if err := clamRepo.Update(req.ID, upMap); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClamService) UpdateStatus(id uint, status string) error {
|
||||
clam, _ := clamRepo.Get(commonRepo.WithByID(id))
|
||||
if clam.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
var (
|
||||
entryID int
|
||||
err error
|
||||
)
|
||||
if status == constant.StatusEnable {
|
||||
entryID, err = xpack.StartClam(clam, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
global.Cron.Remove(cron.EntryID(clam.EntryID))
|
||||
global.LOG.Infof("stop cronjob entryID: %v", clam.EntryID)
|
||||
}
|
||||
|
||||
return clamRepo.Update(clam.ID, map[string]interface{}{"status": status, "entry_id": entryID})
|
||||
}
|
||||
|
||||
func (c *ClamService) Delete(req dto.ClamDelete) error {
|
||||
for _, id := range req.Ids {
|
||||
clam, _ := clamRepo.Get(commonRepo.WithByID(id))
|
||||
if clam.ID == 0 {
|
||||
continue
|
||||
}
|
||||
if req.RemoveRecord {
|
||||
_ = os.RemoveAll(path.Join(global.CONF.System.DataDir, resultDir, clam.Name))
|
||||
}
|
||||
if req.RemoveInfected {
|
||||
_ = os.RemoveAll(path.Join(clam.InfectedDir, "1panel-infected", clam.Name))
|
||||
}
|
||||
if err := clamRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClamService) HandleOnce(req dto.OperateByID) error {
|
||||
if cmd.Which("clamdscan") == false {
|
||||
return buserr.New("ErrClamdscanNotFound")
|
||||
}
|
||||
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if clam.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
if cmd.CheckIllegal(clam.Path) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
timeNow := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
logFile := path.Join(global.CONF.System.DataDir, resultDir, clam.Name, timeNow)
|
||||
if _, err := os.Stat(path.Dir(logFile)); err != nil {
|
||||
_ = os.MkdirAll(path.Dir(logFile), os.ModePerm)
|
||||
}
|
||||
go func() {
|
||||
strategy := ""
|
||||
switch clam.InfectedStrategy {
|
||||
case "remove":
|
||||
strategy = "--remove"
|
||||
case "move":
|
||||
dir := path.Join(clam.InfectedDir, "1panel-infected", clam.Name, timeNow)
|
||||
strategy = "--move=" + dir
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
_ = os.MkdirAll(dir, os.ModePerm)
|
||||
}
|
||||
case "copy":
|
||||
dir := path.Join(clam.InfectedDir, "1panel-infected", clam.Name, timeNow)
|
||||
strategy = "--copy=" + dir
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
_ = os.MkdirAll(dir, os.ModePerm)
|
||||
}
|
||||
}
|
||||
global.LOG.Debugf("clamdscan --fdpass %s %s -l %s", strategy, clam.Path, logFile)
|
||||
stdout, err := cmd.Execf("clamdscan --fdpass %s %s -l %s", strategy, clam.Path, logFile)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("clamdscan failed, stdout: %v, err: %v", stdout, err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClamService) LoadRecords(req dto.ClamLogSearch) (int64, interface{}, error) {
|
||||
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ClamID))
|
||||
if clam.ID == 0 {
|
||||
return 0, nil, constant.ErrRecordNotFound
|
||||
}
|
||||
logPaths := loadFileByName(clam.Name)
|
||||
if len(logPaths) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
var filterFiles []string
|
||||
nyc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||
for _, item := range logPaths {
|
||||
t1, err := time.ParseInLocation(constant.DateTimeSlimLayout, item, nyc)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if t1.After(req.StartTime) && t1.Before(req.EndTime) {
|
||||
filterFiles = append(filterFiles, item)
|
||||
}
|
||||
}
|
||||
if len(filterFiles) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
sort.Slice(filterFiles, func(i, j int) bool {
|
||||
return filterFiles[i] > filterFiles[j]
|
||||
})
|
||||
|
||||
var records []string
|
||||
total, start, end := len(filterFiles), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
if start > total {
|
||||
records = make([]string, 0)
|
||||
} else {
|
||||
if end >= total {
|
||||
end = total
|
||||
}
|
||||
records = filterFiles[start:end]
|
||||
}
|
||||
|
||||
var datas []dto.ClamLog
|
||||
for i := 0; i < len(records); i++ {
|
||||
item := loadResultFromLog(path.Join(global.CONF.System.DataDir, resultDir, clam.Name, records[i]))
|
||||
datas = append(datas, item)
|
||||
}
|
||||
return int64(total), datas, nil
|
||||
}
|
||||
func (c *ClamService) LoadRecordLog(req dto.ClamLogReq) (string, error) {
|
||||
logPath := path.Join(global.CONF.System.DataDir, resultDir, req.ClamName, req.RecordName)
|
||||
var tail string
|
||||
if req.Tail != "0" {
|
||||
tail = req.Tail
|
||||
} else {
|
||||
tail = "+1"
|
||||
}
|
||||
cmd := exec.Command("tail", "-n", tail, logPath)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("tail -n %v failed, err: %v", req.Tail, err)
|
||||
}
|
||||
return string(stdout), nil
|
||||
}
|
||||
|
||||
func (c *ClamService) CleanRecord(req dto.OperateByID) error {
|
||||
clam, _ := clamRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if clam.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
pathItem := path.Join(global.CONF.System.DataDir, resultDir, clam.Name)
|
||||
_ = os.RemoveAll(pathItem)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClamService) LoadFile(req dto.ClamFileReq) (string, error) {
|
||||
filePath := ""
|
||||
switch req.Name {
|
||||
case "clamd":
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
filePath = "/etc/clamav/clamd.conf"
|
||||
} else {
|
||||
filePath = "/etc/clamd.d/scan.conf"
|
||||
}
|
||||
case "clamd-log":
|
||||
filePath = c.loadLogPath("clamd-log")
|
||||
if len(filePath) != 0 {
|
||||
break
|
||||
}
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
filePath = "/var/log/clamav/clamav.log"
|
||||
} else {
|
||||
filePath = "/var/log/clamd.scan"
|
||||
}
|
||||
case "freshclam":
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
filePath = "/etc/clamav/freshclam.conf"
|
||||
} else {
|
||||
filePath = "/etc/freshclam.conf"
|
||||
}
|
||||
case "freshclam-log":
|
||||
filePath = c.loadLogPath("freshclam-log")
|
||||
if len(filePath) != 0 {
|
||||
break
|
||||
}
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
filePath = "/var/log/clamav/freshclam.log"
|
||||
} else {
|
||||
filePath = "/var/log/freshclam.log"
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("not support such type")
|
||||
}
|
||||
if _, err := os.Stat(filePath); err != nil {
|
||||
return "", buserr.New("ErrHttpReqNotFound")
|
||||
}
|
||||
var tail string
|
||||
if req.Tail != "0" {
|
||||
tail = req.Tail
|
||||
} else {
|
||||
tail = "+1"
|
||||
}
|
||||
cmd := exec.Command("tail", "-n", tail, filePath)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("tail -n %v failed, err: %v", req.Tail, err)
|
||||
}
|
||||
return string(stdout), nil
|
||||
}
|
||||
|
||||
func (c *ClamService) UpdateFile(req dto.UpdateByNameAndFile) error {
|
||||
filePath := ""
|
||||
service := ""
|
||||
switch req.Name {
|
||||
case "clamd":
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
service = clamServiceNameUbuntu
|
||||
filePath = "/etc/clamav/clamd.conf"
|
||||
} else {
|
||||
service = clamServiceNameCentOs
|
||||
filePath = "/etc/clamd.d/scan.conf"
|
||||
}
|
||||
case "freshclam":
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
filePath = "/etc/clamav/freshclam.conf"
|
||||
} else {
|
||||
filePath = "/etc/freshclam.conf"
|
||||
}
|
||||
service = "clamav-freshclam.service"
|
||||
default:
|
||||
return fmt.Errorf("not support such type")
|
||||
}
|
||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
|
||||
_ = systemctl.Restart(service)
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadFileByName(name string) []string {
|
||||
var logPaths []string
|
||||
pathItem := path.Join(global.CONF.System.DataDir, resultDir, name)
|
||||
_ = filepath.Walk(pathItem, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if info.IsDir() || info.Name() == name {
|
||||
return nil
|
||||
}
|
||||
logPaths = append(logPaths, info.Name())
|
||||
return nil
|
||||
})
|
||||
return logPaths
|
||||
}
|
||||
func loadResultFromLog(pathItem string) dto.ClamLog {
|
||||
var data dto.ClamLog
|
||||
data.Name = path.Base(pathItem)
|
||||
data.Status = constant.StatusWaiting
|
||||
file, err := os.ReadFile(pathItem)
|
||||
if err != nil {
|
||||
return data
|
||||
}
|
||||
lines := strings.Split(string(file), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "- SCAN SUMMARY -") {
|
||||
data.Status = constant.StatusDone
|
||||
}
|
||||
if data.Status != constant.StatusDone {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(line, "Infected files:"):
|
||||
data.InfectedFiles = strings.TrimPrefix(line, "Infected files:")
|
||||
case strings.HasPrefix(line, "Total errors:"):
|
||||
data.TotalError = strings.TrimPrefix(line, "Total errors:")
|
||||
case strings.HasPrefix(line, "Time:"):
|
||||
if strings.Contains(line, "(") {
|
||||
data.ScanTime = strings.ReplaceAll(strings.Split(line, "(")[1], ")", "")
|
||||
continue
|
||||
}
|
||||
data.ScanTime = strings.TrimPrefix(line, "Time:")
|
||||
case strings.HasPrefix(line, "Start Date:"):
|
||||
data.ScanDate = strings.TrimPrefix(line, "Start Date:")
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
func (c *ClamService) loadLogPath(name string) string {
|
||||
confPath := ""
|
||||
if name == "clamd-log" {
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
confPath = "/etc/clamav/clamd.conf"
|
||||
} else {
|
||||
confPath = "/etc/clamd.d/scan.conf"
|
||||
}
|
||||
} else {
|
||||
if c.serviceName == clamServiceNameUbuntu {
|
||||
confPath = "/etc/clamav/freshclam.conf"
|
||||
} else {
|
||||
confPath = "/etc/freshclam.conf"
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(confPath); err != nil {
|
||||
return ""
|
||||
}
|
||||
content, err := os.ReadFile(confPath)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
lines := strings.Split(string(content), "\n")
|
||||
if name == "clamd-log" {
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "LogFile ") {
|
||||
return strings.Trim(strings.ReplaceAll(line, "LogFile ", ""), " ")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "UpdateLogFile ") {
|
||||
return strings.Trim(strings.ReplaceAll(line, "UpdateLogFile ", ""), " ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -20,8 +17,6 @@ import (
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -34,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"
|
||||
@@ -65,11 +59,9 @@ type IContainerService interface {
|
||||
ContainerListStats() ([]dto.ContainerListStats, error)
|
||||
LoadResourceLimit() (*dto.ResourceLimit, error)
|
||||
ContainerRename(req dto.ContainerRename) error
|
||||
ContainerCommit(req dto.ContainerCommit) error
|
||||
ContainerLogClean(req dto.OperationWithName) error
|
||||
ContainerOperation(req dto.ContainerOperation) error
|
||||
ContainerLogs(wsConn *websocket.Conn, containerType, container, since, tail string, follow bool) error
|
||||
DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error
|
||||
ContainerStats(id string) (*dto.ContainerStats, error)
|
||||
Inspect(req dto.InspectReq) (string, error)
|
||||
DeleteNetwork(req dto.BatchDelete) error
|
||||
@@ -190,7 +182,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
ports := loadContainerPort(item.Ports)
|
||||
info := dto.ContainerInfo{
|
||||
ContainerID: item.ID,
|
||||
CreateTime: time.Unix(item.Created, 0).Format(constant.DateTimeLayout),
|
||||
CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"),
|
||||
Name: item.Names[0][1:],
|
||||
ImageId: strings.Split(item.ImageID, ":")[1],
|
||||
ImageName: item.Image,
|
||||
@@ -344,15 +336,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -604,28 +587,6 @@ func (u *ContainerService) ContainerRename(req dto.ContainerRename) error {
|
||||
return client.ContainerRename(ctx, req.Name, req.NewName)
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerCommit(req dto.ContainerCommit) error {
|
||||
ctx := context.Background()
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
options := container.CommitOptions{
|
||||
Reference: req.NewImageName,
|
||||
Comment: req.Comment,
|
||||
Author: req.Author,
|
||||
Changes: nil,
|
||||
Pause: req.Pause,
|
||||
Config: nil,
|
||||
}
|
||||
_, err = client.ContainerCommit(ctx, req.ContainerId, options)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to commit container, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error {
|
||||
var err error
|
||||
ctx := context.Background()
|
||||
@@ -775,79 +736,6 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error {
|
||||
if cmd.CheckIllegal(container, since, tail) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
commandName := "docker"
|
||||
commandArg := []string{"logs", container}
|
||||
if containerType == "compose" {
|
||||
commandName = "docker-compose"
|
||||
commandArg = []string{"-f", container, "logs"}
|
||||
}
|
||||
if tail != "0" {
|
||||
commandArg = append(commandArg, "--tail")
|
||||
commandArg = append(commandArg, tail)
|
||||
}
|
||||
if since != "all" {
|
||||
commandArg = append(commandArg, "--since")
|
||||
commandArg = append(commandArg, since)
|
||||
}
|
||||
|
||||
cmd := exec.Command(commandName, commandArg...)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
||||
return err
|
||||
}
|
||||
cmd.Stderr = cmd.Stdout
|
||||
if err := cmd.Start(); err != nil {
|
||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
||||
return err
|
||||
}
|
||||
|
||||
tempFile, err := os.CreateTemp("", "cmd_output_*.txt")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tempFile.Close()
|
||||
defer func() {
|
||||
if err := os.Remove(tempFile.Name()); err != nil {
|
||||
global.LOG.Errorf("os.Remove() failed: %v", err)
|
||||
}
|
||||
}()
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if _, err := tempFile.WriteString(line + "\n"); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
errCh <- nil
|
||||
}()
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
global.LOG.Errorf("Error: %v", err)
|
||||
}
|
||||
case <-time.After(3 * time.Second):
|
||||
global.LOG.Errorf("Timeout reached")
|
||||
}
|
||||
info, _ := tempFile.Stat()
|
||||
|
||||
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
|
||||
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
|
||||
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), tempFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error) {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
@@ -973,15 +861,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
|
||||
}
|
||||
}
|
||||
@@ -989,12 +878,12 @@ func checkImageExist(client *client.Client, imageItem string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func pullImages(ctx context.Context, client *client.Client, imageName string) error {
|
||||
options := image.PullOptions{}
|
||||
func pullImages(ctx context.Context, client *client.Client, image string) error {
|
||||
options := types.ImagePullOptions{}
|
||||
repos, _ := imageRepoRepo.List()
|
||||
if len(repos) != 0 {
|
||||
for _, repo := range repos {
|
||||
if strings.HasPrefix(imageName, repo.DownloadUrl) && repo.Auth {
|
||||
if strings.HasPrefix(image, repo.DownloadUrl) && repo.Auth {
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
Password: repo.Password,
|
||||
@@ -1007,13 +896,8 @@ func pullImages(ctx context.Context, client *client.Client, imageName string) er
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hasAuth, authStr := loadAuthInfo(imageName)
|
||||
if hasAuth {
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
}
|
||||
out, err := client.ImagePull(ctx, imageName, options)
|
||||
out, err := client.ImagePull(ctx, image, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1147,7 +1031,7 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
|
||||
}
|
||||
} else {
|
||||
if req.Ipv4 != "" || req.Ipv6 != "" {
|
||||
return nil, nil, nil, fmt.Errorf("please set up the network")
|
||||
return nil, nil, nil, fmt.Errorf("Please set up the network")
|
||||
}
|
||||
networkConf = network.NetworkingConfig{}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
|
||||
ContainerID: container.ID,
|
||||
Name: container.Names[0][1:],
|
||||
State: container.State,
|
||||
CreateTime: time.Unix(container.Created, 0).Format(constant.DateTimeLayout),
|
||||
CreateTime: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if compose, has := composeMap[name]; has {
|
||||
compose.ContainerNumber++
|
||||
@@ -70,7 +70,7 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
|
||||
workdir := container.Labels[composeWorkdirLabel]
|
||||
composeItem := dto.ComposeInfo{
|
||||
ContainerNumber: 1,
|
||||
CreatedAt: time.Unix(container.Created, 0).Format(constant.DateTimeLayout),
|
||||
CreatedAt: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
|
||||
ConfigFile: config,
|
||||
Workdir: workdir,
|
||||
Containers: []dto.ComposeContainer{containerItem},
|
||||
@@ -168,7 +168,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
logItem := fmt.Sprintf("%s/compose_create_%s_%s.log", dockerLogDir, req.Name, time.Now().Format(constant.DateTimeSlimLayout))
|
||||
logItem := fmt.Sprintf("%s/compose_create_%s_%s.log", dockerLogDir, req.Name, time.Now().Format("20060102150405"))
|
||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -232,6 +232,12 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
||||
write.Flush()
|
||||
|
||||
global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.Path)
|
||||
if stdout, err := compose.Down(req.Path); err != nil {
|
||||
if err := recreateCompose(string(oldFile), req.Path); err != nil {
|
||||
return fmt.Errorf("update failed when handle compose down, err: %s, recreate failed: %v", string(stdout), err)
|
||||
}
|
||||
return fmt.Errorf("update failed when handle compose down, err: %s", string(stdout))
|
||||
}
|
||||
if stdout, err := compose.Up(req.Path); err != nil {
|
||||
if err := recreateCompose(string(oldFile), req.Path); err != nil {
|
||||
return fmt.Errorf("update failed when handle compose up, err: %s, recreate failed: %v", string(stdout), err)
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
type CronjobService struct{}
|
||||
|
||||
type ICronjobService interface {
|
||||
SearchWithPage(search dto.PageCronjob) (int64, interface{}, error)
|
||||
SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
|
||||
SearchRecords(search dto.SearchRecord) (int64, interface{}, error)
|
||||
Create(cronjobDto dto.CronjobCreate) error
|
||||
HandleOnce(id uint) error
|
||||
@@ -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
|
||||
@@ -39,7 +39,7 @@ func NewICronjobService() ICronjobService {
|
||||
return &CronjobService{}
|
||||
}
|
||||
|
||||
func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interface{}, error) {
|
||||
func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
|
||||
total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
|
||||
var dtoCronjobs []dto.CronjobInfo
|
||||
for _, cronjob := range cronjobs {
|
||||
@@ -49,7 +49,7 @@ func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interfac
|
||||
}
|
||||
record, _ := cronjobRepo.RecordFirst(cronjob.ID)
|
||||
if record.ID != 0 {
|
||||
item.LastRecordTime = record.StartTime.Format(constant.DateTimeLayout)
|
||||
item.LastRecordTime = record.StartTime.Format("2006-01-02 15:04:05")
|
||||
} else {
|
||||
item.LastRecordTime = "-"
|
||||
}
|
||||
@@ -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(constant.DateTimeLayout)
|
||||
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
|
||||
}
|
||||
@@ -330,7 +327,7 @@ func mkdirAndWriteFile(cronjob *model.Cronjob, startTime time.Time, msg []byte)
|
||||
}
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format(constant.DateTimeSlimLayout))
|
||||
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format("20060102150405"))
|
||||
global.LOG.Infof("cronjob %s has generated some logs %s", cronjob.Name, path)
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
@@ -17,20 +17,15 @@ import (
|
||||
|
||||
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) error {
|
||||
var apps []model.AppInstall
|
||||
if strings.Contains(cronjob.AppID, "all") {
|
||||
if cronjob.AppID == "all" {
|
||||
apps, _ = appInstallRepo.ListBy()
|
||||
} else {
|
||||
appIds := strings.Split(cronjob.AppID, ",")
|
||||
var idItems []uint
|
||||
for i := 0; i < len(appIds); i++ {
|
||||
itemID, _ := strconv.Atoi(appIds[i])
|
||||
idItems = append(idItems, uint(itemID))
|
||||
}
|
||||
appItems, err := appInstallRepo.ListBy(commonRepo.WithIdsIn(idItems))
|
||||
itemID, _ := (strconv.Atoi(cronjob.AppID))
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apps = appItems
|
||||
apps = append(apps, app)
|
||||
}
|
||||
accountMap, err := loadClientMap(cronjob.BackupAccounts)
|
||||
if err != nil {
|
||||
@@ -45,8 +40,8 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
|
||||
record.DetailName = app.Name
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
||||
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
if err := handleAppBackup(&app, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||
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); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
@@ -78,8 +73,8 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||
record.DetailName = web.Alias
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain))
|
||||
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||
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); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
@@ -112,7 +107,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name))
|
||||
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
if err := handleMysqlBackup(dbInfo.Database, dbInfo.DBType, dbInfo.Name, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
@@ -141,9 +136,9 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileName := fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
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
|
||||
@@ -171,10 +166,10 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nameItem := startTime.Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
|
||||
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
|
||||
@@ -215,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(constant.DateTimeSlimLayout)+common.RandStrAndNum(5), cronjob.Secret)
|
||||
name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -237,7 +232,7 @@ type databaseHelper struct {
|
||||
|
||||
func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
|
||||
var dbs []databaseHelper
|
||||
if strings.Contains(cronjob.DBName, "all") {
|
||||
if cronjob.DBName == "all" {
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
mysqlItems, _ := mysqlRepo.List()
|
||||
for _, mysql := range mysqlItems {
|
||||
@@ -259,42 +254,36 @@ func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
|
||||
}
|
||||
return dbs
|
||||
}
|
||||
|
||||
dbNames := strings.Split(cronjob.DBName, ",")
|
||||
for _, name := range dbNames {
|
||||
itemID, _ := strconv.Atoi(name)
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID)))
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysqlItem.MysqlName,
|
||||
Name: mysqlItem.Name,
|
||||
})
|
||||
} else {
|
||||
pgItem, _ := postgresqlRepo.Get(commonRepo.WithByID(uint(itemID)))
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: pgItem.PostgresqlName,
|
||||
Name: pgItem.Name,
|
||||
})
|
||||
}
|
||||
itemID, _ := (strconv.Atoi(cronjob.DBName))
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID)))
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysqlItem.MysqlName,
|
||||
Name: mysqlItem.Name,
|
||||
})
|
||||
} else {
|
||||
pgItem, _ := postgresqlRepo.Get(commonRepo.WithByID(uint(itemID)))
|
||||
dbs = append(dbs, databaseHelper{
|
||||
DBType: cronjob.DBType,
|
||||
Database: pgItem.PostgresqlName,
|
||||
Name: pgItem.Name,
|
||||
})
|
||||
}
|
||||
return dbs
|
||||
}
|
||||
|
||||
func loadWebsForJob(cronjob model.Cronjob) []model.Website {
|
||||
var weblist []model.Website
|
||||
if strings.Contains(cronjob.Website, "all") {
|
||||
if cronjob.Website == "all" {
|
||||
weblist, _ = websiteRepo.List()
|
||||
return weblist
|
||||
}
|
||||
websites := strings.Split(cronjob.Website, ",")
|
||||
var idItems []uint
|
||||
for i := 0; i < len(websites); i++ {
|
||||
itemID, _ := strconv.Atoi(websites[i])
|
||||
idItems = append(idItems, uint(itemID))
|
||||
itemID, _ := (strconv.Atoi(cronjob.Website))
|
||||
webItem, _ := websiteRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
|
||||
if webItem.ID != 0 {
|
||||
weblist = append(weblist, webItem)
|
||||
}
|
||||
weblist, _ = websiteRepo.List(commonRepo.WithIdsIn(idItems))
|
||||
return weblist
|
||||
}
|
||||
|
||||
@@ -314,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
|
||||
@@ -387,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() {
|
||||
|
||||
@@ -124,13 +124,13 @@ func (u *CronjobService) handleNtpSync() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ntp.UpdateSystemTime(ntime.Format(constant.DateTimeLayout)); err != nil {
|
||||
if err := ntp.UpdateSystemTime(ntime.Format("2006-01-02 15:04:05")); err != nil {
|
||||
return err
|
||||
}
|
||||
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)
|
||||
@@ -224,7 +209,7 @@ func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime t
|
||||
_ = os.MkdirAll(dstLogDir, 0755)
|
||||
}
|
||||
|
||||
dstName := fmt.Sprintf("%s_log_%s.gz", website.PrimaryDomain, startTime.Format(constant.DateTimeSlimLayout))
|
||||
dstName := fmt.Sprintf("%s_log_%s.gz", website.PrimaryDomain, startTime.Format("20060102150405"))
|
||||
dstFilePath := path.Join(dstLogDir, dstName)
|
||||
filePaths = append(filePaths, dstFilePath)
|
||||
|
||||
@@ -384,7 +369,7 @@ func (u *CronjobService) generateLogsPath(cronjob model.Cronjob, startTime time.
|
||||
_ = os.MkdirAll(dir, os.ModePerm)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format(constant.DateTimeSlimLayout))
|
||||
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format("20060102150405"))
|
||||
return path
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"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/copier"
|
||||
@@ -65,11 +64,6 @@ func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
|
||||
baseInfo.KernelArch = hostInfo.KernelArch
|
||||
baseInfo.KernelVersion = hostInfo.KernelVersion
|
||||
|
||||
diskInfo, err := disk.Usage(global.CONF.System.BaseDir)
|
||||
if err == nil {
|
||||
baseInfo.DiskSize = int64(diskInfo.Free)
|
||||
}
|
||||
|
||||
if baseInfo.KernelArch == "armv7l" {
|
||||
baseInfo.KernelArch = "armv7"
|
||||
}
|
||||
@@ -100,15 +94,11 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
|
||||
return nil, err
|
||||
}
|
||||
baseInfo.AppInstalledNumber = len(appInstall)
|
||||
postgresqlDbs, err := postgresqlRepo.List()
|
||||
dbs, err := mysqlRepo.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mysqlDbs, err := mysqlRepo.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
baseInfo.DatabaseNumber = len(mysqlDbs) + len(postgresqlDbs)
|
||||
baseInfo.DatabaseNumber = len(dbs)
|
||||
website, err := websiteRepo.GetBy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -136,7 +126,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
var currentInfo dto.DashboardCurrent
|
||||
hostInfo, _ := host.Info()
|
||||
currentInfo.Uptime = hostInfo.Uptime
|
||||
currentInfo.TimeSinceUptime = time.Now().Add(-time.Duration(hostInfo.Uptime) * time.Second).Format(constant.DateTimeLayout)
|
||||
currentInfo.TimeSinceUptime = time.Now().Add(-time.Duration(hostInfo.Uptime) * time.Second).Format("2006-01-02 15:04:05")
|
||||
currentInfo.Procs = hostInfo.Procs
|
||||
|
||||
currentInfo.CPUTotal, _ = cpu.Counts(true)
|
||||
@@ -232,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") {
|
||||
@@ -253,7 +240,7 @@ func loadDiskInfo() []dto.DiskInfo {
|
||||
if isExclude {
|
||||
continue
|
||||
}
|
||||
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: strings.Join(fields[6:], " ")})
|
||||
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: fields[6]})
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -7,8 +7,7 @@ import (
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/postgresql"
|
||||
pgclient "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||
redisclient "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(pgclient.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 := redisclient.NewRedisClient(redisclient.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(pgclient.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 := redisclient.NewRedisClient(redisclient.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(pgclient.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 := redisclient.NewRedisClient(redisclient.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",
|
||||
|
||||
@@ -196,9 +196,6 @@ func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
|
||||
for i := 0; i < len(databases); i++ {
|
||||
if strings.EqualFold(databases[i].Name, data.Name) && strings.EqualFold(databases[i].MysqlName, data.MysqlName) {
|
||||
hasOld = true
|
||||
if databases[i].IsDelete {
|
||||
_ = mysqlRepo.Update(databases[i].ID, map[string]interface{}{"is_delete": false})
|
||||
}
|
||||
deleteList = append(deleteList[:i], deleteList[i+1:]...)
|
||||
break
|
||||
}
|
||||
@@ -243,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 {
|
||||
@@ -366,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
|
||||
}
|
||||
|
||||
@@ -521,11 +507,11 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
|
||||
if value, ok := statusMap["Run"]; ok {
|
||||
uptime, _ := strconv.Atoi(value)
|
||||
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format(constant.DateTimeLayout)
|
||||
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format("2006-01-02 15:04:05")
|
||||
} else {
|
||||
if value, ok := statusMap["Uptime"]; ok {
|
||||
uptime, _ := strconv.Atoi(value)
|
||||
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format(constant.DateTimeLayout)
|
||||
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,9 +222,6 @@ func (u *PostgresqlService) LoadFromRemote(database string) error {
|
||||
for i := 0; i < len(databases); i++ {
|
||||
if strings.EqualFold(databases[i].Name, data.Name) && strings.EqualFold(databases[i].PostgresqlName, data.PostgresqlName) {
|
||||
hasOld = true
|
||||
if databases[i].IsDelete {
|
||||
_ = postgresqlRepo.Update(databases[i].ID, map[string]interface{}{"is_delete": false})
|
||||
}
|
||||
deleteList = append(deleteList[:i], deleteList[i+1:]...)
|
||||
break
|
||||
}
|
||||
@@ -269,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 {
|
||||
@@ -417,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...)
|
||||
|
||||
@@ -158,7 +158,7 @@ func (u *DeviceService) Update(key, value string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts := ntime.Format(constant.DateTimeLayout)
|
||||
ts := ntime.Format("2006-01-02 15:04:05")
|
||||
if err := ntp.UpdateSystemTime(ts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
@@ -9,11 +8,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
@@ -73,7 +67,7 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
snapTree := loadSnapshotTree(fileOp)
|
||||
snapSize := uint64(0)
|
||||
for _, snap := range snapTree {
|
||||
snapSize += snap.Size
|
||||
snapSize += uint64(snap.Size)
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
@@ -88,7 +82,7 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
rollBackTree := loadRollBackTree(fileOp)
|
||||
rollbackSize := uint64(0)
|
||||
for _, rollback := range rollBackTree {
|
||||
rollbackSize += rollback.Size
|
||||
rollbackSize += uint64(rollback.Size)
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
@@ -114,7 +108,7 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
unusedTree := loadUnusedFile(fileOp)
|
||||
unusedSize := uint64(0)
|
||||
for _, unused := range unusedTree {
|
||||
unusedSize += unused.Size
|
||||
unusedSize += uint64(unused.Size)
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
@@ -136,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
|
||||
}
|
||||
|
||||
@@ -268,18 +259,10 @@ 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()
|
||||
}
|
||||
}
|
||||
|
||||
_ = settingRepo.Update("LastCleanTime", time.Now().Format(constant.DateTimeLayout))
|
||||
_ = settingRepo.Update("LastCleanTime", time.Now().Format("2006-01-02 15:04:05"))
|
||||
_ = settingRepo.Update("LastCleanSize", fmt.Sprintf("%v", size))
|
||||
_ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", len(req)))
|
||||
|
||||
@@ -343,7 +326,7 @@ func (u *DeviceService) CleanForCronjob() (string, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
timeNow := time.Now().Format(constant.DateTimeLayout)
|
||||
timeNow := time.Now().Format("2006-01-02 15:04:05")
|
||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, dockerLogPath), &logs, &size, &fileCount)
|
||||
logs += fmt.Sprintf("\n%s: total clean: %s, total count: %d", timeNow, common.LoadSizeUnit2F(float64(size)), fileCount)
|
||||
|
||||
@@ -513,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)
|
||||
@@ -647,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"
|
||||
@@ -103,6 +104,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 {
|
||||
@@ -129,10 +131,13 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
||||
}
|
||||
|
||||
func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
|
||||
err := createIfNotExistDaemonJsonFile()
|
||||
if err != nil {
|
||||
return err
|
||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = os.Create(constant.DaemonJsonPath)
|
||||
}
|
||||
|
||||
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -214,26 +219,15 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func createIfNotExistDaemonJsonFile() error {
|
||||
|
||||
func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
|
||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
var daemonFile *os.File
|
||||
daemonFile, err = os.Create(constant.DaemonJsonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer daemonFile.Close()
|
||||
_, _ = os.Create(constant.DaemonJsonPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
|
||||
err := createIfNotExistDaemonJsonFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -262,9 +256,11 @@ func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
|
||||
}
|
||||
|
||||
func (u *DockerService) UpdateIpv6Option(req dto.Ipv6Option) error {
|
||||
err := createIfNotExistDaemonJsonFile()
|
||||
if err != nil {
|
||||
return err
|
||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = os.Create(constant.DaemonJsonPath)
|
||||
}
|
||||
|
||||
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||
@@ -306,9 +302,11 @@ func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
|
||||
_ = os.Remove(constant.DaemonJsonPath)
|
||||
return nil
|
||||
}
|
||||
err := createIfNotExistDaemonJsonFile()
|
||||
if err != nil {
|
||||
return err
|
||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = os.Create(constant.DaemonJsonPath)
|
||||
}
|
||||
file, err := os.OpenFile(constant.DaemonJsonPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
|
||||
@@ -24,8 +24,6 @@ var (
|
||||
hostRepo = repo.NewIHostRepo()
|
||||
groupRepo = repo.NewIGroupRepo()
|
||||
commandRepo = repo.NewICommandRepo()
|
||||
ftpRepo = repo.NewIFtpRepo()
|
||||
clamRepo = repo.NewIClamRepo()
|
||||
|
||||
settingRepo = repo.NewISettingRepo()
|
||||
backupRepo = repo.NewIBackupRepo()
|
||||
|
||||
+20
-103
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -10,16 +9,11 @@ import (
|
||||
"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/sys/unix"
|
||||
"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"
|
||||
@@ -52,10 +46,6 @@ type IFileService interface {
|
||||
ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error)
|
||||
}
|
||||
|
||||
var filteredPaths = []string{
|
||||
"/.1panel_clash",
|
||||
}
|
||||
|
||||
func NewIFileService() IFileService {
|
||||
return &FileService{}
|
||||
}
|
||||
@@ -84,7 +74,7 @@ func (f *FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (in
|
||||
}
|
||||
if !info.IsDir() {
|
||||
files = append(files, response.UploadInfo{
|
||||
CreatedAt: info.ModTime().Format(constant.DateTimeLayout),
|
||||
CreatedAt: info.ModTime().Format("2006-01-02 15:04:05"),
|
||||
Size: int(info.Size()),
|
||||
Name: info.Name(),
|
||||
})
|
||||
@@ -105,85 +95,34 @@ func (f *FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (in
|
||||
|
||||
func (f *FileService) GetFileTree(op request.FileOption) ([]response.FileTree, error) {
|
||||
var treeArray []response.FileTree
|
||||
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
|
||||
return treeArray, nil
|
||||
}
|
||||
info, err := files.NewFileInfo(op.FileOption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node := response.FileTree{
|
||||
ID: common.GetUuid(),
|
||||
Name: info.Name,
|
||||
Path: info.Path,
|
||||
IsDir: info.IsDir,
|
||||
Extension: info.Extension,
|
||||
ID: common.GetUuid(),
|
||||
Name: info.Name,
|
||||
Path: info.Path,
|
||||
}
|
||||
err = f.buildFileTree(&node, info.Items, op, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, v := range info.Items {
|
||||
if v.IsDir {
|
||||
node.Children = append(node.Children, response.FileTree{
|
||||
ID: common.GetUuid(),
|
||||
Name: v.Name,
|
||||
Path: v.Path,
|
||||
})
|
||||
}
|
||||
}
|
||||
return append(treeArray, node), nil
|
||||
}
|
||||
|
||||
func shouldFilterPath(path string) bool {
|
||||
cleanedPath := filepath.Clean(path)
|
||||
for _, filteredPath := range filteredPaths {
|
||||
cleanedFilteredPath := filepath.Clean(filteredPath)
|
||||
if cleanedFilteredPath == cleanedPath || strings.HasPrefix(cleanedPath, cleanedFilteredPath+"/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 递归构建文件树(只取当前目录以及当前目录下的第一层子节点)
|
||||
func (f *FileService) buildFileTree(node *response.FileTree, items []*files.FileInfo, op request.FileOption, level int) error {
|
||||
for _, v := range items {
|
||||
if shouldFilterPath(v.Path) {
|
||||
global.LOG.Info("File Tree: Skipping %s due to filter\n", v.Path)
|
||||
continue
|
||||
}
|
||||
childNode := response.FileTree{
|
||||
ID: common.GetUuid(),
|
||||
Name: v.Name,
|
||||
Path: v.Path,
|
||||
IsDir: v.IsDir,
|
||||
Extension: v.Extension,
|
||||
}
|
||||
if level > 1 && v.IsDir {
|
||||
if err := f.buildChildNode(&childNode, v, op, level); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
node.Children = append(node.Children, childNode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FileService) buildChildNode(childNode *response.FileTree, fileInfo *files.FileInfo, op request.FileOption, level int) error {
|
||||
op.Path = fileInfo.Path
|
||||
subInfo, err := files.NewFileInfo(op.FileOption)
|
||||
if err != nil {
|
||||
if os.IsPermission(err) || errors.Is(err, unix.EACCES) {
|
||||
global.LOG.Info("File Tree: Skipping %s due to permission denied\n", fileInfo.Path)
|
||||
return nil
|
||||
}
|
||||
global.LOG.Errorf("File Tree: Skipping %s due to error: %s\n", fileInfo.Path, err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return f.buildFileTree(childNode, subInfo.Items, op, level-1)
|
||||
}
|
||||
|
||||
func (f *FileService) Create(op request.FileCreate) error {
|
||||
if files.IsInvalidChar(op.Path) {
|
||||
return buserr.New("ErrInvalidChar")
|
||||
}
|
||||
fo := files.NewFileOp()
|
||||
if fo.Stat(op.Path) {
|
||||
return buserr.New(constant.ErrFileIsExist)
|
||||
return buserr.New(constant.ErrFileIsExit)
|
||||
}
|
||||
mode := op.Mode
|
||||
if mode == 0 {
|
||||
@@ -273,45 +212,24 @@ func (f *FileService) ChangeOwner(req request.FileRoleUpdate) error {
|
||||
func (f *FileService) Compress(c request.FileCompress) error {
|
||||
fo := files.NewFileOp()
|
||||
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
||||
return buserr.New(constant.ErrFileIsExist)
|
||||
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()
|
||||
if c.Type == "tar" && len(c.Secret) != 0 {
|
||||
c.Type = "tar.gz"
|
||||
}
|
||||
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) {
|
||||
info, err := files.NewFileInfo(files.FileOption{
|
||||
Path: op.Path,
|
||||
Expand: true,
|
||||
IsDetail: op.IsDetail,
|
||||
Path: op.Path,
|
||||
Expand: true,
|
||||
})
|
||||
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
|
||||
}
|
||||
|
||||
@@ -386,7 +304,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)
|
||||
@@ -470,7 +388,7 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
||||
}
|
||||
|
||||
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
|
||||
lines, isEndOfFile, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -478,7 +396,6 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||
Content: strings.Join(lines, "\n"),
|
||||
End: isEndOfFile,
|
||||
Path: logFilePath,
|
||||
Total: total,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -29,7 +28,6 @@ type IFirewallService interface {
|
||||
SearchWithPage(search dto.RuleSearch) (int64, interface{}, error)
|
||||
OperateFirewall(operation string) error
|
||||
OperatePortRule(req dto.PortRuleOperate, reload bool) error
|
||||
OperateForwardRule(req dto.ForwardRuleOperate) error
|
||||
OperateAddressRule(req dto.AddrRuleOperate, reload bool) error
|
||||
UpdatePortRule(req dto.PortRuleUpdate) error
|
||||
UpdateAddrRule(req dto.AddrRuleUpdate) error
|
||||
@@ -80,39 +78,42 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
var rules []fireClient.FireInfo
|
||||
switch req.Type {
|
||||
case "port":
|
||||
rules, err = client.ListPort()
|
||||
case "forward":
|
||||
rules, err = client.ListForward()
|
||||
case "address":
|
||||
rules, err = client.ListAddress()
|
||||
}
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if len(req.Info) != 0 {
|
||||
for _, addr := range rules {
|
||||
if strings.Contains(addr.Address, req.Info) ||
|
||||
strings.Contains(addr.Port, req.Info) ||
|
||||
strings.Contains(addr.TargetPort, req.Info) ||
|
||||
strings.Contains(addr.TargetIP, req.Info) {
|
||||
datas = append(datas, addr)
|
||||
if req.Type == "port" {
|
||||
ports, err := client.ListPort()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if len(req.Info) != 0 {
|
||||
for _, port := range ports {
|
||||
if strings.Contains(port.Port, req.Info) {
|
||||
datas = append(datas, port)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
datas = ports
|
||||
}
|
||||
} else {
|
||||
datas = rules
|
||||
addrs, err := client.ListAddress()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if len(req.Info) != 0 {
|
||||
for _, addr := range addrs {
|
||||
if strings.Contains(addr.Address, req.Info) {
|
||||
datas = append(datas, addr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
datas = addrs
|
||||
}
|
||||
}
|
||||
|
||||
if req.Type == "port" {
|
||||
apps := u.loadPortByApp()
|
||||
for i := 0; i < len(datas); i++ {
|
||||
datas[i].UsedStatus = checkPortUsed(datas[i].Port, datas[i].Protocol, apps)
|
||||
}
|
||||
}
|
||||
|
||||
var datasFilterStatus []fireClient.FireInfo
|
||||
if len(req.Status) != 0 {
|
||||
for _, data := range datas {
|
||||
@@ -126,7 +127,6 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
|
||||
} else {
|
||||
datasFilterStatus = datas
|
||||
}
|
||||
|
||||
var datasFilterStrategy []fireClient.FireInfo
|
||||
if len(req.Strategy) != 0 {
|
||||
for _, data := range datasFilterStatus {
|
||||
@@ -300,52 +300,6 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error {
|
||||
client, err := firewall.NewFirewallClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rules, _ := client.ListForward()
|
||||
for _, rule := range rules {
|
||||
for _, reqRule := range req.Rules {
|
||||
if reqRule.Operation == "remove" {
|
||||
continue
|
||||
}
|
||||
if reqRule.TargetIP == "" {
|
||||
reqRule.TargetIP = "127.0.0.1"
|
||||
}
|
||||
if reqRule.Port == rule.Port && reqRule.TargetPort == rule.TargetPort && reqRule.TargetIP == rule.TargetIP {
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.SliceStable(req.Rules, func(i, j int) bool {
|
||||
n1, _ := strconv.Atoi(req.Rules[i].Num)
|
||||
n2, _ := strconv.Atoi(req.Rules[j].Num)
|
||||
return n1 > n2
|
||||
})
|
||||
|
||||
for _, r := range req.Rules {
|
||||
for _, p := range strings.Split(r.Protocol, "/") {
|
||||
if r.TargetIP == "" {
|
||||
r.TargetIP = "127.0.0.1"
|
||||
}
|
||||
if err = client.PortForward(fireClient.Forward{
|
||||
Num: r.Num,
|
||||
Protocol: p,
|
||||
Port: r.Port,
|
||||
TargetIP: r.TargetIP,
|
||||
TargetPort: r.TargetPort,
|
||||
}, r.Operation); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload bool) error {
|
||||
client, err := firewall.NewFirewallClient()
|
||||
if err != nil {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/homedir"
|
||||
)
|
||||
|
||||
type ImageService struct{}
|
||||
@@ -199,7 +198,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format(constant.DateTimeSlimLayout))
|
||||
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format("20060102150405"))
|
||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -249,20 +248,15 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
|
||||
}
|
||||
}
|
||||
imageItemName := strings.ReplaceAll(path.Base(req.ImageName), ":", "_")
|
||||
logItem := fmt.Sprintf("%s/image_pull_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format(constant.DateTimeSlimLayout))
|
||||
logItem := fmt.Sprintf("%s/image_pull_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
|
||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options := image.PullOptions{}
|
||||
if req.RepoID == 0 {
|
||||
hasAuth, authStr := loadAuthInfo(req.ImageName)
|
||||
if hasAuth {
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
go func() {
|
||||
defer file.Close()
|
||||
out, err := client.ImagePull(context.TODO(), req.ImageName, options)
|
||||
out, err := client.ImagePull(context.TODO(), req.ImageName, types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
global.LOG.Errorf("image %s pull failed, err: %v", req.ImageName, err)
|
||||
return
|
||||
@@ -277,6 +271,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options := image.PullOptions{}
|
||||
if repo.Auth {
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
@@ -403,7 +398,7 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
|
||||
}
|
||||
}
|
||||
imageItemName := strings.ReplaceAll(path.Base(req.Name), ":", "_")
|
||||
logItem := fmt.Sprintf("%s/image_push_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format(constant.DateTimeSlimLayout))
|
||||
logItem := fmt.Sprintf("%s/image_push_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
|
||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -469,49 +464,3 @@ func checkUsed(imageID string, containers []types.Container) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func loadAuthInfo(image string) (bool, string) {
|
||||
if !strings.Contains(image, "/") {
|
||||
return false, ""
|
||||
}
|
||||
homeDir := homedir.Get()
|
||||
confPath := path.Join(homeDir, ".docker/config.json")
|
||||
configFileBytes, err := os.ReadFile(confPath)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
var config dockerConfig
|
||||
if err = json.Unmarshal(configFileBytes, &config); err != nil {
|
||||
return false, ""
|
||||
}
|
||||
var (
|
||||
user string
|
||||
passwd string
|
||||
)
|
||||
imagePrefix := strings.Split(image, "/")[0]
|
||||
if val, ok := config.Auths[imagePrefix]; ok {
|
||||
itemByte, _ := base64.StdEncoding.DecodeString(val.Auth)
|
||||
itemStr := string(itemByte)
|
||||
if strings.Contains(itemStr, ":") {
|
||||
user = strings.Split(itemStr, ":")[0]
|
||||
passwd = strings.Split(itemStr, ":")[1]
|
||||
}
|
||||
}
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: user,
|
||||
Password: passwd,
|
||||
}
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
return true, authStr
|
||||
}
|
||||
|
||||
type dockerConfig struct {
|
||||
Auths map[string]authConfig `json:"auths"`
|
||||
}
|
||||
type authConfig struct {
|
||||
Auth string `json:"auth"`
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -91,7 +92,6 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
ticker := time.NewTicker(3 * time.Second)
|
||||
defer ticker.Stop()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
||||
if err := func() error {
|
||||
for range ticker.C {
|
||||
@@ -195,10 +195,13 @@ func (u *ImageRepoService) CheckConn(host, user, password string) error {
|
||||
}
|
||||
|
||||
func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) error {
|
||||
err := createIfNotExistDaemonJsonFile()
|
||||
if err != nil {
|
||||
return err
|
||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = os.Create(constant.DaemonJsonPath)
|
||||
}
|
||||
|
||||
daemonMap := make(map[string]interface{})
|
||||
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||
if err != nil {
|
||||
|
||||
@@ -83,7 +83,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
|
||||
if exist != nil {
|
||||
return nil, buserr.New(constant.ErrImageExist)
|
||||
}
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
case constant.RuntimeNode:
|
||||
if !fileOp.Stat(create.CodeDir) {
|
||||
return nil, buserr.New(constant.ErrPathNotFound)
|
||||
}
|
||||
@@ -133,9 +133,9 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
|
||||
if err = handlePHP(create, runtime, fileOp, appVersionDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
case constant.RuntimeNode:
|
||||
runtime.Port = create.Port
|
||||
if err = handleNodeAndJava(create, runtime, fileOp, appVersionDir); err != nil {
|
||||
if err = handleNode(create, runtime, fileOp, appVersionDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
|
||||
global.LOG.Errorf("delete image id [%s] error %v", imageID, err)
|
||||
}
|
||||
}
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
case constant.RuntimeNode:
|
||||
if out, err := compose.Down(runtime.GetComposePath()); err != nil && !runtimeDelete.ForceDelete {
|
||||
if out != "" {
|
||||
return errors.New(out)
|
||||
@@ -300,7 +300,7 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
|
||||
}
|
||||
}
|
||||
res.AppParams = appParams
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
case constant.RuntimeNode:
|
||||
res.Params = make(map[string]interface{})
|
||||
envs, err := gotenv.Unmarshal(runtime.Env)
|
||||
if err != nil {
|
||||
@@ -308,7 +308,7 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
|
||||
}
|
||||
for k, v := range envs {
|
||||
switch k {
|
||||
case "NODE_APP_PORT", "PANEL_APP_PORT_HTTP", "JAVA_APP_PORT", "GO_APP_PORT":
|
||||
case "NODE_APP_PORT", "PANEL_APP_PORT_HTTP":
|
||||
port, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -361,7 +361,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
if exist != nil {
|
||||
return buserr.New(constant.ErrImageExist)
|
||||
}
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
case constant.RuntimeNode:
|
||||
if runtime.Port != req.Port {
|
||||
if err = checkPortExist(req.Port); err != nil {
|
||||
return err
|
||||
@@ -441,7 +441,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
return err
|
||||
}
|
||||
go buildRuntime(runtime, imageID, req.Rebuild)
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
case constant.RuntimeNode:
|
||||
runtime.Version = req.Version
|
||||
runtime.CodeDir = req.CodeDir
|
||||
runtime.Port = req.Port
|
||||
@@ -610,7 +610,7 @@ func (r *RuntimeService) SyncRuntimeStatus() error {
|
||||
return err
|
||||
}
|
||||
for _, runtime := range runtimes {
|
||||
if runtime.Type == constant.RuntimeNode || runtime.Type == constant.RuntimeJava || runtime.Type == constant.RuntimeGo {
|
||||
if runtime.Type == constant.RuntimeNode {
|
||||
_ = SyncRuntimeContainerStatus(&runtime)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,12 @@ import (
|
||||
"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 handleNodeAndJava(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
|
||||
func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
|
||||
runtimeDir := path.Join(constant.RuntimeDir, create.Type)
|
||||
if err = fileOp.CopyDir(appVersionDir, runtimeDir); err != nil {
|
||||
return
|
||||
@@ -55,10 +54,12 @@ func handleNodeAndJava(create request.RuntimeCreate, runtime *model.Runtime, fil
|
||||
}
|
||||
|
||||
go func() {
|
||||
if _, _, err := httpUtil.HandleGet(nodeDetail.DownloadCallBackUrl, http.MethodGet, constant.TimeOut5s); err != nil {
|
||||
res, err := http.Get(nodeDetail.DownloadCallBackUrl)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("http request failed(handleNode), err: %v", err)
|
||||
return
|
||||
}
|
||||
res.Body.Close()
|
||||
}()
|
||||
go startRuntime(runtime)
|
||||
|
||||
@@ -149,7 +150,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
|
||||
@@ -318,23 +318,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
|
||||
}
|
||||
create.Params["CONTAINER_PACKAGE_URL"] = create.Source
|
||||
|
||||
composeContent, err = handleCompose(env, composeContent, create, projectDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case constant.RuntimeJava:
|
||||
create.Params["CODE_DIR"] = create.CodeDir
|
||||
create.Params["JAVA_VERSION"] = create.Version
|
||||
create.Params["PANEL_APP_PORT_HTTP"] = create.Port
|
||||
composeContent, err = handleCompose(env, composeContent, create, projectDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case constant.RuntimeGo:
|
||||
create.Params["CODE_DIR"] = create.CodeDir
|
||||
create.Params["GO_VERSION"] = create.Version
|
||||
create.Params["PANEL_APP_PORT_HTTP"] = create.Port
|
||||
composeContent, err = handleCompose(env, composeContent, create, projectDir)
|
||||
composeContent, err = handleNodeCompose(env, composeContent, create, projectDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -357,7 +341,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
|
||||
return
|
||||
}
|
||||
|
||||
func handleCompose(env gotenv.Env, composeContent []byte, create request.RuntimeCreate, projectDir string) (composeByte []byte, err error) {
|
||||
func handleNodeCompose(env gotenv.Env, composeContent []byte, create request.RuntimeCreate, projectDir string) (composeByte []byte, err error) {
|
||||
existMap := make(map[string]interface{})
|
||||
composeMap := make(map[string]interface{})
|
||||
if err = yaml.Unmarshal(composeContent, &composeMap); err != nil {
|
||||
@@ -376,17 +360,7 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
|
||||
_, ok := serviceValue["ports"].([]interface{})
|
||||
if ok {
|
||||
var ports []interface{}
|
||||
|
||||
switch create.Type {
|
||||
case constant.RuntimeNode:
|
||||
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${NODE_APP_PORT}")
|
||||
case constant.RuntimeJava:
|
||||
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${JAVA_APP_PORT}")
|
||||
case constant.RuntimeGo:
|
||||
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${GO_APP_PORT}")
|
||||
|
||||
}
|
||||
|
||||
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${NODE_APP_PORT}")
|
||||
for i, port := range create.ExposedPorts {
|
||||
containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i)
|
||||
hostPortStr := fmt.Sprintf("HOST_PORT_%d", i)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -118,7 +111,7 @@ func (u *SettingService) Update(key, value string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format(constant.DateTimeLayout)); err != nil {
|
||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
|
||||
return err
|
||||
}
|
||||
case "BindDomain":
|
||||
@@ -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(constant.DateTimeLayout)
|
||||
}
|
||||
return &data, nil
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error {
|
||||
@@ -410,7 +368,7 @@ func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string)
|
||||
return err
|
||||
}
|
||||
timeout, _ := strconv.Atoi(expiredSetting.Value)
|
||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format(constant.DateTimeLayout)); err != nil {
|
||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -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,9 +411,9 @@ 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(constant.DateTimeLayout),
|
||||
Timeout: certObj.NotAfter.Format("2006-01-02 15:04:05"),
|
||||
RootPath: path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -48,9 +48,13 @@ func NewISnapshotService() ISnapshotService {
|
||||
|
||||
func (u *SnapshotService) SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error) {
|
||||
total, systemBackups, err := snapshotRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info))
|
||||
dtoSnap, err := loadSnapSize(systemBackups)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
var dtoSnap []dto.SnapshotInfo
|
||||
for _, systemBackup := range systemBackups {
|
||||
var item dto.SnapshotInfo
|
||||
if err := copier.Copy(&item, &systemBackup); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
dtoSnap = append(dtoSnap, item)
|
||||
}
|
||||
return total, dtoSnap, err
|
||||
}
|
||||
@@ -119,7 +123,7 @@ type SnapshotJson struct {
|
||||
}
|
||||
|
||||
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
||||
if _, err := u.HandleSnapshot(false, "", req, time.Now().Format(constant.DateTimeSlimLayout), req.Secret); err != nil {
|
||||
if _, err := u.HandleSnapshot(false, "", req, time.Now().Format("20060102150405")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -132,7 +136,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
return err
|
||||
}
|
||||
if hasOs(snap.Name) && !strings.Contains(snap.Name, loadOs()) {
|
||||
return fmt.Errorf("restoring snapshots(%s) between different server architectures(%s) is not supported", snap.Name, loadOs())
|
||||
return fmt.Errorf("Restoring snapshots(%s) between different server architectures(%s) is not supported.", snap.Name, loadOs())
|
||||
}
|
||||
if !req.IsNew && len(snap.InterruptStep) != 0 && len(snap.RollbackStatus) != 0 {
|
||||
return fmt.Errorf("the snapshot has been rolled back and cannot be restored again")
|
||||
@@ -176,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
|
||||
@@ -270,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})
|
||||
@@ -301,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)
|
||||
@@ -319,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
|
||||
}
|
||||
|
||||
@@ -350,7 +354,7 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
|
||||
"interrupt_step": interruptStep,
|
||||
"recover_status": status,
|
||||
"recover_message": message,
|
||||
"last_recovered_at": time.Now().Format(constant.DateTimeLayout),
|
||||
"last_recovered_at": time.Now().Format("2006-01-02 15:04:05"),
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("update snap recover status failed, err: %v", err)
|
||||
}
|
||||
@@ -365,7 +369,7 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
|
||||
"interrupt_step": "",
|
||||
"rollback_status": "",
|
||||
"rollback_message": "",
|
||||
"last_rollbacked_at": time.Now().Format(constant.DateTimeLayout),
|
||||
"last_rollbacked_at": time.Now().Format("2006-01-02 15:04:05"),
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("update snap recover status failed, err: %v", err)
|
||||
}
|
||||
@@ -375,27 +379,21 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
|
||||
if err := snapshotRepo.Update(id, map[string]interface{}{
|
||||
"rollback_status": status,
|
||||
"rollback_message": message,
|
||||
"last_rollbacked_at": time.Now().Format(constant.DateTimeLayout),
|
||||
"last_rollbacked_at": time.Now().Format("2006-01-02 15:04:05"),
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("update snap recover status failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -506,48 +504,3 @@ func loadOs() string {
|
||||
return hostInfo.KernelArch
|
||||
}
|
||||
}
|
||||
|
||||
func loadSnapSize(records []model.Snapshot) ([]dto.SnapshotInfo, error) {
|
||||
var datas []dto.SnapshotInfo
|
||||
clientMap := make(map[string]loadSizeHelper)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < len(records); i++ {
|
||||
var item dto.SnapshotInfo
|
||||
if err := copier.Copy(&item, &records[i]); err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
itemPath := fmt.Sprintf("system_snapshot/%s.tar.gz", item.Name)
|
||||
if _, ok := clientMap[records[i].DefaultDownload]; !ok {
|
||||
backup, err := backupRepo.Get(commonRepo.WithByType(records[i].DefaultDownload))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load backup model %s from db failed, err: %v", records[i].DefaultDownload, err)
|
||||
clientMap[records[i].DefaultDownload] = loadSizeHelper{}
|
||||
datas = append(datas, item)
|
||||
continue
|
||||
}
|
||||
client, err := NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load backup client %s from db failed, err: %v", records[i].DefaultDownload, err)
|
||||
clientMap[records[i].DefaultDownload] = loadSizeHelper{}
|
||||
datas = append(datas, item)
|
||||
continue
|
||||
}
|
||||
item.Size, _ = client.Size(path.Join(strings.TrimLeft(backup.BackupPath, "/"), itemPath))
|
||||
datas = append(datas, item)
|
||||
clientMap[records[i].DefaultDownload] = loadSizeHelper{backupPath: strings.TrimLeft(backup.BackupPath, "/"), client: client, isOk: true}
|
||||
continue
|
||||
}
|
||||
if clientMap[records[i].DefaultDownload].isOk {
|
||||
wg.Add(1)
|
||||
go func(index int) {
|
||||
item.Size, _ = clientMap[records[index].DefaultDownload].client.Size(path.Join(clientMap[records[index].DefaultDownload].backupPath, itemPath))
|
||||
datas = append(datas, item)
|
||||
wg.Done()
|
||||
}(i)
|
||||
} else {
|
||||
datas = append(datas, item)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -73,7 +70,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
|
||||
if snap.InterruptStep == "Readjson" {
|
||||
req.IsNew = true
|
||||
}
|
||||
if isRecover && (req.IsNew || snap.InterruptStep == "AppData") {
|
||||
if req.IsNew || snap.InterruptStep == "AppData" {
|
||||
if err := recoverAppData(snapFileDir); err != nil {
|
||||
updateRecoverStatus(snap.ID, isRecover, "DockerDir", constant.StatusFailed, fmt.Sprintf("handle recover app data failed, err: %v", err))
|
||||
return
|
||||
@@ -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
|
||||
@@ -163,14 +160,14 @@ func backupBeforeRecover(snap model.Snapshot, secret string) error {
|
||||
_ = os.MkdirAll(path.Join(baseDir, "1panel"), os.ModePerm)
|
||||
_ = os.MkdirAll(path.Join(baseDir, "docker"), os.ModePerm)
|
||||
|
||||
wg.Add(4)
|
||||
wg.Add(5)
|
||||
itemHelper.Wg = &wg
|
||||
go snapJson(itemHelper, jsonItem, baseDir)
|
||||
go snapPanel(itemHelper, path.Join(baseDir, "1panel"))
|
||||
go snapDaemonJson(itemHelper, path.Join(baseDir, "docker"))
|
||||
go snapAppData(itemHelper, path.Join(baseDir, "docker"))
|
||||
go snapBackup(itemHelper, global.CONF.System.Backup, path.Join(baseDir, "1panel"))
|
||||
wg.Wait()
|
||||
itemHelper.Status.AppData = constant.StatusDone
|
||||
|
||||
allDone, msg := checkAllDone(status)
|
||||
if !allDone {
|
||||
|
||||
+11
-28
@@ -62,9 +62,7 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
|
||||
active, err := systemctl.IsActive(serviceName)
|
||||
if !active {
|
||||
data.Status = constant.StatusDisable
|
||||
if err != nil {
|
||||
data.Message = err.Error()
|
||||
}
|
||||
data.Message = err.Error()
|
||||
} else {
|
||||
data.Status = constant.StatusEnable
|
||||
}
|
||||
@@ -220,7 +218,7 @@ func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error {
|
||||
}
|
||||
secretFile := fmt.Sprintf("%s/.ssh/id_item_%s", currentUser.HomeDir, req.EncryptionMode)
|
||||
secretPubFile := fmt.Sprintf("%s/.ssh/id_item_%s.pub", currentUser.HomeDir, req.EncryptionMode)
|
||||
authFilePath := currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||
authFile := currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||
|
||||
command := fmt.Sprintf("ssh-keygen -t %s -f %s/.ssh/id_item_%s | echo y", req.EncryptionMode, currentUser.HomeDir, req.EncryptionMode)
|
||||
if len(req.Password) != 0 {
|
||||
@@ -237,12 +235,8 @@ func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error {
|
||||
_ = os.Remove(secretPubFile)
|
||||
}()
|
||||
|
||||
if _, err := os.Stat(authFilePath); err != nil && errors.Is(err, os.ErrNotExist) {
|
||||
authFile, err := os.Create(authFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer authFile.Close()
|
||||
if _, err := os.Stat(authFile); err != nil {
|
||||
_, _ = os.Create(authFile)
|
||||
}
|
||||
stdout1, err := cmd.Execf("cat %s >> %s/.ssh/authorized_keys", secretPubFile, currentUser.HomeDir)
|
||||
if err != nil {
|
||||
@@ -485,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]
|
||||
@@ -551,23 +542,15 @@ func loadDate(currentYear int, DateStr string, nyc *time.Location) time.Time {
|
||||
}
|
||||
|
||||
func analyzeDateStr(parts []string) (int, string) {
|
||||
t, err := time.Parse(time.RFC3339Nano, 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(constant.DateTimeLayout, fmt.Sprintf("%s %s", parts[0], parts[1]))
|
||||
if err == nil {
|
||||
t, err := time.Parse("2006-01-02T15:04:05.999999-07:00", parts[0])
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@@ -11,12 +12,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"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{}
|
||||
@@ -83,7 +82,7 @@ func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
|
||||
func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
global.LOG.Info("start to upgrade now...")
|
||||
fileOp := files.NewFileOp()
|
||||
timeStr := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
timeStr := time.Now().Format("20060102150405")
|
||||
rootDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("upgrade/upgrade_%s/downloads", timeStr))
|
||||
originalDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("upgrade/upgrade_%s/original", timeStr))
|
||||
if err := os.MkdirAll(rootDir, os.ModePerm); err != nil {
|
||||
@@ -109,7 +108,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 +117,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
|
||||
@@ -176,7 +175,7 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
|
||||
return err
|
||||
}
|
||||
checkPointOfWal()
|
||||
if err := handleTar(path.Join(global.CONF.System.BaseDir, "1panel/db"), originalDir, "db.tar.gz", "db/1Panel.db-*", ""); err != nil {
|
||||
if err := handleTar(path.Join(global.CONF.System.BaseDir, "1panel/db"), originalDir, "db.tar.gz", "./1Panel.db-*"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -192,7 +191,7 @@ func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -259,13 +258,15 @@ func (u *UpgradeService) loadVersion(isLatest bool, currentVersion, mode string)
|
||||
if !isLatest {
|
||||
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, 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 ""
|
||||
}
|
||||
version := string(latestVersionRes)
|
||||
if strings.Contains(version, "<") {
|
||||
defer latestVersionRes.Body.Close()
|
||||
versionByte, err := io.ReadAll(latestVersionRes.Body)
|
||||
version := string(versionByte)
|
||||
if err != nil || strings.Contains(version, "<") {
|
||||
global.LOG.Errorf("load latest version from oss failed, err: %v", version)
|
||||
return ""
|
||||
}
|
||||
@@ -274,7 +275,7 @@ func (u *UpgradeService) loadVersion(isLatest bool, currentVersion, mode string)
|
||||
}
|
||||
|
||||
versionMap := make(map[string]string)
|
||||
if err := json.Unmarshal(latestVersionRes, &versionMap); err != nil {
|
||||
if err := json.Unmarshal(versionByte, &versionMap); err != nil {
|
||||
global.LOG.Errorf("load latest version from oss failed (error unmarshal), err: %v", err)
|
||||
return ""
|
||||
}
|
||||
@@ -320,11 +321,16 @@ func (u *UpgradeService) checkVersion(v2, v1 string) string {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
+31
-147
@@ -53,7 +53,7 @@ type WebsiteService struct {
|
||||
}
|
||||
|
||||
type IWebsiteService interface {
|
||||
PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteRes, error)
|
||||
PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteDTO, error)
|
||||
GetWebsites() ([]response.WebsiteDTO, error)
|
||||
CreateWebsite(create request.WebsiteCreate) error
|
||||
OpWebsite(req request.WebsiteOp) error
|
||||
@@ -96,18 +96,15 @@ type IWebsiteService interface {
|
||||
OperateRedirect(req request.NginxRedirectReq) (err error)
|
||||
GetRedirect(id uint) (res []response.NginxRedirectConfig, err error)
|
||||
UpdateRedirectFile(req request.NginxRedirectUpdate) (err error)
|
||||
|
||||
UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error
|
||||
GetDefaultHtml(resourceType string) (*response.WebsiteHtmlRes, error)
|
||||
}
|
||||
|
||||
func NewIWebsiteService() IWebsiteService {
|
||||
return &WebsiteService{}
|
||||
}
|
||||
|
||||
func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteRes, error) {
|
||||
func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteDTO, error) {
|
||||
var (
|
||||
websiteDTOs []response.WebsiteRes
|
||||
websiteDTOs []response.WebsiteDTO
|
||||
opts []repo.DBOption
|
||||
)
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
@@ -157,22 +154,11 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
|
||||
runtimeName = runtime.Name
|
||||
}
|
||||
sitePath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", web.Alias)
|
||||
|
||||
websiteDTOs = append(websiteDTOs, response.WebsiteRes{
|
||||
ID: web.ID,
|
||||
CreatedAt: web.CreatedAt,
|
||||
Protocol: web.Protocol,
|
||||
PrimaryDomain: web.PrimaryDomain,
|
||||
Type: web.Type,
|
||||
Remark: web.Remark,
|
||||
Status: web.Status,
|
||||
Alias: web.Alias,
|
||||
AppName: appName,
|
||||
ExpireDate: web.ExpireDate,
|
||||
SSLExpireDate: web.WebsiteSSL.ExpireDate,
|
||||
SSLStatus: checkSSLStatus(web.WebsiteSSL.ExpireDate),
|
||||
RuntimeName: runtimeName,
|
||||
SitePath: sitePath,
|
||||
websiteDTOs = append(websiteDTOs, response.WebsiteDTO{
|
||||
Website: web,
|
||||
AppName: appName,
|
||||
RuntimeName: runtimeName,
|
||||
SitePath: sitePath,
|
||||
})
|
||||
}
|
||||
return total, websiteDTOs, nil
|
||||
@@ -180,7 +166,7 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
|
||||
|
||||
func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
|
||||
var websiteDTOs []response.WebsiteDTO
|
||||
websites, err := websiteRepo.List(commonRepo.WithOrderRuleBy("primary_domain", "ascending"))
|
||||
websites, err := websiteRepo.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -336,7 +322,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
}
|
||||
website.Proxy = proxy
|
||||
}
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
case constant.RuntimeNode:
|
||||
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
|
||||
}
|
||||
}
|
||||
@@ -345,15 +331,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(create.FtpUser) != 0 && len(create.FtpPassword) != 0 {
|
||||
indexDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
|
||||
itemID, err := NewIFtpService().Create(dto.FtpCreate{User: create.FtpUser, Password: create.FtpPassword, Path: indexDir})
|
||||
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
|
||||
}
|
||||
@@ -442,7 +419,6 @@ func (w WebsiteService) GetWebsite(id uint) (response.WebsiteDTO, error) {
|
||||
res.ErrorLogPath = path.Join(sitePath, "log", "error.log")
|
||||
res.AccessLogPath = path.Join(sitePath, "log", "access.log")
|
||||
res.SitePath = sitePath
|
||||
res.SiteDir = website.SiteDir
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -470,8 +446,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
|
||||
}
|
||||
@@ -480,6 +455,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)
|
||||
@@ -541,7 +524,9 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
}
|
||||
for _, domain := range domainModels {
|
||||
wafSite.Domains = append(wafSite.Domains, domain.Domain)
|
||||
wafSite.Host = append(wafSite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
|
||||
if domain.Port != 80 && domain.Port != 443 {
|
||||
wafSite.Host = append(wafSite.Host, domain.Domain+":"+string(rune(domain.Port)))
|
||||
}
|
||||
}
|
||||
if len(wafSite.Host) == 0 {
|
||||
wafSite.Host = []string{}
|
||||
@@ -633,7 +618,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)
|
||||
@@ -768,7 +753,7 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
|
||||
} else {
|
||||
res.HttpConfig = constant.HTTPToHTTPS
|
||||
}
|
||||
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"ssl_protocols", "ssl_ciphers", "add_header"}, &website)
|
||||
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"ssl_protocols", "ssl_ciphers"}, &website)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -779,9 +764,6 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
|
||||
if p.Name == "ssl_ciphers" {
|
||||
res.Algorithm = p.Params[0]
|
||||
}
|
||||
if p.Name == "add_header" && len(p.Params) > 0 && p.Params[0] == "Strict-Transport-Security" {
|
||||
res.Hsts = true
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -799,7 +781,7 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = ChangeHSTSConfig(req.Hsts, nginxInstall, website); err != nil {
|
||||
if err = ChangeHSTSConfig(req.Enable, nginxInstall, website); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.Enable = req.Enable
|
||||
@@ -910,7 +892,6 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
websiteSSL.Provider = constant.Manual
|
||||
websiteSSL.PrivateKey = privateKey
|
||||
websiteSSL.Pem = certificate
|
||||
websiteSSL.Status = constant.SSLReady
|
||||
|
||||
res.SSL = websiteSSL
|
||||
}
|
||||
@@ -959,7 +940,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{
|
||||
@@ -1023,7 +1004,7 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
|
||||
}
|
||||
}
|
||||
filePath := path.Join(sitePath, "log", req.LogType)
|
||||
lines, end, _, err := files.ReadFileByLine(filePath, req.Page, req.PageSize, false)
|
||||
lines, end, err := files.ReadFileByLine(filePath, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1055,16 +1036,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 {
|
||||
@@ -1634,6 +1613,9 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
}
|
||||
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
|
||||
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
|
||||
if website.Protocol == constant.ProtocolHTTPS {
|
||||
location.UpdateDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""})
|
||||
}
|
||||
location.ChangePath(req.Modifier, req.Match)
|
||||
if req.Cache {
|
||||
location.AddCache(req.CacheTime, req.CacheUnit)
|
||||
@@ -1645,11 +1627,6 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
} else {
|
||||
location.RemoveSubFilter()
|
||||
}
|
||||
if req.SNI {
|
||||
location.UpdateDirective("proxy_ssl_server_name", []string{"on"})
|
||||
} else {
|
||||
location.UpdateDirective("proxy_ssl_server_name", []string{"off"})
|
||||
}
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||
}
|
||||
@@ -1725,11 +1702,6 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e
|
||||
proxyConfig.Modifier = location.Modifier
|
||||
proxyConfig.ProxyHost = location.Host
|
||||
proxyConfig.Replaces = location.Replaces
|
||||
for _, directive := range location.Directives {
|
||||
if directive.GetName() == "proxy_ssl_server_name" {
|
||||
proxyConfig.SNI = directive.GetParameters()[0] == "on"
|
||||
}
|
||||
}
|
||||
res = append(res, proxyConfig)
|
||||
}
|
||||
return
|
||||
@@ -2473,91 +2445,3 @@ func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*res
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetDefaultHtml(resourceType string) (*response.WebsiteHtmlRes, error) {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rootPath := path.Join(nginxInstall.GetPath(), "root")
|
||||
fileOp := files.NewFileOp()
|
||||
defaultPath := path.Join(rootPath, "default")
|
||||
if !fileOp.Stat(defaultPath) {
|
||||
_ = fileOp.CreateDir(defaultPath, 0755)
|
||||
}
|
||||
|
||||
res := &response.WebsiteHtmlRes{}
|
||||
|
||||
switch resourceType {
|
||||
case "404":
|
||||
resourcePath := path.Join(defaultPath, "404.html")
|
||||
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
||||
res.Content = content
|
||||
return res, nil
|
||||
}
|
||||
res.Content = string(nginx_conf.NotFoundHTML)
|
||||
return res, nil
|
||||
case "php":
|
||||
resourcePath := path.Join(defaultPath, "index.php")
|
||||
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
||||
res.Content = content
|
||||
return res, nil
|
||||
}
|
||||
res.Content = string(nginx_conf.IndexPHP)
|
||||
return res, nil
|
||||
case "index":
|
||||
resourcePath := path.Join(defaultPath, "index.html")
|
||||
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
||||
res.Content = content
|
||||
return res, nil
|
||||
}
|
||||
res.Content = string(nginx_conf.Index)
|
||||
return res, nil
|
||||
case "domain404":
|
||||
resourcePath := path.Join(rootPath, "404.html")
|
||||
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
||||
res.Content = content
|
||||
return res, nil
|
||||
}
|
||||
res.Content = string(nginx_conf.DomainNotFoundHTML)
|
||||
return res, nil
|
||||
case "stop":
|
||||
resourcePath := path.Join(rootPath, "stop", "index.html")
|
||||
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
||||
res.Content = content
|
||||
return res, nil
|
||||
}
|
||||
res.Content = string(nginx_conf.StopHTML)
|
||||
return res, nil
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rootPath := path.Join(nginxInstall.GetPath(), "root")
|
||||
fileOp := files.NewFileOp()
|
||||
defaultPath := path.Join(rootPath, "default")
|
||||
if !fileOp.Stat(defaultPath) {
|
||||
_ = fileOp.CreateDir(defaultPath, 0755)
|
||||
}
|
||||
var resourcePath string
|
||||
switch req.Type {
|
||||
case "404":
|
||||
resourcePath = path.Join(defaultPath, "404.html")
|
||||
case "php":
|
||||
resourcePath = path.Join(defaultPath, "index.php")
|
||||
case "index":
|
||||
resourcePath = path.Join(defaultPath, "index.html")
|
||||
case "domain404":
|
||||
resourcePath = path.Join(rootPath, "404.html")
|
||||
case "stop":
|
||||
resourcePath = path.Join(rootPath, "stop", "index.html")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return fileOp.SaveFile(resourcePath, req.Content, 0644)
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@ import (
|
||||
"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/i18n"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||
@@ -40,7 +38,6 @@ type IWebsiteCAService interface {
|
||||
GetCA(id uint) (*response.WebsiteCADTO, error)
|
||||
Delete(id uint) error
|
||||
ObtainSSL(req request.WebsiteCAObtain) (*model.WebsiteSSL, error)
|
||||
DownloadFile(id uint) (*os.File, error)
|
||||
}
|
||||
|
||||
func NewIWebsiteCAService() IWebsiteCAService {
|
||||
@@ -203,10 +200,6 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
CaID: ca.ID,
|
||||
AutoRenew: req.AutoRenew,
|
||||
Description: req.Description,
|
||||
ExecShell: req.ExecShell,
|
||||
}
|
||||
if req.ExecShell {
|
||||
websiteSSL.Shell = req.Shell
|
||||
}
|
||||
if req.PushDir {
|
||||
if !files.NewFileOp().Stat(req.Dir) {
|
||||
@@ -370,18 +363,6 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
logger := log.New(logFile, "", log.LstdFlags)
|
||||
logger.Println(i18n.GetMsgWithMap("ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}))
|
||||
saveCertificateFile(websiteSSL, logger)
|
||||
if websiteSSL.ExecShell {
|
||||
workDir := constant.DataDir
|
||||
if websiteSSL.PushDir {
|
||||
workDir = websiteSSL.Dir
|
||||
}
|
||||
logger.Println(i18n.GetMsgByKey("ExecShellStart"))
|
||||
if err = cmd.ExecShellWithTimeOut(websiteSSL.Shell, workDir, logger, 30*time.Minute); err != nil {
|
||||
logger.Println(i18n.GetMsgWithMap("ErrExecShell", map[string]interface{}{"err": err.Error()}))
|
||||
} else {
|
||||
logger.Println(i18n.GetMsgByKey("ExecShellSuccess"))
|
||||
}
|
||||
}
|
||||
return websiteSSL, nil
|
||||
}
|
||||
|
||||
@@ -416,31 +397,3 @@ func createPrivateKey(keyType string) (privateKey any, publicKey any, privateKey
|
||||
privateKeyBytes = caPrivateKeyPEM.Bytes()
|
||||
return
|
||||
}
|
||||
|
||||
func (w WebsiteCAService) DownloadFile(id uint) (*os.File, error) {
|
||||
ca, err := websiteCARepo.GetFirst(commonRepo.WithByID(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
dir := path.Join(global.CONF.System.BaseDir, "1panel/tmp/ssl", ca.Name)
|
||||
if fileOp.Stat(dir) {
|
||||
if err = fileOp.DeleteDir(dir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = fileOp.CreateDir(dir, 0666); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = fileOp.WriteFile(path.Join(dir, "ca.csr"), strings.NewReader(ca.CSR), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = fileOp.WriteFile(path.Join(dir, "private.key"), strings.NewReader(ca.PrivateKey), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fileName := ca.Name + ".zip"
|
||||
if err = fileOp.Compress([]string{path.Join(dir, "ca.csr"), path.Join(dir, "private.key")}, dir, fileName, files.SdkZip, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.Open(path.Join(dir, fileName))
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user