From 7b21bcbe7f5af9c030e3bf25791aa3f317bea7a0 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Tue, 29 Nov 2022 17:39:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E7=BD=91=E7=AB=99?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/backup.go | 19 +++ backend/app/api/v1/dashboard_test.go | 16 -- backend/app/api/v1/database_mysql.go | 19 --- backend/app/api/v1/website.go | 13 ++ backend/app/dto/backup.go | 7 + backend/app/dto/database.go | 6 - backend/app/repo/app_install.go | 48 ++++++ backend/app/repo/app_install_resource.go | 11 ++ backend/app/repo/databse_mysql.go | 52 ------- backend/app/service/app_install.go | 5 +- backend/app/service/backup.go | 4 +- backend/app/service/cronjob_helper.go | 8 +- backend/app/service/database_mysql.go | 38 ++--- backend/app/service/database_redis.go | 16 +- backend/app/service/nginx.go | 8 +- backend/app/service/website.go | 112 +++++++++++++- backend/router/ro_backup.go | 1 + backend/router/ro_database.go | 1 - backend/router/ro_website.go | 1 + frontend/src/api/interface/backup.ts | 7 + frontend/src/api/modules/backup.ts | 4 + frontend/src/api/modules/database.ts | 4 - frontend/src/api/modules/website.ts | 4 + frontend/src/views/app-store/apps/index.vue | 2 +- .../src/views/app-store/installed/index.vue | 2 +- .../src/views/database/mysql/backup/index.vue | 9 +- .../views/website/website/backup/index.vue | 144 ++++++++++++++++++ frontend/src/views/website/website/index.vue | 17 +-- 28 files changed, 413 insertions(+), 165 deletions(-) delete mode 100644 backend/app/api/v1/dashboard_test.go create mode 100644 frontend/src/views/website/website/backup/index.vue diff --git a/backend/app/api/v1/backup.go b/backend/app/api/v1/backup.go index 25d66b142..7713982c0 100644 --- a/backend/app/api/v1/backup.go +++ b/backend/app/api/v1/backup.go @@ -61,6 +61,25 @@ func (b *BaseApi) DeleteBackup(c *gin.Context) { helper.SuccessWithData(c, nil) } +func (b *BaseApi) SearchBackupRecords(c *gin.Context) { + var req dto.RecordSearch + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + total, list, err := backupService.SearchRecordsWithPage(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + helper.SuccessWithData(c, dto.PageResult{ + Items: list, + Total: total, + }) +} + func (b *BaseApi) DownloadRecord(c *gin.Context) { var req dto.DownloadRecord if err := c.ShouldBindJSON(&req); err != nil { diff --git a/backend/app/api/v1/dashboard_test.go b/backend/app/api/v1/dashboard_test.go deleted file mode 100644 index b8c7982d3..000000000 --- a/backend/app/api/v1/dashboard_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package v1 - -import ( - "fmt" - "testing" - - "github.com/shirou/gopsutil/net" -) - -func TestCopu(t *testing.T) { - fmt.Println(net.IOCounters(false)) - fmt.Println(net.IOCounters(true)) -} - -// [{"name":"all","bytesSent":15498384367,"bytesRecv":18415197440,"packetsSent":11608058,"packetsRecv":12976591,"errin":0,"errout":21,"dropin":0,"dropout":1181,"fifoin":0,"fifoout":0}] -// [{"name":"lo0","bytesSent":12947010452,"bytesRecv":12947010452,"packetsSent":6519135,"packetsRecv":6519135,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"gif0","bytesSent":0,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"stf0","bytesSent":0,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"ap1","bytesSent":0,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"en0","bytesSent":2531548007,"bytesRecv":5443547837,"packetsSent":5019082,"packetsRecv":6374381,"errin":0,"errout":0,"dropin":0,"dropout":1065,"fifoin":0,"fifoout":0} {"name":"en1","bytesSent":0,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"en2","bytesSent":0,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"bridge0","bytesSent":0,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"awdl0","bytesSent":103717,"bytesRecv":157244,"packetsSent":412,"packetsRecv":460,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"llw0","bytesSent":0,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"utun0","bytesSent":21810,"bytesRecv":0,"packetsSent":121,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"utun1","bytesSent":21810,"bytesRecv":0,"packetsSent":121,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"utun2","bytesSent":21810,"bytesRecv":0,"packetsSent":121,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0} {"name":"en5","bytesSent":6093969,"bytesRecv":6264468,"packetsSent":47985,"packetsRecv":48051,"errin":0,"errout":21,"dropin":0,"dropout":116,"fifoin":0,"fifoout":0} {"name":"utun3","bytesSent":13576933,"bytesRecv":18231580,"packetsSent":21129,"packetsRecv":34612,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0}] diff --git a/backend/app/api/v1/database_mysql.go b/backend/app/api/v1/database_mysql.go index adf71c09c..96af36ecf 100644 --- a/backend/app/api/v1/database_mysql.go +++ b/backend/app/api/v1/database_mysql.go @@ -146,25 +146,6 @@ func (b *BaseApi) ListDBName(c *gin.Context) { helper.SuccessWithData(c, list) } -func (b *BaseApi) SearchDBBackups(c *gin.Context) { - var req dto.SearchBackupsWithPage - if err := c.ShouldBindJSON(&req); err != nil { - helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) - return - } - - total, list, err := mysqlService.SearchBackupsWithPage(req) - if err != nil { - helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) - return - } - - helper.SuccessWithData(c, dto.PageResult{ - Items: list, - Total: total, - }) -} - func (b *BaseApi) BackupMysql(c *gin.Context) { var req dto.BackupDB if err := c.ShouldBindJSON(&req); err != nil { diff --git a/backend/app/api/v1/website.go b/backend/app/api/v1/website.go index 177ba6b4a..581fab6bc 100644 --- a/backend/app/api/v1/website.go +++ b/backend/app/api/v1/website.go @@ -38,6 +38,19 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) { helper.SuccessWithData(c, nil) } +func (b *BaseApi) BackupWebsite(c *gin.Context) { + id, err := helper.GetParamID(c) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := websiteService.Backup(id); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + func (b *BaseApi) DeleteWebSite(c *gin.Context) { var req dto.WebSiteDel if err := c.ShouldBindJSON(&req); err != nil { diff --git a/backend/app/dto/backup.go b/backend/app/dto/backup.go index 1ecb8dfb0..d9a0216d0 100644 --- a/backend/app/dto/backup.go +++ b/backend/app/dto/backup.go @@ -24,6 +24,13 @@ type BackupSearch struct { DetailName string `json:"detailName"` } +type RecordSearch struct { + PageInfo + Type string `json:"type" validate:"required"` + Name string `json:"name" validate:"required"` + DetailName string `json:"detailName"` +} + type BackupRecords struct { ID uint `json:"id"` CreatedAt time.Time `json:"createdAt"` diff --git a/backend/app/dto/database.go b/backend/app/dto/database.go index f7d25c56f..c315e7f81 100644 --- a/backend/app/dto/database.go +++ b/backend/app/dto/database.go @@ -112,12 +112,6 @@ type SearchDBWithPage struct { MysqlName string `json:"mysqlName" validate:"required"` } -type SearchBackupsWithPage struct { - PageInfo - MysqlName string `json:"mysqlName" validate:"required"` - DBName string `json:"dbName" validate:"required"` -} - type BackupDB struct { MysqlName string `json:"mysqlName" validate:"required"` DBName string `json:"dbName" validate:"required"` diff --git a/backend/app/repo/app_install.go b/backend/app/repo/app_install.go index 73711770c..5b18be938 100644 --- a/backend/app/repo/app_install.go +++ b/backend/app/repo/app_install.go @@ -2,7 +2,10 @@ package repo import ( "context" + "encoding/json" + "github.com/1Panel-dev/1Panel/backend/app/model" + "github.com/1Panel-dev/1Panel/backend/global" "gorm.io/gorm" ) @@ -96,3 +99,48 @@ func (a AppInstallRepo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOpt } return db.Debug().Updates(&maps).Error } + +type RootInfo struct { + ID uint `json:"id"` + Name string `json:"name"` + Port int64 `json:"port"` + Password string `json:"password"` + ContainerName string `json:"containerName"` + Param string `json:"param"` + Env string `json:"env"` + Key string `json:"key"` + Version string `json:"version"` +} + +func (u *AppInstallRepo) LoadBaseInfoByKey(key string) (*RootInfo, error) { + var ( + app model.App + appInstall model.AppInstall + info RootInfo + ) + if err := global.DB.Where("key = ?", key).First(&app).Error; err != nil { + return nil, err + } + if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil { + return nil, err + } + envMap := make(map[string]interface{}) + if err := json.Unmarshal([]byte(appInstall.Env), &envMap); err != nil { + return nil, err + } + password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string) + if ok { + info.Password = password + } + port, ok := envMap["PANEL_APP_PORT_HTTP"].(float64) + if ok { + info.Port = int64(port) + } + info.ID = appInstall.ID + info.ContainerName = appInstall.ContainerName + info.Name = appInstall.Name + info.Env = appInstall.Env + info.Param = appInstall.Param + info.Version = appInstall.Version + return &info, nil +} diff --git a/backend/app/repo/app_install_resource.go b/backend/app/repo/app_install_resource.go index 66975c535..6f9441b37 100644 --- a/backend/app/repo/app_install_resource.go +++ b/backend/app/repo/app_install_resource.go @@ -2,6 +2,7 @@ package repo import ( "context" + "github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/global" "gorm.io/gorm" @@ -26,6 +27,16 @@ func (a AppInstallResourceRpo) GetBy(opts ...DBOption) ([]model.AppInstallResour return resources, err } +func (a AppInstallResourceRpo) GetFirst(opts ...DBOption) (model.AppInstallResource, error) { + db := global.DB.Model(&model.AppInstallResource{}) + var resources model.AppInstallResource + for _, opt := range opts { + db = opt(db) + } + err := db.First(&resources).Error + return resources, err +} + func (a AppInstallResourceRpo) Create(ctx context.Context, resource *model.AppInstallResource) error { db := getTx(ctx).Model(&model.AppInstallResource{}) return db.Create(&resource).Error diff --git a/backend/app/repo/databse_mysql.go b/backend/app/repo/databse_mysql.go index 757fbce3d..b31216cbc 100644 --- a/backend/app/repo/databse_mysql.go +++ b/backend/app/repo/databse_mysql.go @@ -2,8 +2,6 @@ package repo import ( "context" - "encoding/json" - "errors" "github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/global" @@ -20,7 +18,6 @@ type IMysqlRepo interface { Create(ctx context.Context, mysql *model.DatabaseMysql) error Delete(ctx context.Context, opts ...DBOption) error Update(id uint, vars map[string]interface{}) error - LoadBaseInfoByKey(key string) (*RootInfo, error) UpdateDatabaseInfo(id uint, vars map[string]interface{}) error } @@ -60,55 +57,6 @@ func (u *MysqlRepo) Page(page, size int, opts ...DBOption) (int64, []model.Datab return count, users, err } -type RootInfo struct { - ID uint `json:"id"` - Name string `json:"name"` - Port int64 `json:"port"` - Password string `json:"password"` - ContainerName string `json:"containerName"` - Param string `json:"param"` - Env string `json:"env"` - Key string `json:"key"` - Version string `json:"version"` -} - -func (u *MysqlRepo) LoadBaseInfoByKey(key string) (*RootInfo, error) { - var ( - app model.App - appInstall model.AppInstall - info RootInfo - ) - if err := global.DB.Where("key = ?", key).First(&app).Error; err != nil { - return nil, err - } - if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil { - return nil, err - } - envMap := make(map[string]interface{}) - if err := json.Unmarshal([]byte(appInstall.Env), &envMap); err != nil { - return nil, err - } - password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string) - if ok { - info.Password = password - } else { - return nil, errors.New("error password in db") - } - port, ok := envMap["PANEL_APP_PORT_HTTP"].(float64) - if ok { - info.Port = int64(port) - } else { - return nil, errors.New("error port in db") - } - info.ID = appInstall.ID - info.ContainerName = appInstall.ContainerName - info.Name = appInstall.Name - info.Env = appInstall.Env - info.Param = appInstall.Param - info.Version = appInstall.Version - return &info, nil -} - func (u *MysqlRepo) Create(ctx context.Context, mysql *model.DatabaseMysql) error { return getTx(ctx).Create(mysql).Error } diff --git a/backend/app/service/app_install.go b/backend/app/service/app_install.go index 4d2bf6d7e..ad15192a5 100644 --- a/backend/app/service/app_install.go +++ b/backend/app/service/app_install.go @@ -3,7 +3,6 @@ package service import ( "context" "fmt" - "github.com/1Panel-dev/1Panel/backend/app/repo" "io/ioutil" "os" "path" @@ -11,6 +10,8 @@ import ( "strconv" "strings" + "github.com/1Panel-dev/1Panel/backend/app/repo" + "github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/constant" @@ -247,7 +248,7 @@ func (a AppInstallService) ChangeAppPort(req dto.PortUpdate) error { files []string newFiles []string ) - app, err := mysqlRepo.LoadBaseInfoByKey(req.Key) + app, err := appInstallRepo.LoadBaseInfoByKey(req.Key) if err != nil { return err } diff --git a/backend/app/service/backup.go b/backend/app/service/backup.go index 91ed32799..6dc2be950 100644 --- a/backend/app/service/backup.go +++ b/backend/app/service/backup.go @@ -18,7 +18,7 @@ type BackupService struct{} type IBackupService interface { List() ([]dto.BackupInfo, error) - SearchRecordWithPage(search dto.BackupSearch) (int64, []dto.BackupRecords, error) + SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error) DownloadRecord(info dto.DownloadRecord) (string, error) Create(backupDto dto.BackupOperate) error GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error) @@ -45,7 +45,7 @@ func (u *BackupService) List() ([]dto.BackupInfo, error) { return dtobas, err } -func (u *BackupService) SearchRecordWithPage(search dto.BackupSearch) (int64, []dto.BackupRecords, error) { +func (u *BackupService) SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error) { total, records, err := backupRepo.PageRecord( search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"), diff --git a/backend/app/service/cronjob_helper.go b/backend/app/service/cronjob_helper.go index 744e15b05..5fde1330a 100644 --- a/backend/app/service/cronjob_helper.go +++ b/backend/app/service/cronjob_helper.go @@ -78,10 +78,6 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim if err != nil { return "", err } - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") - if err != nil { - return "", err - } if cronjob.KeepLocal || cronjob.Type != "LOCAL" { localDir, err := loadLocalDir() if err != nil { @@ -93,6 +89,10 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim } if cronjob.Type == "database" { + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") + if err != nil { + return "", err + } fileName = fmt.Sprintf("db_%s_%s.sql.gz", cronjob.DBName, time.Now().Format("20060102150405")) backupDir = fmt.Sprintf("database/mysql/%s/%s", app.Name, cronjob.DBName) err = backupMysql(backup.Type, baseDir, backupDir, app.Name, cronjob.DBName, fileName) diff --git a/backend/app/service/database_mysql.go b/backend/app/service/database_mysql.go index 632e47644..8abfc9a61 100644 --- a/backend/app/service/database_mysql.go +++ b/backend/app/service/database_mysql.go @@ -33,7 +33,6 @@ type MysqlService struct{} type IMysqlService interface { SearchWithPage(search dto.PageInfo) (int64, interface{}, error) ListDBName() ([]string, error) - SearchBackupsWithPage(search dto.SearchBackupsWithPage) (int64, interface{}, error) Create(mysqlDto dto.MysqlDBCreate) error ChangeInfo(info dto.ChangeDBInfo) error UpdateVariables(updatas []dto.MysqlVariablesUpdate) error @@ -137,7 +136,7 @@ func (u *MysqlService) UpFile(mysqlName string, files []*multipart.FileHeader) e } func (u *MysqlService) RecoverByUpload(req dto.UploadRecover) error { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } @@ -223,26 +222,11 @@ func (u *MysqlService) ListDBName() ([]string, error) { return dbNames, err } -func (u *MysqlService) SearchBackupsWithPage(search dto.SearchBackupsWithPage) (int64, interface{}, error) { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") - if err != nil { - return 0, nil, err - } - searchDto := dto.BackupSearch{ - Type: "database-mysql", - PageInfo: search.PageInfo, - Name: app.Name, - DetailName: search.DBName, - } - - return NewIBackupService().SearchRecordWithPage(searchDto) -} - func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error { if mysqlDto.Username == "root" { return errors.New("Cannot set root as user name") } - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } @@ -289,7 +273,7 @@ func (u *MysqlService) Backup(db dto.BackupDB) error { } func (u *MysqlService) Recover(db dto.RecoverDB) error { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } @@ -314,7 +298,7 @@ func (u *MysqlService) Recover(db dto.RecoverDB) error { } func (u *MysqlService) Delete(ids []uint) error { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } @@ -349,7 +333,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error { return err } } - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } @@ -417,7 +401,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error { } func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } @@ -437,7 +421,7 @@ func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error { } func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } @@ -479,7 +463,7 @@ func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) { var data dto.DBBaseInfo - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return nil, err } @@ -502,7 +486,7 @@ func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) { } func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return nil, err } @@ -520,7 +504,7 @@ func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) { } func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return nil, err } @@ -604,7 +588,7 @@ func excuteSql(containerName, password, command string) error { } func backupMysql(backupType, baseDir, backupDir, mysqlName, dbName, fileName string) error { - app, err := mysqlRepo.LoadBaseInfoByKey("mysql") + app, err := appInstallRepo.LoadBaseInfoByKey("mysql") if err != nil { return err } diff --git a/backend/app/service/database_redis.go b/backend/app/service/database_redis.go index 086bcad64..a673cb4a8 100644 --- a/backend/app/service/database_redis.go +++ b/backend/app/service/database_redis.go @@ -37,7 +37,7 @@ func NewIRedisService() IRedisService { } func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error { - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return err } @@ -70,7 +70,7 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error { } func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error { - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return err } @@ -97,7 +97,7 @@ func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) } func (u *RedisService) LoadStatus() (*dto.RedisStatus, error) { - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return nil, err } @@ -125,7 +125,7 @@ func (u *RedisService) LoadStatus() (*dto.RedisStatus, error) { } func (u *RedisService) LoadConf() (*dto.RedisConf, error) { - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return nil, err } @@ -150,7 +150,7 @@ func (u *RedisService) LoadConf() (*dto.RedisConf, error) { } func (u *RedisService) LoadPersistenceConf() (*dto.RedisPersistence, error) { - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return nil, err } @@ -169,7 +169,7 @@ func (u *RedisService) LoadPersistenceConf() (*dto.RedisPersistence, error) { } func (u *RedisService) Backup() error { - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return err } @@ -214,7 +214,7 @@ func (u *RedisService) Backup() error { } func (u *RedisService) Recover(req dto.RedisBackupRecover) error { - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return err } @@ -254,7 +254,7 @@ func (u *RedisService) SearchBackupListWithPage(req dto.PageInfo) (int64, interf list []dto.DatabaseFileRecords backDatas []dto.DatabaseFileRecords ) - redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis") + redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis") if err != nil { return 0, nil, err } diff --git a/backend/app/service/nginx.go b/backend/app/service/nginx.go index 16797d5ab..23280c493 100644 --- a/backend/app/service/nginx.go +++ b/backend/app/service/nginx.go @@ -1,13 +1,15 @@ package service import ( + "errors" "fmt" + "path" + "strings" + "github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/utils/cmd" "github.com/1Panel-dev/1Panel/backend/utils/files" - "path" - "strings" ) type NginxService struct { @@ -57,7 +59,7 @@ func (n NginxService) GetStatus() (dto.NginxStatus, error) { } res, err := cmd.Exec(fmt.Sprintf("docker exec -i %s curl http://127.0.0.1/nginx_status", nginxInstall.ContainerName)) if err != nil { - return dto.NginxStatus{}, err + return dto.NginxStatus{}, errors.New(res) } var status dto.NginxStatus resArray := strings.Split(res, " ") diff --git a/backend/app/service/website.go b/backend/app/service/website.go index 2ec880c42..a98de45ef 100644 --- a/backend/app/service/website.go +++ b/backend/app/service/website.go @@ -5,16 +5,21 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "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/files" - "github.com/pkg/errors" - "gorm.io/gorm" + "io" + "os" + "os/exec" "path" "reflect" "strings" "time" + + "github.com/1Panel-dev/1Panel/backend/app/dto" + "github.com/1Panel-dev/1Panel/backend/app/model" + "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/1Panel-dev/1Panel/backend/global" + "github.com/1Panel-dev/1Panel/backend/utils/files" + "github.com/pkg/errors" + "gorm.io/gorm" ) type WebsiteService struct { @@ -101,6 +106,101 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error { return nil } +func (w WebsiteService) Backup(id uint) error { + website, err := websiteRepo.GetFirst(commonRepo.WithByID(id)) + if err != nil { + return err + } + app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID)) + if err != nil { + return err + } + resource, err := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(website.AppInstallID)) + if err != nil { + return err + } + mysqlInfo, err := appInstallRepo.LoadBaseInfoByKey(resource.Key) + if err != nil { + return err + } + nginxInfo, err := appInstallRepo.LoadBaseInfoByKey("nginx") + if err != nil { + return err + } + db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId)) + if err != nil { + return err + } + localDir, err := loadLocalDir() + if err != nil { + return err + } + name := fmt.Sprintf("%s_%s", website.PrimaryDomain, time.Now().Format("20060102150405")) + backupDir := fmt.Sprintf("website/%s/%s", website.PrimaryDomain, name) + fullDir := fmt.Sprintf("%s/%s", localDir, backupDir) + if _, err := os.Stat(fullDir); err != nil && os.IsNotExist(err) { + if err = os.MkdirAll(fullDir, os.ModePerm); err != nil { + if err != nil { + return fmt.Errorf("mkdir %s failed, err: %v", fullDir, err) + } + } + } + nginxConfFile := fmt.Sprintf("%s/nginx/%s/conf/conf.d/%s.conf", constant.AppInstallDir, nginxInfo.Name, website.PrimaryDomain) + src, err := os.OpenFile(nginxConfFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775) + if err != nil { + return err + } + defer src.Close() + out, err := os.Create(fmt.Sprintf("%s/%s.conf", fullDir, website.PrimaryDomain)) + if err != nil { + return err + } + defer out.Close() + _, _ = io.Copy(out, src) + + if website.Type == "deployment" { + dbFile := fmt.Sprintf("%s/%s.sql", fullDir, website.PrimaryDomain) + outfile, _ := os.OpenFile(dbFile, os.O_RDWR|os.O_CREATE, 0755) + cmd := exec.Command("docker", "exec", mysqlInfo.ContainerName, "mysqldump", "-uroot", "-p"+mysqlInfo.Password, db.Name) + cmd.Stdout = outfile + _ = cmd.Run() + _ = cmd.Wait() + + websiteDir := fmt.Sprintf("%s/%s/%s", constant.AppInstallDir, app.App.Key, app.Name) + if err := handleTar(websiteDir, fullDir, fmt.Sprintf("%s.web.tar.gz", website.PrimaryDomain), ""); err != nil { + return err + } + } else { + websiteDir := fmt.Sprintf("%s/nginx/%s/www/%s", constant.AppInstallDir, nginxInfo.Name, website.PrimaryDomain) + if err := handleTar(websiteDir, fullDir, fmt.Sprintf("%s.web.tar.gz", website.PrimaryDomain), ""); err != nil { + return err + } + } + tarDir := fmt.Sprintf("%s/website/%s", localDir, website.PrimaryDomain) + tarName := fmt.Sprintf("%s.tar.gz", name) + itemDir := strings.ReplaceAll(fullDir[strings.LastIndex(fullDir, "/"):], "/", "") + aheadDir := strings.ReplaceAll(fullDir, itemDir, "") + tarcmd := exec.Command("tar", "zcvf", fullDir+".tar.gz", "-C", aheadDir, itemDir) + stdout, err := tarcmd.CombinedOutput() + if err != nil { + return errors.New(string(stdout)) + } + + record := &model.BackupRecord{ + Type: "website-" + website.Type, + Name: website.PrimaryDomain, + DetailName: "", + Source: "LOCAL", + BackupType: "LOCAL", + FileDir: tarDir, + FileName: tarName, + } + if err := backupRepo.CreateRecord(record); err != nil { + global.LOG.Errorf("save backup record failed, err: %v", err) + } + return nil +} + func (w WebsiteService) UpdateWebsite(req dto.WebSiteUpdate) error { website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID)) if err != nil { diff --git a/backend/router/ro_backup.go b/backend/router/ro_backup.go index 08ec01aba..ad67ff6eb 100644 --- a/backend/router/ro_backup.go +++ b/backend/router/ro_backup.go @@ -25,6 +25,7 @@ func (s *BackupRouter) InitBackupRouter(Router *gin.RouterGroup) { baRouter.POST("/buckets", baseApi.ListBuckets) withRecordRouter.POST("", baseApi.CreateBackup) withRecordRouter.POST("/del", baseApi.DeleteBackup) + withRecordRouter.POST("/record/search", baseApi.SearchBackupRecords) withRecordRouter.POST("/record/download", baseApi.DownloadRecord) withRecordRouter.POST("/record/del", baseApi.DeleteBackupRecord) withRecordRouter.PUT(":id", baseApi.UpdateBackup) diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go index 3abf5c2d9..110375692 100644 --- a/backend/router/ro_database.go +++ b/backend/router/ro_database.go @@ -28,7 +28,6 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) { cmdRouter.POST("/uplist/upload/:mysqlName", baseApi.UploadMysqlFiles) withRecordRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload) withRecordRouter.POST("/recover", baseApi.RecoverMysql) - withRecordRouter.POST("/backups/search", baseApi.SearchDBBackups) withRecordRouter.POST("/del", baseApi.DeleteMysql) withRecordRouter.POST("/variables/update", baseApi.UpdateMysqlVariables) withRecordRouter.POST("/conf/update/byfile", baseApi.UpdateMysqlConfByFile) diff --git a/backend/router/ro_website.go b/backend/router/ro_website.go index 6153aa1a8..5f94025fd 100644 --- a/backend/router/ro_website.go +++ b/backend/router/ro_website.go @@ -16,6 +16,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) { baseApi := v1.ApiGroupApp.BaseApi { groupRouter.POST("", baseApi.CreateWebsite) + groupRouter.POST("/backup/:id", baseApi.BackupWebsite) groupRouter.POST("/update", baseApi.UpdateWebSite) groupRouter.GET("/:id", baseApi.GetWebSite) groupRouter.GET("/:id/nginx", baseApi.GetWebSiteNginx) diff --git a/frontend/src/api/interface/backup.ts b/frontend/src/api/interface/backup.ts index 409e3b9ec..36802fcbc 100644 --- a/frontend/src/api/interface/backup.ts +++ b/frontend/src/api/interface/backup.ts @@ -1,3 +1,5 @@ +import { ReqPage } from '.'; + export namespace Backup { export interface BackupInfo { id: number; @@ -31,4 +33,9 @@ export namespace Backup { credential: string; vars: string; } + export interface SearchBackupRecord extends ReqPage { + type: string; + name: string; + detailName: string; + } } diff --git a/frontend/src/api/modules/backup.ts b/frontend/src/api/modules/backup.ts index cca67c22d..da0bd1cd3 100644 --- a/frontend/src/api/modules/backup.ts +++ b/frontend/src/api/modules/backup.ts @@ -1,5 +1,6 @@ import http from '@/api'; import { Backup } from '../interface/backup'; +import { ResPage } from '../interface'; export const getBackupList = () => { return http.get>(`/backups/search`); @@ -23,6 +24,9 @@ export const downloadBackupRecord = (params: Backup.RecordDownload) => { export const deleteBackupRecord = (params: { ids: number[] }) => { return http.post(`/backups/record/del`, params); }; +export const searchBackupRecords = (params: Backup.SearchBackupRecord) => { + return http.post>(`/backups/record/search`, params); +}; export const listBucket = (params: Backup.ForBucket) => { return http.post(`/backups/buckets`, params); diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index 1b8fc12df..c741aa95c 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -1,6 +1,5 @@ import http from '@/api'; import { ReqPage, ResPage } from '../interface'; -import { Backup } from '../interface/backup'; import { Database } from '../interface/database'; import { File } from '@/api/interface/file'; @@ -23,9 +22,6 @@ export const recover = (params: Database.Recover) => { export const recoverByUpload = (params: Database.RecoverByUpload) => { return http.post(`/databases/recover/byupload`, params); }; -export const searchBackupRecords = (params: Database.SearchBackupRecord) => { - return http.post>(`/databases/backups/search`, params); -}; export const addMysqlDB = (params: Database.MysqlDBCreate) => { return http.post(`/databases`, params); diff --git a/frontend/src/api/modules/website.ts b/frontend/src/api/modules/website.ts index 36da3aae8..b16989edc 100644 --- a/frontend/src/api/modules/website.ts +++ b/frontend/src/api/modules/website.ts @@ -11,6 +11,10 @@ export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => { return http.post(`/websites`, req); }; +export const BackupWebsite = (id: number) => { + return http.post(`/websites/backup/${id}`); +}; + export const UpdateWebsite = (req: WebSite.WebSiteUpdateReq) => { return http.post(`/websites/update`, req); }; diff --git a/frontend/src/views/app-store/apps/index.vue b/frontend/src/views/app-store/apps/index.vue index 7a8392072..8e9a5edb3 100644 --- a/frontend/src/views/app-store/apps/index.vue +++ b/frontend/src/views/app-store/apps/index.vue @@ -2,7 +2,7 @@ - {{ $t('app.sync') }} + {{ $t('app.sync') }}
diff --git a/frontend/src/views/app-store/installed/index.vue b/frontend/src/views/app-store/installed/index.vue index a7ec9ea9b..8564f58fd 100644 --- a/frontend/src/views/app-store/installed/index.vue +++ b/frontend/src/views/app-store/installed/index.vue @@ -4,7 +4,7 @@