1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-03-13 17:24:44 +08:00

feat: Complete the node initialization logic (#7570)

This commit is contained in:
ssongliu 2024-12-26 14:13:41 +08:00 committed by GitHub
parent e56c0c7fba
commit 5dbd16a28d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 372 additions and 347 deletions

View File

@ -25,6 +25,36 @@ func (b *BaseApi) CheckBackupUsed(c *gin.Context) {
helper.SuccessWithOutData(c)
}
func (b *BaseApi) SyncBackupAccount(c *gin.Context) {
var req dto.SyncFromMaster
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := backupService.Sync(req); err != nil {
helper.BadRequest(c, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Backup Account
// @Summary Load backup account options
// @Description 获取备份账号选项
// @Accept json
// @Success 200 {array} dto.BackupOption
// @Security ApiKeyAuth
// @Router /backup/options [get]
func (b *BaseApi) LoadBackupOptions(c *gin.Context) {
list, err := backupService.LoadBackupOptions()
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Backup Account
// @Summary Page backup records
// @Description 获取备份记录列表分页

View File

@ -1,18 +1,10 @@
package v2
import (
"net/http"
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
"github.com/gin-gonic/gin"
)
func (b *BaseApi) CheckHealth(c *gin.Context) {
_, err := xpack.RequestToMaster("/api/v2/agent/xpack/health", http.MethodGet, nil)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithOutData(c)
}

View File

@ -4,6 +4,18 @@ import (
"time"
)
type SyncFromMaster struct {
Name string `json:"name" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=create delete update"`
Data string `json:"data"`
}
type BackupOption struct {
ID uint `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
}
type CommonBackup struct {
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"`
Name string `json:"name"`

View File

@ -0,0 +1,6 @@
package model
type AppLauncher struct {
BaseModel
Key string `json:"key"`
}

View File

@ -2,13 +2,15 @@ package model
type BackupAccount struct {
BaseModel
Name string `json:"name"`
Type string `json:"type"`
Name string `gorm:"not null" json:"name"`
Type string `gorm:"not null" json:"type"`
Bucket string `json:"bucket"`
AccessKey string `json:"accessKey"`
Credential string `json:"credential"`
BackupPath string `json:"backupPath"`
Vars string `json:"vars"`
RememberAuth bool `json:"rememberAuth"`
}
// Source ---> SourceAccountIDs

View File

@ -8,11 +8,10 @@ type Setting struct {
}
type NodeInfo struct {
BaseDir string `json:"baseDir"`
Version string `json:"version"`
MasterAddr string `json:"masterAddr"`
EncryptKey string `json:"encryptKey"`
ServerCrt string `json:"serverCrt"`
ServerKey string `json:"serverKey"`
CurrentNode string `json:"currentNode"`
Scope string `json:"scope"`
BaseDir string `json:"baseDir"`
Version string `json:"version"`
EncryptKey string `json:"encryptKey"`
ServerCrt string `json:"serverCrt"`
ServerKey string `json:"serverKey"`
}

View File

@ -0,0 +1,55 @@
package repo
import (
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/global"
)
type LauncherRepo struct{}
type ILauncherRepo interface {
Get(opts ...DBOption) (model.AppLauncher, error)
List(opts ...DBOption) ([]model.AppLauncher, error)
Create(launcher *model.AppLauncher) error
Save(launcher *model.AppLauncher) error
Delete(opts ...DBOption) error
}
func NewILauncherRepo() ILauncherRepo {
return &LauncherRepo{}
}
func (u *LauncherRepo) Get(opts ...DBOption) (model.AppLauncher, error) {
var launcher model.AppLauncher
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&launcher).Error
return launcher, err
}
func (u *LauncherRepo) List(opts ...DBOption) ([]model.AppLauncher, error) {
var ops []model.AppLauncher
db := global.DB.Model(&model.AppLauncher{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&ops).Error
return ops, err
}
func (u *LauncherRepo) Create(launcher *model.AppLauncher) error {
return global.DB.Create(launcher).Error
}
func (u *LauncherRepo) Save(launcher *model.AppLauncher) error {
return global.DB.Save(launcher).Error
}
func (u *LauncherRepo) Delete(opts ...DBOption) error {
db := global.DB
for _, opt := range opts {
db = opt(db)
}
return db.Delete(&model.AppLauncher{}).Error
}

View File

@ -11,6 +11,12 @@ import (
type BackupRepo struct{}
type IBackupRepo interface {
Get(opts ...DBOption) (model.BackupAccount, error)
List(opts ...DBOption) ([]model.BackupAccount, error)
Create(backup *model.BackupAccount) error
Save(backup *model.BackupAccount) error
Delete(opts ...DBOption) error
ListRecord(opts ...DBOption) ([]model.BackupRecord, error)
PageRecord(page, size int, opts ...DBOption) (int64, []model.BackupRecord, error)
CreateRecord(record *model.BackupRecord) error
@ -26,6 +32,54 @@ func NewIBackupRepo() IBackupRepo {
return &BackupRepo{}
}
func (u *BackupRepo) Get(opts ...DBOption) (model.BackupAccount, error) {
var backup model.BackupAccount
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&backup).Error
return backup, err
}
func (u *BackupRepo) Page(page, size int, opts ...DBOption) (int64, []model.BackupAccount, error) {
var ops []model.BackupAccount
db := global.DB.Model(&model.BackupAccount{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&ops).Error
return count, ops, err
}
func (u *BackupRepo) List(opts ...DBOption) ([]model.BackupAccount, error) {
var ops []model.BackupAccount
db := global.DB.Model(&model.BackupAccount{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&ops).Error
return ops, err
}
func (u *BackupRepo) Create(backup *model.BackupAccount) error {
return global.DB.Create(backup).Error
}
func (u *BackupRepo) Save(backup *model.BackupAccount) error {
return global.DB.Save(backup).Error
}
func (u *BackupRepo) Delete(opts ...DBOption) error {
db := global.DB
for _, opt := range opts {
db = opt(db)
}
return db.Delete(&model.BackupAccount{}).Error
}
func (u *BackupRepo) ListRecord(opts ...DBOption) ([]model.BackupRecord, error) {
var users []model.BackupRecord
db := global.DB.Model(&model.BackupRecord{})

View File

@ -1,12 +1,10 @@
package service
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"os"
"path"
"sort"
@ -21,7 +19,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/cloud_storage"
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
)
@ -30,6 +27,9 @@ type BackupService struct{}
type IBackupService interface {
CheckUsed(id uint) error
Sync(req dto.SyncFromMaster) error
LoadBackupOptions() ([]dto.BackupOption, error)
SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error)
SearchRecordsByCronjobWithPage(search dto.RecordSearchByCronjob) (int64, []dto.BackupRecords, error)
@ -61,6 +61,53 @@ func NewIBackupService() IBackupService {
return &BackupService{}
}
func (u *BackupService) Sync(req dto.SyncFromMaster) error {
var accountItem model.BackupAccount
if err := json.Unmarshal([]byte(req.Data), &accountItem); err != nil {
return err
}
accountItem.AccessKey, _ = encrypt.StringEncryptWithBase64(accountItem.AccessKey)
accountItem.Credential, _ = encrypt.StringEncryptWithBase64(accountItem.Credential)
account, _ := backupRepo.Get(commonRepo.WithByName(req.Name))
switch req.Operation {
case "create":
if account.ID != 0 {
accountItem.ID = account.ID
return backupRepo.Save(&accountItem)
}
return backupRepo.Create(&accountItem)
case "delete":
if account.ID == 0 {
return constant.ErrRecordNotFound
}
return backupRepo.Delete(commonRepo.WithByID(account.ID))
case "update":
if account.ID == 0 {
return constant.ErrRecordNotFound
}
accountItem.ID = account.ID
return backupRepo.Save(&accountItem)
default:
return fmt.Errorf("not support such operation %s", req.Operation)
}
}
func (u *BackupService) LoadBackupOptions() ([]dto.BackupOption, error) {
accounts, err := backupRepo.List(commonRepo.WithOrderBy("created_at desc"))
if err != nil {
return nil, err
}
var data []dto.BackupOption
for _, account := range accounts {
var item dto.BackupOption
if err := copier.Copy(&item, &account); err != nil {
global.LOG.Errorf("copy backup account to dto backup info failed, err: %v", err)
}
data = append(data, item)
}
return data, nil
}
func (u *BackupService) SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error) {
total, records, err := backupRepo.PageRecord(
search.Page, search.PageSize,
@ -289,29 +336,7 @@ func NewBackupClientWithID(id uint) (*model.BackupAccount, cloud_storage.CloudSt
account.AccessKey, _ = encrypt.StringDecryptWithKey(account.AccessKey, setting.Value)
account.Credential, _ = encrypt.StringDecryptWithKey(account.Credential, setting.Value)
} else {
bodyItem, err := json.Marshal(dto.OperateByID{ID: id})
if err != nil {
return nil, nil, err
}
data, err := xpack.RequestToMaster("/api/v2/agent/xpack/backup", http.MethodPost, bytes.NewReader(bodyItem))
if err != nil {
return nil, nil, err
}
item, err := json.Marshal(data)
if err != nil {
return nil, nil, err
}
if err := json.Unmarshal(item, &account); err != nil {
return nil, nil, fmt.Errorf("err response from master: %v", data)
}
if account.Type == constant.Local {
localDir, err := LoadLocalDirByStr(account.Vars)
if err != nil {
return nil, nil, err
}
global.CONF.System.Backup = localDir
}
account, _ = backupRepo.Get(commonRepo.WithByID(id))
}
backClient, err := newClient(&account)
if err != nil {
@ -351,24 +376,7 @@ func NewBackupClientMap(ids []string) (map[string]backupClientHelper, error) {
item, _ := strconv.Atoi(ids[i])
idItems = append(idItems, uint(item))
}
operateByIDs := struct {
IDs []uint `json:"ids"`
}{IDs: idItems}
bodyItem, err := json.Marshal(operateByIDs)
if err != nil {
return nil, err
}
data, err := xpack.RequestToMaster("/api/v2/agent/xpack/backup/list", http.MethodPost, bytes.NewReader(bodyItem))
if err != nil {
return nil, err
}
item, err := json.Marshal(data)
if err != nil {
return nil, err
}
if err := json.Unmarshal(item, &accounts); err != nil {
return nil, fmt.Errorf("err response from master: %v", data)
}
accounts, _ = backupRepo.List(commonRepo.WithByIDs(idItems))
}
clientMap := make(map[string]backupClientHelper)
for _, item := range accounts {

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
network "net"
"net/http"
"os"
"sort"
"strings"
@ -12,6 +11,7 @@ import (
"time"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
@ -29,6 +29,8 @@ import (
type DashboardService struct{}
type IDashboardService interface {
Sync(req dto.SyncFromMaster) error
LoadOsInfo() (*dto.OsInfo, error)
LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error)
LoadCurrentInfoForNode() *dto.NodeCurrent
@ -43,6 +45,35 @@ func NewIDashboardService() IDashboardService {
return &DashboardService{}
}
func (u *DashboardService) Sync(req dto.SyncFromMaster) error {
var launcherItem model.AppLauncher
if err := json.Unmarshal([]byte(req.Data), &launcherItem); err != nil {
return err
}
launcher, _ := launcherRepo.Get(settingRepo.WithByKey(req.Name))
switch req.Operation {
case "create":
if launcher.ID != 0 {
launcherItem.ID = launcher.ID
return launcherRepo.Save(&launcherItem)
}
return launcherRepo.Create(&launcherItem)
case "delete":
if launcher.ID == 0 {
return constant.ErrRecordNotFound
}
return launcherRepo.Delete(commonRepo.WithByID(launcher.ID))
case "update":
if launcher.ID == 0 {
return constant.ErrRecordNotFound
}
launcherItem.ID = launcher.ID
return launcherRepo.Save(&launcherItem)
default:
return fmt.Errorf("not support such operation %s", req.Operation)
}
}
func (u *DashboardService) Restart(operation string) error {
if operation != "1panel" && operation != "system" {
return fmt.Errorf("handle restart operation %s failed, err: nonsupport such operation", operation)
@ -487,16 +518,9 @@ func loadShowList() []string {
}
return data
}
res, err := xpack.RequestToMaster("/api/v2/core/launcher/search", http.MethodGet, nil)
if err != nil {
return data
}
item, err := json.Marshal(res)
if err != nil {
return data
}
if err := json.Unmarshal(item, &data); err != nil {
return data
list, _ := launcherRepo.List()
for _, item := range list {
data = append(data, item.Key)
}
return data
}

View File

@ -10,6 +10,7 @@ var (
appDetailRepo = repo.NewIAppDetailRepo()
tagRepo = repo.NewITagRepo()
appInstallRepo = repo.NewIAppInstallRepo()
launcherRepo = repo.NewILauncherRepo()
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
mysqlRepo = repo.NewIMysqlRepo()

View File

@ -76,6 +76,7 @@ func (u *SettingService) ReloadConn() error {
return nil
}
if isLocal {
global.IsMaster = true
return nil
}
@ -90,7 +91,7 @@ func (u *SettingService) ReloadConn() error {
global.LOG.Errorf("update server crt failed, err: %v", err)
return nil
}
if err := settingRepo.Update("CurrentNode", nodeInfo.CurrentNode); err != nil {
if err := settingRepo.Update("NodeScope", nodeInfo.Scope); err != nil {
global.LOG.Errorf("update current node failed, err: %v", err)
return nil
}
@ -102,15 +103,10 @@ func (u *SettingService) ReloadConn() error {
global.LOG.Errorf("update base dir failed, err: %v", err)
return nil
}
if err := settingRepo.Update("MasterAddr", nodeInfo.MasterAddr); err != nil {
global.LOG.Errorf("update master addr failed, err: %v", err)
return nil
}
global.CONF.System.BaseDir, _ = settingRepo.GetValueByKey("BaseDir")
global.CONF.System.Version, _ = settingRepo.GetValueByKey("SystemVersion")
global.CONF.System.EncryptKey, _ = settingRepo.GetValueByKey("EncryptKey")
global.CONF.System.CurrentNode, _ = settingRepo.GetValueByKey("CurrentNode")
global.CONF.System.MasterAddr, _ = settingRepo.GetValueByKey("MasterAddr")
global.CONF.System.BaseDir = nodeInfo.BaseDir
global.CONF.System.Version = nodeInfo.Version
global.CONF.System.EncryptKey = nodeInfo.EncryptKey
global.IsMaster = nodeInfo.Scope == "master"
return nil
}

View File

@ -3,11 +3,9 @@ package configs
type System struct {
Mode string `mapstructure:"mode"`
Version string `mapstructure:"version"`
BaseDir string `mapstructure:"base_dir"`
CurrentNode string `mapstructure:"base_dir"`
MasterAddr string `mapstructure:"master_addr"`
EncryptKey string `mapstructure:"encrypt_key"`
Version string `mapstructure:"version"`
BaseDir string `mapstructure:"base_dir"`
EncryptKey string `mapstructure:"encrypt_key"`
DbFile string `mapstructure:"db_agent_file"`
DbPath string `mapstructure:"db_path"`

View File

@ -16,6 +16,4 @@ const (
UPYUN = "UPYUN"
ALIYUN = "ALIYUN"
GoogleDrive = "GoogleDrive"
OneDriveRedirectURI = "http://localhost/login/authorized"
)

View File

@ -22,9 +22,8 @@ var (
CACHE *badger_db.Cache
Viper *viper.Viper
Cron *cron.Cron
MonitorCronID cron.EntryID
OneDriveCronID cron.EntryID
Cron *cron.Cron
MonitorCronID cron.EntryID
IsMaster bool

View File

@ -9,12 +9,9 @@ import (
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
)
func Init() {
service.NewISettingService().ReloadConn()
initGlobalData()
handleCronjobStatus()
handleSnapStatus()
@ -30,16 +27,9 @@ func initGlobalData() {
global.LOG.Fatalf("init service before start failed, err: %v", err)
}
global.CONF.System.BaseDir, _ = settingRepo.GetValueByKey("BaseDir")
global.CONF.System.Version, _ = settingRepo.GetValueByKey("SystemVersion")
global.CONF.System.EncryptKey, _ = settingRepo.GetValueByKey("EncryptKey")
global.CONF.System.CurrentNode, _ = settingRepo.GetValueByKey("CurrentNode")
global.IsMaster = global.CONF.System.CurrentNode == "127.0.0.1" || len(global.CONF.System.CurrentNode) == 0
_ = service.NewISettingService().ReloadConn()
if global.IsMaster {
global.CoreDB = common.LoadDBConnByPath(path.Join(global.CONF.System.DbPath, "core.db"), "core")
} else {
global.CONF.System.MasterAddr, _ = settingRepo.GetValueByKey("MasterAddr")
}
}
@ -99,45 +89,3 @@ func loadLocalDir() {
}
global.CONF.System.Backup = localDir
}
func initWithNodeJson() {
if global.IsMaster {
return
}
isLocal, nodeInfo, err := xpack.LoadNodeInfo()
if err != nil {
global.LOG.Errorf("load new node info failed, err: %v", err)
return
}
if isLocal {
return
}
settingRepo := repo.NewISettingRepo()
itemKey, _ := encrypt.StringEncrypt(nodeInfo.ServerKey)
if err := settingRepo.Update("ServerKey", itemKey); err != nil {
global.LOG.Errorf("update server key failed, err: %v", err)
return
}
itemCrt, _ := encrypt.StringEncrypt(nodeInfo.ServerCrt)
if err := settingRepo.Update("ServerCrt", itemCrt); err != nil {
global.LOG.Errorf("update server crt failed, err: %v", err)
return
}
if err := settingRepo.Update("CurrentNode", nodeInfo.CurrentNode); err != nil {
global.LOG.Errorf("update current node failed, err: %v", err)
return
}
if err := settingRepo.Update("SystemVersion", nodeInfo.Version); err != nil {
global.LOG.Errorf("update system version failed, err: %v", err)
return
}
if err := settingRepo.Update("BaseDir", nodeInfo.BaseDir); err != nil {
global.LOG.Errorf("update base dir failed, err: %v", err)
return
}
if err := settingRepo.Update("MasterAddr", nodeInfo.MasterAddr); err != nil {
global.LOG.Errorf("update master addr failed, err: %v", err)
return
}
}

View File

@ -15,7 +15,6 @@ func Init() {
migrations.InitImageRepo,
migrations.InitDefaultCA,
migrations.InitPHPExtensions,
migrations.InitBaseDir,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View File

@ -24,6 +24,8 @@ var AddTable = &gormigrate.Migration{
&model.AppTag{},
&model.Tag{},
&model.App{},
&model.AppLauncher{},
&model.BackupAccount{},
&model.BackupRecord{},
&model.Clam{},
&model.ComposeTemplate{},
@ -79,9 +81,6 @@ var InitSetting = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "BaseDir", Value: nodeInfo.BaseDir}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "CurrentNode", Value: nodeInfo.CurrentNode}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "EncryptKey", Value: nodeInfo.EncryptKey}).Error; err != nil {
return err
}
@ -93,7 +92,7 @@ var InitSetting = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "ServerCrt", Value: itemCrt}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "MasterAddr", Value: nodeInfo.MasterAddr}).Error; err != nil {
if err := tx.Create(&model.Setting{Key: "NodeScope", Value: nodeInfo.Scope}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "SystemVersion", Value: nodeInfo.Version}).Error; err != nil {
@ -218,13 +217,3 @@ var InitPHPExtensions = &gormigrate.Migration{
return nil
},
}
var InitBaseDir = &gormigrate.Migration{
ID: "20241122-init-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "BaseDir", Value: global.CONF.System.BaseDir}).Error; err != nil {
return err
}
return nil
},
}

View File

@ -12,6 +12,9 @@ func (s *BackupRouter) InitRouter(Router *gin.RouterGroup) {
baseApi := v2.ApiGroupApp.BaseApi
{
backupRouter.GET("/check/:id", baseApi.CheckBackupUsed)
backupRouter.POST("/sync", baseApi.SyncBackupAccount)
backupRouter.GET("/options", baseApi.LoadBackupOptions)
backupRouter.POST("/backup", baseApi.Backup)
backupRouter.POST("/recover", baseApi.Recover)
backupRouter.POST("/recover/byupload", baseApi.RecoverByUpload)

View File

@ -5,7 +5,6 @@ package xpack
import (
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
"strings"
@ -50,6 +49,7 @@ func LoadNodeInfo() (bool, model.NodeInfo, error) {
info.BaseDir = loadParams("BASE_DIR")
info.Version = loadParams("ORIGINAL_VERSION")
info.EncryptKey = common.RandStr(16)
info.Scope = "master"
return false, info, nil
}
@ -65,10 +65,6 @@ func loadParams(param string) string {
return info
}
func RequestToMaster(reqUrl, reqMethod string, reqBody io.Reader) (interface{}, error) {
return nil, nil
}
func GetImagePrefix() string {
return ""
}

View File

@ -31,12 +31,12 @@ func (b *BaseApi) CreateBackup(c *gin.Context) {
}
// @Tags Backup Account
// @Summary Refresh OneDrive token
// @Description 刷新 OneDrive token
// @Summary Refresh token
// @Description 刷新 token
// @Success 200
// @Security ApiKeyAuth
// @Router /core/backup/refresh/onedrive [post]
func (b *BaseApi) RefreshOneDriveToken(c *gin.Context) {
// @Router /core/backup/refresh/token [post]
func (b *BaseApi) RefreshToken(c *gin.Context) {
backupService.Run()
helper.SuccessWithData(c, nil)
}
@ -64,13 +64,13 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
}
// @Tags Backup Account
// @Summary Load OneDrive info
// @Description 获取 OneDrive 信息
// @Summary Load backup account base info
// @Description 获取预定义备份账号信息
// @Accept json
// @Success 200 {object} dto.OneDriveInfo
// @Security ApiKeyAuth
// @Router /core/backup/client/:clientType [get]
func (b *BaseApi) LoadOneDriveInfo(c *gin.Context) {
func (b *BaseApi) LoadBackupClientInfo(c *gin.Context) {
clientType, ok := c.Params.Get("clientType")
if !ok {
helper.BadRequest(c, fmt.Errorf("error %s in path", "clientType"))
@ -84,22 +84,6 @@ func (b *BaseApi) LoadOneDriveInfo(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Tags Backup Account
// @Summary Load backup account options
// @Description 获取备份账号选项
// @Accept json
// @Success 200 {array} dto.BackupOption
// @Security ApiKeyAuth
// @Router /core/backup/options [get]
func (b *BaseApi) LoadBackupOptions(c *gin.Context) {
list, err := backupService.LoadBackupOptions()
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Backup Account
// @Summary Delete backup account
// @Description 删除备份账号

View File

@ -2,6 +2,12 @@ package dto
import "time"
type SyncToAgent struct {
Name string `json:"name" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=create delere update"`
Data string `json:"data"`
}
type BackupOperate struct {
ID uint `json:"id"`
Name string `json:"name"`
@ -15,12 +21,6 @@ type BackupOperate struct {
RememberAuth bool `json:"rememberAuth"`
}
type BackupOption struct {
ID uint `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
}
type BackupInfo struct {
ID uint `json:"id"`
Name string `json:"name"`

View File

@ -6,7 +6,6 @@ type SettingInfo struct {
UserName string `json:"userName"`
SystemVersion string `json:"systemVersion"`
DeveloperMode string `json:"developerMode"`
MasterAddr string `json:"masterAddr"`
SessionTimeout string `json:"sessionTimeout"`
Port string `json:"port"`

View File

@ -1,7 +1,5 @@
package model
import "time"
type BackupAccount struct {
BaseModel
Name string `gorm:"not null" json:"name"`
@ -12,6 +10,5 @@ type BackupAccount struct {
BackupPath string `json:"backupPath"`
Vars string `json:"vars"`
RememberAuth bool `json:"rememberAuth"`
DeletedAt time.Time `json:"deletedAt"`
RememberAuth bool `json:"rememberAuth"`
}

View File

@ -1,9 +1,15 @@
package service
import (
"bytes"
"encoding/json"
"net/http"
"github.com/1Panel-dev/1Panel/core/app/dto"
"github.com/1Panel-dev/1Panel/core/app/model"
"github.com/1Panel-dev/1Panel/core/app/repo"
"github.com/1Panel-dev/1Panel/core/constant"
"github.com/1Panel-dev/1Panel/core/utils/xpack"
)
type LauncherService struct{}
@ -36,11 +42,25 @@ func (u *LauncherService) ChangeShow(req dto.SettingUpdate) error {
return nil
}
launcher.Key = req.Key
return launcherRepo.Create(&launcher)
if err := launcherRepo.Create(&launcher); err != nil {
return err
}
go syncLauncherToAgent(launcher, "create")
return nil
}
if launcher.ID == 0 {
return nil
}
return launcherRepo.Delete(repo.WithByKey(req.Key))
if err := launcherRepo.Delete(repo.WithByKey(req.Key)); err != nil {
return err
}
go syncLauncherToAgent(launcher, "delete")
return nil
}
func syncLauncherToAgent(launcher model.AppLauncher, operation string) {
itemData, _ := json.Marshal(launcher)
itemJson := dto.SyncToAgent{Name: launcher.Key, Operation: operation, Data: string(itemData)}
bodyItem, _ := json.Marshal(itemJson)
_ = xpack.RequestToAgent("/api/v2/backups/sync", http.MethodPost, bytes.NewReader((bodyItem)))
}

View File

@ -2,6 +2,7 @@ package service
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
@ -34,7 +35,6 @@ type IBackupService interface {
List(req dto.OperateByIDs) ([]dto.BackupInfo, error)
GetLocalDir() (string, error)
LoadBackupOptions() ([]dto.BackupOption, error)
SearchWithPage(search dto.SearchPageWithType) (int64, interface{}, error)
LoadBackupClientInfo(clientType string) (dto.BackupClientInfo, error)
Create(backupDto dto.BackupOperate) error
@ -106,22 +106,6 @@ func (u *BackupService) GetLocalDir() (string, error) {
return dir, nil
}
func (u *BackupService) LoadBackupOptions() ([]dto.BackupOption, error) {
accounts, err := backupRepo.List(repo.WithOrderBy("created_at desc"))
if err != nil {
return nil, err
}
var data []dto.BackupOption
for _, account := range accounts {
var item dto.BackupOption
if err := copier.Copy(&item, &account); err != nil {
global.LOG.Errorf("copy backup account to dto backup info failed, err: %v", err)
}
data = append(data, item)
}
return data, nil
}
func (u *BackupService) SearchWithPage(req dto.SearchPageWithType) (int64, interface{}, error) {
count, accounts, err := backupRepo.Page(
req.Page,
@ -245,6 +229,7 @@ func (u *BackupService) Create(req dto.BackupOperate) error {
if err := backupRepo.Create(&backup); err != nil {
return err
}
go syncAccountToAgent(backup, "create")
return nil
}
@ -296,6 +281,7 @@ func (u *BackupService) Delete(id uint) error {
return buserr.New(constant.ErrBackupInUsed)
}
go syncAccountToAgent(backup, "delete")
return backupRepo.Delete(repo.WithByID(id))
}
@ -362,6 +348,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
if err := backupRepo.Save(&newBackup); err != nil {
return err
}
go syncAccountToAgent(backup, "update")
return nil
}
@ -551,5 +538,16 @@ func refreshToken() {
varsItem, _ := json.Marshal(varMap)
_ = global.DB.Model(&model.BackupAccount{}).Where("id = ?", backupItem.ID).Updates(map[string]interface{}{"vars": varsItem}).Error
go syncAccountToAgent(backupItem, "update")
}
}
func syncAccountToAgent(backup model.BackupAccount, operation string) {
backup.AccessKey, _ = encrypt.StringDecryptWithBase64(backup.AccessKey)
backup.Credential, _ = encrypt.StringDecryptWithBase64(backup.Credential)
itemData, _ := json.Marshal(backup)
itemJson := dto.SyncToAgent{Name: backup.Name, Operation: operation, Data: string(itemData)}
bodyItem, _ := json.Marshal(itemJson)
_ = xpack.RequestToAgent("/api/v2/backups/sync", http.MethodPost, bytes.NewReader((bodyItem)))
}

View File

@ -9,7 +9,6 @@ import (
"net"
"os"
"path"
"regexp"
"strconv"
"strings"
"time"
@ -23,7 +22,6 @@ import (
"github.com/1Panel-dev/1Panel/core/utils/common"
"github.com/1Panel-dev/1Panel/core/utils/encrypt"
"github.com/1Panel-dev/1Panel/core/utils/firewall"
"github.com/1Panel-dev/1Panel/core/utils/xpack"
"github.com/gin-gonic/gin"
)
@ -113,12 +111,6 @@ func (u *SettingService) Update(key, value string) error {
}
case "UserName", "Password":
_ = global.SESSION.Clean()
case "MasterAddr":
go func() {
if err := xpack.UpdateMasterAddr(value); err != nil {
global.LOG.Errorf("update master addr failed, err: %v", err)
}
}()
}
return nil
@ -203,27 +195,8 @@ func (u *SettingService) UpdatePort(port uint) error {
}
go func() {
time.Sleep(1 * time.Second)
defer func() {
if _, err := cmd.Exec("systemctl restart 1panel.service"); err != nil {
global.LOG.Errorf("restart system port failed, err: %v", err)
}
}()
masterAddr, err := settingRepo.Get(repo.WithByKey("MasterAddr"))
if err != nil {
global.LOG.Errorf("load master addr from db failed, err: %v", err)
return
}
if len(masterAddr.Value) != 0 {
oldMasterPort := loadPort(masterAddr.Value)
if len(oldMasterPort) != 0 {
newMasterAddr := strings.ReplaceAll(masterAddr.Value, oldMasterPort, fmt.Sprintf("%v", port))
_ = settingRepo.Update("MasterAddr", newMasterAddr)
if err := xpack.UpdateMasterAddr(newMasterAddr); err != nil {
global.LOG.Errorf("update master addr from db failed, err: %v", err)
return
}
}
if _, err := cmd.Exec("systemctl restart 1panel.service"); err != nil {
global.LOG.Errorf("restart system port failed, err: %v", err)
}
}()
return nil
@ -291,31 +264,7 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
return err
}
if err := u.UpdateSystemSSL(); err != nil {
return err
}
go func() {
oldSSL, _ := settingRepo.Get(repo.WithByKey("SSL"))
if oldSSL.Value != req.SSL {
masterAddr, err := settingRepo.Get(repo.WithByKey("MasterAddr"))
if err != nil {
global.LOG.Errorf("load master addr from db failed, err: %v", err)
return
}
addrItem := masterAddr.Value
if req.SSL == constant.StatusDisable {
addrItem = strings.ReplaceAll(addrItem, "https://", "http://")
} else {
addrItem = strings.ReplaceAll(addrItem, "http://", "https://")
}
_ = settingRepo.Update("MasterAddr", addrItem)
if err := xpack.UpdateMasterAddr(addrItem); err != nil {
global.LOG.Errorf("update master addr from db failed, err: %v", err)
}
}
}()
return nil
return u.UpdateSystemSSL()
}
func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
@ -517,17 +466,3 @@ func checkCertValid() error {
return nil
}
func loadPort(address string) string {
re := regexp.MustCompile(`(?:(?:\[([0-9a-fA-F:]+)\])|([^:/\s]+))(?::(\d+))?$`)
matches := re.FindStringSubmatch(address)
if len(matches) <= 0 {
return ""
}
var port string
port = matches[3]
if len(port) != 0 {
return port
}
return ""
}

View File

@ -64,7 +64,6 @@ var (
var (
ErrBackupInUsed = "ErrBackupInUsed"
ErrBackupLocalDelete = "ErrBackupLocalDelete"
ErrMasterAddr = "ErrMasterAddr"
)
var (

View File

@ -17,7 +17,6 @@ ErrEntrance: "安全入口信息错误,请检查后重试!"
ErrGroupIsDefault: '默认分组,无法删除'
ErrGroupIsUsed: "分组正在使用中,无法删除"
ErrLocalDelete: "无法删除本地节点!"
ErrMasterAddr: "当前未设置主节点地址,无法添加节点!"
#app
ErrPortInUsed: "{{ .detail }} 端口已被占用!"

View File

@ -12,7 +12,6 @@ func Init() {
migrations.AddTable,
migrations.InitSetting,
migrations.InitOneDrive,
migrations.InitMasterAddr,
migrations.InitHost,
migrations.InitTerminalSetting,
migrations.InitAppLauncher,

View File

@ -197,16 +197,6 @@ var InitOneDrive = &gormigrate.Migration{
},
}
var InitMasterAddr = &gormigrate.Migration{
ID: "20240814-init-master-addr",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "MasterAddr", Value: ""}).Error; err != nil {
return err
}
return nil
},
}
var InitTerminalSetting = &gormigrate.Migration{
ID: "20240814-init-terminal-setting",
Migrate: func(tx *gorm.DB) error {

View File

@ -3,21 +3,21 @@ package router
import (
"encoding/base64"
"fmt"
"github.com/1Panel-dev/1Panel/core/app/service"
"github.com/1Panel-dev/1Panel/core/cmd/server/res"
"github.com/1Panel-dev/1Panel/core/constant"
"net/http"
"regexp"
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/core/app/service"
"github.com/1Panel-dev/1Panel/core/cmd/server/res"
"github.com/1Panel-dev/1Panel/core/constant"
"github.com/1Panel-dev/1Panel/core/cmd/server/docs"
"github.com/1Panel-dev/1Panel/core/cmd/server/web"
"github.com/1Panel-dev/1Panel/core/global"
"github.com/1Panel-dev/1Panel/core/i18n"
"github.com/1Panel-dev/1Panel/core/middleware"
rou "github.com/1Panel-dev/1Panel/core/router"
"github.com/1Panel-dev/1Panel/core/utils/xpack"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
swaggerfiles "github.com/swaggo/files"
@ -157,9 +157,6 @@ func Routers() *gin.Engine {
setWebStatic(PublicGroup)
}
agentRouter := Router.Group("/api/v2/agent")
xpack.InitAgentRouter(agentRouter)
Router.Use(middleware.OperationLog())
if global.CONF.System.IsDemo {
Router.Use(middleware.DemoHandle())

View File

@ -9,17 +9,16 @@ import (
type BackupRouter struct{}
func (s *BackupRouter) InitRouter(Router *gin.RouterGroup) {
backupRouter := Router.Group("backup").
backupRouter := Router.Group("backups").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{
backupRouter.GET("/local", baseApi.GetLocalDir)
backupRouter.GET("/onedrive", baseApi.LoadOneDriveInfo)
backupRouter.GET("/options", baseApi.LoadBackupOptions)
backupRouter.GET("/client/:clientType", baseApi.LoadBackupClientInfo)
backupRouter.POST("/search", baseApi.SearchBackup)
backupRouter.POST("/refresh/onedrive", baseApi.RefreshOneDriveToken)
backupRouter.POST("/refresh/token", baseApi.RefreshToken)
backupRouter.POST("/buckets", baseApi.ListBuckets)
backupRouter.POST("", baseApi.CreateBackup)
backupRouter.POST("/del", baseApi.DeleteBackup)

View File

@ -3,6 +3,8 @@
package xpack
import (
"io"
"github.com/gin-gonic/gin"
)
@ -12,6 +14,4 @@ func UpdateGroup(name string, group, newGroup uint) error { return nil }
func CheckBackupUsed(id uint) error { return nil }
func InitAgentRouter(Router *gin.RouterGroup) {}
func UpdateMasterAddr(newAddr string) error { return nil }
func RequestToAgent(reqUrl, reqMethod string, reqBody io.Reader) error { return nil }

View File

@ -24,7 +24,7 @@ export namespace Backup {
varsJson: object;
createdAt: Date;
}
export interface OneDriveInfo {
export interface ClientInfo {
client_id: string;
client_secret: string;
redirect_uri: string;

View File

@ -6,7 +6,6 @@ export namespace Setting {
password: string;
email: string;
systemIP: string;
masterAddr: string;
systemVersion: string;
dockerSockPath: string;
developerMode: string;

View File

@ -6,6 +6,9 @@ import { Backup } from '../interface/backup';
import { TimeoutEnum } from '@/enums/http-enum';
// backup-agent
export const listBackupOptions = () => {
return http.get<Array<Backup.BackupOption>>(`/backups/options`);
};
export const handleBackup = (params: Backup.Backup) => {
return http.post(`/backups/backup`, params, TimeoutEnum.T_1H);
};
@ -32,20 +35,17 @@ export const getFilesFromBackup = (id: number) => {
};
// backup-core
export const refreshOneDrive = () => {
return http.post(`/core/backup/refresh/onedrive`, {});
};
export const getBackupList = () => {
return http.get<Array<Backup.BackupOption>>(`/core/backup/options`);
export const refreshToken = () => {
return http.post(`/core/backups/refresh/token`, {});
};
export const getLocalBackupDir = () => {
return http.get<string>(`/core/backup/local`);
return http.get<string>(`/core/backups/local`);
};
export const searchBackup = (params: Backup.SearchWithType) => {
return http.post<ResPage<Backup.BackupInfo>>(`/core/backup/search`, params);
return http.post<ResPage<Backup.BackupInfo>>(`/core/backups/search`, params);
};
export const getClientInfo = (clientType: string) => {
return http.get<Backup.OneDriveInfo>(`/core/backup/client/${clientType}`);
return http.get<Backup.ClientInfo>(`/core/backups/client/${clientType}`);
};
export const addBackup = (params: Backup.BackupOperate) => {
let request = deepCopy(params) as Backup.BackupOperate;
@ -55,7 +55,7 @@ export const addBackup = (params: Backup.BackupOperate) => {
if (request.credential) {
request.credential = Base64.encode(request.credential);
}
return http.post<Backup.BackupOperate>(`/core/backup`, request, TimeoutEnum.T_60S);
return http.post<Backup.BackupOperate>(`/core/backups`, request, TimeoutEnum.T_60S);
};
export const editBackup = (params: Backup.BackupOperate) => {
let request = deepCopy(params) as Backup.BackupOperate;
@ -65,10 +65,10 @@ export const editBackup = (params: Backup.BackupOperate) => {
if (request.credential) {
request.credential = Base64.encode(request.credential);
}
return http.post(`/core/backup/update`, request);
return http.post(`/core/backups/update`, request);
};
export const deleteBackup = (params: { id: number }) => {
return http.post(`/core/backup/del`, params);
return http.post(`/core/backups/del`, params);
};
export const listBucket = (params: Backup.ForBucket) => {
let request = deepCopy(params) as Backup.BackupOperate;
@ -78,5 +78,5 @@ export const listBucket = (params: Backup.ForBucket) => {
if (request.credential) {
request.credential = Base64.encode(request.credential);
}
return http.post(`/core/backup/buckets`, request);
return http.post(`/core/backups/buckets`, request);
};

View File

@ -500,7 +500,7 @@
import { reactive, ref } from 'vue';
import { Rules } from '@/global/form-rules';
import FileList from '@/components/file-list/index.vue';
import { getBackupList } from '@/api/modules/backup';
import { listBackupOptions } from '@/api/modules/backup';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { Cronjob } from '@/api/interface/cronjob';
@ -864,12 +864,13 @@ const handleFileDelete = (index: number) => {
};
const loadBackups = async () => {
const res = await getBackupList();
const res = await listBackupOptions();
let options = res.data || [];
backupOptions.value = [];
if (!dialogData.value.rowData!.sourceAccounts) {
dialogData.value.rowData!.sourceAccounts = [1];
}
for (const item of res.data) {
for (const item of options) {
if (item.id === 0) {
continue;
}

View File

@ -56,7 +56,7 @@
<br />
{{ $t('setting.refreshTime') + ':' + row.varsJson['refresh_time'] }}
</template>
<el-tag @click="refreshToken" v-if="row.type === 'OneDrive'" class="ml-1">
<el-tag @click="refreshItemToken" v-if="row.type === 'OneDrive'" class="ml-1">
{{ 'Token ' + $t('commons.button.refresh') }}
</el-tag>
</el-tooltip>
@ -97,7 +97,7 @@
<script setup lang="ts">
import { dateFormat } from '@/utils/util';
import { onMounted, ref } from 'vue';
import { searchBackup, deleteBackup, refreshOneDrive } from '@/api/modules/backup';
import { searchBackup, deleteBackup, refreshToken } from '@/api/modules/backup';
import Operate from '@/views/setting/backup-account/operate/index.vue';
import { Backup } from '@/api/interface/backup';
import i18n from '@/lang';
@ -177,8 +177,8 @@ const onOpenDialog = async (
dialogRef.value!.acceptParams(params);
};
const refreshToken = async () => {
await refreshOneDrive();
const refreshItemToken = async () => {
await refreshToken();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
search();
};

View File

@ -283,7 +283,7 @@
<div v-if="hasClient()">
<el-form-item v-if="isOneDrive()">
<el-radio-group v-model="dialogData.rowData!.varsJson['isCN']" @change="changeOnedriveFrom">
<el-radio-group v-model="dialogData.rowData!.varsJson['isCN']" @change="changeClientFrom">
<el-radio-button :value="false">{{ $t('setting.isNotCN') }}</el-radio-button>
<el-radio-button :value="true">{{ $t('setting.isCN') }}</el-radio-button>
</el-radio-group>
@ -393,7 +393,7 @@ const loading = ref(false);
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const buckets = ref();
const oneDriveInfo = ref();
const clientInfo = ref();
const regionInput = ref();
@ -553,7 +553,7 @@ const changeType = async () => {
case 'OneDrive':
dialogData.value.rowData.varsJson['isCN'] = false;
const res = await getClientInfo('Onedrive');
oneDriveInfo.value = res.data;
clientInfo.value = res.data;
if (!dialogData.value.rowData.id) {
dialogData.value.rowData.varsJson = {
isCN: false,
@ -564,7 +564,7 @@ const changeType = async () => {
}
case 'GoogleDrive':
const res2 = await getClientInfo('GoogleDrive');
oneDriveInfo.value = res2.data;
clientInfo.value = res2.data;
if (!dialogData.value.rowData.id) {
dialogData.value.rowData.varsJson = {
client_id: res2.data.client_id,
@ -577,7 +577,7 @@ const changeType = async () => {
dialogData.value.rowData.varsJson['authMode'] = 'password';
}
};
const changeOnedriveFrom = () => {
const changeClientFrom = () => {
if (dialogData.value.rowData.varsJson['isCN']) {
dialogData.value.rowData.varsJson = {
isCN: true,
@ -588,9 +588,9 @@ const changeOnedriveFrom = () => {
} else {
dialogData.value.rowData.varsJson = {
isCN: false,
client_id: oneDriveInfo.value.client_id,
client_secret: oneDriveInfo.value.client_secret,
redirect_uri: oneDriveInfo.value.redirect_uri,
client_id: clientInfo.value.client_id,
client_secret: clientInfo.value.client_secret,
redirect_uri: clientInfo.value.redirect_uri,
};
}
};

View File

@ -153,7 +153,7 @@ import { loadSnapshotInfo, snapshotCreate } from '@/api/modules/setting';
import { computeSize, newUUID } from '@/utils/util';
import i18n from '@/lang';
import TaskLog from '@/components/task-log/index.vue';
import { getBackupList } from '@/api/modules/backup';
import { listBackupOptions } from '@/api/modules/backup';
import { Rules } from '@/global/form-rules';
import { ElForm } from 'element-plus';
import { MsgSuccess } from '@/utils/message';
@ -273,7 +273,7 @@ const loadApp18n = (label: string) => {
};
const loadBackups = async () => {
const res = await getBackupList();
const res = await listBackupOptions();
backupOptions.value = [];
for (const item of res.data) {
if (item.id !== 0) {

View File

@ -41,7 +41,7 @@ import { reactive, ref } from 'vue';
import { FormInstance } from 'element-plus';
import i18n from '@/lang';
import { snapshotImport } from '@/api/modules/setting';
import { getBackupList, getFilesFromBackup } from '@/api/modules/backup';
import { listBackupOptions, getFilesFromBackup } from '@/api/modules/backup';
import { Rules } from '@/global/form-rules';
import { MsgSuccess } from '@/utils/message';
import router from '@/routers';
@ -115,7 +115,7 @@ const submitImport = async (formEl: FormInstance | undefined) => {
const loadBackups = async () => {
loading.value = true;
await getBackupList()
await listBackupOptions()
.then((res) => {
loading.value = false;
backupOptions.value = [];