feat: 修改配置文件,动态获取数据目录

pull/104/head
ssongliu 2 years ago committed by ssongliu
parent dc5b6fba55
commit 4c4f379b4b

@ -1,21 +1,11 @@
base_dir: /opt
system:
port: 9999
db_type: sqlite
data_dir: ${base_dir}/1Panel/data
cache: ${base_dir}/1Panel/data/cache
backup: ${base_dir}/1Panel/data/backup
app_oss: "https://1panel.oss-cn-hangzhou.aliyuncs.com/apps/list.json"
sqlite:
path: ${base_dir}/1Panel/data/db
db_file: 1Panel.db
app_oss: "https://1panel.oss-cn-hangzhou.aliyuncs.com/apps/list.json"
log:
level: debug
time_zone: Asia/Shanghai
path: ${base_dir}/1Panel/log
log_name: 1Panel
log_suffix: .log
log_backup: 10

@ -188,12 +188,7 @@ func (b *BaseApi) UpdateBackup(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
upMap := make(map[string]interface{})
upMap["bucket"] = req.Bucket
upMap["credential"] = req.Credential
upMap["vars"] = req.Vars
if err := backupService.Update(req.ID, upMap); err != nil {
if err := backupService.Update(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

@ -77,10 +77,8 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if global.CONF.System.DbType == "sqlite" {
req.StartTime = req.StartTime.Add(8 * time.Hour)
req.EndTime = req.EndTime.Add(8 * time.Hour)
}
req.StartTime = req.StartTime.Add(8 * time.Hour)
req.EndTime = req.EndTime.Add(8 * time.Hour)
total, list, err := cronjobService.SearchRecords(req)
if err != nil {

@ -23,10 +23,8 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if global.CONF.System.DbType == "sqlite" {
req.StartTime = req.StartTime.Add(8 * time.Hour)
req.EndTime = req.EndTime.Add(8 * time.Hour)
}
req.StartTime = req.StartTime.Add(8 * time.Hour)
req.EndTime = req.EndTime.Add(8 * time.Hour)
var backdatas []dto.MonitorData
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {

@ -82,6 +82,33 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Update system port
// @Description 更新系统端口
// @Accept json
// @Param request body dto.PortUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/port/update [post]
// @x-panel-log {"bodyKeys":["serverPort"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统端口 => [serverPort]","formatEN":"update system port => [serverPort]"}
func (b *BaseApi) UpdatePort(c *gin.Context) {
var req dto.PortUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := settingService.UpdatePort(req.ServerPort); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Reset system password expired
// @Description 重置过期系统登录密码
@ -132,6 +159,16 @@ func (b *BaseApi) SyncTime(c *gin.Context) {
helper.SuccessWithData(c, ntime.Format("2006-01-02 15:04:05 MST -0700"))
}
// @Tags System Setting
// @Summary Load local backup dir
// @Description 获取安装根目录
// @Success 200 {string} path
// @Security ApiKeyAuth
// @Router /settings/basedir [get]
func (b *BaseApi) LoadBaseDir(c *gin.Context) {
helper.SuccessWithData(c, global.CONF.System.DataDir)
}
// @Tags System Setting
// @Summary Clean monitor datas
// @Description 清空监控数据

@ -10,6 +10,7 @@ type SettingInfo struct {
SessionTimeout string `json:"sessionTimeout"`
LocalTime string `json:"localTime"`
Port string `json:"port"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
Language string `json:"language"`
@ -41,6 +42,10 @@ type PasswordUpdate struct {
NewPassword string `json:"newPassword" validate:"required"`
}
type PortUpdate struct {
ServerPort uint `json:"serverPort" validate:"required,number,max=65535,min=1"`
}
type SnapshotCreate struct {
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO"`
Description string `json:"description"`

@ -5,12 +5,14 @@ import (
"encoding/json"
"fmt"
"os"
"path"
"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/cloud_storage"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
)
@ -23,7 +25,7 @@ type IBackupService interface {
DownloadRecord(info dto.DownloadRecord) (string, error)
Create(backupDto dto.BackupOperate) error
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
Update(id uint, upMap map[string]interface{}) error
Update(ireq dto.BackupOperate) error
BatchDelete(ids []uint) error
BatchDeleteRecord(ids []uint) error
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
@ -114,7 +116,7 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
if err != nil {
return "", fmt.Errorf("new cloud storage client failed, err: %v", err)
}
tempPath := fmt.Sprintf("%s%s", constant.DownloadDir, info.FileDir)
tempPath := fmt.Sprintf("%sdownload%s", constant.DataDir, info.FileDir)
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(tempPath, os.ModePerm); err != nil {
fmt.Println(err)
@ -141,10 +143,6 @@ func (u *BackupService) Create(backupDto dto.BackupOperate) error {
if err := backupRepo.Create(&backup); err != nil {
return err
}
var backupinfo dto.BackupInfo
if err := copier.Copy(&backupinfo, &backup); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
return nil
}
@ -200,8 +198,32 @@ func (u *BackupService) BatchDeleteRecord(ids []uint) error {
return backupRepo.DeleteRecord(context.Background(), commonRepo.WithIdsIn(ids))
}
func (u *BackupService) Update(id uint, upMap map[string]interface{}) error {
return backupRepo.Update(id, upMap)
func (u *BackupService) Update(req dto.BackupOperate) error {
backup, err := backupRepo.Get(commonRepo.WithByID(req.ID))
if err != nil {
return constant.ErrRecordNotFound
}
varMap := make(map[string]string)
if err := json.Unmarshal([]byte(req.Vars), &varMap); err != nil {
return err
}
upMap := make(map[string]interface{})
upMap["bucket"] = req.Bucket
upMap["credential"] = req.Credential
upMap["vars"] = req.Vars
if err := backupRepo.Update(req.ID, upMap); err != nil {
return err
}
if backup.Type == "LOCAL" {
if dir, ok := varMap["dir"]; ok {
if err := updateBackupDir(dir); err != nil {
upMap["vars"] = backup.Vars
_ = backupRepo.Update(req.ID, upMap)
return err
}
}
}
return nil
}
func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) {
@ -256,3 +278,23 @@ func loadLocalDir() (string, error) {
}
return "", fmt.Errorf("error type dir: %T", varMap["dir"])
}
func updateBackupDir(dir string) error {
oldDir := global.CONF.System.Backup
fileOp := files.NewFileOp()
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return err
}
}
global.Viper.Set("system.backup", path.Join(dir, "backup"))
if err := global.Viper.WriteConfig(); err != nil {
return err
}
if err := fileOp.CopyDir(oldDir, dir); err != nil {
global.Viper.Set("system.backup", oldDir)
_ = global.Viper.WriteConfig()
return err
}
return nil
}

@ -122,7 +122,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
req.File = template.Content
}
if req.From == "edit" {
dir := fmt.Sprintf("%s/%s", constant.TmpComposeBuildDir, req.Name)
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return err

@ -119,7 +119,7 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
if cronjob.Type == "database" {
name = fmt.Sprintf("%s%s.gz", commonDir, record.StartTime.Format("20060102150405"))
}
tempPath := fmt.Sprintf("%s/%s", constant.DownloadDir, commonDir)
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, commonDir)
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(tempPath, os.ModePerm); err != nil {
fmt.Println(err)
@ -274,7 +274,7 @@ func (u *CronjobService) AddCronJob(cronjob *model.Cronjob) (int, error) {
}
func mkdirAndWriteFile(cronjob *model.Cronjob, startTime time.Time, msg []byte) (string, error) {
dir := fmt.Sprintf("%s/%s/%s", constant.TaskDir, cronjob.Type, cronjob.Name)
dir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronjob.Type, cronjob.Name)
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return "", err

@ -151,10 +151,10 @@ func (u *CronjobService) HandleDelete(id uint) error {
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(id)))
dir := fmt.Sprintf("%s/%s/%s", constant.TaskDir, cronjob.Type, cronjob.Name)
dir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronjob.Type, cronjob.Name)
if _, err := os.Stat(dir); err == nil {
if err := os.RemoveAll(dir); err != nil {
global.LOG.Errorf("rm file %s/%s failed, err: %v", constant.TaskDir, commonDir, err)
global.LOG.Errorf("rm file %s/task/%s failed, err: %v", constant.DataDir, commonDir, err)
}
}
return nil

@ -286,7 +286,7 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
}
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
uploadDir := fmt.Sprintf("%s/uploads/database/mysql/%s/%s", constant.DefaultDataDir, app.Name, db.Name)
uploadDir := fmt.Sprintf("%s/uploads/database/mysql/%s/%s", constant.DataDir, app.Name, db.Name)
if _, err := os.Stat(uploadDir); err == nil {
_ = os.RemoveAll(uploadDir)
}

@ -20,7 +20,7 @@ import (
"github.com/docker/docker/pkg/archive"
)
const dockerLogDir = constant.TmpDir + "/docker_logs"
var dockerLogDir = constant.TmpDir + "/docker_logs"
type ImageService struct{}
@ -104,7 +104,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
return "", err
}
if req.From == "edit" {
dir := fmt.Sprintf("%s/%s", constant.TmpDockerBuildDir, req.Name)
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, req.Name)
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return "", err

@ -2,12 +2,14 @@ package service
import (
"encoding/json"
"errors"
"strconv"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/gin-gonic/gin"
)
@ -18,6 +20,7 @@ type ISettingService interface {
GetSettingInfo() (*dto.SettingInfo, error)
Update(c *gin.Context, key, value string) error
UpdatePassword(c *gin.Context, old, new string) error
UpdatePort(port uint) error
HandlePasswordExpired(c *gin.Context, old, new string) error
}
@ -59,6 +62,19 @@ func (u *SettingService) Update(c *gin.Context, key, value string) error {
return nil
}
func (u *SettingService) UpdatePort(port uint) error {
global.Viper.Set("system.port", port)
if err := global.Viper.WriteConfig(); err != nil {
return err
}
_ = settingRepo.Update("ServerPort", strconv.Itoa(int(port)))
stdout, err := cmd.Exec("systemctl restart 1panel.service")
if err != nil {
return errors.New(stdout)
}
return nil
}
func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error {
setting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil {

@ -779,7 +779,7 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
if err != nil {
return errors.New(stdout)
}
time.Sleep(10 * time.Second)
time.Sleep(5 * time.Second)
return nil
}

@ -7,26 +7,9 @@ import (
"strings"
"testing"
"github.com/1Panel-dev/1Panel/backend/init/db"
"github.com/1Panel-dev/1Panel/backend/init/viper"
"github.com/google/go-github/github"
)
func TestDw(t *testing.T) {
viper.Init()
db.Init()
backup, err := backupRepo.Get(commonRepo.WithByType("OSS"))
if err != nil {
fmt.Println(err)
}
client, err := NewIBackupService().NewClient(&backup)
if err != nil {
fmt.Println(err)
}
fmt.Println(client.Download("system_snapshot/1panel_snapshot_20230112135640.tar.gz", "/opt/1Panel/data/backup/system/test.tar.gz"))
}
func TestDi(t *testing.T) {
docker := "var/lib/docker"
fmt.Println(docker[strings.LastIndex(docker, "/"):])

@ -3,7 +3,6 @@ package configs
type ServerConfig struct {
BaseDir string `mapstructure:"base_dir"`
System System `mapstructure:"system"`
Sqlite Sqlite `mapstructure:"sqlite"`
LogConfig LogConfig `mapstructure:"log"`
CORS CORS `mapstructure:"cors"`
Encrypt Encrypt `mapstructure:"encrypt"`

@ -3,7 +3,6 @@ package configs
type LogConfig struct {
Level string `mapstructure:"level"`
TimeZone string `mapstructure:"timeZone"`
Path string `mapstructure:"path"`
LogName string `mapstructure:"log_name"`
LogSuffix string `mapstructure:"log_suffix"`
LogBackup int `mapstructure:"log_backup"`

@ -1,25 +0,0 @@
package configs
import (
"fmt"
"os"
)
type Sqlite struct {
Path string `mapstructure:"path"`
DbFile string `mapstructure:"db_file"`
}
func (s *Sqlite) Dsn() string {
if _, err := os.Stat(s.Path); err != nil {
if err := os.MkdirAll(s.Path, os.ModePerm); err != nil {
panic(fmt.Errorf("init db dir falied, err: %v", err))
}
}
if _, err := os.Stat(s.Path + "/" + s.DbFile); err != nil {
if _, err := os.Create(s.Path + "/" + s.DbFile); err != nil {
panic(fmt.Errorf("init db file falied, err: %v", err))
}
}
return s.Path + "/" + s.DbFile
}

@ -2,7 +2,9 @@ package configs
type System struct {
Port int `mapstructure:"port"`
DbType string `mapstructure:"db_type"`
DbFile string `mapstructure:"db_file"`
DbPath string `mapstructure:"db_path"`
LogPath string `mapstructure:"log_path"`
DataDir string `mapstructure:"data_dir"`
Cache string `mapstructure:"cache"`
Backup string `mapstructure:"backup"`

@ -8,7 +8,4 @@ const (
OSS = "OSS"
Sftp = "SFTP"
MinIo = "MINIO"
DatabaseBackupDir = "/opt/1Panel/data/backup/database"
WebsiteBackupDir = "/opt/1Panel/data/backup/website"
)

@ -14,7 +14,5 @@ const (
ComposeOpRestart = "restart"
ComposeOpRemove = "remove"
TmpDockerBuildDir = "/opt/1Panel/data/docker/build"
TmpComposeBuildDir = "/opt/1Panel/data/docker/compose"
DaemonJsonPath = "/etc/docker/daemon.json"
DaemonJsonPath = "/etc/docker/daemon.json"
)

@ -2,18 +2,14 @@ package constant
import (
"path"
"github.com/1Panel-dev/1Panel/backend/global"
)
var (
DefaultDataDir = "/opt/1Panel/data"
ResourceDir = path.Join(DefaultDataDir, "resource")
DataDir = global.CONF.System.DataDir
ResourceDir = path.Join(DataDir, "resource")
AppResourceDir = path.Join(ResourceDir, "apps")
AppInstallDir = path.Join(DefaultDataDir, "apps")
)
const (
TmpDir = "/opt/1Panel/data/tmp"
TaskDir = "/opt/1Panel/data/task"
DownloadDir = "/opt/1Panel/data/download"
UploadDir = "/opt/1Panel/data/uploads"
AppInstallDir = path.Join(DataDir, "apps")
TmpDir = path.Join(DataDir, "tmp")
)

@ -7,6 +7,7 @@ import (
"github.com/go-playground/validator/v10"
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"gorm.io/gorm"
)
@ -17,6 +18,7 @@ var (
VALID *validator.Validate
SESSION *psession.PSession
CACHE *badger_db.Cache
Viper *viper.Viper
Cron *cron.Cron
)

@ -2,19 +2,22 @@ package app
import (
"fmt"
"path"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"path"
)
func Init() {
constant.DefaultDataDir = "/opt/1Panel/data"
constant.ResourceDir = path.Join(constant.DefaultDataDir, "resource")
constant.DataDir = global.CONF.System.DataDir
constant.ResourceDir = path.Join(constant.DataDir, "resource")
constant.AppResourceDir = path.Join(constant.ResourceDir, "apps")
constant.AppInstallDir = path.Join(constant.DefaultDataDir, "apps")
constant.AppInstallDir = path.Join(constant.DataDir, "apps")
constant.TmpDir = path.Join(constant.DataDir, "tmp")
dirs := []string{constant.DefaultDataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir}
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir}
fileOp := files.NewFileOp()
for _, dir := range dirs {

@ -1,14 +1,27 @@
package db
import (
"fmt"
"os"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func Init() {
s := global.CONF.Sqlite
db, err := gorm.Open(sqlite.Open(s.Dsn()), &gorm.Config{})
if _, err := os.Stat(global.CONF.System.DbPath); err != nil {
if err := os.MkdirAll(global.CONF.System.DbPath, os.ModePerm); err != nil {
panic(fmt.Errorf("init db dir falied, err: %v", err))
}
}
fullPath := global.CONF.System.DbPath + "/" + global.CONF.System.DbFile
if _, err := os.Stat(fullPath); err != nil {
if _, err := os.Create(fullPath); err != nil {
panic(fmt.Errorf("init db file falied, err: %v", err))
}
}
db, err := gorm.Open(sqlite.Open(fullPath), &gorm.Config{})
if err != nil {
panic(err)
}

@ -2,12 +2,13 @@ package log
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/log"
"io"
"os"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/log"
"github.com/1Panel-dev/1Panel/backend/configs"
"github.com/1Panel-dev/1Panel/backend/global"
@ -29,7 +30,7 @@ func Init() {
func setOutput(logger *logrus.Logger, config configs.LogConfig) {
writer, err := log.NewWriterFromConfig(&log.Config{
LogPath: config.Path,
LogPath: global.CONF.System.LogPath,
FileName: config.LogName,
TimeTagFormat: FileTImeFormat,
MaxRemain: config.LogBackup,

@ -1,10 +1,12 @@
package migrations
import (
"fmt"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
@ -85,7 +87,7 @@ var AddTableSetting = &gormigrate.Migration{
return err
}
if err := tx.Create(&model.Setting{Key: "ServerPort", Value: "4004"}).Error; err != nil {
if err := tx.Create(&model.Setting{Key: "ServerPort", Value: "9999"}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "SecurityEntrance", Value: "onepanel"}).Error; err != nil {
@ -139,9 +141,10 @@ var AddTableBackupAccount = &gormigrate.Migration{
if err := tx.AutoMigrate(&model.BackupAccount{}, &model.BackupRecord{}); err != nil {
return err
}
item := &model.BackupAccount{
Type: "LOCAL",
Vars: "{\"dir\":\"/opt/1Panel/data/backup\"}",
Vars: fmt.Sprintf("{\"dir\":\"%s\"}", global.CONF.System.Backup),
}
if err := tx.Create(item).Error; err != nil {
return err

@ -2,7 +2,7 @@ package viper
import (
"fmt"
"strings"
"path"
"github.com/1Panel-dev/1Panel/backend/configs"
"github.com/1Panel-dev/1Panel/backend/global"
@ -11,10 +11,11 @@ import (
)
func Init() {
baseDir := "/opt"
v := viper.NewWithOptions()
v.SetConfigName("app")
v.SetConfigType("yml")
v.AddConfigPath("/opt/1Panel/conf")
v.SetConfigType("yaml")
v.AddConfigPath(path.Dir(baseDir + "/1Panel/conf/app.yaml"))
if err := v.ReadInConfig(); err != nil {
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
@ -25,16 +26,16 @@ func Init() {
panic(err)
}
})
for _, k := range v.AllKeys() {
value := v.GetString(k)
if strings.HasPrefix(value, "${") && strings.Contains(value, "}") {
itemKey := strings.ReplaceAll(value[strings.Index(value, "${"):strings.Index(value, "}")], "${", "")
v.Set(k, strings.ReplaceAll(value, fmt.Sprintf("${%s}", itemKey), v.GetString(itemKey)))
}
}
serverConfig := configs.ServerConfig{}
if err := v.Unmarshal(&serverConfig); err != nil {
panic(err)
}
global.CONF = serverConfig
global.CONF.BaseDir = baseDir
global.CONF.System.DataDir = global.CONF.BaseDir + "/1Panel/data"
global.CONF.System.Cache = global.CONF.BaseDir + "/1Panel/data/cache"
global.CONF.System.Backup = global.CONF.BaseDir + "/1Panel/data/backup"
global.CONF.System.DbPath = global.CONF.BaseDir + "/1Panel/data/db"
global.CONF.System.LogPath = global.CONF.BaseDir + "/1Panel/log"
global.Viper = v
}

@ -18,6 +18,7 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
settingRouter.POST("/search", baseApi.GetSettingInfo)
settingRouter.POST("/expired/handle", baseApi.HandlePasswordExpired)
settingRouter.POST("/update", baseApi.UpdateSetting)
settingRouter.POST("/port/update", baseApi.UpdatePort)
settingRouter.POST("/password/update", baseApi.UpdatePassword)
settingRouter.POST("/time/sync", baseApi.SyncTime)
settingRouter.POST("/monitor/clean", baseApi.CleanMonitor)
@ -29,5 +30,6 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
settingRouter.POST("/snapshot/recover", baseApi.RecoverSnapshot)
settingRouter.POST("/snapshot/rollback", baseApi.RollbackSnapshot)
settingRouter.GET("/upgrade", baseApi.GetUpgradeInfo)
settingRouter.GET("/basedir", baseApi.LoadBaseDir)
}
}

@ -3,7 +3,6 @@ package client
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"testing"
@ -56,7 +55,7 @@ func TestCron(t *testing.T) {
fmt.Println("my objects:", getObjectsFormResponse(lor))
name := "directory/directory-test1/20220928104331.tar.gz"
targetPath := constant.DownloadDir + "directory/directory-test1/"
targetPath := constant.DataDir + "/download/directory/directory-test1/"
if _, err := os.Stat(targetPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(targetPath, os.ModePerm); err != nil {
fmt.Println(err)
@ -67,17 +66,6 @@ func TestCron(t *testing.T) {
}
}
func TestDir(t *testing.T) {
files, err := ioutil.ReadDir("/opt/1Panel/task/directory/directory-test1-3")
if len(files) <= 10 {
return
}
for i := 0; i < len(files)-10; i++ {
os.Remove("/opt/1Panel/task/directory/directory-test1-3/" + files[i].Name())
}
fmt.Println(files, err)
}
func getObjectsFormResponse(lor oss.ListObjectsResult) string {
var output string
for _, object := range lor.Objects {

@ -6144,6 +6144,48 @@ var doc = `{
}
}
},
"/settings/port/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新系统端口",
"consumes": [
"application/json"
],
"tags": [
"System Setting"
],
"summary": "Update system port",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PortUpdate"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"serverPort"
],
"formatEN": "update system port =\u003e [serverPort]",
"formatZH": "修改系统端口 =\u003e [serverPort]",
"paramKeys": []
}
}
},
"/settings/search": {
"post": {
"security": [
@ -6200,11 +6242,11 @@ var doc = `{
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"name",
"from",
"description"
],
"formatEN": "Create system backup [name][description]",
"formatZH": "创建系统快照 [name][description]",
"formatEN": "Create system backup [description] to [from]",
"formatZH": "创建系统快照 [description] 到 [from]",
"paramKeys": []
}
}
@ -9909,6 +9951,19 @@ var doc = `{
}
}
},
"dto.PortUpdate": {
"type": "object",
"required": [
"serverPort"
],
"properties": {
"serverPort": {
"type": "integer",
"maximum": 65535,
"minimum": 1
}
}
},
"dto.RecordSearch": {
"type": "object",
"required": [
@ -10186,6 +10241,9 @@ var doc = `{
"panelName": {
"type": "string"
},
"port": {
"type": "string"
},
"securityEntrance": {
"type": "string"
},

@ -6130,6 +6130,48 @@
}
}
},
"/settings/port/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新系统端口",
"consumes": [
"application/json"
],
"tags": [
"System Setting"
],
"summary": "Update system port",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PortUpdate"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"serverPort"
],
"formatEN": "update system port =\u003e [serverPort]",
"formatZH": "修改系统端口 =\u003e [serverPort]",
"paramKeys": []
}
}
},
"/settings/search": {
"post": {
"security": [
@ -6186,11 +6228,11 @@
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"name",
"from",
"description"
],
"formatEN": "Create system backup [name][description]",
"formatZH": "创建系统快照 [name][description]",
"formatEN": "Create system backup [description] to [from]",
"formatZH": "创建系统快照 [description] 到 [from]",
"paramKeys": []
}
}
@ -9895,6 +9937,19 @@
}
}
},
"dto.PortUpdate": {
"type": "object",
"required": [
"serverPort"
],
"properties": {
"serverPort": {
"type": "integer",
"maximum": 65535,
"minimum": 1
}
}
},
"dto.RecordSearch": {
"type": "object",
"required": [
@ -10172,6 +10227,9 @@
"panelName": {
"type": "string"
},
"port": {
"type": "string"
},
"securityEntrance": {
"type": "string"
},

@ -1090,6 +1090,15 @@ definitions:
hostPort:
type: integer
type: object
dto.PortUpdate:
properties:
serverPort:
maximum: 65535
minimum: 1
type: integer
required:
- serverPort
type: object
dto.RecordSearch:
properties:
detailName:
@ -1274,6 +1283,8 @@ definitions:
type: string
panelName:
type: string
port:
type: string
securityEntrance:
type: string
serverPort:
@ -6464,6 +6475,33 @@ paths:
formatEN: update system password
formatZH: 修改系统密码
paramKeys: []
/settings/port/update:
post:
consumes:
- application/json
description: 更新系统端口
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.PortUpdate'
responses:
"200":
description: ""
security:
- ApiKeyAuth: []
summary: Update system port
tags:
- System Setting
x-panel-log:
BeforeFuntions: []
bodyKeys:
- serverPort
formatEN: update system port => [serverPort]
formatZH: 修改系统端口 => [serverPort]
paramKeys: []
/settings/search:
post:
description: 加载系统配置信息
@ -6500,10 +6538,10 @@ paths:
x-panel-log:
BeforeFuntions: []
bodyKeys:
- name
- from
- description
formatEN: Create system backup [name][description]
formatZH: 创建系统快照 [name][description]
formatEN: Create system backup [description] to [from]
formatZH: 创建系统快照 [description] 到 [from]
paramKeys: []
/settings/snapshot/del:
post:

@ -38,6 +38,9 @@ export namespace Setting {
oldPassword: string;
newPassword: string;
}
export interface PortUpdate {
serverPort: number;
}
export interface MFAInfo {
secret: string;
qrImage: string;

@ -14,6 +14,10 @@ export const updatePassword = (param: Setting.PasswordUpdate) => {
return http.post(`/settings/password/update`, param);
};
export const updatePort = (param: Setting.PortUpdate) => {
return http.post(`/settings/port/update`, param);
};
export const handleExpired = (param: Setting.PasswordUpdate) => {
return http.post(`/settings/expired/handle`, param);
};
@ -38,6 +42,10 @@ export const bindMFA = (param: Setting.MFABind) => {
return http.post(`/settings/mfa/bind`, param);
};
export const loadBaseDir = () => {
return http.get<string>(`/settings/basedir`);
};
// snapshot
export const snapshotCreate = (param: Setting.SnapshotCreate) => {
return http.post(`/settings/snapshot`, param);

@ -679,8 +679,15 @@ export default {
setting: {
all: 'All',
panel: 'Panel',
user: 'UserName',
passwd: 'Password',
emailHelper: 'For password retrieval',
title: 'Panel alias',
panelPort: 'Panel port',
portHelper:
'The recommended port range is 8888 to 65535. Note: If the server has a security group, permit the new port from the security group in advance',
portChange: 'Port change',
portChangeHelper: 'Modify the service port and restart the service. Do you want to continue?',
theme: 'Theme',
dark: 'Dark',
light: 'Light',
@ -699,6 +706,7 @@ export default {
duplicatePassword: 'The new password cannot be the same as the original password, please re-enter!',
backup: 'Backup',
thirdParty: 'Third-party',
createBackupAccount: 'Create {0} backup account',
noTypeForCreate: 'No backup type is currently created',
serverDisk: 'Server disks',
@ -716,9 +724,6 @@ export default {
path: 'Path',
safe: 'Safe',
panelPort: 'Panel port',
portHelper:
'The recommended port range is 8888 to 65535. Note: If the server has a security group, permit the new port from the security group in advance',
safeEntrance: 'Security entrance',
safeEntranceHelper:
'Panel management portal. You can log in to the panel only through a specified security portal, for example: onepanel',

@ -694,12 +694,18 @@ export default {
setting: {
all: '',
panel: '',
user: '',
passwd: '',
emailHelper: '',
title: '',
theme: '',
panelPort: '',
portHelper: '8888 - 65535',
portChange: '',
portChangeHelper: '',
theme: '',
componentSize: '',
dark: '',
light: '',
dark: '',
light: '',
language: '',
languageHelper: '',
sessionTimeout: '',
@ -713,6 +719,7 @@ export default {
duplicatePassword: '',
backup: '',
thirdParty: '',
createBackupAccount: ' {0} ',
noTypeForCreate: '',
serverDisk: '',
@ -756,8 +763,6 @@ export default {
upgradeNow: '',
safe: '',
panelPort: '',
portHelper: '8888 - 65535',
safeEntrance: '',
safeEntranceHelper: ': onepanel',
expirationTime: '',

@ -101,6 +101,7 @@ import { loadMysqlBaseInfo, loadMysqlVariables, updateMysqlConfByFile } from '@/
import { ChangePort, GetAppDefaultConfig } from '@/api/modules/app';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { loadBaseDir } from '@/api/modules/setting';
const loading = ref(false);
@ -241,7 +242,8 @@ const loadBaseInfo = async () => {
mysqlName.value = res.data?.name;
baseInfo.port = res.data?.port;
baseInfo.containerID = res.data?.containerName;
loadMysqlConf(`/opt/1Panel/data/apps/mysql/${mysqlName.value}/conf/my.cnf`);
const pathRes = await loadBaseDir();
loadMysqlConf(`${pathRes.data}/apps/mysql/${mysqlName.value}/conf/my.cnf`);
loadContainerLog(baseInfo.containerID);
};

@ -59,6 +59,7 @@ import { updateMysqlVariables } from '@/api/modules/database';
import { ElMessage } from 'element-plus';
import { dateFromatForName } from '@/utils/util';
import i18n from '@/lang';
import { loadBaseDir } from '@/api/modules/setting';
const loading = ref();
const extensions = [javascript(), oneDark];
@ -84,12 +85,13 @@ interface DialogProps {
mysqlName: string;
variables: Database.MysqlVariables;
}
const acceptParams = (params: DialogProps): void => {
const acceptParams = async (params: DialogProps): Promise<void> => {
mysqlName.value = params.mysqlName;
variables.slow_query_log = params.variables.slow_query_log;
variables.long_query_time = Number(params.variables.long_query_time);
let path = `/opt/1Panel/data/apps/mysql/${mysqlName.value}/data/1Panel-slow.log`;
const pathRes = await loadBaseDir();
let path = `${pathRes.data}/apps/mysql/${mysqlName.value}/data/1Panel-slow.log`;
if (variables.slow_query_log === 'ON') {
loadMysqlSlowlogs(path);
}

@ -73,6 +73,7 @@ import i18n from '@/lang';
import { ElMessage, UploadFile, UploadFiles, UploadInstance, UploadProps } from 'element-plus';
import { File } from '@/api/interface/file';
import { BatchDeleteFile, GetFilesList, UploadFileData } from '@/api/modules/files';
import { loadBaseDir } from '@/api/modules/setting';
const selects = ref<any>([]);
const baseDir = ref();
@ -91,10 +92,12 @@ interface DialogProps {
mysqlName: string;
dbName: string;
}
const acceptParams = (params: DialogProps): void => {
const acceptParams = async (params: DialogProps): Promise<void> => {
mysqlName.value = params.mysqlName;
dbName.value = params.dbName;
baseDir.value = '/opt/1Panel/data/uploads/database/mysql/' + mysqlName.value + '/' + dbName.value + '/';
const pathRes = await loadBaseDir();
baseDir.value = `${pathRes.data}/uploads/database/mysql/${mysqlName.value}/${dbName.value}/`;
upVisiable.value = true;
search();
};

@ -120,6 +120,7 @@ import { loadRedisConf, updateRedisConf, updateRedisConfByFile } from '@/api/mod
import i18n from '@/lang';
import { Rules } from '@/global/form-rules';
import { ChangePort, GetAppDefaultConfig } from '@/api/modules/app';
import { loadBaseDir } from '@/api/modules/setting';
const extensions = [javascript(), oneDark];
@ -292,7 +293,8 @@ const loadform = async () => {
};
const loadConfFile = async () => {
let path = `/opt/1Panel/data/apps/redis/${redisName.value}/conf/redis.conf`;
const pathRes = await loadBaseDir();
let path = `${pathRes.data}/apps/redis/${redisName.value}/conf/redis.conf`;
const res = await LoadFile({ path: path });
redisConf.value = res.data;
};

@ -28,6 +28,7 @@ import { oneDark } from '@codemirror/theme-one-dark';
import { nextTick, onMounted, ref, shallowRef } from 'vue';
import Submenu from '@/views/log/index.vue';
import { LoadFile } from '@/api/modules/files';
import { loadBaseDir } from '@/api/modules/setting';
const extensions = [javascript(), oneDark];
const logs = ref();
@ -37,7 +38,9 @@ const handleReady = (payload) => {
};
const loadSystemlogs = async () => {
const res = await LoadFile({ path: '/opt/1Panel/log/1Panel.log' });
const pathRes = await loadBaseDir();
let logPath = pathRes.data.replaceAll('/data', '/log');
const res = await LoadFile({ path: `${logPath}/1Panel.log` });
logs.value = res.data;
nextTick(() => {
const state = view.value.state;

@ -2,7 +2,8 @@
<div>
<Submenu activeName="backupaccount" />
<el-form label-position="left" label-width="130px" :v-key="reflash">
<el-row :gutter="20" style="margin-top: 20px">
<div style="margin-top: 20px"><span style="font-size: 16px; font-weight: 500">Local</span></div>
<el-row :gutter="20" style="margin-top: 10px">
<el-col :span="24">
<el-card>
<template #header>
@ -23,11 +24,14 @@
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 20px">
<div style="margin-top: 20px">
<span style="font-size: 16px; font-weight: 500">{{ $t('setting.thirdParty') }}</span>
</div>
<el-row :gutter="20" style="margin-top: 10px">
<el-col :span="12">
<el-card>
<template #header>
<svg-icon style="font-size: 7px" iconName="p-MINIO"></svg-icon>
<svg-icon style="font-size: 7px" iconName="p-minio"></svg-icon>
<span style="font-size: 16px; font-weight: 500">&nbsp;MIMIO</span>
<div style="float: right">
<el-button :disabled="minioData.id === 0" round @click="onBatchDelete(minioData)">
@ -63,7 +67,7 @@
<el-col :span="12">
<el-card>
<template #header>
<svg-icon style="font-size: 7px" iconName="p-OSS"></svg-icon>
<svg-icon style="font-size: 7px" iconName="p-oss"></svg-icon>
<span style="font-size: 16px; font-weight: 500">&nbsp;OSS</span>
<div style="float: right">
<el-button round :disabled="ossData.id === 0" @click="onBatchDelete(ossData)">
@ -241,7 +245,7 @@ const sftpData = ref<Backup.BackupInfo>({
vars: '',
varsJson: {
address: '',
port: 0,
port: 22,
},
createdAt: new Date(),
});
@ -303,7 +307,6 @@ const onOpenDialog = async (
varsJson: {},
},
) => {
console.log(rowData);
let params = {
title,
rowData: { ...rowData },

@ -16,13 +16,12 @@
:rules="Rules.requiredInput"
prop="monitorStatus"
>
<el-radio-group
<el-switch
@change="onSave(panelFormRef, 'MonitorStatus', form.monitorStatus)"
v-model="form.monitorStatus"
>
<el-radio-button label="enable">{{ $t('commons.button.enable') }}</el-radio-button>
<el-radio-button label="disable">{{ $t('commons.button.disable') }}</el-radio-button>
</el-radio-group>
active-value="enable"
inactive-value="disable"
/>
</el-form-item>
<el-form-item :label="$t('setting.storeDays')" :rules="Rules.number" prop="monitorStoreDays">
<el-input clearable v-model.number="form.monitorStoreDays">
@ -56,7 +55,7 @@ import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
const form = reactive({
monitorStatus: '',
monitorStatus: 'disable',
monitorStoreDays: 30,
});
const panelFormRef = ref<FormInstance>();
@ -78,7 +77,6 @@ const onSave = async (formEl: FormInstance | undefined, key: string, val: any) =
}
switch (key) {
case 'MonitorStoreDays':
case 'ServerPort':
val = val + '';
break;
}

@ -7,11 +7,7 @@
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form-item
:label="$t('commons.login.username')"
:rules="Rules.requiredInput"
prop="userName"
>
<el-form-item :label="$t('setting.user')" :rules="Rules.requiredInput" prop="userName">
<el-input clearable v-model="form.userName">
<template #append>
<el-button
@ -37,19 +33,32 @@
</el-input>
</el-form-item>
<!-- <el-form-item :label="$t('setting.panelPort')" :rules="Rules.port" prop="serverPort">
<el-input clearable v-model.number="form.serverPort">
<template #append>
<el-button
@click="onSavePort(panelFormRef, 'ServerPort', form.serverPort)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
</el-form-item> -->
<el-form-item :label="$t('setting.theme')" :rules="Rules.requiredSelect" prop="theme">
<el-radio-group
@change="onSave(panelFormRef, 'Theme', form.theme)"
v-model="form.theme"
>
<el-radio-button label="dark">
<el-icon><Moon /></el-icon>
{{ $t('setting.dark') }}
</el-radio-button>
<el-radio-button label="light">
<el-icon><Sunny /></el-icon>
{{ $t('setting.light') }}
</el-radio-button>
<el-radio-button label="dark">
<el-icon><Moon /></el-icon>
{{ $t('setting.dark') }}
</el-radio-button>
</el-radio-group>
</el-form-item>
@ -131,6 +140,7 @@ type FormInstance = InstanceType<typeof ElForm>;
const form = reactive({
userName: '',
email: '',
serverPort: 9999,
sessionTimeout: 0,
localTime: '',
panelName: '',
@ -149,6 +159,7 @@ const search = async () => {
form.userName = res.data.userName;
form.sessionTimeout = Number(res.data.sessionTimeout);
form.localTime = res.data.localTime;
form.serverPort = Number(res.data.serverPort);
form.panelName = res.data.panelName;
form.theme = res.data.theme;
form.language = res.data.language;
@ -205,6 +216,33 @@ const onSave = async (formEl: FormInstance | undefined, key: string, val: any) =
});
};
// const onSavePort = async (formEl: FormInstance | undefined, key: string, val: any) => {
// if (!formEl) return;
// const result = await formEl.validateField(key.replace(key[0], key[0].toLowerCase()), callback);
// if (!result) {
// return;
// }
// ElMessageBox.confirm(i18n.t('setting.portChangeHelper'), i18n.t('setting.portChange'), {
// confirmButtonText: i18n.t('commons.button.confirm'),
// cancelButtonText: i18n.t('commons.button.cancel'),
// type: 'info',
// }).then(async () => {
// loading.value = true;
// let param = {
// serverPort: val,
// };
// await updatePort(param)
// .then(() => {
// loading.value = false;
// ElMessage.success(i18n.t('commons.msg.operationSuccess'));
// search();
// })
// .catch(() => {
// loading.value = false;
// });
// });
// };
function countdown() {
count.value = TIME_COUNT.value;
show.value = true;

@ -7,11 +7,7 @@
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form-item
:label="$t('commons.login.password')"
:rules="Rules.requiredInput"
prop="password"
>
<el-form-item :label="$t('setting.passwd')" :rules="Rules.requiredInput" prop="password">
<el-input type="password" clearable disabled v-model="form.password">
<template #append>
<el-button icon="Setting" @click="onChangePassword">

@ -75,6 +75,7 @@ import { ElMessage, UploadFile, UploadFiles, UploadInstance, UploadProps } from
import { File } from '@/api/interface/file';
import { BatchDeleteFile, GetFilesList, UploadFileData } from '@/api/modules/files';
import { RecoverWebsiteByUpload } from '@/api/modules/website';
import { loadBaseDir } from '@/api/modules/setting';
const selects = ref<any>([]);
const baseDir = ref();
@ -95,11 +96,12 @@ interface DialogProps {
websiteName: string;
websiteType: string;
}
const acceptParams = (params: DialogProps): void => {
const acceptParams = async (params: DialogProps): Promise<void> => {
websiteName.value = params.websiteName;
websiteType.value = params.websiteType;
upVisiable.value = true;
baseDir.value = '/opt/1Panel/data/uploads/website/' + websiteName.value;
const pathRes = await loadBaseDir();
baseDir.value = `${pathRes.data}/uploads/website/${websiteName.value}`;
search();
};

Loading…
Cancel
Save