Skip to content

Commit 63ae173

Browse files
authored
feat: 计划任务支持备份应用 (#2040)
Refs #1788 #1713
1 parent f196d02 commit 63ae173

File tree

20 files changed

+332
-21
lines changed

20 files changed

+332
-21
lines changed

backend/app/api/v1/app_install.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import (
1414
)
1515

1616
// @Tags App
17-
// @Summary List app installed
18-
// @Description 获取已安装应用列表
17+
// @Summary Page app installed
18+
// @Description 分页获取已安装应用列表
1919
// @Accept json
2020
// @Param request body request.AppInstalledSearch true "request"
2121
// @Success 200
@@ -47,6 +47,22 @@ func (b *BaseApi) SearchAppInstalled(c *gin.Context) {
4747
}
4848
}
4949

50+
// @Tags App
51+
// @Summary List app installed
52+
// @Description 获取已安装应用列表
53+
// @Accept json
54+
// @Success 200 array dto.AppInstallInfo
55+
// @Security ApiKeyAuth
56+
// @Router /apps/installed/list [get]
57+
func (b *BaseApi) ListAppInstalled(c *gin.Context) {
58+
list, err := appInstallService.GetInstallList()
59+
if err != nil {
60+
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
61+
return
62+
}
63+
helper.SuccessWithData(c, list)
64+
}
65+
5066
// @Tags App
5167
// @Summary Check app installed
5268
// @Description 检查应用安装情况

backend/app/dto/app.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,9 @@ var AppToolMap = map[string]string{
132132
"mysql": "phpmyadmin",
133133
"redis": "redis-commander",
134134
}
135+
136+
type AppInstallInfo struct {
137+
ID uint `json:"id"`
138+
Key string `json:"key"`
139+
Name string `json:"name"`
140+
}

