mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-16 18:54:43 +08:00
feat: 完成网站备份功能
This commit is contained in:
parent
1f717bea0e
commit
7b21bcbe7f
@ -61,6 +61,25 @@ func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, nil)
|
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) {
|
func (b *BaseApi) DownloadRecord(c *gin.Context) {
|
||||||
var req dto.DownloadRecord
|
var req dto.DownloadRecord
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
@ -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}] <nil>
|
|
||||||
// [{"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}] <nil>
|
|
@ -146,25 +146,6 @@ func (b *BaseApi) ListDBName(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, list)
|
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) {
|
func (b *BaseApi) BackupMysql(c *gin.Context) {
|
||||||
var req dto.BackupDB
|
var req dto.BackupDB
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
@ -38,6 +38,19 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, nil)
|
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) {
|
func (b *BaseApi) DeleteWebSite(c *gin.Context) {
|
||||||
var req dto.WebSiteDel
|
var req dto.WebSiteDel
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
@ -24,6 +24,13 @@ type BackupSearch struct {
|
|||||||
DetailName string `json:"detailName"`
|
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 {
|
type BackupRecords struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
@ -112,12 +112,6 @@ type SearchDBWithPage struct {
|
|||||||
MysqlName string `json:"mysqlName" validate:"required"`
|
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 {
|
type BackupDB struct {
|
||||||
MysqlName string `json:"mysqlName" validate:"required"`
|
MysqlName string `json:"mysqlName" validate:"required"`
|
||||||
DBName string `json:"dbName" validate:"required"`
|
DBName string `json:"dbName" validate:"required"`
|
||||||
|
@ -2,7 +2,10 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -96,3 +99,48 @@ func (a AppInstallRepo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOpt
|
|||||||
}
|
}
|
||||||
return db.Debug().Updates(&maps).Error
|
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
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@ -26,6 +27,16 @@ func (a AppInstallResourceRpo) GetBy(opts ...DBOption) ([]model.AppInstallResour
|
|||||||
return resources, err
|
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 {
|
func (a AppInstallResourceRpo) Create(ctx context.Context, resource *model.AppInstallResource) error {
|
||||||
db := getTx(ctx).Model(&model.AppInstallResource{})
|
db := getTx(ctx).Model(&model.AppInstallResource{})
|
||||||
return db.Create(&resource).Error
|
return db.Create(&resource).Error
|
||||||
|
@ -2,8 +2,6 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
@ -20,7 +18,6 @@ type IMysqlRepo interface {
|
|||||||
Create(ctx context.Context, mysql *model.DatabaseMysql) error
|
Create(ctx context.Context, mysql *model.DatabaseMysql) error
|
||||||
Delete(ctx context.Context, opts ...DBOption) error
|
Delete(ctx context.Context, opts ...DBOption) error
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
LoadBaseInfoByKey(key string) (*RootInfo, error)
|
|
||||||
UpdateDatabaseInfo(id uint, vars map[string]interface{}) 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
|
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 {
|
func (u *MysqlRepo) Create(ctx context.Context, mysql *model.DatabaseMysql) error {
|
||||||
return getTx(ctx).Create(mysql).Error
|
return getTx(ctx).Create(mysql).Error
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -11,6 +10,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
@ -247,7 +248,7 @@ func (a AppInstallService) ChangeAppPort(req dto.PortUpdate) error {
|
|||||||
files []string
|
files []string
|
||||||
newFiles []string
|
newFiles []string
|
||||||
)
|
)
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey(req.Key)
|
app, err := appInstallRepo.LoadBaseInfoByKey(req.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ type BackupService struct{}
|
|||||||
|
|
||||||
type IBackupService interface {
|
type IBackupService interface {
|
||||||
List() ([]dto.BackupInfo, error)
|
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)
|
DownloadRecord(info dto.DownloadRecord) (string, error)
|
||||||
Create(backupDto dto.BackupOperate) error
|
Create(backupDto dto.BackupOperate) error
|
||||||
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
||||||
@ -45,7 +45,7 @@ func (u *BackupService) List() ([]dto.BackupInfo, error) {
|
|||||||
return dtobas, err
|
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(
|
total, records, err := backupRepo.PageRecord(
|
||||||
search.Page, search.PageSize,
|
search.Page, search.PageSize,
|
||||||
commonRepo.WithOrderBy("created_at desc"),
|
commonRepo.WithOrderBy("created_at desc"),
|
||||||
|
@ -78,10 +78,6 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if cronjob.KeepLocal || cronjob.Type != "LOCAL" {
|
if cronjob.KeepLocal || cronjob.Type != "LOCAL" {
|
||||||
localDir, err := loadLocalDir()
|
localDir, err := loadLocalDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -93,6 +89,10 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cronjob.Type == "database" {
|
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"))
|
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)
|
backupDir = fmt.Sprintf("database/mysql/%s/%s", app.Name, cronjob.DBName)
|
||||||
err = backupMysql(backup.Type, baseDir, backupDir, app.Name, cronjob.DBName, fileName)
|
err = backupMysql(backup.Type, baseDir, backupDir, app.Name, cronjob.DBName, fileName)
|
||||||
|
@ -33,7 +33,6 @@ type MysqlService struct{}
|
|||||||
type IMysqlService interface {
|
type IMysqlService interface {
|
||||||
SearchWithPage(search dto.PageInfo) (int64, interface{}, error)
|
SearchWithPage(search dto.PageInfo) (int64, interface{}, error)
|
||||||
ListDBName() ([]string, error)
|
ListDBName() ([]string, error)
|
||||||
SearchBackupsWithPage(search dto.SearchBackupsWithPage) (int64, interface{}, error)
|
|
||||||
Create(mysqlDto dto.MysqlDBCreate) error
|
Create(mysqlDto dto.MysqlDBCreate) error
|
||||||
ChangeInfo(info dto.ChangeDBInfo) error
|
ChangeInfo(info dto.ChangeDBInfo) error
|
||||||
UpdateVariables(updatas []dto.MysqlVariablesUpdate) 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 {
|
func (u *MysqlService) RecoverByUpload(req dto.UploadRecover) error {
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -223,26 +222,11 @@ func (u *MysqlService) ListDBName() ([]string, error) {
|
|||||||
return dbNames, err
|
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 {
|
func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error {
|
||||||
if mysqlDto.Username == "root" {
|
if mysqlDto.Username == "root" {
|
||||||
return errors.New("Cannot set root as user name")
|
return errors.New("Cannot set root as user name")
|
||||||
}
|
}
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -289,7 +273,7 @@ func (u *MysqlService) Backup(db dto.BackupDB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlService) Recover(db dto.RecoverDB) error {
|
func (u *MysqlService) Recover(db dto.RecoverDB) error {
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -314,7 +298,7 @@ func (u *MysqlService) Recover(db dto.RecoverDB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlService) Delete(ids []uint) error {
|
func (u *MysqlService) Delete(ids []uint) error {
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -349,7 +333,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -417,7 +401,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error {
|
func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error {
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -437,7 +421,7 @@ func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error {
|
func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error {
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -479,7 +463,7 @@ func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error
|
|||||||
|
|
||||||
func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) {
|
func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) {
|
||||||
var data dto.DBBaseInfo
|
var data dto.DBBaseInfo
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -502,7 +486,7 @@ func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) {
|
func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) {
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -520,7 +504,7 @@ func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
|
func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
|
||||||
app, err := mysqlRepo.LoadBaseInfoByKey("mysql")
|
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -604,7 +588,7 @@ func excuteSql(containerName, password, command string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func backupMysql(backupType, baseDir, backupDir, mysqlName, dbName, fileName 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func NewIRedisService() IRedisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error {
|
func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error {
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) LoadStatus() (*dto.RedisStatus, error) {
|
func (u *RedisService) LoadStatus() (*dto.RedisStatus, error) {
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ func (u *RedisService) LoadStatus() (*dto.RedisStatus, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) LoadConf() (*dto.RedisConf, error) {
|
func (u *RedisService) LoadConf() (*dto.RedisConf, error) {
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ func (u *RedisService) LoadConf() (*dto.RedisConf, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) LoadPersistenceConf() (*dto.RedisPersistence, error) {
|
func (u *RedisService) LoadPersistenceConf() (*dto.RedisPersistence, error) {
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ func (u *RedisService) LoadPersistenceConf() (*dto.RedisPersistence, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) Backup() error {
|
func (u *RedisService) Backup() error {
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -214,7 +214,7 @@ func (u *RedisService) Backup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) Recover(req dto.RedisBackupRecover) error {
|
func (u *RedisService) Recover(req dto.RedisBackupRecover) error {
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -254,7 +254,7 @@ func (u *RedisService) SearchBackupListWithPage(req dto.PageInfo) (int64, interf
|
|||||||
list []dto.DatabaseFileRecords
|
list []dto.DatabaseFileRecords
|
||||||
backDatas []dto.DatabaseFileRecords
|
backDatas []dto.DatabaseFileRecords
|
||||||
)
|
)
|
||||||
redisInfo, err := mysqlRepo.LoadBaseInfoByKey("redis")
|
redisInfo, err := appInstallRepo.LoadBaseInfoByKey("redis")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type NginxService struct {
|
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))
|
res, err := cmd.Exec(fmt.Sprintf("docker exec -i %s curl http://127.0.0.1/nginx_status", nginxInstall.ContainerName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dto.NginxStatus{}, err
|
return dto.NginxStatus{}, errors.New(res)
|
||||||
}
|
}
|
||||||
var status dto.NginxStatus
|
var status dto.NginxStatus
|
||||||
resArray := strings.Split(res, " ")
|
resArray := strings.Split(res, " ")
|
||||||
|
@ -5,16 +5,21 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"io"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"os"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"os/exec"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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 {
|
type WebsiteService struct {
|
||||||
@ -101,6 +106,101 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
|
|||||||
return nil
|
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 {
|
func (w WebsiteService) UpdateWebsite(req dto.WebSiteUpdate) error {
|
||||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -25,6 +25,7 @@ func (s *BackupRouter) InitBackupRouter(Router *gin.RouterGroup) {
|
|||||||
baRouter.POST("/buckets", baseApi.ListBuckets)
|
baRouter.POST("/buckets", baseApi.ListBuckets)
|
||||||
withRecordRouter.POST("", baseApi.CreateBackup)
|
withRecordRouter.POST("", baseApi.CreateBackup)
|
||||||
withRecordRouter.POST("/del", baseApi.DeleteBackup)
|
withRecordRouter.POST("/del", baseApi.DeleteBackup)
|
||||||
|
withRecordRouter.POST("/record/search", baseApi.SearchBackupRecords)
|
||||||
withRecordRouter.POST("/record/download", baseApi.DownloadRecord)
|
withRecordRouter.POST("/record/download", baseApi.DownloadRecord)
|
||||||
withRecordRouter.POST("/record/del", baseApi.DeleteBackupRecord)
|
withRecordRouter.POST("/record/del", baseApi.DeleteBackupRecord)
|
||||||
withRecordRouter.PUT(":id", baseApi.UpdateBackup)
|
withRecordRouter.PUT(":id", baseApi.UpdateBackup)
|
||||||
|
@ -28,7 +28,6 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
|
|||||||
cmdRouter.POST("/uplist/upload/:mysqlName", baseApi.UploadMysqlFiles)
|
cmdRouter.POST("/uplist/upload/:mysqlName", baseApi.UploadMysqlFiles)
|
||||||
withRecordRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload)
|
withRecordRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload)
|
||||||
withRecordRouter.POST("/recover", baseApi.RecoverMysql)
|
withRecordRouter.POST("/recover", baseApi.RecoverMysql)
|
||||||
withRecordRouter.POST("/backups/search", baseApi.SearchDBBackups)
|
|
||||||
withRecordRouter.POST("/del", baseApi.DeleteMysql)
|
withRecordRouter.POST("/del", baseApi.DeleteMysql)
|
||||||
withRecordRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
|
withRecordRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
|
||||||
withRecordRouter.POST("/conf/update/byfile", baseApi.UpdateMysqlConfByFile)
|
withRecordRouter.POST("/conf/update/byfile", baseApi.UpdateMysqlConfByFile)
|
||||||
|
@ -16,6 +16,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
|||||||
baseApi := v1.ApiGroupApp.BaseApi
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
{
|
{
|
||||||
groupRouter.POST("", baseApi.CreateWebsite)
|
groupRouter.POST("", baseApi.CreateWebsite)
|
||||||
|
groupRouter.POST("/backup/:id", baseApi.BackupWebsite)
|
||||||
groupRouter.POST("/update", baseApi.UpdateWebSite)
|
groupRouter.POST("/update", baseApi.UpdateWebSite)
|
||||||
groupRouter.GET("/:id", baseApi.GetWebSite)
|
groupRouter.GET("/:id", baseApi.GetWebSite)
|
||||||
groupRouter.GET("/:id/nginx", baseApi.GetWebSiteNginx)
|
groupRouter.GET("/:id/nginx", baseApi.GetWebSiteNginx)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { ReqPage } from '.';
|
||||||
|
|
||||||
export namespace Backup {
|
export namespace Backup {
|
||||||
export interface BackupInfo {
|
export interface BackupInfo {
|
||||||
id: number;
|
id: number;
|
||||||
@ -31,4 +33,9 @@ export namespace Backup {
|
|||||||
credential: string;
|
credential: string;
|
||||||
vars: string;
|
vars: string;
|
||||||
}
|
}
|
||||||
|
export interface SearchBackupRecord extends ReqPage {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
detailName: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import http from '@/api';
|
import http from '@/api';
|
||||||
import { Backup } from '../interface/backup';
|
import { Backup } from '../interface/backup';
|
||||||
|
import { ResPage } from '../interface';
|
||||||
|
|
||||||
export const getBackupList = () => {
|
export const getBackupList = () => {
|
||||||
return http.get<Array<Backup.BackupInfo>>(`/backups/search`);
|
return http.get<Array<Backup.BackupInfo>>(`/backups/search`);
|
||||||
@ -23,6 +24,9 @@ export const downloadBackupRecord = (params: Backup.RecordDownload) => {
|
|||||||
export const deleteBackupRecord = (params: { ids: number[] }) => {
|
export const deleteBackupRecord = (params: { ids: number[] }) => {
|
||||||
return http.post(`/backups/record/del`, params);
|
return http.post(`/backups/record/del`, params);
|
||||||
};
|
};
|
||||||
|
export const searchBackupRecords = (params: Backup.SearchBackupRecord) => {
|
||||||
|
return http.post<ResPage<Backup.RecordInfo>>(`/backups/record/search`, params);
|
||||||
|
};
|
||||||
|
|
||||||
export const listBucket = (params: Backup.ForBucket) => {
|
export const listBucket = (params: Backup.ForBucket) => {
|
||||||
return http.post(`/backups/buckets`, params);
|
return http.post(`/backups/buckets`, params);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import http from '@/api';
|
import http from '@/api';
|
||||||
import { ReqPage, ResPage } from '../interface';
|
import { ReqPage, ResPage } from '../interface';
|
||||||
import { Backup } from '../interface/backup';
|
|
||||||
import { Database } from '../interface/database';
|
import { Database } from '../interface/database';
|
||||||
import { File } from '@/api/interface/file';
|
import { File } from '@/api/interface/file';
|
||||||
|
|
||||||
@ -23,9 +22,6 @@ export const recover = (params: Database.Recover) => {
|
|||||||
export const recoverByUpload = (params: Database.RecoverByUpload) => {
|
export const recoverByUpload = (params: Database.RecoverByUpload) => {
|
||||||
return http.post(`/databases/recover/byupload`, params);
|
return http.post(`/databases/recover/byupload`, params);
|
||||||
};
|
};
|
||||||
export const searchBackupRecords = (params: Database.SearchBackupRecord) => {
|
|
||||||
return http.post<ResPage<Backup.RecordInfo>>(`/databases/backups/search`, params);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
|
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
|
||||||
return http.post(`/databases`, params);
|
return http.post(`/databases`, params);
|
||||||
|
@ -11,6 +11,10 @@ export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => {
|
|||||||
return http.post<any>(`/websites`, req);
|
return http.post<any>(`/websites`, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const BackupWebsite = (id: number) => {
|
||||||
|
return http.post(`/websites/backup/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
export const UpdateWebsite = (req: WebSite.WebSiteUpdateReq) => {
|
export const UpdateWebsite = (req: WebSite.WebSiteUpdateReq) => {
|
||||||
return http.post<any>(`/websites/update`, req);
|
return http.post<any>(`/websites/update`, req);
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<el-card v-loading="loading">
|
<el-card v-loading="loading">
|
||||||
<el-row :gutter="5">
|
<el-row :gutter="5">
|
||||||
<el-col :span="2">
|
<el-col :span="2">
|
||||||
<el-button @click="sync" type="primary" plain="true">{{ $t('app.sync') }}</el-button>
|
<el-button @click="sync" type="primary" :plain="true">{{ $t('app.sync') }}</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="22">
|
<el-col :span="22">
|
||||||
<div style="float: right">
|
<div style="float: right">
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="18">
|
<el-col :span="18">
|
||||||
<el-button @click="sync" type="primary" plain="true">{{ $t('app.sync') }}</el-button>
|
<el-button @click="sync" type="primary" :plain="true">{{ $t('app.sync') }}</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<div style="float: right">
|
<div style="float: right">
|
||||||
|
@ -36,10 +36,10 @@ import ComplexTable from '@/components/complex-table/index.vue';
|
|||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { dateFromat } from '@/utils/util';
|
import { dateFromat } from '@/utils/util';
|
||||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||||
import { backup, recover, searchBackupRecords } from '@/api/modules/database';
|
import { backup, recover } from '@/api/modules/database';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { deleteBackupRecord, downloadBackupRecord } from '@/api/modules/backup';
|
import { deleteBackupRecord, downloadBackupRecord, searchBackupRecords } from '@/api/modules/backup';
|
||||||
import { Backup } from '@/api/interface/backup';
|
import { Backup } from '@/api/interface/backup';
|
||||||
|
|
||||||
const selects = ref<any>([]);
|
const selects = ref<any>([]);
|
||||||
@ -69,8 +69,9 @@ const search = async () => {
|
|||||||
let params = {
|
let params = {
|
||||||
page: paginationConfig.currentPage,
|
page: paginationConfig.currentPage,
|
||||||
pageSize: paginationConfig.pageSize,
|
pageSize: paginationConfig.pageSize,
|
||||||
mysqlName: mysqlName.value,
|
type: 'database-mysql',
|
||||||
dbName: dbName.value,
|
name: mysqlName.value,
|
||||||
|
detailName: dbName.value,
|
||||||
};
|
};
|
||||||
const res = await searchBackupRecords(params);
|
const res = await searchBackupRecords(params);
|
||||||
data.value = res.data.items || [];
|
data.value = res.data.items || [];
|
||||||
|
144
frontend/src/views/website/website/backup/index.vue
Normal file
144
frontend/src/views/website/website/backup/index.vue
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog v-model="backupVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="50%">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>{{ $t('database.backup') }} - {{ websiteName }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" @search="search" :data="data">
|
||||||
|
<template #toolbar>
|
||||||
|
<el-button type="primary" @click="onBackup()">
|
||||||
|
{{ $t('database.backup') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
|
||||||
|
{{ $t('commons.button.delete') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
<el-table-column type="selection" fix />
|
||||||
|
<el-table-column :label="$t('commons.table.name')" prop="fileName" show-overflow-tooltip />
|
||||||
|
<el-table-column :label="$t('database.source')" prop="backupType" />
|
||||||
|
<el-table-column
|
||||||
|
prop="createdAt"
|
||||||
|
:label="$t('commons.table.date')"
|
||||||
|
:formatter="dateFromat"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
|
||||||
|
<fu-table-operations :buttons="buttons" :label="$t('commons.table.operate')" fix />
|
||||||
|
</ComplexTable>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import { dateFromat } from '@/utils/util';
|
||||||
|
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { deleteBackupRecord, downloadBackupRecord, searchBackupRecords } from '@/api/modules/backup';
|
||||||
|
import { Backup } from '@/api/interface/backup';
|
||||||
|
import { BackupWebsite } from '@/api/modules/website';
|
||||||
|
|
||||||
|
const selects = ref<any>([]);
|
||||||
|
|
||||||
|
const data = ref();
|
||||||
|
const paginationConfig = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const backupVisiable = ref(false);
|
||||||
|
const websiteName = ref();
|
||||||
|
const websiteID = ref();
|
||||||
|
const websiteType = ref();
|
||||||
|
|
||||||
|
interface DialogProps {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
const acceptParams = (params: DialogProps): void => {
|
||||||
|
websiteName.value = params.name;
|
||||||
|
websiteID.value = params.id;
|
||||||
|
websiteType.value = params.type;
|
||||||
|
backupVisiable.value = true;
|
||||||
|
search();
|
||||||
|
};
|
||||||
|
|
||||||
|
const search = async () => {
|
||||||
|
let params = {
|
||||||
|
page: paginationConfig.currentPage,
|
||||||
|
pageSize: paginationConfig.pageSize,
|
||||||
|
type: 'website-' + websiteType.value,
|
||||||
|
name: websiteName.value,
|
||||||
|
detailName: '',
|
||||||
|
};
|
||||||
|
const res = await searchBackupRecords(params);
|
||||||
|
data.value = res.data.items || [];
|
||||||
|
paginationConfig.total = res.data.total;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onBackup = async () => {
|
||||||
|
await BackupWebsite(websiteID.value);
|
||||||
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
search();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDownload = async (row: Backup.RecordInfo) => {
|
||||||
|
let params = {
|
||||||
|
source: row.source,
|
||||||
|
fileDir: row.fileDir,
|
||||||
|
fileName: row.fileName,
|
||||||
|
};
|
||||||
|
const res = await downloadBackupRecord(params);
|
||||||
|
const downloadUrl = window.URL.createObjectURL(new Blob([res]));
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.style.display = 'none';
|
||||||
|
a.href = downloadUrl;
|
||||||
|
a.download = row.fileName;
|
||||||
|
const event = new MouseEvent('click');
|
||||||
|
a.dispatchEvent(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onBatchDelete = async (row: Backup.RecordInfo | null) => {
|
||||||
|
let ids: Array<number> = [];
|
||||||
|
if (row) {
|
||||||
|
ids.push(row.id);
|
||||||
|
} else {
|
||||||
|
selects.value.forEach((item: Backup.RecordInfo) => {
|
||||||
|
ids.push(item.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await useDeleteData(deleteBackupRecord, { ids: ids }, 'commons.msg.delete', true);
|
||||||
|
search();
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttons = [
|
||||||
|
{
|
||||||
|
label: i18n.global.t('commons.button.delete'),
|
||||||
|
click: (row: Backup.RecordInfo) => {
|
||||||
|
onBatchDelete(row);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// label: i18n.global.t('commons.button.recover'),
|
||||||
|
// click: (row: Backup.RecordInfo) => {
|
||||||
|
// onRecover(row);
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
label: i18n.global.t('commons.button.download'),
|
||||||
|
click: (row: Backup.RecordInfo) => {
|
||||||
|
onDownload(row);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
acceptParams,
|
||||||
|
});
|
||||||
|
</script>
|
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import BackupRecords from '@/views/database/mysql/backup/index.vue';
|
import BackupRecords from '@/views/website/website/backup/index.vue';
|
||||||
import UploadDialog from '@/views/database/mysql/upload/index.vue';
|
import UploadDialog from '@/views/database/mysql/upload/index.vue';
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
||||||
@ -110,13 +110,7 @@ const openConfig = (id: number) => {
|
|||||||
|
|
||||||
const uploadRef = ref();
|
const uploadRef = ref();
|
||||||
const dialogBackupRef = ref();
|
const dialogBackupRef = ref();
|
||||||
const onOpenBackupDialog = async (dbName: string) => {
|
|
||||||
let params = {
|
|
||||||
mysqlName: 'test',
|
|
||||||
dbName: dbName,
|
|
||||||
};
|
|
||||||
dialogBackupRef.value!.acceptParams(params);
|
|
||||||
};
|
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{
|
{
|
||||||
label: i18n.global.t('website.config'),
|
label: i18n.global.t('website.config'),
|
||||||
@ -127,7 +121,12 @@ const buttons = [
|
|||||||
{
|
{
|
||||||
label: i18n.global.t('database.backupList'),
|
label: i18n.global.t('database.backupList'),
|
||||||
click: (row: WebSite.WebSite) => {
|
click: (row: WebSite.WebSite) => {
|
||||||
onOpenBackupDialog(row.primaryDomain);
|
let params = {
|
||||||
|
id: row.id,
|
||||||
|
type: row.type,
|
||||||
|
name: row.primaryDomain,
|
||||||
|
};
|
||||||
|
dialogBackupRef.value!.acceptParams(params);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user