backend/app/dto/cronjob.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type CronjobCreate struct {
1414

1515
Script string `json:"script"`
1616
ContainerName string `json:"containerName"`
17+
AppID string `json:"appID"`
1718
Website string `json:"website"`
1819
ExclusionRules string `json:"exclusionRules"`
1920
DBName string `json:"dbName"`
@@ -36,6 +37,7 @@ type CronjobUpdate struct {
3637

3738
Script string `json:"script"`
3839
ContainerName string `json:"containerName"`
40+
AppID string `json:"appID"`
3941
Website string `json:"website"`
4042
ExclusionRules string `json:"exclusionRules"`
4143
DBName string `json:"dbName"`
@@ -79,6 +81,7 @@ type CronjobInfo struct {
7981

8082
Script string `json:"script"`
8183
ContainerName string `json:"containerName"`
84+
AppID string `json:"appID"`
8285
Website string `json:"website"`
8386
ExclusionRules string `json:"exclusionRules"`
8487
DBName string `json:"dbName"`

backend/app/model/cronjob.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type Cronjob struct {
1818
ContainerName string `gorm:"type:varchar(64)" json:"containerName"`
1919
Script string `gorm:"longtext" json:"script"`
2020
Website string `gorm:"type:varchar(64)" json:"website"`
21+
AppID string `gorm:"type:varchar(64)" json:"appID"`
2122
DBName string `gorm:"type:varchar(64)" json:"dbName"`
2223
URL string `gorm:"type:varchar(256)" json:"url"`
2324
SourceDir string `gorm:"type:varchar(256)" json:"sourceDir"`

backend/app/service/app_install.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7-
"github.com/1Panel-dev/1Panel/backend/i18n"
87
"math"
98
"os"
109
"path"
1110
"reflect"
1211
"strconv"
1312
"strings"
1413

14+
"github.com/1Panel-dev/1Panel/backend/i18n"
15+
1516
"github.com/1Panel-dev/1Panel/backend/utils/files"
1617
"gopkg.in/yaml.v3"
1718

@@ -54,12 +55,26 @@ type IAppInstallService interface {
5455
ChangeAppPort(req request.PortUpdate) error
5556
GetDefaultConfigByKey(key string) (string, error)
5657
DeleteCheck(installId uint) ([]dto.AppResource, error)
58+
59+
GetInstallList() ([]dto.AppInstallInfo, error)
5760
}
5861

5962
func NewIAppInstalledService() IAppInstallService {
6063
return &AppInstallService{}
6164
}
6265

66+
func (a *AppInstallService) GetInstallList() ([]dto.AppInstallInfo, error) {
67+
var datas []dto.AppInstallInfo
68+
appInstalls, err := appInstallRepo.ListBy()
69+
if err != nil {
70+
return nil, err
71+
}
72+
for _, install := range appInstalls {
73+
datas = append(datas, dto.AppInstallInfo{ID: install.ID, Key: install.App.Key, Name: install.Name})
74+
}
75+
return datas, nil
76+
}
77+
6378
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
6479
var (
6580
opts []repo.DBOption

backend/app/service/cornjob.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, inter
4646
if err := copier.Copy(&item, &cronjob); err != nil {
4747
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
4848
}
49-
if item.Type == "website" || item.Type == "database" || item.Type == "directory" {
49+
if item.Type == "app" || item.Type == "website" || item.Type == "database" || item.Type == "directory" {
5050
backup, _ := backupRepo.Get(commonRepo.WithByID(uint(item.TargetDirID)))
5151
if len(backup.Type) != 0 {
5252
item.TargetDir = backup.Type
@@ -103,7 +103,7 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
103103
if err != nil {
104104
return err
105105
}
106-
if req.CleanData && (cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory") {
106+
if req.CleanData && (cronjob.Type == "app" || cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory") {
107107
cronjob.RetainCopies = 0
108108
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
109109
if err != nil {

backend/app/service/cronjob_helper.go

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
4747
case "ntp":
4848
err = u.handleNtpSync()
4949
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
50-
case "website":
51-
record.File, err = u.handleBackup(cronjob, record.StartTime)
52-
case "database":
50+
case "website", "database", "app":
5351
record.File, err = u.handleBackup(cronjob, record.StartTime)
5452
case "directory":
5553
if len(cronjob.SourceDir) == 0 {
@@ -120,6 +118,9 @@ func (u *CronjobService) handleBackup(cronjob *model.Cronjob, startTime time.Tim
120118
case "database":
121119
paths, err := u.handleDatabase(*cronjob, backup, startTime)
122120
return strings.Join(paths, ","), err
121+
case "app":
122+
paths, err := u.handleApp(*cronjob, backup, startTime)
123+
return strings.Join(paths, ","), err
123124
case "website":
124125
paths, err := u.handleWebsite(*cronjob, backup, startTime)
125126
return strings.Join(paths, ","), err
@@ -221,7 +222,7 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
221222
path = sourceDir
222223
}
223224

224-
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
225+
commands := fmt.Sprintf("tar -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
225226
global.LOG.Debug(commands)
226227
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
227228
if err != nil {
@@ -396,6 +397,84 @@ func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime t
396397
return strings.Join(filePaths, ","), nil
397398
}
398399

400+
func (u *CronjobService) handleApp(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
401+
var paths []string
402+
localDir, err := loadLocalDir()
403+
if err != nil {
404+
return paths, err
405+
}
406+
407+
var applist []model.AppInstall
408+
if cronjob.AppID == "all" {
409+
applist, err = appInstallRepo.ListBy()
410+
if err != nil {
411+
return paths, err
412+
}
413+
} else {
414+
itemID, _ := (strconv.Atoi(cronjob.AppID))
415+
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
416+
if err != nil {
417+
return paths, err
418+
}
419+
applist = append(applist, app)
420+
}
421+
422+
var client cloud_storage.CloudStorageClient
423+
if backup.Type != "LOCAL" {
424+
client, err = NewIBackupService().NewClient(&backup)
425+
if err != nil {
426+
return paths, err
427+
}
428+
}
429+
430+
for _, app := range applist {
431+
var record model.BackupRecord
432+
record.Type = "app"
433+
record.Name = app.App.Key
434+
record.DetailName = app.Name
435+
record.Source = "LOCAL"
436+
record.BackupType = backup.Type
437+
backupDir := path.Join(localDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
438+
record.FileDir = backupDir
439+
itemFileDir := strings.TrimPrefix(backupDir, localDir+"/")
440+
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
441+
record.Source = backup.Type
442+
record.FileDir = strings.TrimPrefix(backupDir, localDir+"/")
443+
}
444+
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405"))
445+
if err := handleAppBackup(&app, backupDir, record.FileName); err != nil {
446+
return paths, err
447+
}
448+
record.Name = app.Name
449+
if err := backupRepo.CreateRecord(&record); err != nil {
450+
global.LOG.Errorf("save backup record failed, err: %v", err)
451+
return paths, err
452+
}
453+
if backup.Type != "LOCAL" {
454+
if !cronjob.KeepLocal {
455+
defer func() {
456+
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
457+
}()
458+
}
459+
if len(backup.BackupPath) != 0 {
460+
itemPath := strings.TrimPrefix(backup.BackupPath, "/")
461+
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
462+
itemFileDir = itemPath + itemFileDir
463+
}
464+
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
465+
return paths, err
466+
}
467+
}
468+
if backup.Type == "LOCAL" || cronjob.KeepLocal {
469+
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
470+
} else {
471+
paths = append(paths, fmt.Sprintf("%s/%s", itemFileDir, record.FileName))
472+
}
473+
}
474+
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client)
475+
return paths, nil
476+
}
477+
399478
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
400479
var paths []string
401480
localDir, err := loadLocalDir()

backend/init/migration/migrations/init.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,9 @@ var UpdateCronjobWithDb = &gormigrate.Migration{
572572
}
573573

574574
var AddTableFirewall = &gormigrate.Migration{
575-
ID: "20230821-add-table-firewall",
575+
ID: "20230823-add-table-firewall",
576576
Migrate: func(tx *gorm.DB) error {
577-
if err := tx.AutoMigrate(&model.Firewall{}, model.SnapshotStatus{}); err != nil {
577+
if err := tx.AutoMigrate(&model.Firewall{}, model.SnapshotStatus{}, &model.Cronjob{}); err != nil {
578578
return err
579579
}
580580
return nil

backend/router/ro_app.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
2929
appRouter.GET("/installed/conninfo/:key", baseApi.LoadConnInfo)
3030
appRouter.GET("/installed/delete/check/:appInstallId", baseApi.DeleteCheck)
3131
appRouter.POST("/installed/search", baseApi.SearchAppInstalled)
32+
appRouter.GET("/installed/list", baseApi.ListAppInstalled)
3233
appRouter.POST("/installed/op", baseApi.OperateInstalled)
3334
appRouter.POST("/installed/sync", baseApi.SyncInstalled)
3435
appRouter.POST("/installed/port/change", baseApi.ChangeAppPort)

cmd/server/docs/docs.go

Lines changed: 50 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)